Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass user authentication to Tiller #1932

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions _proto/hapi/release/info.proto
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,7 @@ message Info {

// Description is human-friendly "log entry" about this release.
string Description = 5;

// Username is the authenticated user who performed this release.
string Username = 6;
}
2 changes: 1 addition & 1 deletion cmd/helm/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
get.release = args[0]
if get.client == nil {
get.client = helm.NewClient(helm.Host(settings.TillerHost))
get.client = helm.NewClient(helm.Host(settings.TillerHost), helm.WithContext(loadAuthHeaders))
}
return get.run()
},
Expand Down
2 changes: 1 addition & 1 deletion cmd/helm/get_manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func newGetManifestCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
get.release = args[0]
if get.client == nil {
get.client = helm.NewClient(helm.Host(settings.TillerHost))
get.client = helm.NewClient(helm.Host(settings.TillerHost), helm.WithContext(loadAuthHeaders))
}
return get.run()
},
Expand Down
3 changes: 2 additions & 1 deletion cmd/helm/get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package main

import (
"fmt"
"io"
"testing"

Expand All @@ -29,7 +30,7 @@ func TestGetCmd(t *testing.T) {
name: "get with a release",
resp: releaseMock(&releaseOptions{name: "thomas-guide"}),
args: []string{"thomas-guide"},
expected: "REVISION: 1\nRELEASED: (.*)\nCHART: foo-0.1.0-beta.1\nUSER-SUPPLIED VALUES:\nname: \"value\"\nCOMPUTED VALUES:\nname: value\n\nHOOKS:\n---\n# pre-install-hook\n" + mockHookTemplate + "\nMANIFEST:",
expected: fmt.Sprintf("REVISION: 1\nRELEASED: (.*)\nRELEASED BY: %s\nCHART: foo-0.1.0-beta.1\nUSER-SUPPLIED VALUES:\nname: \"value\"\nCOMPUTED VALUES:\nname: value\n\nHOOKS:\n---\n# pre-install-hook\n"+mockHookTemplate+"\nMANIFEST:", username),
},
{
name: "get requires release name arg",
Expand Down
42 changes: 41 additions & 1 deletion cmd/helm/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package main // import "k8s.io/helm/cmd/helm"

import (
"encoding/base64"
"errors"
"fmt"
"io/ioutil"
Expand All @@ -25,8 +26,10 @@ import (
"strings"

"github.com/spf13/cobra"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
Expand Down Expand Up @@ -279,6 +282,43 @@ func getInternalKubeClient(context string) (*rest.Config, internalclientset.Inte
return config, client, nil
}

func loadAuthHeaders(ctx context.Context) context.Context {
c, err := kube.GetConfig(kubeContext).ClientConfig()
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to extract authentication headers: %s\n", err)
os.Exit(1)
}
m := map[string]string{}

if c.AuthProvider != nil {
switch c.AuthProvider.Name {
case "gcp":
m[string(kube.Authorization)] = "Bearer " + c.AuthProvider.Config["access-token"]
case "oidc":
m[string(kube.Authorization)] = "Bearer " + c.AuthProvider.Config["id-token"]
default:
fmt.Fprintf(os.Stderr, "Unknown auth provider: %s\n", c.AuthProvider.Name)
os.Exit(1)
}
}

if len(c.BearerToken) != 0 {
m[string(kube.Authorization)] = "Bearer " + c.BearerToken
}
if len(c.Username) != 0 && len(c.Password) != 0 {
m[string(kube.Authorization)] = "Basic " + base64.StdEncoding.EncodeToString([]byte(c.Username+":"+c.Password))
}

md, _ := metadata.FromContext(ctx)
return metadata.NewContext(ctx, metadata.Join(md, metadata.New(m)))
}

// getKubeCmd is a convenience method for creating kubernetes cmd client
// for a given kubeconfig context
func getKubeCmd(context string) *kube.Client {
return kube.New(kube.GetConfig(context))
}

// ensureHelmClient returns a new helm client impl. if h is not nil.
func ensureHelmClient(h helm.Interface) helm.Interface {
if h != nil {
Expand All @@ -288,7 +328,7 @@ func ensureHelmClient(h helm.Interface) helm.Interface {
}

func newClient() helm.Interface {
options := []helm.Option{helm.Host(settings.TillerHost)}
options := []helm.Option{helm.Host(settings.TillerHost), helm.WithContext(loadAuthHeaders)}

if tlsVerify || tlsEnable {
tlsopts := tlsutil.Options{KeyFile: tlsKeyFile, CertFile: tlsCertFile, InsecureSkipVerify: true}
Expand Down
3 changes: 3 additions & 0 deletions cmd/helm/helm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ type releaseOptions struct {
namespace string
}

var username = "John"

func releaseMock(opts *releaseOptions) *release.Release {
date := timestamp.Timestamp{Seconds: 242085845, Nanos: 0}

Expand Down Expand Up @@ -104,6 +106,7 @@ func releaseMock(opts *releaseOptions) *release.Release {
LastDeployed: &date,
Status: &release.Status{Code: scode},
Description: "Release mock",
Username: username,
},
Chart: ch,
Config: &chart.Config{Raw: `name: "value"`},
Expand Down
17 changes: 9 additions & 8 deletions cmd/helm/history.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ configures the maximum length of the revision list returned.
The historical release set is printed as a formatted table, e.g:

$ helm history angry-bird --max=4
REVISION UPDATED STATUS CHART DESCRIPTION
1 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 Initial install
2 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 Upgraded successfully
3 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 Rolled back to 2
4 Mon Oct 3 10:15:13 2016 DEPLOYED alpine-0.1.0 Upgraded successfully
REVISION UPDATED STATUS CHART DESCRIPTION RELEASED BY
1 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 Initial install x
2 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 Upgraded successfully y
3 Mon Oct 3 10:15:13 2016 SUPERSEDED alpine-0.1.0 Rolled back to 2 z
4 Mon Oct 3 10:15:13 2016 DEPLOYED alpine-0.1.0 Upgraded successfully x
`

type historyCmd struct {
Expand All @@ -66,7 +66,7 @@ func newHistoryCmd(c helm.Interface, w io.Writer) *cobra.Command {
case len(args) == 0:
return errReleaseRequired
case his.helmc == nil:
his.helmc = helm.NewClient(helm.Host(settings.TillerHost))
his.helmc = helm.NewClient(helm.Host(settings.TillerHost), helm.WithContext(loadAuthHeaders))
}
his.rls = args[0]
return his.run()
Expand Down Expand Up @@ -94,15 +94,16 @@ func (cmd *historyCmd) run() error {
func formatHistory(rls []*release.Release) string {
tbl := uitable.New()
tbl.MaxColWidth = 60
tbl.AddRow("REVISION", "UPDATED", "STATUS", "CHART", "DESCRIPTION")
tbl.AddRow("REVISION", "UPDATED", "STATUS", "CHART", "DESCRIPTION", "RELEASED BY")
for i := len(rls) - 1; i >= 0; i-- {
r := rls[i]
c := formatChartname(r.Chart)
t := timeconv.String(r.Info.LastDeployed)
s := r.Info.Status.Code.String()
v := r.Version
d := r.Info.Description
tbl.AddRow(v, t, s, c, d)
u := r.Info.Username
tbl.AddRow(v, t, s, c, d, u)
}
return tbl.String()
}
Expand Down
5 changes: 3 additions & 2 deletions cmd/helm/history_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package main

import (
"bytes"
"fmt"
"regexp"
"testing"

Expand Down Expand Up @@ -50,7 +51,7 @@ func TestHistoryCmd(t *testing.T) {
mk("angry-bird", 2, rpb.Status_SUPERSEDED),
mk("angry-bird", 1, rpb.Status_SUPERSEDED),
},
xout: "REVISION\tUPDATED \tSTATUS \tCHART \tDESCRIPTION \n1 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\tRelease mock\n2 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\tRelease mock\n3 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\tRelease mock\n4 \t(.*)\tDEPLOYED \tfoo-0.1.0-beta.1\tRelease mock\n",
xout: fmt.Sprintf("REVISION\tUPDATED \tSTATUS \tCHART \tDESCRIPTION \tRELEASED BY\n1 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\tRelease mock\t%s \n2 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\tRelease mock\t%s \n3 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\tRelease mock\t%s \n4 \t(.*)\tDEPLOYED \tfoo-0.1.0-beta.1\tRelease mock\t%s \n", username, username, username, username),
},
{
cmds: "helm history --max=MAX RELEASE_NAME",
Expand All @@ -60,7 +61,7 @@ func TestHistoryCmd(t *testing.T) {
mk("angry-bird", 4, rpb.Status_DEPLOYED),
mk("angry-bird", 3, rpb.Status_SUPERSEDED),
},
xout: "REVISION\tUPDATED \tSTATUS \tCHART \tDESCRIPTION \n3 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\tRelease mock\n4 \t(.*)\tDEPLOYED \tfoo-0.1.0-beta.1\tRelease mock\n",
xout: fmt.Sprintf("REVISION\tUPDATED \tSTATUS \tCHART \tDESCRIPTION \tRELEASED BY\n3 \t(.*)\tSUPERSEDED\tfoo-0.1.0-beta.1\tRelease mock\t%s \n4 \t(.*)\tDEPLOYED \tfoo-0.1.0-beta.1\tRelease mock\t%s \n", username, username),
},
}

Expand Down
7 changes: 4 additions & 3 deletions cmd/helm/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func newListCmd(client helm.Interface, out io.Writer) *cobra.Command {
list.filter = strings.Join(args, " ")
}
if list.client == nil {
list.client = helm.NewClient(helm.Host(settings.TillerHost))
list.client = helm.NewClient(helm.Host(settings.TillerHost), helm.WithContext(loadAuthHeaders))
}
return list.run()
},
Expand Down Expand Up @@ -202,14 +202,15 @@ func (l *listCmd) statusCodes() []release.Status_Code {
func formatList(rels []*release.Release) string {
table := uitable.New()
table.MaxColWidth = 60
table.AddRow("NAME", "REVISION", "UPDATED", "STATUS", "CHART", "NAMESPACE")
table.AddRow("NAME", "REVISION", "UPDATED", "STATUS", "CHART", "NAMESPACE", "RELEASED BY")
for _, r := range rels {
c := fmt.Sprintf("%s-%s", r.Chart.Metadata.Name, r.Chart.Metadata.Version)
t := timeconv.String(r.Info.LastDeployed)
s := r.Info.Status.Code.String()
v := r.Version
n := r.Namespace
table.AddRow(r.Name, v, t, s, c, n)
u := r.Info.Username
table.AddRow(r.Name, v, t, s, c, n, u)
}
return table.String()
}
3 changes: 2 additions & 1 deletion cmd/helm/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package main

import (
"bytes"
"fmt"
"regexp"
"testing"

Expand Down Expand Up @@ -45,7 +46,7 @@ func TestListCmd(t *testing.T) {
resp: []*release.Release{
releaseMock(&releaseOptions{name: "atlas"}),
},
expected: "NAME \tREVISION\tUPDATED \tSTATUS \tCHART \tNAMESPACE\natlas\t1 \t(.*)\tDEPLOYED\tfoo-0.1.0-beta.1\tdefault \n",
expected: fmt.Sprintf("NAME \tREVISION\tUPDATED \tSTATUS \tCHART \tNAMESPACE\tRELEASED BY\natlas\t1 \t(.*)\tDEPLOYED\tfoo-0.1.0-beta.1\tdefault \t%s \n", username),
},
{
name: "list, one deployed, one failed",
Expand Down
2 changes: 2 additions & 0 deletions cmd/helm/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (

var printReleaseTemplate = `REVISION: {{.Release.Version}}
RELEASED: {{.ReleaseDate}}
RELEASED BY: {{.ReleasedBy}}
CHART: {{.Release.Chart.Metadata.Name}}-{{.Release.Chart.Metadata.Version}}
USER-SUPPLIED VALUES:
{{.Release.Config.Raw}}
Expand Down Expand Up @@ -62,6 +63,7 @@ func printRelease(out io.Writer, rel *release.Release) error {
"Release": rel,
"ComputedValues": cfgStr,
"ReleaseDate": timeconv.Format(rel.Info.LastDeployed, time.ANSIC),
"ReleasedBy": rel.Info.Username,
}
return tpl(printReleaseTemplate, data, out)
}
Expand Down
4 changes: 3 additions & 1 deletion cmd/helm/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ The status consists of:
- last deployment time
- k8s namespace in which the release lives
- state of the release (can be: UNKNOWN, DEPLOYED, DELETED, SUPERSEDED, FAILED or DELETING)
- name of the user who deployed the release
- list of resources that this release consists of, sorted by kind
- details on last test suite run, if applicable
- additional notes provided by the chart
Expand Down Expand Up @@ -67,7 +68,7 @@ func newStatusCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
status.release = args[0]
if status.client == nil {
status.client = helm.NewClient(helm.Host(settings.TillerHost))
status.client = helm.NewClient(helm.Host(settings.TillerHost), helm.WithContext(loadAuthHeaders))
}
return status.run()
},
Expand Down Expand Up @@ -96,6 +97,7 @@ func PrintStatus(out io.Writer, res *services.GetReleaseStatusResponse) {
}
fmt.Fprintf(out, "NAMESPACE: %s\n", res.Namespace)
fmt.Fprintf(out, "STATUS: %s\n", res.Info.Status.Code)
fmt.Fprintf(out, "RELEASED BY: %s\n", res.Info.Username)
fmt.Fprintf(out, "\n")
if len(res.Info.Status.Resources) > 0 {
re := regexp.MustCompile(" +")
Expand Down
14 changes: 8 additions & 6 deletions cmd/helm/status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ func TestStatusCmd(t *testing.T) {
{
name: "get status of a deployed release",
args: []string{"flummoxed-chickadee"},
expected: outputWithStatus("DEPLOYED\n\n"),
expected: outputWithStatus("DEPLOYED", username+"\n\n"),
rel: releaseMockWithStatus(&release.Status{
Code: release.Status_DEPLOYED,
}),
},
{
name: "get status of a deployed release with notes",
args: []string{"flummoxed-chickadee"},
expected: outputWithStatus("DEPLOYED\n\nNOTES:\nrelease notes\n"),
expected: outputWithStatus("DEPLOYED", username+"\n\nNOTES:\nrelease notes\n"),
rel: releaseMockWithStatus(&release.Status{
Code: release.Status_DEPLOYED,
Notes: "release notes",
Expand All @@ -67,7 +67,7 @@ func TestStatusCmd(t *testing.T) {
{
name: "get status of a deployed release with resources",
args: []string{"flummoxed-chickadee"},
expected: outputWithStatus("DEPLOYED\n\nRESOURCES:\nresource A\nresource B\n\n"),
expected: outputWithStatus("DEPLOYED", username+"\n\nRESOURCES:\nresource A\nresource B\n\n"),
rel: releaseMockWithStatus(&release.Status{
Code: release.Status_DEPLOYED,
Resources: "resource A\nresource B\n",
Expand Down Expand Up @@ -131,10 +131,11 @@ func TestStatusCmd(t *testing.T) {
}
}

func outputWithStatus(status string) string {
return fmt.Sprintf("LAST DEPLOYED: %s\nNAMESPACE: \nSTATUS: %s",
func outputWithStatus(status string, username string) string {
return fmt.Sprintf("LAST DEPLOYED: %s\nNAMESPACE: \nSTATUS: %s\nRELEASED BY: %s",
dateString,
status)
status,
username)
}

func releaseMockWithStatus(status *release.Status) *release.Release {
Expand All @@ -144,6 +145,7 @@ func releaseMockWithStatus(status *release.Status) *release.Release {
FirstDeployed: &date,
LastDeployed: &date,
Status: status,
Username: username,
},
}
}
5 changes: 3 additions & 2 deletions cmd/tiller/tiller.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ func newLogger(prefix string) *log.Logger {
}

func start(c *cobra.Command, args []string) {
clientset, err := kube.New(nil).ClientSet()
client := kube.New(nil)
clientset, err := client.ClientSet()
if err != nil {
logger.Fatalf("Cannot initialize Kubernetes connection: %s", err)
}
Expand Down Expand Up @@ -177,7 +178,7 @@ func start(c *cobra.Command, args []string) {
opts = append(opts, grpc.Creds(credentials.NewTLS(cfg)))
}

rootServer = tiller.NewServer(opts...)
rootServer = tiller.NewServer(client, opts...)

lstn, err := net.Listen("tcp", grpcAddr)
if err != nil {
Expand Down
Loading