Browse Source

wip: aws-jwt auth

Moritz Johner 5 years ago
parent
commit
472dcae852

+ 2 - 2
.github/workflows/e2e.yml

@@ -67,7 +67,7 @@ jobs:
       with:
       with:
         version: "v0.11.1"
         version: "v0.11.1"
         wait: 10m
         wait: 10m
-        node_image: kindest/node:v1.20.2
+        node_image: kindest/node:v1.20.7
         name: external-secrets
         name: external-secrets
 
 
     - name: Run e2e Tests
     - name: Run e2e Tests
@@ -124,7 +124,7 @@ jobs:
       with:
       with:
         version: "v0.11.1"
         version: "v0.11.1"
         wait: 10m
         wait: 10m
-        node_image: kindest/node:v1.20.2
+        node_image: kindest/node:v1.20.7
         name: external-secrets
         name: external-secrets
 
 
     - name: Run e2e Tests
     - name: Run e2e Tests

+ 7 - 3
apis/externalsecrets/v1alpha1/secretstore_aws_types.go

@@ -20,7 +20,8 @@ import (
 
 
 // AWSAuth contains a secretRef for credentials.
 // AWSAuth contains a secretRef for credentials.
 type AWSAuth struct {
 type AWSAuth struct {
-	SecretRef AWSAuthSecretRef `json:"secretRef"`
+	SecretRef *AWSAuthSecretRef `json:"secretRef,omitempty"`
+	JWTAuth   *AWSJWTAuth       `json:"jwt,omitempty"`
 }
 }
 
 
 // AWSAuthSecretRef holds secret references for aws credentials
 // AWSAuthSecretRef holds secret references for aws credentials
@@ -33,6 +34,10 @@ type AWSAuthSecretRef struct {
 	SecretAccessKey esmeta.SecretKeySelector `json:"secretAccessKeySecretRef,omitempty"`
 	SecretAccessKey esmeta.SecretKeySelector `json:"secretAccessKeySecretRef,omitempty"`
 }
 }
 
 
+type AWSJWTAuth struct {
+	ServiceAccountRef *esmeta.ServiceAccountSelector `json:"serviceAccountRef,omitempty"`
+}
+
 // AWSServiceType is a enum that defines the service/API that is used to fetch the secrets.
 // AWSServiceType is a enum that defines the service/API that is used to fetch the secrets.
 // +kubebuilder:validation:Enum=SecretsManager;ParameterStore
 // +kubebuilder:validation:Enum=SecretsManager;ParameterStore
 type AWSServiceType string
 type AWSServiceType string
