From 90658a1b75ae2abea2b689fdf672c12c62d91ba0 Mon Sep 17 00:00:00 2001 From: Paul Czarkowski Date: Tue, 12 Mar 2019 13:43:18 -0500 Subject: [PATCH] Add namespace claim to config This allows you to set a JWT claim to use for the namespace field to be filled out in the kubeconfig. Useful if you give each user their own namespace. If left out, will be left blank in kubeconfig and thus default namespace. Signed-off-by: Paul Czarkowski --- cmd/gangway/handlers.go | 17 ++++++++++++++--- docs/configuration.md | 1 + internal/config/config.go | 6 ++++-- templates/commandline.tmpl | 12 ++++++------ 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/cmd/gangway/handlers.go b/cmd/gangway/handlers.go index d9bec5ee4..ac740932c 100644 --- a/cmd/gangway/handlers.go +++ b/cmd/gangway/handlers.go @@ -42,6 +42,7 @@ const ( type userInfo struct { ClusterName string Username string + Namespace string Email string IDToken string RefreshToken string @@ -110,8 +111,9 @@ func generateKubeConfig(cfg *userInfo) clientcmdapi.Config { { Name: cfg.ClusterName, Context: clientcmdapi.Context{ - Cluster: cfg.ClusterName, - AuthInfo: cfg.Email, + Cluster: cfg.ClusterName, + AuthInfo: cfg.Email, + Namespace: cfg.Namespace, }, }, }, @@ -344,6 +346,15 @@ func generateInfo(w http.ResponseWriter, r *http.Request) *userInfo { http.Error(w, "Could not parse Username claim", http.StatusInternalServerError) return nil } + namespace := "" + if cfg.NamespaceClaim != "" { + namespace, ok = claims[cfg.NamespaceClaim].(string) + if !ok { + http.Error(w, "Could not parse Namespace claim", http.StatusInternalServerError) + return nil + } + } + email := strings.Join([]string{username, cfg.ClusterName}, "@") if cfg.EmailClaim != "" { email, ok = claims[cfg.EmailClaim].(string) @@ -363,10 +374,10 @@ func generateInfo(w http.ResponseWriter, r *http.Request) *userInfo { if cfg.ClientSecret == "" { log.Warn("Setting an empty Client Secret should only be done if you have no other option and is an inherent security risk.") } - info := &userInfo{ ClusterName: cfg.ClusterName, Username: username, + Namespace: namespace, Email: email, IDToken: idToken, RefreshToken: refreshToken, diff --git a/docs/configuration.md b/docs/configuration.md index 87d41b31f..821bbf0e5 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -25,6 +25,7 @@ The following table describes the options that can be set via the YAML configura | `clientSecret` | API client secret as indicated by the identity provider | | `allowEmptyClientSecret` | Some identity providers accept an empty client secret, this is not generally considered a good idea. If you have to use an empty secret and accept the risks that come with that then you can set this to true. Defaults to `false`. | | `usernameClaim` | The JWT claim to use as the username. This is used in UI. This is combined with the clusterName for the "user" portion of the kubeconfig. Defaults to `nickname`. | +| `namespaceClaim` | The JWT claim to use as the namespace. This is used to set a namespace in the kubeconfig context. Leave unset for default namespace. | | `emailClaim` | Deprecated. Defaults to `email`. | | `apiServerURL` | The API server endpoint used to configure kubectl | | `clusterCAPath` | The path to find the CA bundle for the API server. Used to configure kubectl. This is typically mounted into the default location for workloads running on a Kubernetes cluster and doesn't need to be set. Defaults to `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt` | diff --git a/internal/config/config.go b/internal/config/config.go index 01a532426..d58f1d567 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -39,6 +39,7 @@ type Config struct { Scopes []string `yaml:"scopes" envconfig:"scopes"` UsernameClaim string `yaml:"usernameClaim" envconfig:"username_claim"` EmailClaim string `yaml:"emailClaim" envconfig:"email_claim"` + NamespaceClaim string `yaml:"namespaceClaim" envconfig:"namespace_claim"` ServeTLS bool `yaml:"serveTLS" envconfig:"serve_tls"` CertFile string `yaml:"certFile" envconfig:"cert_file"` KeyFile string `yaml:"keyFile" envconfig:"key_file"` @@ -55,12 +56,13 @@ type Config struct { func NewConfig(configFile string) (*Config, error) { cfg := &Config{ - Host: "0.0.0.0", - Port: 8080, + Host: "0.0.0.0", + Port: 8080, AllowEmptyClientSecret: false, Scopes: []string{"openid", "profile", "email", "offline_access"}, UsernameClaim: "nickname", EmailClaim: "email", + NamespaceClaim: "", ServeTLS: false, CertFile: "/etc/gangway/tls/tls.crt", KeyFile: "/etc/gangway/tls/tls.key", diff --git a/templates/commandline.tmpl b/templates/commandline.tmpl index 0787bb67b..bcc71894a 100644 --- a/templates/commandline.tmpl +++ b/templates/commandline.tmpl @@ -59,12 +59,12 @@ echo "{{ .ClusterCA }}" \ > ca-{{ .ClusterName }}.pem kubectl config set-cluster {{ .ClusterName }} --server={{ .APIServerURL }} --certificate-authority=ca-{{ .ClusterName }}.pem --embed-certs kubectl config set-credentials {{ .Email }} \ --auth-provider=oidc \ - --auth-provider-arg='idp-issuer-url={{ .IssuerURL }}' \ - --auth-provider-arg='client-id={{ .ClientID }}' \ - --auth-provider-arg='client-secret={{ .ClientSecret }}' \ - --auth-provider-arg='refresh-token={{ .RefreshToken }}' \ - --auth-provider-arg='id-token={{ .IDToken }}' -kubectl config set-context {{ .ClusterName }} --cluster={{ .ClusterName }} --user={{ .Email }} + --auth-provider-arg=idp-issuer-url={{ .IssuerURL }} \ + --auth-provider-arg=client-id={{ .ClientID }} \ + --auth-provider-arg=client-secret={{ .ClientSecret }} \ + --auth-provider-arg=refresh-token={{ .RefreshToken }} \ + --auth-provider-arg=id-token={{ .IDToken }} +kubectl config set-context {{ .ClusterName }} --cluster={{ .ClusterName }} --user={{ .Email }} --namespace={{ .Namespace }} kubectl config use-context {{ .ClusterName }} rm ca-{{ .ClusterName }}.pem