From b557a93f83e92760b2c763423e2e9be51c1f18ef Mon Sep 17 00:00:00 2001 From: Tommy Murphy Date: Thu, 1 Oct 2020 15:46:37 -0400 Subject: [PATCH] auth: support nodePublishSecretRef --- config/config.go | 12 ++++++++++- config/config_test.go | 46 +++++++++++++++++++++++++++++++++++++++++++ server/server.go | 17 ++++++++++------ 3 files changed, 68 insertions(+), 7 deletions(-) diff --git a/config/config.go b/config/config.go index 96474fc4..2794524c 100644 --- a/config/config.go +++ b/config/config.go @@ -17,12 +17,15 @@ package config import ( + "context" "encoding/json" "errors" "fmt" "log" "os" + "golang.org/x/oauth2" + "golang.org/x/oauth2/google" "gopkg.in/yaml.v2" "k8s.io/apimachinery/pkg/types" ) @@ -52,6 +55,7 @@ type MountConfig struct { PodInfo *PodInfo TargetPath string Permissions os.FileMode + TokenSource oauth2.TokenSource } // MountParams hold unparsed arguments from the CSI Driver from the mount event. @@ -85,10 +89,16 @@ func Parse(in *MountParams) (*MountConfig, error) { // The secrets here are the relevant CSI driver (k8s) secrets. See // https://kubernetes-csi.github.io/docs/secrets-and-credentials-storage-class.html - // Currently unused. if err := json.Unmarshal([]byte(in.KubeSecrets), &secret); err != nil { return nil, fmt.Errorf("failed to unmarshal secrets: %v", err) } + if _, ok := secret["key.json"]; ok { + creds, err := google.CredentialsFromJSON(context.Background(), []byte(secret["key.json"]), "https://www.googleapis.com/auth/cloud-platform") + if err != nil { + return nil, fmt.Errorf("unable to generate credentials from key.json: %w", err) + } + out.TokenSource = creds.TokenSource + } if os.Getenv("DEBUG") == "true" { log.Printf("attributes: %v", attrib) diff --git a/config/config_test.go b/config/config_test.go index 860198b0..a001e5b2 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -160,3 +160,49 @@ func TestParseErrors(t *testing.T) { }) } } + +func TestParseSecret(t *testing.T) { + in := &MountParams{ + Attributes: ` + { + "secrets": "- resourceName: \"projects/project/secrets/test/versions/latest\"\n fileName: \"good1.txt\"\n", + "csi.storage.k8s.io/pod.namespace": "default", + "csi.storage.k8s.io/pod.name": "mypod", + "csi.storage.k8s.io/pod.uid": "123", + "csi.storage.k8s.io/serviceAccount.name": "mysa" + } + `, + KubeSecrets: `{"key.json":"{\"private_key_id\": \"123\",\"private_key\": \"a-secret\",\"token_uri\": \"https://example.com/token\",\"type\": \"service_account\"}"}`, + TargetPath: "/tmp/foo", + Permissions: 777, + } + + got, err := Parse(in) + if err != nil { + t.Errorf("Parse() failed: %v", err) + } + if got == nil || got.TokenSource == nil { + t.Errorf("TokenSource missing.") + } +} + +func TestParseSecretError(t *testing.T) { + in := &MountParams{ + Attributes: ` + { + "secrets": "- resourceName: \"projects/project/secrets/test/versions/latest\"\n fileName: \"good1.txt\"\n", + "csi.storage.k8s.io/pod.namespace": "default", + "csi.storage.k8s.io/pod.name": "mypod", + "csi.storage.k8s.io/pod.uid": "123", + "csi.storage.k8s.io/serviceAccount.name": "mysa" + } + `, + KubeSecrets: `{"key.json":"a"}`, + TargetPath: "/tmp/foo", + Permissions: 777, + } + + if _, err := Parse(in); err == nil { + t.Errorf("Parse() succeeded for malformed input, want error") + } +} diff --git a/server/server.go b/server/server.go index 2030d734..5cdbc5c1 100644 --- a/server/server.go +++ b/server/server.go @@ -74,13 +74,18 @@ func (s *Server) Mount(ctx context.Context, req *v1alpha1.MountRequest) (*v1alph smOpts := []option.ClientOption{option.WithUserAgent(s.UA)} - // Build the workload identity auth token if possible (fallback to node ID) - token, err := auth.Token(ctx, cfg, s.Kubeconfig) - if err != nil { - log.Printf("unable to use workload identity: %v", err) - return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("Unable to obtain workload identity auth: %v", err)) + if cfg.TokenSource == nil { + // Build the workload identity auth token + token, err := auth.Token(ctx, cfg, s.Kubeconfig) + if err != nil { + log.Printf("unable to use workload identity: %v", err) + return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("Unable to obtain workload identity auth: %v", err)) + } else { + smOpts = append(smOpts, option.WithTokenSource(oauth2.StaticTokenSource(token))) + } } else { - smOpts = append(smOpts, option.WithTokenSource(oauth2.StaticTokenSource(token))) + // Use the secret provided in the CSI mount command for auth + smOpts = append(smOpts, option.WithTokenSource(cfg.TokenSource)) } // Build the secret manager client