@@ -54,9 +59,8 @@ type AWSProvider struct {
 	// Auth defines the information necessary to authenticate against AWS
 	// Auth defines the information necessary to authenticate against AWS
 	// if not set aws sdk will infer credentials from your environment
 	// if not set aws sdk will infer credentials from your environment
 	// see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials
 	// see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials
-	// +nullable
 	// +optional
 	// +optional
-	Auth *AWSAuth `json:"auth"`
+	Auth AWSAuth `json:"auth"`
 
 
 	// Role is a Role ARN which the SecretManager provider will assume
 	// Role is a Role ARN which the SecretManager provider will assume
 	// +optional
 	// +optional

+ 30 - 5
apis/externalsecrets/v1alpha1/zz_generated.deepcopy.go

@@ -27,7 +27,16 @@ import (
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *AWSAuth) DeepCopyInto(out *AWSAuth) {
 func (in *AWSAuth) DeepCopyInto(out *AWSAuth) {
 	*out = *in
 	*out = *in
-	in.SecretRef.DeepCopyInto(&out.SecretRef)
+	if in.SecretRef != nil {
+		in, out := &in.SecretRef, &out.SecretRef
+		*out = new(AWSAuthSecretRef)
+		(*in).DeepCopyInto(*out)
+	}
+	if in.JWTAuth != nil {
+		in, out := &in.JWTAuth, &out.JWTAuth
+		*out = new(AWSJWTAuth)
+		(*in).DeepCopyInto(*out)
+	}
 }
 }
 
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSAuth.
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSAuth.
@@ -58,15 +67,31 @@ func (in *AWSAuthSecretRef) DeepCopy() *AWSAuthSecretRef {
 }
 }
 
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *AWSProvider) DeepCopyInto(out *AWSProvider) {
+func (in *AWSJWTAuth) DeepCopyInto(out *AWSJWTAuth) {
 	*out = *in
 	*out = *in
-	if in.Auth != nil {
-		in, out := &in.Auth, &out.Auth
-		*out = new(AWSAuth)
+	if in.ServiceAccountRef != nil {
+		in, out := &in.ServiceAccountRef, &out.ServiceAccountRef
+		*out = new(metav1.ServiceAccountSelector)
 		(*in).DeepCopyInto(*out)
 		(*in).DeepCopyInto(*out)
 	}
 	}
 }
 }
 
 
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSJWTAuth.
+func (in *AWSJWTAuth) DeepCopy() *AWSJWTAuth {
+	if in == nil {
+		return nil
+	}
+	out := new(AWSJWTAuth)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AWSProvider) DeepCopyInto(out *AWSProvider) {
+	*out = *in
+	in.Auth.DeepCopyInto(&out.Auth)
+}
+
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSProvider.
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSProvider.
 func (in *AWSProvider) DeepCopy() *AWSProvider {
 func (in *AWSProvider) DeepCopy() *AWSProvider {
 	if in == nil {
 	if in == nil {

+ 6 - 0
deploy/charts/external-secrets/templates/rbac.yaml

@@ -43,6 +43,12 @@ rules:
     - "create"
     - "create"
     - "update"
     - "update"
     - "delete"
     - "delete"
+  - apiGroups:
+    - ""
+    resources:
+    - "serviceaccounts/token"
+    verbs:
+    - "create"
   - apiGroups:
   - apiGroups:
     - ""
     - ""
     resources:
     resources:

+ 19 - 3
deploy/crds/external-secrets.io_clustersecretstores.yaml

@@ -62,8 +62,26 @@ spec:
                         description: 'Auth defines the information necessary to authenticate
                         description: 'Auth defines the information necessary to authenticate
                           against AWS if not set aws sdk will infer credentials from
                           against AWS if not set aws sdk will infer credentials from
                           your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials'
                           your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials'
-                        nullable: true
                         properties:
                         properties:
+                          jwt:
+                            properties:
+                              serviceAccountRef:
+                                description: A reference to a ServiceAccount resource.
+                                properties:
+                                  name:
+                                    description: The name of the ServiceAccount resource
+                                      being referred to.
+                                    type: string
+                                  namespace:
+                                    description: Namespace of the resource being referred
+                                      to. Ignored if referent is not cluster-scoped.
+                                      cluster-scoped defaults to the namespace of
+                                      the referent.
+                                    type: string
+                                required:
+                                - name
+                                type: object
+                            type: object
                           secretRef:
                           secretRef:
                             description: AWSAuthSecretRef holds secret references
                             description: AWSAuthSecretRef holds secret references
                               for aws credentials both AccessKeyID and SecretAccessKey
                               for aws credentials both AccessKeyID and SecretAccessKey
@@ -114,8 +132,6 @@ spec:
                                 - name
                                 - name
                                 type: object
                                 type: object
                             type: object
                             type: object
-                        required:
-                        - secretRef
                         type: object
                         type: object
                       region:
                       region:
                         description: AWS Region to be used for the provider
                         description: AWS Region to be used for the provider

+ 19 - 3
deploy/crds/external-secrets.io_secretstores.yaml

@@ -62,8 +62,26 @@ spec:
                         description: 'Auth defines the information necessary to authenticate
                         description: 'Auth defines the information necessary to authenticate
                           against AWS if not set aws sdk will infer credentials from
                           against AWS if not set aws sdk will infer credentials from
                           your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials'
                           your environment see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials'
-                        nullable: true
                         properties:
                         properties:
+                          jwt:
+                            properties:
+                              serviceAccountRef:
+                                description: A reference to a ServiceAccount resource.
+                                properties:
+                                  name:
+                                    description: The name of the ServiceAccount resource
+                                      being referred to.
+                                    type: string
+                                  namespace:
+                                    description: Namespace of the resource being referred
+                                      to. Ignored if referent is not cluster-scoped.
+                                      cluster-scoped defaults to the namespace of
+                                      the referent.
+                                    type: string
+                                required:
+                                - name
+                                type: object
+                            type: object
                           secretRef:
                           secretRef:
                             description: AWSAuthSecretRef holds secret references
                             description: AWSAuthSecretRef holds secret references
                               for aws credentials both AccessKeyID and SecretAccessKey
                               for aws credentials both AccessKeyID and SecretAccessKey
@@ -114,8 +132,6 @@ spec:
                                 - name
                                 - name
                                 type: object
                                 type: object
                             type: object
                             type: object
-                        required:
-                        - secretRef
                         type: object
                         type: object
                       region:
                       region:
                         description: AWS Region to be used for the provider
                         description: AWS Region to be used for the provider

+ 1 - 1
e2e/Makefile

@@ -4,7 +4,7 @@ SHELL       := /bin/bash
 
 
 IMG_TAG     = test
 IMG_TAG     = test
 IMG         = local/external-secrets-e2e:$(IMG_TAG)
 IMG         = local/external-secrets-e2e:$(IMG_TAG)
-K8S_VERSION = "1.19.1"
+K8S_VERSION = "1.20.7"
 
 
 start-kind: ## Start kind cluster
 start-kind: ## Start kind cluster
 	kind create cluster \
 	kind create cluster \

+ 6 - 0
e2e/k8s/eso.values.yaml

@@ -5,3 +5,9 @@ image:
 extraEnv:
 extraEnv:
   - name: AWS_SECRETSMANAGER_ENDPOINT
   - name: AWS_SECRETSMANAGER_ENDPOINT
     value: "http://localstack.default"
     value: "http://localstack.default"
+  - name: AWS_STS_ENDPOINT
+    value: "http://localstack.default"
+  - name: AWS_SSM_ENDPOINT
+    value: "http://localstack.default"
+  - name: LOGLEVEL
+    value: "debug"

+ 2 - 0
e2e/k8s/localstack.values.yaml

@@ -1,3 +1,5 @@
+image:
+  tag: "0.12.14"
 service:
 service:
   type: ClusterIP
   type: ClusterIP
   edgeService:
   edgeService:

+ 8 - 0
e2e/kind.yaml

@@ -1,6 +1,14 @@
 kind: Cluster
 kind: Cluster
 apiVersion: kind.x-k8s.io/v1alpha4
 apiVersion: kind.x-k8s.io/v1alpha4
 kubeadmConfigPatches:
 kubeadmConfigPatches:
+- |
+  kind: ClusterConfiguration
+  apiServer:
+    extraArgs:
+      api-audiences: "sts.amazonaws.com"
+      service-account-key-file: "/etc/kubernetes/pki/sa.pub"
+      service-account-signing-key-file: "/etc/kubernetes/pki/sa.key"
+      service-account-issuer: "https://s3-XXXXXXXXXX.amazonaws.com/XXXXXXXXXXXXXXXXXXXXX"
 - |
 - |
   apiVersion: kubelet.config.k8s.io/v1beta1
   apiVersion: kubelet.config.k8s.io/v1beta1
   kind: KubeletConfiguration
   kind: KubeletConfiguration

+ 160 - 7
e2e/suite/aws/secretsmanager.go

@@ -62,8 +62,8 @@ var _ = Describe("[aws] ", func() {
 					AWS: &esv1alpha1.AWSProvider{
 					AWS: &esv1alpha1.AWSProvider{
 						Service: esv1alpha1.AWSServiceSecretsManager,
 						Service: esv1alpha1.AWSServiceSecretsManager,
 						Region:  "us-east-1",
 						Region:  "us-east-1",
-						Auth: &esv1alpha1.AWSAuth{
-							SecretRef: esv1alpha1.AWSAuthSecretRef{
+						Auth: esv1alpha1.AWSAuth{
+							SecretRef: &esv1alpha1.AWSAuthSecretRef{
 								AccessKeyID: esmeta.SecretKeySelector{
 								AccessKeyID: esmeta.SecretKeySelector{
 									Name: f.Namespace.Name,
 									Name: f.Namespace.Name,
 									Key:  "kid",
 									Key:  "kid",
@@ -183,11 +183,11 @@ var _ = Describe("[aws] ", func() {
 		secretValue := fmt.Sprintf(
 		secretValue := fmt.Sprintf(
 			`{
 			`{
 				"name": {"first": "%s", "last": "Anderson"},
 				"name": {"first": "%s", "last": "Anderson"},
-				"friends": 
-				[ 
-					{"first": "Dale", "last": "Murphy"}, 
-					{"first": "%s", "last": "Craig"}, 
-					{"first": "Jane", "last": "Murphy"} 
+				"friends":
+				[
+					{"first": "Dale", "last": "Murphy"},
+					{"first": "%s", "last": "Craig"},
+					{"first": "Jane", "last": "Murphy"}
 				]
 				]
 			}`, targetSecretValue1, targetSecretValue2)
 			}`, targetSecretValue1, targetSecretValue2)
 		err := CreateAWSSecretsManagerSecret(
 		err := CreateAWSSecretsManagerSecret(
@@ -232,4 +232,157 @@ var _ = Describe("[aws] ", func() {
 		})
 		})
 		Expect(err).ToNot(HaveOccurred())
 		Expect(err).ToNot(HaveOccurred())
 	})
 	})
+
+	It("should sync secrets with cluster secret store", func() {
+		By("creating a AWS SM Secret")
+		clusterStoreName := fmt.Sprintf("cluster-%s", f.Namespace.Name)
+		targetSecretKey := "FOOB"
+		secretKey := fmt.Sprintf("%s-%s", f.Namespace.Name, "one")
+		secretValue := "MYVAL"
+		err := CreateAWSSecretsManagerSecret(
+			localstackURL,
+			secretKey, secretValue)
+		Expect(err).ToNot(HaveOccurred())
+
+		css := &esv1alpha1.ClusterSecretStore{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: clusterStoreName,
+			},
+			Spec: esv1alpha1.SecretStoreSpec{
+				Provider: &esv1alpha1.SecretStoreProvider{
+					AWS: &esv1alpha1.AWSProvider{
+						Service: esv1alpha1.AWSServiceSecretsManager,
+						Region:  "us-east-1",
+						Auth: esv1alpha1.AWSAuth{
+							SecretRef: &esv1alpha1.AWSAuthSecretRef{
+								AccessKeyID: esmeta.SecretKeySelector{
+									Name:      f.Namespace.Name,
+									Namespace: &f.Namespace.Name,
+									Key:       "kid",
+								},
+								SecretAccessKey: esmeta.SecretKeySelector{
+									Name:      f.Namespace.Name,
+									Namespace: &f.Namespace.Name,
+									Key:       "sak",
+								},
+							},
+						},
+					},
+				},
+			},
+		}
+		err = f.CRClient.Create(context.Background(), css)
+		Expect(err).ToNot(HaveOccurred())
+		defer func() {
+			err = f.CRClient.Delete(context.Background(), css)
+			Expect(err).ToNot(HaveOccurred())
+		}()
+
+		err = f.CRClient.Create(context.Background(), &esv1alpha1.ExternalSecret{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "datafrom-sync",
+				Namespace: f.Namespace.Name,
+			},
+			Spec: esv1alpha1.ExternalSecretSpec{
+				SecretStoreRef: esv1alpha1.SecretStoreRef{
+					Name: clusterStoreName,
+					Kind: esv1alpha1.ClusterSecretStoreKind,
+				},
+				Target: esv1alpha1.ExternalSecretTarget{
+					Name: targetSecret,
+				},
+				Data: []esv1alpha1.ExternalSecretData{
+					{
+						SecretKey: targetSecretKey,
+						RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
+							Key: secretKey,
+						},
+					},
+				},
+			},
+		})
+		Expect(err).ToNot(HaveOccurred())
+
+		_, err = f.WaitForSecretValue(f.Namespace.Name, targetSecret, map[string][]byte{
+			targetSecretKey: []byte(secretValue),
+		})
+		Expect(err).ToNot(HaveOccurred())
+	})
+
+	It("should use jwt auth tokens", func() {
+		By("creating a AWS SM Secret")
+		clusterStoreName := fmt.Sprintf("cluster-jwt-%s", f.Namespace.Name)
+		targetSecretKey := "FOOB"
+		saName := "my-sa"
+		secretKey := fmt.Sprintf("%s-%s", f.Namespace.Name, "jwt-token")
+		secretValue := "MYVAL"
+		err := CreateAWSSecretsManagerSecret(
+			localstackURL,
+			secretKey, secretValue)
+		Expect(err).ToNot(HaveOccurred())
+
+		err = f.CRClient.Create(context.Background(), &v1.ServiceAccount{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      saName,
+				Namespace: f.Namespace.Name,
+				Annotations: map[string]string{
+					"eks.amazonaws.com/role-arn": "arn:aws:iam::account:role/my-example-role",
+				},
+			},
+		})
+		Expect(err).ToNot(HaveOccurred())
+
+		err = f.CRClient.Create(context.Background(), &esv1alpha1.ClusterSecretStore{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: clusterStoreName,
+			},
+			Spec: esv1alpha1.SecretStoreSpec{
+				Provider: &esv1alpha1.SecretStoreProvider{
+					AWS: &esv1alpha1.AWSProvider{
+						Service: esv1alpha1.AWSServiceSecretsManager,
+						Region:  "us-east-1",
+						Auth: esv1alpha1.AWSAuth{
+							JWTAuth: &esv1alpha1.AWSJWTAuth{
+								ServiceAccountRef: &esmeta.ServiceAccountSelector{
+									Name:      saName,
+									Namespace: &f.Namespace.Name,
+								},
+							},
+						},
+					},
+				},
+			},
+		})
+		Expect(err).ToNot(HaveOccurred())
+
+		err = f.CRClient.Create(context.Background(), &esv1alpha1.ExternalSecret{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "jwt-sync",
+				Namespace: f.Namespace.Name,
+			},
+			Spec: esv1alpha1.ExternalSecretSpec{
+				SecretStoreRef: esv1alpha1.SecretStoreRef{
+					Name: clusterStoreName,
+					Kind: esv1alpha1.ClusterSecretStoreKind,
+				},
+				Target: esv1alpha1.ExternalSecretTarget{
+					Name: targetSecret,
+				},
+				Data: []esv1alpha1.ExternalSecretData{
+					{
+						SecretKey: targetSecretKey,
+						RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
+							Key: secretKey,
+						},
+					},
+				},
+			},
+		})
+		Expect(err).ToNot(HaveOccurred())
+
+		_, err = f.WaitForSecretValue(f.Namespace.Name, targetSecret, map[string][]byte{
+			targetSecretKey: []byte(secretValue),
+		})
+		Expect(err).ToNot(HaveOccurred())
+	})
 })
 })

+ 2 - 2
e2e/suite/aws/util.go

@@ -18,7 +18,7 @@ import (
 	"github.com/aws/aws-sdk-go/aws/session"
 	"github.com/aws/aws-sdk-go/aws/session"
 	"github.com/aws/aws-sdk-go/service/secretsmanager"
 	"github.com/aws/aws-sdk-go/service/secretsmanager"
 
 
-	prov "github.com/external-secrets/external-secrets/pkg/provider/aws"
+	"github.com/external-secrets/external-secrets/pkg/provider/aws/auth"
 )
 )
 
 
 // CreateAWSSecretsManagerSecret creates a sm secret with the given value.
 // CreateAWSSecretsManagerSecret creates a sm secret with the given value.
@@ -26,7 +26,7 @@ func CreateAWSSecretsManagerSecret(endpoint, secretName, secretValue string) err
 	sess, err := session.NewSessionWithOptions(session.Options{
 	sess, err := session.NewSessionWithOptions(session.Options{
 		Config: aws.Config{
 		Config: aws.Config{
 			Credentials: credentials.NewStaticCredentials("foobar", "foobar", "secret-manager"),
 			Credentials: credentials.NewStaticCredentials("foobar", "foobar", "secret-manager"),
-			EndpointResolver: prov.ResolveEndpointWithServiceMap(map[string]string{
+			EndpointResolver: auth.ResolveEndpointWithServiceMap(map[string]string{
 				"secretsmanager": endpoint,
 				"secretsmanager": endpoint,
 			}),
 			}),
 			Region: aws.String("eu-east-1"),
 			Region: aws.String("eu-east-1"),

+ 2 - 0
go.mod

@@ -55,6 +55,7 @@ require (
 	github.com/hashicorp/vault/api v1.0.5-0.20210224012239-b540be4b7ec4
 	github.com/hashicorp/vault/api v1.0.5-0.20210224012239-b540be4b7ec4
 	github.com/kr/pretty v0.2.1 // indirect
 	github.com/kr/pretty v0.2.1 // indirect
 	github.com/lestrrat-go/jwx v1.2.1
 	github.com/lestrrat-go/jwx v1.2.1
+	github.com/namsral/flag v1.7.4-pre
 	github.com/onsi/ginkgo v1.16.4
 	github.com/onsi/ginkgo v1.16.4
 	github.com/onsi/gomega v1.13.0
 	github.com/onsi/gomega v1.13.0
 	github.com/pierrec/lz4 v2.5.2+incompatible // indirect
 	github.com/pierrec/lz4 v2.5.2+incompatible // indirect
@@ -64,6 +65,7 @@ require (
 	github.com/stretchr/testify v1.7.0
 	github.com/stretchr/testify v1.7.0
 	github.com/tidwall/gjson v1.7.5
 	github.com/tidwall/gjson v1.7.5
 	github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a
 	github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a
+	go.uber.org/zap v1.17.0
 	golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
 	golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
 	golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 // indirect
 	golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 // indirect
 	golang.org/x/oauth2 v0.0.0-20210201163806-010130855d6c
 	golang.org/x/oauth2 v0.0.0-20210201163806-010130855d6c

+ 2 - 0
go.sum

@@ -501,6 +501,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
 github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/namsral/flag v1.7.4-pre h1:b2ScHhoCUkbsq0d2C15Mv+VU8bl8hAXV8arnWiOHNZs=
+github.com/namsral/flag v1.7.4-pre/go.mod h1:OXldTctbM6SWH1K899kPZcf65KxJiD7MsceFUpB5yDo=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=

+ 12 - 2
main.go

@@ -15,9 +15,10 @@ limitations under the License.
 package main
 package main
 
 
 import (
 import (
-	"flag"
 	"os"
 	"os"
 
 
+	"github.com/namsral/flag"
+	"go.uber.org/zap/zapcore"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime"
 	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
 	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
 	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
 	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
@@ -43,14 +44,23 @@ func main() {
 	var metricsAddr string
 	var metricsAddr string
 	var controllerClass string
 	var controllerClass string
 	var enableLeaderElection bool
 	var enableLeaderElection bool
+	var loglevel string
 	flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
 	flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
 	flag.StringVar(&controllerClass, "controller-class", "default", "the controller is instantiated with a specific controller name and filters ES based on this property")
 	flag.StringVar(&controllerClass, "controller-class", "default", "the controller is instantiated with a specific controller name and filters ES based on this property")
 	flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
 	flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
 		"Enable leader election for controller manager. "+
 		"Enable leader election for controller manager. "+
 			"Enabling this will ensure there is only one active controller manager.")
 			"Enabling this will ensure there is only one active controller manager.")
+	flag.StringVar(&loglevel, "loglevel", "info", "loglevel to use")
 	flag.Parse()
 	flag.Parse()
 
 
-	ctrl.SetLogger(zap.New(zap.UseDevMode(true)))
+	var lvl zapcore.Level
+	err := lvl.UnmarshalText([]byte(loglevel))
+	if err != nil {
+		setupLog.Error(err, "error unmarshaling loglevel")
+		os.Exit(1)
+	}
+	logger := zap.New(zap.Level(lvl))
+	ctrl.SetLogger(logger)
 
 
 	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
 	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
 		Scheme:             scheme,
 		Scheme:             scheme,

+ 150 - 99
pkg/provider/aws/auth/auth.go

@@ -17,21 +17,24 @@ package auth
 import (
 import (
 	"context"
 	"context"
 	"fmt"
 	"fmt"
-	"os"
 
 
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws/credentials"
 	"github.com/aws/aws-sdk-go/aws/credentials"
 	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
 	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
-	"github.com/aws/aws-sdk-go/aws/endpoints"
+	"github.com/aws/aws-sdk-go/aws/defaults"
 	"github.com/aws/aws-sdk-go/aws/request"
 	"github.com/aws/aws-sdk-go/aws/request"
 	"github.com/aws/aws-sdk-go/aws/session"
 	"github.com/aws/aws-sdk-go/aws/session"
-	awssess "github.com/aws/aws-sdk-go/aws/session"
 	"github.com/aws/aws-sdk-go/service/sts"
 	"github.com/aws/aws-sdk-go/service/sts"
-	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
-	"github.com/external-secrets/external-secrets/pkg/provider/aws/util"
+	"github.com/aws/aws-sdk-go/service/sts/stsiface"
 	v1 "k8s.io/api/core/v1"
 	v1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/client-go/kubernetes"
 	ctrl "sigs.k8s.io/controller-runtime"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/client"
+	ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
+
+	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
+	"github.com/external-secrets/external-secrets/pkg/provider/aws/util"
 )
 )
 
 
 // Config contains configuration to create a new AWS provider.
 // Config contains configuration to create a new AWS provider.
@@ -44,9 +47,7 @@ type Config struct {
 var log = ctrl.Log.WithName("provider").WithName("aws")
 var log = ctrl.Log.WithName("provider").WithName("aws")
 
 
 const (
 const (
-	SecretsManagerEndpointEnv = "AWS_SECRETSMANAGER_ENDPOINT"
-	STSEndpointEnv            = "AWS_STS_ENDPOINT"
-	SSMEndpointEnv            = "AWS_SSM_ENDPOINT"
+	roleARNAnnotation = "eks.amazonaws.com/role-arn"
 
 
 	errInvalidClusterStoreMissingAKIDNamespace = "invalid ClusterSecretStore: missing AWS AccessKeyID Namespace"
 	errInvalidClusterStoreMissingAKIDNamespace = "invalid ClusterSecretStore: missing AWS AccessKeyID Namespace"
 	errInvalidClusterStoreMissingSAKNamespace  = "invalid ClusterSecretStore: missing AWS SecretAccessKey Namespace"
 	errInvalidClusterStoreMissingSAKNamespace  = "invalid ClusterSecretStore: missing AWS SecretAccessKey Namespace"
@@ -56,125 +57,175 @@ const (
 	errMissingAKID                             = "missing AccessKeyID"
 	errMissingAKID                             = "missing AccessKeyID"
 )
 )
 
 
-// New creates a new aws session based on a store
-// it looks up credentials at the provided secrets.
-func New(ctx context.Context, store esv1alpha1.GenericStore, kube client.Client, namespace string, assumeRoler STSProvider) (*session.Session, error) {
+// New creates a new aws session based on the provided store
+// it uses the following authentication mechanisms in order:
+// * service-account token authentication via AssumeRoleWithWebIdentity
+// * static credentials from a Kind=Secret, optionally with doing a AssumeRole.
+// * sdk default provider chain, see: https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html#credentials-default
+func New(ctx context.Context, store esv1alpha1.GenericStore, kube client.Client, namespace string, assumeRoler STSProvider, jwtProvider jwtProviderFactory) (*session.Session, error) {
 	prov, err := util.GetAWSProvider(store)
 	prov, err := util.GetAWSProvider(store)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	var sak, aks string
-	// use provided credentials via secret reference
-	if prov.Auth != nil {
-		log.V(1).Info("fetching secrets for authentication")
-		ke := client.ObjectKey{
-			Name:      prov.Auth.SecretRef.AccessKeyID.Name,
-			Namespace: namespace, // default to ExternalSecret namespace
-		}
-		// only ClusterStore is allowed to set namespace (and then it's required)
-		if store.GetObjectKind().GroupVersionKind().Kind == esv1alpha1.ClusterSecretStoreKind {
-			if prov.Auth.SecretRef.AccessKeyID.Namespace == nil {
-				return nil, fmt.Errorf(errInvalidClusterStoreMissingAKIDNamespace)
-			}
-			ke.Namespace = *prov.Auth.SecretRef.AccessKeyID.Namespace
-		}
-		akSecret := v1.Secret{}
-		err := kube.Get(ctx, ke, &akSecret)
+	var creds *credentials.Credentials
+
+	// use credentials via service account token
+	jwtAuth := prov.Auth.JWTAuth
+	if jwtAuth != nil {
+		creds, err = sessionFromServiceAccount(ctx, prov, store, kube, namespace, jwtProvider)
 		if err != nil {
 		if err != nil {
-			return nil, fmt.Errorf(errFetchAKIDSecret, err)
-		}
-		ke = client.ObjectKey{
-			Name:      prov.Auth.SecretRef.SecretAccessKey.Name,
-			Namespace: namespace, // default to ExternalSecret namespace
+			return nil, err
 		}
 		}
-		// only ClusterStore is allowed to set namespace (and then it's required)
-		if store.GetObjectKind().GroupVersionKind().Kind == esv1alpha1.ClusterSecretStoreKind {
-			if prov.Auth.SecretRef.SecretAccessKey.Namespace == nil {
-				return nil, fmt.Errorf(errInvalidClusterStoreMissingSAKNamespace)
-			}
-			ke.Namespace = *prov.Auth.SecretRef.SecretAccessKey.Namespace
-		}
-		sakSecret := v1.Secret{}
-		err = kube.Get(ctx, ke, &sakSecret)
+	}
+
+	// use credentials from sercretRef
+	secretRef := prov.Auth.SecretRef
+	if secretRef != nil {
+		log.V(1).Info("using credentials from secretRef")
+		creds, err = sessionFromSecretRef(ctx, prov, store, kube, namespace)
 		if err != nil {
 		if err != nil {
-			return nil, fmt.Errorf(errFetchSAKSecret, err)
-		}
-		sak = string(sakSecret.Data[prov.Auth.SecretRef.SecretAccessKey.Key])
-		aks = string(akSecret.Data[prov.Auth.SecretRef.AccessKeyID.Key])
-		if sak == "" {
-			return nil, fmt.Errorf(errMissingSAK)
-		}
-		if aks == "" {
-			return nil, fmt.Errorf(errMissingAKID)
+			return nil, err
 		}
 		}
 	}
 	}
-	session, err := NewSession(sak, aks, prov.Region, prov.Role, assumeRoler)
+
+	config := aws.NewConfig().WithEndpointResolver(ResolveEndpoint())
+	if creds != nil {
+		config.WithCredentials(creds)
+	}
+	if prov.Region != "" {
+		config.WithRegion(prov.Region)
+	}
+	handlers := defaults.Handlers()
+	handlers.Build.PushBack(request.WithAppendUserAgent("external-secrets"))
+	sess, err := session.NewSessionWithOptions(session.Options{
+		Config:            *config,
+		Handlers:          handlers,
+		SharedConfigState: session.SharedConfigDisable,
+	})
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	session.Config.EndpointResolver = ResolveEndpoint()
-	return session, nil
+	if prov.Role != "" {
+		stsclient := assumeRoler(sess)
+		sess.Config.WithCredentials(stscreds.NewCredentialsWithClient(stsclient, prov.Role))
+	}
+	log.Info("using aws session", "region", *sess.Config.Region, "credentials", creds)
+	return sess, nil
 }
 }
 
 
-// New creates a new aws session based on the supported input methods.
-// https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials
-func NewSession(sak, aks, region, role string, stsprovider STSProvider) (*awssess.Session, error) {
-	config := aws.NewConfig()
-	sessionOpts := awssess.Options{
-		Config: *config,
+func sessionFromSecretRef(ctx context.Context, prov *esv1alpha1.AWSProvider, store esv1alpha1.GenericStore, kube client.Client, namespace string) (*credentials.Credentials, error) {
+	ke := client.ObjectKey{
+		Name:      prov.Auth.SecretRef.AccessKeyID.Name,
+		Namespace: namespace, // default to ExternalSecret namespace
 	}
 	}
-	if sak != "" && aks != "" {
-		sessionOpts.Config.Credentials = credentials.NewStaticCredentials(aks, sak, "")
-		sessionOpts.SharedConfigState = awssess.SharedConfigDisable
+	// only ClusterStore is allowed to set namespace (and then it's required)
+	if store.GetObjectKind().GroupVersionKind().Kind == esv1alpha1.ClusterSecretStoreKind {
+		if prov.Auth.SecretRef.AccessKeyID.Namespace == nil {
+			return nil, fmt.Errorf(errInvalidClusterStoreMissingAKIDNamespace)
+		}
+		ke.Namespace = *prov.Auth.SecretRef.AccessKeyID.Namespace
 	}
 	}
-	sess, err := awssess.NewSessionWithOptions(sessionOpts)
+	akSecret := v1.Secret{}
+	err := kube.Get(ctx, ke, &akSecret)
 	if err != nil {
 	if err != nil {
-		return nil, fmt.Errorf("unable to create aws session: %w", err)
+		return nil, fmt.Errorf(errFetchAKIDSecret, err)
 	}
 	}
-	if region != "" {
-		log.V(1).Info("using region", "region", region)
-		sess.Config.WithRegion(region)
+	ke = client.ObjectKey{
+		Name:      prov.Auth.SecretRef.SecretAccessKey.Name,
+		Namespace: namespace, // default to ExternalSecret namespace
 	}
 	}
-
-	if role != "" {
-		log.V(1).Info("assuming role", "role", role)
-		stsclient := stsprovider(sess)
-		sess.Config.WithCredentials(stscreds.NewCredentialsWithClient(stsclient, role))
+	// only ClusterStore is allowed to set namespace (and then it's required)
+	if store.GetObjectKind().GroupVersionKind().Kind == esv1alpha1.ClusterSecretStoreKind {
+		if prov.Auth.SecretRef.SecretAccessKey.Namespace == nil {
+			return nil, fmt.Errorf(errInvalidClusterStoreMissingSAKNamespace)
+		}
+		ke.Namespace = *prov.Auth.SecretRef.SecretAccessKey.Namespace
 	}
 	}
-	sess.Handlers.Build.PushBack(request.WithAppendUserAgent("external-secrets"))
-	return sess, nil
+	sakSecret := v1.Secret{}
+	err = kube.Get(ctx, ke, &sakSecret)
+	if err != nil {
+		return nil, fmt.Errorf(errFetchSAKSecret, err)
+	}
+	sak := string(sakSecret.Data[prov.Auth.SecretRef.SecretAccessKey.Key])
+	aks := string(akSecret.Data[prov.Auth.SecretRef.AccessKeyID.Key])
+	if sak == "" {
+		return nil, fmt.Errorf(errMissingSAK)
+	}
+	if aks == "" {
+		return nil, fmt.Errorf(errMissingAKID)
+	}
+
+	return credentials.NewStaticCredentials(aks, sak, ""), err
 }
 }
 
 
-type STSProvider func(*awssess.Session) stscreds.AssumeRoler
+func sessionFromServiceAccount(ctx context.Context, prov *esv1alpha1.AWSProvider, store esv1alpha1.GenericStore, kube client.Client, namespace string, jwtProvider jwtProviderFactory) (*credentials.Credentials, error) {
+	if store.GetObjectKind().GroupVersionKind().Kind == esv1alpha1.ClusterSecretStoreKind {
+		namespace = *prov.Auth.JWTAuth.ServiceAccountRef.Namespace
+	}
+	name := prov.Auth.JWTAuth.ServiceAccountRef.Name
+	sa := v1.ServiceAccount{}
+	err := kube.Get(ctx, types.NamespacedName{
+		Name:      name,
+		Namespace: namespace,
+	}, &sa)
+	if err != nil {
+		return nil, err
+	}
+	// the service account is expected to have a well-known annotation
+	// this is used as input to assumeRoleWithWebIdentity
+	roleArn := sa.Annotations[roleARNAnnotation]
+	if roleArn == "" {
+		return nil, fmt.Errorf("an IAM role must be associated with service account %s (namespace: %s)", name, namespace)
+	}
+	jwtProv, err := jwtProvider(name, namespace, roleArn, prov.Region)
+	if err != nil {
+		return nil, err
+	}
 
 
-func DefaultSTSProvider(sess *awssess.Session) stscreds.AssumeRoler {
-	return sts.New(sess)
+	log.V(1).Info("using credentials via service account", "role", roleArn, "region", prov.Region)
+	return credentials.NewCredentials(jwtProv), nil
 }
 }
 
 
-// ResolveEndpoint returns a ResolverFunc with
-// customizable endpoints.
-func ResolveEndpoint() endpoints.ResolverFunc {
-	customEndpoints := make(map[string]string)
-	if v := os.Getenv(SecretsManagerEndpointEnv); v != "" {
-		customEndpoints["secretsmanager"] = v
+type jwtProviderFactory func(name, namespace, roleArn, region string) (credentials.Provider, error)
+
+// DefaultJWTProvider returns a credentials.Provider that calls the AssumeRoleWithWebidentity
+// controller-runtime/client does not support TokenRequest or other subresource APIs
+// so we need to construct our own client and use it to fetch tokens.
+func DefaultJWTProvider(name, namespace, roleArn, region string) (credentials.Provider, error) {
+	cfg, err := ctrlcfg.GetConfig()
+	if err != nil {
+		return nil, err
 	}
 	}
-	if v := os.Getenv(SSMEndpointEnv); v != "" {
-		customEndpoints["ssm"] = v
+	clientset, err := kubernetes.NewForConfig(cfg)
+	if err != nil {
+		return nil, err
 	}
 	}
-	if v := os.Getenv(STSEndpointEnv); v != "" {
-		customEndpoints["sts"] = v
+	handlers := defaults.Handlers()
+	handlers.Build.PushBack(request.WithAppendUserAgent("external-secrets"))
+	awscfg := aws.NewConfig().WithEndpointResolver(ResolveEndpoint())
+	if region != "" {
+		awscfg.WithRegion(region)
+	}
+	sess, err := session.NewSessionWithOptions(session.Options{
+		Config:            *awscfg,
+		SharedConfigState: session.SharedConfigDisable,
+		Handlers:          handlers,
+	})
+	if err != nil {
+		return nil, err
 	}
 	}
-	return ResolveEndpointWithServiceMap(customEndpoints)
+	tokenFetcher := &authTokenFetcher{
+		Namespace:      namespace,
+		ServiceAccount: name,
+		k8sClient:      clientset.CoreV1(),
+	}
+
+	return stscreds.NewWebIdentityRoleProviderWithToken(
+		sts.New(sess), roleArn, "external-secrets-provider-aws", tokenFetcher), nil
 }
 }
 
 
-func ResolveEndpointWithServiceMap(customEndpoints map[string]string) endpoints.ResolverFunc {
-	defaultResolver := endpoints.DefaultResolver()
-	return func(service, region string, opts ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
-		if ep, ok := customEndpoints[service]; ok {
-			return endpoints.ResolvedEndpoint{
-				URL: ep,
-			}, nil
-		}
-		return defaultResolver.EndpointFor(service, region, opts...)
-	}
+type STSProvider func(*session.Session) stsiface.STSAPI
+
+func DefaultSTSProvider(sess *session.Session) stsiface.STSAPI {
+	return sts.New(sess)
 }
 }

+ 486 - 43
pkg/provider/aws/auth/auth_test.go

@@ -15,57 +15,87 @@ limitations under the License.
 package auth
 package auth
 
 
 import (
 import (
+	"context"
+	"os"
+	"strings"
 	"testing"
 	"testing"
 	"time"
 	"time"
 
 
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
-	"github.com/aws/aws-sdk-go/aws/session"
+	"github.com/aws/aws-sdk-go/aws/credentials"
+	awssess "github.com/aws/aws-sdk-go/aws/session"
 	"github.com/aws/aws-sdk-go/service/sts"
 	"github.com/aws/aws-sdk-go/service/sts"
+	"github.com/aws/aws-sdk-go/service/sts/stsiface"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/assert"
+	authv1 "k8s.io/api/authentication/v1"
+	v1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
 
 
-	fake "github.com/external-secrets/external-secrets/pkg/provider/aws/auth/fake"
+	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
+	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
+	fakesess "github.com/external-secrets/external-secrets/pkg/provider/aws/auth/fake"
 )
 )
 
 
-func TestSession(t *testing.T) {
-	tbl := []struct {
-		test              string
-		aks               string
-		sak               string
-		region            string
-		role              string
-		sts               STSProvider
-		expectedKeyID     string
-		expectedSecretKey string
-	}{
+func TestNewSession(t *testing.T) {
+	rows := []TestSessionRow{
 		{
 		{
-			test:              "test default role provider",
-			aks:               "2222",
-			sak:               "1111",
-			region:            "xxxxx",
-			role:              "",
-			sts:               DefaultSTSProvider,
-			expectedSecretKey: "1111",
-			expectedKeyID:     "2222",
+			name:      "nil store",
+			expectErr: "found nil store",
+			store:     nil,
 		},
 		},
 		{
 		{
-			test:   "test custom sts provider",
-			aks:    "1111",
-			sak:    "2222",
-			region: "xxxxx",
-			role:   "zzzzz",
-			sts: func(*session.Session) stscreds.AssumeRoler {
-				return &fake.AssumeRoler{
+			name:      "not store spec",
+			expectErr: "storeSpec is missing provider",
+			store:     &esv1alpha1.SecretStore{},
+		},
+		{
+			name:      "store spec has no provider",
+			expectErr: "storeSpec is missing provider",
+			store: &esv1alpha1.SecretStore{
+				Spec: esv1alpha1.SecretStoreSpec{},
+			},
+		},
+		{
+			name:      "spec has no awssm field",
+			expectErr: "Missing AWS field",
+			store: &esv1alpha1.SecretStore{
+				Spec: esv1alpha1.SecretStoreSpec{
+					Provider: &esv1alpha1.SecretStoreProvider{},
+				},
+			},
+		},
+		{
+			name: "configure aws using environment variables",
+			store: &esv1alpha1.SecretStore{
+				Spec: esv1alpha1.SecretStoreSpec{
+					Provider: &esv1alpha1.SecretStoreProvider{
+						AWS: &esv1alpha1.AWSProvider{},
+					},
+				},
+			},
+			env: map[string]string{
+				"AWS_ACCESS_KEY_ID":     "1111",
+				"AWS_SECRET_ACCESS_KEY": "2222",
+			},
+			expectProvider:    true,
+			expectedKeyID:     "1111",
+			expectedSecretKey: "2222",
+		},
+		{
+			name: "configure aws using environment variables + assume role",
+			stsProvider: func(*awssess.Session) stsiface.STSAPI {
+				return &fakesess.AssumeRoler{
 					AssumeRoleFunc: func(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) {
 					AssumeRoleFunc: func(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) {
-						assert.Equal(t, *input.RoleArn, "zzzzz")
+						assert.Equal(t, *input.RoleArn, "foo-bar-baz")
 						return &sts.AssumeRoleOutput{
 						return &sts.AssumeRoleOutput{
 							AssumedRoleUser: &sts.AssumedRoleUser{
 							AssumedRoleUser: &sts.AssumedRoleUser{
 								Arn:           aws.String("1123132"),
 								Arn:           aws.String("1123132"),
 								AssumedRoleId: aws.String("xxxxx"),
 								AssumedRoleId: aws.String("xxxxx"),
 							},
 							},
 							Credentials: &sts.Credentials{
 							Credentials: &sts.Credentials{
-								SecretAccessKey: aws.String("3333"),
-								AccessKeyId:     aws.String("4444"),
+								AccessKeyId:     aws.String("3333"),
+								SecretAccessKey: aws.String("4444"),
 								Expiration:      aws.Time(time.Now().Add(time.Hour)),
 								Expiration:      aws.Time(time.Now().Add(time.Hour)),
 								SessionToken:    aws.String("6666"),
 								SessionToken:    aws.String("6666"),
 							},
 							},
@@ -73,19 +103,432 @@ func TestSession(t *testing.T) {
 					},
 					},
 				}
 				}
 			},
 			},
-			expectedSecretKey: "3333",
-			expectedKeyID:     "4444",
+			store: &esv1alpha1.SecretStore{
+				Spec: esv1alpha1.SecretStoreSpec{
+					Provider: &esv1alpha1.SecretStoreProvider{
+						AWS: &esv1alpha1.AWSProvider{
+							Role: "foo-bar-baz",
+						},
+					},
+				},
+			},
+			env: map[string]string{
+				"AWS_ACCESS_KEY_ID":     "1111",
+				"AWS_SECRET_ACCESS_KEY": "2222",
+			},
+			expectProvider:    true,
+			expectedKeyID:     "3333",
+			expectedSecretKey: "4444",
+		},
+		{
+			name:      "error out when secret with credentials does not exist",
+			namespace: "foo",
+			store: &esv1alpha1.SecretStore{
+				Spec: esv1alpha1.SecretStoreSpec{
+					Provider: &esv1alpha1.SecretStoreProvider{
+						AWS: &esv1alpha1.AWSProvider{
+							Auth: esv1alpha1.AWSAuth{
+								SecretRef: &esv1alpha1.AWSAuthSecretRef{
+									AccessKeyID: esmeta.SecretKeySelector{
+										Name: "othersecret",
+										Key:  "one",
+									},
+									SecretAccessKey: esmeta.SecretKeySelector{
+										Name: "othersecret",
+										Key:  "two",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			expectErr: `secrets "othersecret" not found`,
+		},
+		{
+			name:      "use credentials from secret to configure aws",
+			namespace: "foo",
+			store: &esv1alpha1.SecretStore{
+				Spec: esv1alpha1.SecretStoreSpec{
+					Provider: &esv1alpha1.SecretStoreProvider{
+						AWS: &esv1alpha1.AWSProvider{
+							Auth: esv1alpha1.AWSAuth{
+								SecretRef: &esv1alpha1.AWSAuthSecretRef{
+									AccessKeyID: esmeta.SecretKeySelector{
+										Name: "onesecret",
+										// Namespace is not set
+										Key: "one",
+									},
+									SecretAccessKey: esmeta.SecretKeySelector{
+										Name: "onesecret",
+										// Namespace is not set
+										Key: "two",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			secrets: []v1.Secret{
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "onesecret",
+						Namespace: "foo",
+					},
+					Data: map[string][]byte{
+						"one": []byte("1111"),
+						"two": []byte("2222"),
+					},
+				},
+			},
+			expectProvider:    true,
+			expectedKeyID:     "1111",
+			expectedSecretKey: "2222",
+		},
+		{
+			name:      "error out when secret key does not exist",
+			namespace: "foo",
+			store: &esv1alpha1.SecretStore{
+				Spec: esv1alpha1.SecretStoreSpec{
+					Provider: &esv1alpha1.SecretStoreProvider{
+						AWS: &esv1alpha1.AWSProvider{
+							Auth: esv1alpha1.AWSAuth{
+								SecretRef: &esv1alpha1.AWSAuthSecretRef{
+									AccessKeyID: esmeta.SecretKeySelector{
+										Name: "brokensecret",
+										Key:  "one",
+									},
+									SecretAccessKey: esmeta.SecretKeySelector{
+										Name: "brokensecret",
+										Key:  "two",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			secrets: []v1.Secret{
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "brokensecret",
+						Namespace: "foo",
+					},
+					Data: map[string][]byte{},
+				},
+			},
+			expectErr: "missing SecretAccessKey",
+		},
+		{
+			name:      "should not be able to access secrets from different namespace",
+			namespace: "foo",
+			store: &esv1alpha1.SecretStore{
+				Spec: esv1alpha1.SecretStoreSpec{
+					Provider: &esv1alpha1.SecretStoreProvider{
+						AWS: &esv1alpha1.AWSProvider{
+							Auth: esv1alpha1.AWSAuth{
+								SecretRef: &esv1alpha1.AWSAuthSecretRef{
+									AccessKeyID: esmeta.SecretKeySelector{
+										Name:      "onesecret",
+										Namespace: aws.String("evil"), // this should not be possible!
+										Key:       "one",
+									},
+									SecretAccessKey: esmeta.SecretKeySelector{
+										Name:      "onesecret",
+										Namespace: aws.String("evil"),
+										Key:       "two",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			secrets: []v1.Secret{
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "onesecret",
+						Namespace: "evil",
+					},
+					Data: map[string][]byte{
+						"one": []byte("1111"),
+						"two": []byte("2222"),
+					},
+				},
+			},
+			expectErr: `secrets "onesecret" not found`,
+		},
+		{
+			name:      "ClusterStore should use credentials from a specific namespace",
+			namespace: "es-namespace",
+			store: &esv1alpha1.ClusterSecretStore{
+				TypeMeta: metav1.TypeMeta{
+					APIVersion: esv1alpha1.ClusterSecretStoreKindAPIVersion,
+					Kind:       esv1alpha1.ClusterSecretStoreKind,
+				},
+				Spec: esv1alpha1.SecretStoreSpec{
+					Provider: &esv1alpha1.SecretStoreProvider{
+						AWS: &esv1alpha1.AWSProvider{
+							Auth: esv1alpha1.AWSAuth{
+								SecretRef: &esv1alpha1.AWSAuthSecretRef{
+									AccessKeyID: esmeta.SecretKeySelector{
+										Name:      "onesecret",
+										Namespace: aws.String("platform-team-ns"),
+										Key:       "one",
+									},
+									SecretAccessKey: esmeta.SecretKeySelector{
+										Name:      "onesecret",
+										Namespace: aws.String("platform-team-ns"),
+										Key:       "two",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			secrets: []v1.Secret{
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "onesecret",
+						Namespace: "platform-team-ns",
+					},
+					Data: map[string][]byte{
+						"one": []byte("1111"),
+						"two": []byte("2222"),
+					},
+				},
+			},
+			expectProvider:    true,
+			expectedKeyID:     "1111",
+			expectedSecretKey: "2222",
+		},
+		{
+			name:      "namespace is mandatory when using ClusterStore with SecretKeySelector",
+			namespace: "es-namespace",
+			store: &esv1alpha1.ClusterSecretStore{
+				TypeMeta: metav1.TypeMeta{
+					APIVersion: esv1alpha1.ClusterSecretStoreKindAPIVersion,
+					Kind:       esv1alpha1.ClusterSecretStoreKind,
+				},
+				Spec: esv1alpha1.SecretStoreSpec{
+					Provider: &esv1alpha1.SecretStoreProvider{
+						AWS: &esv1alpha1.AWSProvider{
+							Auth: esv1alpha1.AWSAuth{
+								SecretRef: &esv1alpha1.AWSAuthSecretRef{
+									AccessKeyID: esmeta.SecretKeySelector{
+										Name: "onesecret",
+										Key:  "one",
+									},
+									SecretAccessKey: esmeta.SecretKeySelector{
+										Name: "onesecret",
+										Key:  "two",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			expectErr: "invalid ClusterSecretStore: missing AWS AccessKeyID Namespace",
+		},
+		{
+			name:      "jwt auth via cluster secret store",
+			namespace: "es-namespace",
+			sa: &v1.ServiceAccount{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "my-service-account",
+					Namespace: "other-ns",
+					Annotations: map[string]string{
+						roleARNAnnotation: "my-sa-role",
+					},
+				},
+			},
+			jwtProvider: func(name, namespace, roleArn, region string) (credentials.Provider, error) {
+				assert.Equal(t, "my-service-account", name)
+				assert.Equal(t, "other-ns", namespace)
+				assert.Equal(t, "my-sa-role", roleArn)
+				return fakesess.CredentialsProvider{
+					RetrieveFunc: func() (credentials.Value, error) {
+						return credentials.Value{
+							AccessKeyID:     "3333",
+							SecretAccessKey: "4444",
+							SessionToken:    "1234",
+							ProviderName:    "fake",
+						}, nil
+					},
+					IsExpiredFunc: func() bool { return false },
+				}, nil
+			},
+			store: &esv1alpha1.ClusterSecretStore{
+				TypeMeta: metav1.TypeMeta{
+					APIVersion: esv1alpha1.ClusterSecretStoreKindAPIVersion,
+					Kind:       esv1alpha1.ClusterSecretStoreKind,
+				},
+				Spec: esv1alpha1.SecretStoreSpec{
+					Provider: &esv1alpha1.SecretStoreProvider{
+						AWS: &esv1alpha1.AWSProvider{
+							Auth: esv1alpha1.AWSAuth{
+								JWTAuth: &esv1alpha1.AWSJWTAuth{
+									ServiceAccountRef: &esmeta.ServiceAccountSelector{
+										Name:      "my-service-account",
+										Namespace: aws.String("other-ns"),
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			expectProvider:    true,
+			expectedKeyID:     "3333",
+			expectedSecretKey: "4444",
 		},
 		},
 	}
 	}
-	for i := range tbl {
-		row := tbl[i]
-		t.Run(row.test, func(t *testing.T) {
-			sess, err := NewSession(row.sak, row.aks, row.region, row.role, row.sts)
-			assert.Nil(t, err)
-			creds, err := sess.Config.Credentials.Get()
-			assert.Nil(t, err)
-			assert.Equal(t, row.expectedKeyID, creds.AccessKeyID)
-			assert.Equal(t, row.expectedSecretKey, creds.SecretAccessKey)
+	for i := range rows {
+		row := rows[i]
+		t.Run(row.name, func(t *testing.T) {
+			testRow(t, row)
 		})
 		})
 	}
 	}
 }
 }
+
+type TestSessionRow struct {
+	name              string
+	store             esv1alpha1.GenericStore
+	secrets           []v1.Secret
+	sa                *v1.ServiceAccount
+	jwtProvider       jwtProviderFactory
+	namespace         string
+	stsProvider       STSProvider
+	expectProvider    bool
+	expectErr         string
+	expectedKeyID     string
+	expectedSecretKey string
+	env               map[string]string
+}
+
+func testRow(t *testing.T, row TestSessionRow) {
+	kc := clientfake.NewClientBuilder().Build()
+	for i := range row.secrets {
+		err := kc.Create(context.Background(), &row.secrets[i])
+		assert.Nil(t, err)
+	}
+	for k, v := range row.env {
+		os.Setenv(k, v)
+	}
+	if row.sa != nil {
+		err := kc.Create(context.Background(), row.sa)
+		assert.Nil(t, err)
+	}
+	err := kc.Create(context.Background(), &authv1.TokenRequest{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "my-service-account",
+			Namespace: "other-ns",
+		},
+	})
+	assert.Nil(t, err)
+	defer func() {
+		for k := range row.env {
+			os.Unsetenv(k)
+		}
+	}()
+	s, err := New(context.Background(), row.store, kc, row.namespace, row.stsProvider, row.jwtProvider)
+	if !ErrorContains(err, row.expectErr) {
+		t.Errorf("expected error %s but found %s", row.expectErr, err.Error())
+	}
+	// pass test on expected error
+	if err != nil {
+		return
+	}
+	if row.expectProvider && s == nil {
+		t.Errorf("expected provider object, found nil")
+		return
+	}
+	creds, _ := s.Config.Credentials.Get()
+	assert.Equal(t, row.expectedKeyID, creds.AccessKeyID)
+	assert.Equal(t, row.expectedSecretKey, creds.SecretAccessKey)
+}
+
+func TestSMEnvCredentials(t *testing.T) {
+	k8sClient := clientfake.NewClientBuilder().Build()
+	os.Setenv("AWS_SECRET_ACCESS_KEY", "1111")
+	os.Setenv("AWS_ACCESS_KEY_ID", "2222")
+	defer os.Unsetenv("AWS_SECRET_ACCESS_KEY")
+	defer os.Unsetenv("AWS_ACCESS_KEY_ID")
+	s, err := New(context.Background(), &esv1alpha1.SecretStore{
+		Spec: esv1alpha1.SecretStoreSpec{
+			Provider: &esv1alpha1.SecretStoreProvider{
+				// defaults
+				AWS: &esv1alpha1.AWSProvider{},
+			},
+		},
+	}, k8sClient, "example-ns", DefaultSTSProvider, nil)
+	assert.Nil(t, err)
+	assert.NotNil(t, s)
+	creds, err := s.Config.Credentials.Get()
+	assert.Nil(t, err)
+	assert.Equal(t, creds.AccessKeyID, "2222")
+	assert.Equal(t, creds.SecretAccessKey, "1111")
+}
+
+func TestSMAssumeRole(t *testing.T) {
+	k8sClient := clientfake.NewClientBuilder().Build()
+	sts := &fakesess.AssumeRoler{
+		AssumeRoleFunc: func(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) {
+			// make sure the correct role is passed in
+			assert.Equal(t, *input.RoleArn, "my-awesome-role")
+			return &sts.AssumeRoleOutput{
+				AssumedRoleUser: &sts.AssumedRoleUser{
+					Arn:           aws.String("1123132"),
+					AssumedRoleId: aws.String("xxxxx"),
+				},
+				Credentials: &sts.Credentials{
+					AccessKeyId:     aws.String("3333"),
+					SecretAccessKey: aws.String("4444"),
+					Expiration:      aws.Time(time.Now().Add(time.Hour)),
+					SessionToken:    aws.String("6666"),
+				},
+			}, nil
+		},
+	}
+	os.Setenv("AWS_SECRET_ACCESS_KEY", "1111")
+	os.Setenv("AWS_ACCESS_KEY_ID", "2222")
+	defer os.Unsetenv("AWS_SECRET_ACCESS_KEY")
+	defer os.Unsetenv("AWS_ACCESS_KEY_ID")
+	s, err := New(context.Background(), &esv1alpha1.SecretStore{
+		Spec: esv1alpha1.SecretStoreSpec{
+			Provider: &esv1alpha1.SecretStoreProvider{
+				// do assume role!
+				AWS: &esv1alpha1.AWSProvider{
+					Role: "my-awesome-role",
+				},
+			},
+		},
+	}, k8sClient, "example-ns", func(se *awssess.Session) stsiface.STSAPI {
+		// check if the correct temporary credentials were used
+		creds, err := se.Config.Credentials.Get()
+		assert.Nil(t, err)
+		assert.Equal(t, creds.AccessKeyID, "2222")
+		assert.Equal(t, creds.SecretAccessKey, "1111")
+		return sts
+	}, nil)
+	assert.Nil(t, err)
+	assert.NotNil(t, s)
+
+	creds, err := s.Config.Credentials.Get()
+	assert.Nil(t, err)
+	assert.Equal(t, creds.AccessKeyID, "3333")
+	assert.Equal(t, creds.SecretAccessKey, "4444")
+}
+
+func ErrorContains(out error, want string) bool {
+	if out == nil {
+		return want == ""
+	}
+	if want == "" {
+		return false
+	}
+	return strings.Contains(out.Error(), want)
+}

+ 25 - 1
pkg/provider/aws/auth/fake/assumeroler.go

@@ -13,12 +13,36 @@ limitations under the License.
 */
 */
 package fake
 package fake
 
 
-import "github.com/aws/aws-sdk-go/service/sts"
+import (
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/credentials"
+	"github.com/aws/aws-sdk-go/aws/request"
+	"github.com/aws/aws-sdk-go/service/sts"
+	"github.com/aws/aws-sdk-go/service/sts/stsiface"
+)
 
 
 type AssumeRoler struct {
 type AssumeRoler struct {
+	stsiface.STSAPI
 	AssumeRoleFunc func(*sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
 	AssumeRoleFunc func(*sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
 }
 }
 
 
 func (f *AssumeRoler) AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) {
 func (f *AssumeRoler) AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) {
 	return f.AssumeRoleFunc(input)
 	return f.AssumeRoleFunc(input)
 }
 }
+
+func (f *AssumeRoler) AssumeRoleWithContext(ctx aws.Context, input *sts.AssumeRoleInput, opts ...request.Option) (*sts.AssumeRoleOutput, error) {
+	return f.AssumeRoleFunc(input)
+}
+
+type CredentialsProvider struct {
+	RetrieveFunc  func() (credentials.Value, error)
+	IsExpiredFunc func() bool
+}
+
+func (t CredentialsProvider) Retrieve() (credentials.Value, error) {
+	return t.RetrieveFunc()
+}
+
+func (t CredentialsProvider) IsExpired() bool {
+	return t.IsExpiredFunc()
+}

+ 54 - 0
pkg/provider/aws/auth/resolver.go

@@ -0,0 +1,54 @@
+/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package auth
+
+import (
+	"os"
+
+	"github.com/aws/aws-sdk-go/aws/endpoints"
+)
+
+const (
+	SecretsManagerEndpointEnv = "AWS_SECRETSMANAGER_ENDPOINT"
+	STSEndpointEnv            = "AWS_STS_ENDPOINT"
+	SSMEndpointEnv            = "AWS_SSM_ENDPOINT"
+)
+
+// ResolveEndpoint returns a ResolverFunc with
+// customizable endpoints.
+func ResolveEndpoint() endpoints.ResolverFunc {
+	customEndpoints := make(map[string]string)
+	if v := os.Getenv(SecretsManagerEndpointEnv); v != "" {
+		customEndpoints["secretsmanager"] = v
+	}
+	if v := os.Getenv(SSMEndpointEnv); v != "" {
+		customEndpoints["ssm"] = v
+	}
+	if v := os.Getenv(STSEndpointEnv); v != "" {
+		customEndpoints["sts"] = v
+	}
+	return ResolveEndpointWithServiceMap(customEndpoints)
+}
+
+func ResolveEndpointWithServiceMap(customEndpoints map[string]string) endpoints.ResolverFunc {
+	defaultResolver := endpoints.DefaultResolver()
+	return func(service, region string, opts ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
+		if ep, ok := customEndpoints[service]; ok {
+			return endpoints.ResolvedEndpoint{
+				URL: ep,
+			}, nil
+		}
+		return defaultResolver.EndpointFor(service, region, opts...)
+	}
+}

+ 58 - 0
pkg/provider/aws/auth/resolver_test.go

@@ -0,0 +1,58 @@
+/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package auth
+
+import (
+	"os"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestResolver(t *testing.T) {
+	tbl := []struct {
+		env     string
+		service string
+		url     string
+	}{
+		{
+			env:     SecretsManagerEndpointEnv,
+			service: "secretsmanager",
+			url:     "http://sm.foo",
+		},
+		{
+			env:     SSMEndpointEnv,
+			service: "ssm",
+			url:     "http://ssm.foo",
+		},
+		{
+			env:     STSEndpointEnv,
+			service: "sts",
+			url:     "http://sts.foo",
+		},
+	}
+
+	for _, item := range tbl {
+		os.Setenv(item.env, item.url)
+		defer os.Unsetenv(item.env)
+	}
+
+	f := ResolveEndpoint()
+
+	for _, item := range tbl {
+		ep, err := f.EndpointFor(item.service, "")
+		assert.Nil(t, err)
+		assert.Equal(t, item.url, ep.URL)
+	}
+}

+ 50 - 0
pkg/provider/aws/auth/token_fetcher.go

@@ -0,0 +1,50 @@
+/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package auth
+
+import (
+	"fmt"
+
+	"github.com/aws/aws-sdk-go/aws/credentials"
+	authv1 "k8s.io/api/authentication/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
+)
+
+// mostly taken from:
+// https://github.com/aws/secrets-store-csi-driver-provider-aws/blob/main/auth/auth.go#L140-L145
+const (
+	tokenAudience = "sts.amazonaws.com"
+)
+
+type authTokenFetcher struct {
+	Namespace      string
+	ServiceAccount string
+	k8sClient      corev1.CoreV1Interface
+}
+
+// FetchToken satisfies the stscreds.TokenFetcher interface
+// it is used to generate service account tokens which are consumed by the aws sdk.
+func (p authTokenFetcher) FetchToken(ctx credentials.Context) ([]byte, error) {
+	log.V(1).Info("fetching token", "ns", p.Namespace, "sa", p.ServiceAccount)
+	tokRsp, err := p.k8sClient.ServiceAccounts(p.Namespace).CreateToken(ctx, p.ServiceAccount, &authv1.TokenRequest{
+		Spec: authv1.TokenRequestSpec{
+			Audiences: []string{tokenAudience},
+		},
+	}, metav1.CreateOptions{})
+	if err != nil {
+		return nil, fmt.Errorf("error creating service account token: %w", err)
+	}
+	return []byte(tokRsp.Status.Token), nil
+}

+ 63 - 0
pkg/provider/aws/auth/token_fetcher_test.go

@@ -0,0 +1,63 @@
+/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package auth
+
+import (
+	"context"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	authv1 "k8s.io/api/authentication/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	k8sv1 "k8s.io/client-go/kubernetes/typed/core/v1"
+)
+
+func TestTokenFetcher(t *testing.T) {
+	tf := &authTokenFetcher{
+		ServiceAccount: "foobar",
+		Namespace:      "example",
+		k8sClient:      &mockK8sV1{},
+	}
+	token, err := tf.FetchToken(context.Background())
+	assert.Nil(t, err)
+	assert.Equal(t, []byte("FAKETOKEN"), token)
+}
+
+// Mock K8s client for creating tokens.
+type mockK8sV1 struct {
+	k8sv1.CoreV1Interface
+}
+
+func (m *mockK8sV1) ServiceAccounts(namespace string) k8sv1.ServiceAccountInterface {
+	return &mockK8sV1SA{v1mock: m}
+}
+
+// Mock the K8s service account client.
+type mockK8sV1SA struct {
+	k8sv1.ServiceAccountInterface
+	v1mock *mockK8sV1
+}
+
+func (ma *mockK8sV1SA) CreateToken(
+	ctx context.Context,
+	serviceAccountName string,
+	tokenRequest *authv1.TokenRequest,
+	opts metav1.CreateOptions,
+) (*authv1.TokenRequest, error) {
+	return &authv1.TokenRequest{
+		Status: authv1.TokenRequestStatus{
+			Token: "FAKETOKEN",
+		},
+	}, nil
+}

+ 0 - 10
pkg/provider/aws/parameterstore/parameterstore_test.go

@@ -22,21 +22,11 @@ import (
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/service/ssm"
 	"github.com/aws/aws-sdk-go/service/ssm"
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp"
-	"github.com/stretchr/testify/assert"
 
 
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
-	"github.com/external-secrets/external-secrets/pkg/provider/aws/auth"
 	fake "github.com/external-secrets/external-secrets/pkg/provider/aws/parameterstore/fake"
 	fake "github.com/external-secrets/external-secrets/pkg/provider/aws/parameterstore/fake"
 )
 )
 
 
-func TestConstructor(t *testing.T) {
-	s, err := auth.NewSession("1111", "2222", "foo", "", nil)
-	assert.Nil(t, err)
-	c, err := New(s)
-	assert.Nil(t, err)
-	assert.NotNil(t, c.client)
-}
-
 type parameterstoreTestCase struct {
 type parameterstoreTestCase struct {
 	fakeClient     *fake.Client
 	fakeClient     *fake.Client
 	apiInput       *ssm.GetParameterInput
 	apiInput       *ssm.GetParameterInput

+ 1 - 1
pkg/provider/aws/provider.go

@@ -47,7 +47,7 @@ func newClient(ctx context.Context, store esv1alpha1.GenericStore, kube client.C
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	sess, err := awsauth.New(ctx, store, kube, namespace, assumeRoler)
+	sess, err := awsauth.New(ctx, store, kube, namespace, assumeRoler, awsauth.DefaultJWTProvider)
 	if err != nil {
 	if err != nil {
 		return nil, fmt.Errorf(errUnableCreateSession, err)
 		return nil, fmt.Errorf(errUnableCreateSession, err)
 	}
 	}

+ 2 - 481
pkg/provider/aws/provider_test.go

@@ -16,24 +16,14 @@ package aws
 
 
 import (
 import (
 	"context"
 	"context"
-	"os"
-	"strings"
 	"testing"
 	"testing"
-	"time"
 
 
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws"
-	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
-	awssess "github.com/aws/aws-sdk-go/aws/session"
-	"github.com/aws/aws-sdk-go/service/sts"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/assert"
-	v1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
 	clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
 
 
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
-	session "github.com/external-secrets/external-secrets/pkg/provider/aws/auth"
-	fakesess "github.com/external-secrets/external-secrets/pkg/provider/aws/auth/fake"
 	"github.com/external-secrets/external-secrets/pkg/provider/aws/parameterstore"
 	"github.com/external-secrets/external-secrets/pkg/provider/aws/parameterstore"
 	"github.com/external-secrets/external-secrets/pkg/provider/aws/secretsmanager"
 	"github.com/external-secrets/external-secrets/pkg/provider/aws/secretsmanager"
 )
 )
@@ -118,8 +108,8 @@ func TestProvider(t *testing.T) {
 					Provider: &esv1alpha1.SecretStoreProvider{
 					Provider: &esv1alpha1.SecretStoreProvider{
 						AWS: &esv1alpha1.AWSProvider{
 						AWS: &esv1alpha1.AWSProvider{
 							Service: esv1alpha1.AWSServiceParameterStore,
 							Service: esv1alpha1.AWSServiceParameterStore,
-							Auth: &esv1alpha1.AWSAuth{
-								SecretRef: esv1alpha1.AWSAuthSecretRef{
+							Auth: esv1alpha1.AWSAuth{
+								SecretRef: &esv1alpha1.AWSAuthSecretRef{
 									AccessKeyID: esmeta.SecretKeySelector{
 									AccessKeyID: esmeta.SecretKeySelector{
 										Name:      "foo",
 										Name:      "foo",
 										Namespace: aws.String("NOOP"),
 										Namespace: aws.String("NOOP"),
@@ -147,472 +137,3 @@ func TestProvider(t *testing.T) {
 		})
 		})
 	}
 	}
 }
 }
-
-func TestNewSession(t *testing.T) {
-	rows := []TestSessionRow{
-		{
-			name:      "nil store",
-			expectErr: "found nil store",
-			store:     nil,
-		},
-		{
-			name:      "not store spec",
-			expectErr: "storeSpec is missing provider",
-			store:     &esv1alpha1.SecretStore{},
-		},
-		{
-			name:      "store spec has no provider",
-			expectErr: "storeSpec is missing provider",
-			store: &esv1alpha1.SecretStore{
-				Spec: esv1alpha1.SecretStoreSpec{},
-			},
-		},
-		{
-			name:      "spec has no awssm field",
-			expectErr: "Missing AWS field",
-			store: &esv1alpha1.SecretStore{
-				Spec: esv1alpha1.SecretStoreSpec{
-					Provider: &esv1alpha1.SecretStoreProvider{},
-				},
-			},
-		},
-		{
-			name: "configure aws using environment variables",
-			store: &esv1alpha1.SecretStore{
-				Spec: esv1alpha1.SecretStoreSpec{
-					Provider: &esv1alpha1.SecretStoreProvider{
-						AWS: &esv1alpha1.AWSProvider{},
-					},
-				},
-			},
-			env: map[string]string{
-				"AWS_ACCESS_KEY_ID":     "1111",
-				"AWS_SECRET_ACCESS_KEY": "2222",
-			},
-			expectProvider:    true,
-			expectedKeyID:     "1111",
-			expectedSecretKey: "2222",
-		},
-		{
-			name: "configure aws using environment variables + assume role",
-
-			stsProvider: func(*awssess.Session) stscreds.AssumeRoler {
-				return &fakesess.AssumeRoler{
-					AssumeRoleFunc: func(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) {
-						assert.Equal(t, *input.RoleArn, "foo-bar-baz")
-						return &sts.AssumeRoleOutput{
-							AssumedRoleUser: &sts.AssumedRoleUser{
-								Arn:           aws.String("1123132"),
-								AssumedRoleId: aws.String("xxxxx"),
-							},
-							Credentials: &sts.Credentials{
-								AccessKeyId:     aws.String("3333"),
-								SecretAccessKey: aws.String("4444"),
-								Expiration:      aws.Time(time.Now().Add(time.Hour)),
-								SessionToken:    aws.String("6666"),
-							},
-						}, nil
-					},
-				}
-			},
-			store: &esv1alpha1.SecretStore{
-				Spec: esv1alpha1.SecretStoreSpec{
-					Provider: &esv1alpha1.SecretStoreProvider{
-						AWS: &esv1alpha1.AWSProvider{
-							Role: "foo-bar-baz",
-						},
-					},
-				},
-			},
-			env: map[string]string{
-				"AWS_ACCESS_KEY_ID":     "1111",
-				"AWS_SECRET_ACCESS_KEY": "2222",
-			},
-			expectProvider:    true,
-			expectedKeyID:     "3333",
-			expectedSecretKey: "4444",
-		},
-		{
-			name:      "error out when secret with credentials does not exist",
-			namespace: "foo",
-			store: &esv1alpha1.SecretStore{
-				Spec: esv1alpha1.SecretStoreSpec{
-					Provider: &esv1alpha1.SecretStoreProvider{
-						AWS: &esv1alpha1.AWSProvider{
-							Auth: &esv1alpha1.AWSAuth{
-								SecretRef: esv1alpha1.AWSAuthSecretRef{
-									AccessKeyID: esmeta.SecretKeySelector{
-										Name: "othersecret",
-										Key:  "one",
-									},
-									SecretAccessKey: esmeta.SecretKeySelector{
-										Name: "othersecret",
-										Key:  "two",
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: `secrets "othersecret" not found`,
-		},
-		{
-			name:      "use credentials from secret to configure aws",
-			namespace: "foo",
-			store: &esv1alpha1.SecretStore{
-				Spec: esv1alpha1.SecretStoreSpec{
-					Provider: &esv1alpha1.SecretStoreProvider{
-						AWS: &esv1alpha1.AWSProvider{
-							Auth: &esv1alpha1.AWSAuth{
-								SecretRef: esv1alpha1.AWSAuthSecretRef{
-									AccessKeyID: esmeta.SecretKeySelector{
-										Name: "onesecret",
-										// Namespace is not set
-										Key: "one",
-									},
-									SecretAccessKey: esmeta.SecretKeySelector{
-										Name: "onesecret",
-										// Namespace is not set
-										Key: "two",
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-			secrets: []v1.Secret{
-				{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "onesecret",
-						Namespace: "foo",
-					},
-					Data: map[string][]byte{
-						"one": []byte("1111"),
-						"two": []byte("2222"),
-					},
-				},
-			},
-			expectProvider:    true,
-			expectedKeyID:     "1111",
-			expectedSecretKey: "2222",
-		},
-		{
-			name:      "error out when secret key does not exist",
-			namespace: "foo",
-			store: &esv1alpha1.SecretStore{
-				Spec: esv1alpha1.SecretStoreSpec{
-					Provider: &esv1alpha1.SecretStoreProvider{
-						AWS: &esv1alpha1.AWSProvider{
-							Auth: &esv1alpha1.AWSAuth{
-								SecretRef: esv1alpha1.AWSAuthSecretRef{
-									AccessKeyID: esmeta.SecretKeySelector{
-										Name: "brokensecret",
-										Key:  "one",
-									},
-									SecretAccessKey: esmeta.SecretKeySelector{
-										Name: "brokensecret",
-										Key:  "two",
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-			secrets: []v1.Secret{
-				{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "brokensecret",
-						Namespace: "foo",
-					},
-					Data: map[string][]byte{},
-				},
-			},
-			expectErr: "missing SecretAccessKey",
-		},
-		{
-			name:      "should not be able to access secrets from different namespace",
-			namespace: "foo",
-			store: &esv1alpha1.SecretStore{
-				Spec: esv1alpha1.SecretStoreSpec{
-					Provider: &esv1alpha1.SecretStoreProvider{
-						AWS: &esv1alpha1.AWSProvider{
-							Auth: &esv1alpha1.AWSAuth{
-								SecretRef: esv1alpha1.AWSAuthSecretRef{
-									AccessKeyID: esmeta.SecretKeySelector{
-										Name:      "onesecret",
-										Namespace: aws.String("evil"), // this should not be possible!
-										Key:       "one",
-									},
-									SecretAccessKey: esmeta.SecretKeySelector{
-										Name:      "onesecret",
-										Namespace: aws.String("evil"),
-										Key:       "two",
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-			secrets: []v1.Secret{
-				{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "onesecret",
-						Namespace: "evil",
-					},
-					Data: map[string][]byte{
-						"one": []byte("1111"),
-						"two": []byte("2222"),
-					},
-				},
-			},
-			expectErr: `secrets "onesecret" not found`,
-		},
-		{
-			name:      "ClusterStore should use credentials from a specific namespace",
-			namespace: "es-namespace",
-			store: &esv1alpha1.ClusterSecretStore{
-				TypeMeta: metav1.TypeMeta{
-					APIVersion: esv1alpha1.ClusterSecretStoreKindAPIVersion,
-					Kind:       esv1alpha1.ClusterSecretStoreKind,
-				},
-				Spec: esv1alpha1.SecretStoreSpec{
-					Provider: &esv1alpha1.SecretStoreProvider{
-						AWS: &esv1alpha1.AWSProvider{
-							Auth: &esv1alpha1.AWSAuth{
-								SecretRef: esv1alpha1.AWSAuthSecretRef{
-									AccessKeyID: esmeta.SecretKeySelector{
-										Name:      "onesecret",
-										Namespace: aws.String("platform-team-ns"),
-										Key:       "one",
-									},
-									SecretAccessKey: esmeta.SecretKeySelector{
-										Name:      "onesecret",
-										Namespace: aws.String("platform-team-ns"),
-										Key:       "two",
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-			secrets: []v1.Secret{
-				{
-					ObjectMeta: metav1.ObjectMeta{
-						Name:      "onesecret",
-						Namespace: "platform-team-ns",
-					},
-					Data: map[string][]byte{
-						"one": []byte("1111"),
-						"two": []byte("2222"),
-					},
-				},
-			},
-			expectProvider:    true,
-			expectedKeyID:     "1111",
-			expectedSecretKey: "2222",
-		},
-		{
-			name:      "namespace is mandatory when using ClusterStore with SecretKeySelector",
-			namespace: "es-namespace",
-			store: &esv1alpha1.ClusterSecretStore{
-				TypeMeta: metav1.TypeMeta{
-					APIVersion: esv1alpha1.ClusterSecretStoreKindAPIVersion,
-					Kind:       esv1alpha1.ClusterSecretStoreKind,
-				},
-				Spec: esv1alpha1.SecretStoreSpec{
-					Provider: &esv1alpha1.SecretStoreProvider{
-						AWS: &esv1alpha1.AWSProvider{
-							Auth: &esv1alpha1.AWSAuth{
-								SecretRef: esv1alpha1.AWSAuthSecretRef{
-									AccessKeyID: esmeta.SecretKeySelector{
-										Name: "onesecret",
-										Key:  "one",
-									},
-									SecretAccessKey: esmeta.SecretKeySelector{
-										Name: "onesecret",
-										Key:  "two",
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: "invalid ClusterSecretStore: missing AWS AccessKeyID Namespace",
-		},
-	}
-	for i := range rows {
-		row := rows[i]
-		t.Run(row.name, func(t *testing.T) {
-			testRow(t, row)
-		})
-	}
-}
-
-type TestSessionRow struct {
-	name              string
-	store             esv1alpha1.GenericStore
-	secrets           []v1.Secret
-	namespace         string
-	stsProvider       session.STSProvider
-	expectProvider    bool
-	expectErr         string
-	expectedKeyID     string
-	expectedSecretKey string
-	env               map[string]string
-}
-
-func testRow(t *testing.T, row TestSessionRow) {
-	kc := clientfake.NewClientBuilder().Build()
-	for i := range row.secrets {
-		err := kc.Create(context.Background(), &row.secrets[i])
-		assert.Nil(t, err)
-	}
-	for k, v := range row.env {
-		os.Setenv(k, v)
-	}
-	defer func() {
-		for k := range row.env {
-			os.Unsetenv(k)
-		}
-	}()
-	s, err := session.New(context.Background(), row.store, kc, row.namespace, row.stsProvider)
-	if !ErrorContains(err, row.expectErr) {
-		t.Errorf("expected error %s but found %s", row.expectErr, err.Error())
-	}
-	// pass test on expected error
-	if err != nil {
-		return
-	}
-	if row.expectProvider && s == nil {
-		t.Errorf("expected provider object, found nil")
-		return
-	}
-	creds, _ := s.Config.Credentials.Get()
-	assert.Equal(t, creds.AccessKeyID, row.expectedKeyID)
-	assert.Equal(t, creds.SecretAccessKey, row.expectedSecretKey)
-}
-
-func TestSMEnvCredentials(t *testing.T) {
-	k8sClient := clientfake.NewClientBuilder().Build()
-	os.Setenv("AWS_SECRET_ACCESS_KEY", "1111")
-	os.Setenv("AWS_ACCESS_KEY_ID", "2222")
-	defer os.Unsetenv("AWS_SECRET_ACCESS_KEY")
-	defer os.Unsetenv("AWS_ACCESS_KEY_ID")
-	s, err := session.New(context.Background(), &esv1alpha1.SecretStore{
-		Spec: esv1alpha1.SecretStoreSpec{
-			Provider: &esv1alpha1.SecretStoreProvider{
-				// defaults
-				AWS: &esv1alpha1.AWSProvider{},
-			},
-		},
-	}, k8sClient, "example-ns", session.DefaultSTSProvider)
-	assert.Nil(t, err)
-	assert.NotNil(t, s)
-	creds, err := s.Config.Credentials.Get()
-	assert.Nil(t, err)
-	assert.Equal(t, creds.AccessKeyID, "2222")
-	assert.Equal(t, creds.SecretAccessKey, "1111")
-}
-
-func TestSMAssumeRole(t *testing.T) {
-	k8sClient := clientfake.NewClientBuilder().Build()
-	sts := &fakesess.AssumeRoler{
-		AssumeRoleFunc: func(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) {
-			// make sure the correct role is passed in
-			assert.Equal(t, *input.RoleArn, "my-awesome-role")
-			return &sts.AssumeRoleOutput{
-				AssumedRoleUser: &sts.AssumedRoleUser{
-					Arn:           aws.String("1123132"),
-					AssumedRoleId: aws.String("xxxxx"),
-				},
-				Credentials: &sts.Credentials{
-					AccessKeyId:     aws.String("3333"),
-					SecretAccessKey: aws.String("4444"),
-					Expiration:      aws.Time(time.Now().Add(time.Hour)),
-					SessionToken:    aws.String("6666"),
-				},
-			}, nil
-		},
-	}
-	os.Setenv("AWS_SECRET_ACCESS_KEY", "1111")
-	os.Setenv("AWS_ACCESS_KEY_ID", "2222")
-	defer os.Unsetenv("AWS_SECRET_ACCESS_KEY")
-	defer os.Unsetenv("AWS_ACCESS_KEY_ID")
-	s, err := session.New(context.Background(), &esv1alpha1.SecretStore{
-		Spec: esv1alpha1.SecretStoreSpec{
-			Provider: &esv1alpha1.SecretStoreProvider{
-				// do assume role!
-				AWS: &esv1alpha1.AWSProvider{
-					Role: "my-awesome-role",
-				},
-			},
-		},
-	}, k8sClient, "example-ns", func(se *awssess.Session) stscreds.AssumeRoler {
-		// check if the correct temporary credentials were used
-		creds, err := se.Config.Credentials.Get()
-		assert.Nil(t, err)
-		assert.Equal(t, creds.AccessKeyID, "2222")
-		assert.Equal(t, creds.SecretAccessKey, "1111")
-		return sts
-	})
-	assert.Nil(t, err)
-	assert.NotNil(t, s)
-
-	creds, err := s.Config.Credentials.Get()
-	assert.Nil(t, err)
-	assert.Equal(t, creds.AccessKeyID, "3333")
-	assert.Equal(t, creds.SecretAccessKey, "4444")
-}
-
-func TestResolver(t *testing.T) {
-	tbl := []struct {
-		env     string
-		service string
-		url     string
-	}{
-		{
-			env:     session.SecretsManagerEndpointEnv,
-			service: "secretsmanager",
-			url:     "http://sm.foo",
-		},
-		{
-			env:     session.SSMEndpointEnv,
-			service: "ssm",
-			url:     "http://ssm.foo",
-		},
-		{
-			env:     session.STSEndpointEnv,
-			service: "sts",
-			url:     "http://sts.foo",
-		},
-	}
-
-	for _, item := range tbl {
-		os.Setenv(item.env, item.url)
-		defer os.Unsetenv(item.env)
-	}
-
-	f := session.ResolveEndpoint()
-
-	for _, item := range tbl {
-		ep, err := f.EndpointFor(item.service, "")
-		assert.Nil(t, err)
-		assert.Equal(t, item.url, ep.URL)
-	}
-}
-
-func ErrorContains(out error, want string) bool {
-	if out == nil {
-		return want == ""
-	}
-	if want == "" {
-		return false
-	}
-	return strings.Contains(out.Error(), want)
-}

+ 0 - 10
pkg/provider/aws/secretsmanager/secretsmanager_test.go

@@ -22,21 +22,11 @@ import (
 	"github.com/aws/aws-sdk-go/aws"
 	"github.com/aws/aws-sdk-go/aws"
 	awssm "github.com/aws/aws-sdk-go/service/secretsmanager"
 	awssm "github.com/aws/aws-sdk-go/service/secretsmanager"
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp"
-	"github.com/stretchr/testify/assert"
 
 
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
 	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
-	"github.com/external-secrets/external-secrets/pkg/provider/aws/auth"
 	fakesm "github.com/external-secrets/external-secrets/pkg/provider/aws/secretsmanager/fake"
 	fakesm "github.com/external-secrets/external-secrets/pkg/provider/aws/secretsmanager/fake"
 )
 )
 
 
-func TestConstructor(t *testing.T) {
-	s, err := auth.NewSession("1111", "2222", "foo", "", nil)
-	assert.Nil(t, err)
-	c, err := New(s)
-	assert.Nil(t, err)
-	assert.NotNil(t, c.client)
-}
-
 type secretsManagerTestCase struct {
 type secretsManagerTestCase struct {
 	fakeClient     *fakesm.Client
 	fakeClient     *fakesm.Client
 	apiInput       *awssm.GetSecretValueInput
 	apiInput       *awssm.GetSecretValueInput

+ 13 - 0
pkg/provider/aws/util/provider.go

@@ -1,3 +1,16 @@
+/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
 package util
 package util
 
 
 import (
 import (