Browse Source

fix: respect aud annotation at IRSA

Moritz Johner 3 years ago
parent
commit
8f85e53f17

+ 12 - 4
pkg/provider/aws/auth/auth.go

@@ -47,7 +47,9 @@ type Config struct {
 var log = ctrl.Log.WithName("provider").WithName("aws")
 
 const (
-	roleARNAnnotation = "eks.amazonaws.com/role-arn"
+	roleARNAnnotation    = "eks.amazonaws.com/role-arn"
+	audienceAnnotation   = "eks.amazonaws.com/audience"
+	defaultTokenAudience = "sts.amazonaws.com"
 
 	errInvalidClusterStoreMissingAKIDNamespace = "invalid ClusterSecretStore: missing AWS AccessKeyID Namespace"
 	errInvalidClusterStoreMissingSAKNamespace  = "invalid ClusterSecretStore: missing AWS SecretAccessKey Namespace"
@@ -180,7 +182,12 @@ func sessionFromServiceAccount(ctx context.Context, prov *esv1beta1.AWSProvider,
 	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)
+
+	tokenAud := sa.Annotations[audienceAnnotation]
+	if tokenAud == "" {
+		tokenAud = defaultTokenAudience
+	}
+	jwtProv, err := jwtProvider(name, namespace, roleArn, tokenAud, prov.Region)
 	if err != nil {
 		return nil, err
 	}
@@ -189,12 +196,12 @@ func sessionFromServiceAccount(ctx context.Context, prov *esv1beta1.AWSProvider,
 	return credentials.NewCredentials(jwtProv), nil
 }
 
-type jwtProviderFactory func(name, namespace, roleArn, region string) (credentials.Provider, error)
+type jwtProviderFactory func(name, namespace, roleArn, aud, 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) {
+func DefaultJWTProvider(name, namespace, roleArn, aud, region string) (credentials.Provider, error) {
 	cfg, err := ctrlcfg.GetConfig()
 	if err != nil {
 		return nil, err
@@ -219,6 +226,7 @@ func DefaultJWTProvider(name, namespace, roleArn, region string) (credentials.Pr
 	}
 	tokenFetcher := &authTokenFetcher{
 		Namespace:      namespace,
+		Audience:       aud,
 		ServiceAccount: name,
 		k8sClient:      clientset.CoreV1(),
 	}

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

@@ -352,7 +352,7 @@ func TestNewSession(t *testing.T) {
 					},
 				},
 			},
-			jwtProvider: func(name, namespace, roleArn, region string) (credentials.Provider, error) {
+			jwtProvider: func(name, namespace, roleArn, aud, region string) (credentials.Provider, error) {
 				assert.Equal(t, myServiceAccountKey, name)
 				assert.Equal(t, otherNsName, namespace)
 				assert.Equal(t, "my-sa-role", roleArn)

+ 6 - 5
pkg/provider/aws/auth/token_fetcher.go

@@ -24,12 +24,13 @@ import (
 
 // 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
+	Namespace string
+	// Audience is the token aud claim
+	// which is verified by the aws oidc provider
+	// see: https://github.com/external-secrets/external-secrets/issues/1251#issuecomment-1161745849
+	Audience       string
 	ServiceAccount string
 	k8sClient      corev1.CoreV1Interface
 }
@@ -40,7 +41,7 @@ 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},
+			Audiences: []string{p.Audience},
 		},
 	}, metav1.CreateOptions{})
 	if err != nil {