Browse Source

feat: add support for GCP Workload Identity Federation (#4654)

* 1038: Updates SecretStore API with GCP Workload Identity Federation support

Signed-off-by: Bharath B <bhb@redhat.com>

* 1038: Updates GCP generator with GCP Workload Identity Federation support

Signed-off-by: Bharath B <bhb@redhat.com>

* 1038: Updates GCP generator with GCP Workload Identity Federation support

Signed-off-by: Bharath B <bhb@redhat.com>

* updates api-docs/Makefile docker command

Signed-off-by: Bharath B <bhb@redhat.com>

* incorporate review suggestions on the API changes

Signed-off-by: Bharath B <bhb@redhat.com>

* fmt tool suggested changes

Signed-off-by: Bharath B <bhb@redhat.com>

* updates ClusterGenerator limitation on referenced objects

Signed-off-by: Bharath B <bhb@redhat.com>

---------

Signed-off-by: Bharath B <bhb@redhat.com>
Co-authored-by: Gergely Brautigam <skarlso777@gmail.com>
Bharath B 7 months ago
parent
commit
6ec15bded7

+ 93 - 0
apis/externalsecrets/v1/secretstore_gcpsm_types.go

@@ -23,6 +23,8 @@ type GCPSMAuth struct {
 	SecretRef *GCPSMAuthSecretRef `json:"secretRef,omitempty"`
 	// +optional
 	WorkloadIdentity *GCPWorkloadIdentity `json:"workloadIdentity,omitempty"`
+	// +optional
+	WorkloadIdentityFederation *GCPWorkloadIdentityFederation `json:"workloadIdentityFederation,omitempty"`
 }
 
 type GCPSMAuthSecretRef struct {
@@ -60,3 +62,94 @@ type GCPSMProvider struct {
 	// Location optionally defines a location for a secret
 	Location string `json:"location,omitempty"`
 }
+
+// GCPWorkloadIdentityFederation holds the configurations required for generating federated access tokens.
+type GCPWorkloadIdentityFederation struct {
+	// credConfig holds the configmap reference containing the GCP external account credential configuration in JSON format and the key name containing the json data.
+	// For using Kubernetes cluster as the identity provider, use serviceAccountRef instead. Operators mounted serviceaccount token cannot be used as the token source, instead
+	// serviceAccountRef must be used by providing operators service account details.
+	// +kubebuilder:validation:Optional
+	CredConfig *ConfigMapReference `json:"credConfig,omitempty"`
+
+	// serviceAccountRef is the reference to the kubernetes ServiceAccount to be used for obtaining the tokens,
+	// when Kubernetes is configured as provider in workload identity pool.
+	// +kubebuilder:validation:Optional
+	ServiceAccountRef *esmeta.ServiceAccountSelector `json:"serviceAccountRef,omitempty"`
+
+	// awsSecurityCredentials is for configuring AWS region and credentials to use for obtaining the access token,
+	// when using the AWS metadata server is not an option.
+	// +kubebuilder:validation:Optional
+	AwsSecurityCredentials *AwsCredentialsConfig `json:"awsSecurityCredentials,omitempty"`
+
+	// audience is the Secure Token Service (STS) audience which contains the resource name for the workload identity pool and the provider identifier in that pool.
+	// If specified, Audience found in the external account credential config will be overridden with the configured value.
+	// audience must be provided when serviceAccountRef or awsSecurityCredentials is configured.
+	// +kubebuilder:validation:Optional
+	Audience string `json:"audience,omitempty"`
+
+	// externalTokenEndpoint is the endpoint explicitly set up to provide tokens, which will be matched against the
+	// credential_source.url in the provided credConfig. This field is merely to double-check the external token source
+	// URL is having the expected value.
+	// +kubebuilder:validation:Optional
+	ExternalTokenEndpoint string `json:"externalTokenEndpoint,omitempty"`
+}
+
+// ConfigMapReference holds the details of a configmap.
+type ConfigMapReference struct {
+	// name of the configmap.
+	// +kubebuilder:validation:MinLength:=1
+	// +kubebuilder:validation:MaxLength:=253
+	// +kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+	// +kubebuilder:validation:Required
+	Name string `json:"name"`
+
+	// namespace in which the configmap exists. If empty, configmap will looked up in local namespace.
+	// +kubebuilder:validation:MinLength:=1
+	// +kubebuilder:validation:MaxLength:=63
+	// +kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+	// +kubebuilder:validation:Optional
+	Namespace string `json:"namespace,omitempty"`
+
+	// key name holding the external account credential config.
+	// +kubebuilder:validation:MinLength:=1
+	// +kubebuilder:validation:MaxLength:=253
+	// +kubebuilder:validation:Pattern:=^[-._a-zA-Z0-9]+$
+	// +kubebuilder:validation:Required
+	Key string `json:"key"`
+}
+
+// AwsCredentialsConfig holds the region and the Secret reference which contains the AWS credentials.
+type AwsCredentialsConfig struct {
+	// region is for configuring the AWS region to be used.
+	// +kubebuilder:validation:MinLength:=1
+	// +kubebuilder:validation:MaxLength:=50
+	// +kubebuilder:validation:Pattern:=`^[a-z0-9-]+$`
+	// +kubebuilder:example:="ap-south-1"
+	// +kubebuilder:validation:Required
+	Region string `json:"region"`
+
+	// awsCredentialsSecretRef is the reference to the secret which holds the AWS credentials.
+	// Secret should be created with below names for keys
+	// - aws_access_key_id: Access Key ID, which is the unique identifier for the AWS account or the IAM user.
+	// - aws_secret_access_key: Secret Access Key, which is used to authenticate requests made to AWS services.
+	// - aws_session_token: Session Token, is the short-lived token to authenticate requests made to AWS services.
+	// +kubebuilder:validation:Required
+	AwsCredentialsSecretRef *SecretReference `json:"awsCredentialsSecretRef"`
+}
+
+// SecretReference holds the details of a secret.
+type SecretReference struct {
+	// name of the secret.
+	// +kubebuilder:validation:MinLength:=1
+	// +kubebuilder:validation:MaxLength:=253
+	// +kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+	// +kubebuilder:validation:Required
+	Name string `json:"name"`
+
+	// namespace in which the secret exists. If empty, secret will looked up in local namespace.
+	// +kubebuilder:validation:MinLength:=1
+	// +kubebuilder:validation:MaxLength:=63
+	// +kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+	// +kubebuilder:validation:Optional
+	Namespace string `json:"namespace,omitempty"`
+}

+ 85 - 0
apis/externalsecrets/v1/zz_generated.deepcopy.go

@@ -342,6 +342,26 @@ func (in *AwsAuthCredentials) DeepCopy() *AwsAuthCredentials {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AwsCredentialsConfig) DeepCopyInto(out *AwsCredentialsConfig) {
+	*out = *in
+	if in.AwsCredentialsSecretRef != nil {
+		in, out := &in.AwsCredentialsSecretRef, &out.AwsCredentialsSecretRef
+		*out = new(SecretReference)
+		**out = **in
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AwsCredentialsConfig.
+func (in *AwsCredentialsConfig) DeepCopy() *AwsCredentialsConfig {
+	if in == nil {
+		return nil
+	}
+	out := new(AwsCredentialsConfig)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *AzureAuthCredentials) DeepCopyInto(out *AzureAuthCredentials) {
 	*out = *in
 	in.IdentityID.DeepCopyInto(&out.IdentityID)
@@ -985,6 +1005,21 @@ func (in *ClusterSecretStoreList) DeepCopyObject() runtime.Object {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ConfigMapReference) DeepCopyInto(out *ConfigMapReference) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapReference.
+func (in *ConfigMapReference) DeepCopy() *ConfigMapReference {
+	if in == nil {
+		return nil
+	}
+	out := new(ConfigMapReference)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *ConjurAPIKey) DeepCopyInto(out *ConjurAPIKey) {
 	*out = *in
 	if in.UserRef != nil {
@@ -1781,6 +1816,11 @@ func (in *GCPSMAuth) DeepCopyInto(out *GCPSMAuth) {
 		*out = new(GCPWorkloadIdentity)
 		(*in).DeepCopyInto(*out)
 	}
+	if in.WorkloadIdentityFederation != nil {
+		in, out := &in.WorkloadIdentityFederation, &out.WorkloadIdentityFederation
+		*out = new(GCPWorkloadIdentityFederation)
+		(*in).DeepCopyInto(*out)
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GCPSMAuth.
@@ -1842,6 +1882,36 @@ func (in *GCPWorkloadIdentity) DeepCopy() *GCPWorkloadIdentity {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *GCPWorkloadIdentityFederation) DeepCopyInto(out *GCPWorkloadIdentityFederation) {
+	*out = *in
+	if in.CredConfig != nil {
+		in, out := &in.CredConfig, &out.CredConfig
+		*out = new(ConfigMapReference)
+		**out = **in
+	}
+	if in.ServiceAccountRef != nil {
+		in, out := &in.ServiceAccountRef, &out.ServiceAccountRef
+		*out = new(apismetav1.ServiceAccountSelector)
+		(*in).DeepCopyInto(*out)
+	}
+	if in.AwsSecurityCredentials != nil {
+		in, out := &in.AwsSecurityCredentials, &out.AwsSecurityCredentials
+		*out = new(AwsCredentialsConfig)
+		(*in).DeepCopyInto(*out)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GCPWorkloadIdentityFederation.
+func (in *GCPWorkloadIdentityFederation) DeepCopy() *GCPWorkloadIdentityFederation {
+	if in == nil {
+		return nil
+	}
+	out := new(GCPWorkloadIdentityFederation)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *GcpIamAuthCredentials) DeepCopyInto(out *GcpIamAuthCredentials) {
 	*out = *in
 	in.IdentityID.DeepCopyInto(&out.IdentityID)
@@ -2836,6 +2906,21 @@ func (in *ScalewayProviderSecretRef) DeepCopy() *ScalewayProviderSecretRef {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretReference) DeepCopyInto(out *SecretReference) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretReference.
+func (in *SecretReference) DeepCopy() *SecretReference {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretReference)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *SecretServerProvider) DeepCopyInto(out *SecretServerProvider) {
 	*out = *in
 	if in.Username != nil {

+ 3 - 0
apis/generators/v1alpha1/types_gcr.go

@@ -17,6 +17,7 @@ package v1alpha1
 import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
+	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
 )
 
@@ -32,6 +33,8 @@ type GCPSMAuth struct {
 	SecretRef *GCPSMAuthSecretRef `json:"secretRef,omitempty"`
 	// +optional
 	WorkloadIdentity *GCPWorkloadIdentity `json:"workloadIdentity,omitempty"`
+	// +optional
+	WorkloadIdentityFederation *esv1.GCPWorkloadIdentityFederation `json:"workloadIdentityFederation,omitempty"`
 }
 
 type GCPSMAuthSecretRef struct {

+ 5 - 0
apis/generators/v1alpha1/zz_generated.deepcopy.go

@@ -542,6 +542,11 @@ func (in *GCPSMAuth) DeepCopyInto(out *GCPSMAuth) {
 		*out = new(GCPWorkloadIdentity)
 		(*in).DeepCopyInto(*out)
 	}
+	if in.WorkloadIdentityFederation != nil {
+		in, out := &in.WorkloadIdentityFederation, &out.WorkloadIdentityFederation
+		*out = new(externalsecretsv1.GCPWorkloadIdentityFederation)
+		(*in).DeepCopyInto(*out)
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GCPSMAuth.

+ 5 - 5
cmd/controller/root.go

@@ -143,16 +143,16 @@ var rootCmd = &cobra.Command{
 		}
 		metricsOpts := server.Options{
 			BindAddress: metricsAddr,
-	 	}
-	 	if metricsSecure {
+		}
+		if metricsSecure {
 			metricsOpts.SecureServing = true
 			metricsOpts.CertDir = metricsCertDir
 			metricsOpts.CertName = metricsCertName
 			metricsOpts.KeyName = metricsKeyName
 		}
-	 	mgrOpts := ctrl.Options{
-			Scheme: scheme,
-			Metrics: metricsOpts,
+		mgrOpts := ctrl.Options{
+			Scheme:                 scheme,
+			Metrics:                metricsOpts,
 			HealthProbeBindAddress: liveAddr,
 			WebhookServer: webhook.NewServer(webhook.Options{
 				Port: 9443,

+ 121 - 0
config/crds/bases/external-secrets.io_clustersecretstores.yaml

@@ -1908,6 +1908,127 @@ spec:
                             required:
                             - serviceAccountRef
                             type: object
+                          workloadIdentityFederation:
+                            description: GCPWorkloadIdentityFederation holds the configurations
+                              required for generating federated access tokens.
+                            properties:
+                              audience:
+                                description: |-
+                                  audience is the Secure Token Service (STS) audience which contains the resource name for the workload identity pool and the provider identifier in that pool.
+                                  If specified, Audience found in the external account credential config will be overridden with the configured value.
+                                  audience must be provided when serviceAccountRef or awsSecurityCredentials is configured.
+                                type: string
+                              awsSecurityCredentials:
+                                description: |-
+                                  awsSecurityCredentials is for configuring AWS region and credentials to use for obtaining the access token,
+                                  when using the AWS metadata server is not an option.
+                                properties:
+                                  awsCredentialsSecretRef:
+                                    description: |-
+                                      awsCredentialsSecretRef is the reference to the secret which holds the AWS credentials.
+                                      Secret should be created with below names for keys
+                                      - aws_access_key_id: Access Key ID, which is the unique identifier for the AWS account or the IAM user.
+                                      - aws_secret_access_key: Secret Access Key, which is used to authenticate requests made to AWS services.
+                                      - aws_session_token: Session Token, is the short-lived token to authenticate requests made to AWS services.
+                                    properties:
+                                      name:
+                                        description: name of the secret.
+                                        maxLength: 253
+                                        minLength: 1
+                                        pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                        type: string
+                                      namespace:
+                                        description: namespace in which the secret
+                                          exists. If empty, secret will looked up
+                                          in local namespace.
+                                        maxLength: 63
+                                        minLength: 1
+                                        pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                        type: string
+                                    required:
+                                    - name
+                                    type: object
+                                  region:
+                                    description: region is for configuring the AWS
+                                      region to be used.
+                                    example: ap-south-1
+                                    maxLength: 50
+                                    minLength: 1
+                                    pattern: ^[a-z0-9-]+$
+                                    type: string
+                                required:
+                                - awsCredentialsSecretRef
+                                - region
+                                type: object
+                              credConfig:
+                                description: |-
+                                  credConfig holds the configmap reference containing the GCP external account credential configuration in JSON format and the key name containing the json data.
+                                  For using Kubernetes cluster as the identity provider, use serviceAccountRef instead. Operators mounted serviceaccount token cannot be used as the token source, instead
+                                  serviceAccountRef must be used by providing operators service account details.
+                                properties:
+                                  key:
+                                    description: key name holding the external account
+                                      credential config.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[-._a-zA-Z0-9]+$
+                                    type: string
+                                  name:
+                                    description: name of the configmap.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                    type: string
+                                  namespace:
+                                    description: namespace in which the configmap
+                                      exists. If empty, configmap will looked up in
+                                      local namespace.
+                                    maxLength: 63
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                    type: string
+                                required:
+                                - key
+                                - name
+                                type: object
+                              externalTokenEndpoint:
+                                description: |-
+                                  externalTokenEndpoint is the endpoint explicitly set up to provide tokens, which will be matched against the
+                                  credential_source.url in the provided credConfig. This field is merely to double-check the external token source
+                                  URL is having the expected value.
+                                type: string
+                              serviceAccountRef:
+                                description: |-
+                                  serviceAccountRef is the reference to the kubernetes ServiceAccount to be used for obtaining the tokens,
+                                  when Kubernetes is configured as provider in workload identity pool.
+                                properties:
+                                  audiences:
+                                    description: |-
+                                      Audience specifies the `aud` claim for the service account token
+                                      If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity
+                                      then this audiences will be appended to the list
+                                    items:
+                                      type: string
+                                    type: array
+                                  name:
+                                    description: The name of the ServiceAccount resource
+                                      being referred to.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                    type: string
+                                  namespace:
+                                    description: |-
+                                      Namespace of the resource being referred to.
+                                      Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                                    maxLength: 63
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                    type: string
+                                required:
+                                - name
+                                type: object
+                            type: object
                         type: object
                       location:
                         description: Location optionally defines a location for a

+ 121 - 0
config/crds/bases/external-secrets.io_secretstores.yaml

@@ -1908,6 +1908,127 @@ spec:
                             required:
                             - serviceAccountRef
                             type: object
+                          workloadIdentityFederation:
+                            description: GCPWorkloadIdentityFederation holds the configurations
+                              required for generating federated access tokens.
+                            properties:
+                              audience:
+                                description: |-
+                                  audience is the Secure Token Service (STS) audience which contains the resource name for the workload identity pool and the provider identifier in that pool.
+                                  If specified, Audience found in the external account credential config will be overridden with the configured value.
+                                  audience must be provided when serviceAccountRef or awsSecurityCredentials is configured.
+                                type: string
+                              awsSecurityCredentials:
+                                description: |-
+                                  awsSecurityCredentials is for configuring AWS region and credentials to use for obtaining the access token,
+                                  when using the AWS metadata server is not an option.
+                                properties:
+                                  awsCredentialsSecretRef:
+                                    description: |-
+                                      awsCredentialsSecretRef is the reference to the secret which holds the AWS credentials.
+                                      Secret should be created with below names for keys
+                                      - aws_access_key_id: Access Key ID, which is the unique identifier for the AWS account or the IAM user.
+                                      - aws_secret_access_key: Secret Access Key, which is used to authenticate requests made to AWS services.
+                                      - aws_session_token: Session Token, is the short-lived token to authenticate requests made to AWS services.
+                                    properties:
+                                      name:
+                                        description: name of the secret.
+                                        maxLength: 253
+                                        minLength: 1
+                                        pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                        type: string
+                                      namespace:
+                                        description: namespace in which the secret
+                                          exists. If empty, secret will looked up
+                                          in local namespace.
+                                        maxLength: 63
+                                        minLength: 1
+                                        pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                        type: string
+                                    required:
+                                    - name
+                                    type: object
+                                  region:
+                                    description: region is for configuring the AWS
+                                      region to be used.
+                                    example: ap-south-1
+                                    maxLength: 50
+                                    minLength: 1
+                                    pattern: ^[a-z0-9-]+$
+                                    type: string
+                                required:
+                                - awsCredentialsSecretRef
+                                - region
+                                type: object
+                              credConfig:
+                                description: |-
+                                  credConfig holds the configmap reference containing the GCP external account credential configuration in JSON format and the key name containing the json data.
+                                  For using Kubernetes cluster as the identity provider, use serviceAccountRef instead. Operators mounted serviceaccount token cannot be used as the token source, instead
+                                  serviceAccountRef must be used by providing operators service account details.
+                                properties:
+                                  key:
+                                    description: key name holding the external account
+                                      credential config.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[-._a-zA-Z0-9]+$
+                                    type: string
+                                  name:
+                                    description: name of the configmap.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                    type: string
+                                  namespace:
+                                    description: namespace in which the configmap
+                                      exists. If empty, configmap will looked up in
+                                      local namespace.
+                                    maxLength: 63
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                    type: string
+                                required:
+                                - key
+                                - name
+                                type: object
+                              externalTokenEndpoint:
+                                description: |-
+                                  externalTokenEndpoint is the endpoint explicitly set up to provide tokens, which will be matched against the
+                                  credential_source.url in the provided credConfig. This field is merely to double-check the external token source
+                                  URL is having the expected value.
+                                type: string
+                              serviceAccountRef:
+                                description: |-
+                                  serviceAccountRef is the reference to the kubernetes ServiceAccount to be used for obtaining the tokens,
+                                  when Kubernetes is configured as provider in workload identity pool.
+                                properties:
+                                  audiences:
+                                    description: |-
+                                      Audience specifies the `aud` claim for the service account token
+                                      If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity
+                                      then this audiences will be appended to the list
+                                    items:
+                                      type: string
+                                    type: array
+                                  name:
+                                    description: The name of the ServiceAccount resource
+                                      being referred to.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                    type: string
+                                  namespace:
+                                    description: |-
+                                      Namespace of the resource being referred to.
+                                      Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                                    maxLength: 63
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                    type: string
+                                required:
+                                - name
+                                type: object
+                            type: object
                         type: object
                       location:
                         description: Location optionally defines a location for a

+ 121 - 0
config/crds/bases/generators.external-secrets.io_clustergenerators.yaml

@@ -450,6 +450,127 @@ spec:
                             - clusterName
                             - serviceAccountRef
                             type: object
+                          workloadIdentityFederation:
+                            description: GCPWorkloadIdentityFederation holds the configurations
+                              required for generating federated access tokens.
+                            properties:
+                              audience:
+                                description: |-
+                                  audience is the Secure Token Service (STS) audience which contains the resource name for the workload identity pool and the provider identifier in that pool.
+                                  If specified, Audience found in the external account credential config will be overridden with the configured value.
+                                  audience must be provided when serviceAccountRef or awsSecurityCredentials is configured.
+                                type: string
+                              awsSecurityCredentials:
+                                description: |-
+                                  awsSecurityCredentials is for configuring AWS region and credentials to use for obtaining the access token,
+                                  when using the AWS metadata server is not an option.
+                                properties:
+                                  awsCredentialsSecretRef:
+                                    description: |-
+                                      awsCredentialsSecretRef is the reference to the secret which holds the AWS credentials.
+                                      Secret should be created with below names for keys
+                                      - aws_access_key_id: Access Key ID, which is the unique identifier for the AWS account or the IAM user.
+                                      - aws_secret_access_key: Secret Access Key, which is used to authenticate requests made to AWS services.
+                                      - aws_session_token: Session Token, is the short-lived token to authenticate requests made to AWS services.
+                                    properties:
+                                      name:
+                                        description: name of the secret.
+                                        maxLength: 253
+                                        minLength: 1
+                                        pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                        type: string
+                                      namespace:
+                                        description: namespace in which the secret
+                                          exists. If empty, secret will looked up
+                                          in local namespace.
+                                        maxLength: 63
+                                        minLength: 1
+                                        pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                        type: string
+                                    required:
+                                    - name
+                                    type: object
+                                  region:
+                                    description: region is for configuring the AWS
+                                      region to be used.
+                                    example: ap-south-1
+                                    maxLength: 50
+                                    minLength: 1
+                                    pattern: ^[a-z0-9-]+$
+                                    type: string
+                                required:
+                                - awsCredentialsSecretRef
+                                - region
+                                type: object
+                              credConfig:
+                                description: |-
+                                  credConfig holds the configmap reference containing the GCP external account credential configuration in JSON format and the key name containing the json data.
+                                  For using Kubernetes cluster as the identity provider, use serviceAccountRef instead. Operators mounted serviceaccount token cannot be used as the token source, instead
+                                  serviceAccountRef must be used by providing operators service account details.
+                                properties:
+                                  key:
+                                    description: key name holding the external account
+                                      credential config.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[-._a-zA-Z0-9]+$
+                                    type: string
+                                  name:
+                                    description: name of the configmap.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                    type: string
+                                  namespace:
+                                    description: namespace in which the configmap
+                                      exists. If empty, configmap will looked up in
+                                      local namespace.
+                                    maxLength: 63
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                    type: string
+                                required:
+                                - key
+                                - name
+                                type: object
+                              externalTokenEndpoint:
+                                description: |-
+                                  externalTokenEndpoint is the endpoint explicitly set up to provide tokens, which will be matched against the
+                                  credential_source.url in the provided credConfig. This field is merely to double-check the external token source
+                                  URL is having the expected value.
+                                type: string
+                              serviceAccountRef:
+                                description: |-
+                                  serviceAccountRef is the reference to the kubernetes ServiceAccount to be used for obtaining the tokens,
+                                  when Kubernetes is configured as provider in workload identity pool.
+                                properties:
+                                  audiences:
+                                    description: |-
+                                      Audience specifies the `aud` claim for the service account token
+                                      If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity
+                                      then this audiences will be appended to the list
+                                    items:
+                                      type: string
+                                    type: array
+                                  name:
+                                    description: The name of the ServiceAccount resource
+                                      being referred to.
+                                    maxLength: 253
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                    type: string
+                                  namespace:
+                                    description: |-
+                                      Namespace of the resource being referred to.
+                                      Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                                    maxLength: 63
+                                    minLength: 1
+                                    pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                    type: string
+                                required:
+                                - name
+                                type: object
+                            type: object
                         type: object
                       projectID:
                         description: ProjectID defines which project to use to authenticate

+ 119 - 0
config/crds/bases/generators.external-secrets.io_gcraccesstokens.yaml

@@ -119,6 +119,125 @@ spec:
                     - clusterName
                     - serviceAccountRef
                     type: object
+                  workloadIdentityFederation:
+                    description: GCPWorkloadIdentityFederation holds the configurations
+                      required for generating federated access tokens.
+                    properties:
+                      audience:
+                        description: |-
+                          audience is the Secure Token Service (STS) audience which contains the resource name for the workload identity pool and the provider identifier in that pool.
+                          If specified, Audience found in the external account credential config will be overridden with the configured value.
+                          audience must be provided when serviceAccountRef or awsSecurityCredentials is configured.
+                        type: string
+                      awsSecurityCredentials:
+                        description: |-
+                          awsSecurityCredentials is for configuring AWS region and credentials to use for obtaining the access token,
+                          when using the AWS metadata server is not an option.
+                        properties:
+                          awsCredentialsSecretRef:
+                            description: |-
+                              awsCredentialsSecretRef is the reference to the secret which holds the AWS credentials.
+                              Secret should be created with below names for keys
+                              - aws_access_key_id: Access Key ID, which is the unique identifier for the AWS account or the IAM user.
+                              - aws_secret_access_key: Secret Access Key, which is used to authenticate requests made to AWS services.
+                              - aws_session_token: Session Token, is the short-lived token to authenticate requests made to AWS services.
+                            properties:
+                              name:
+                                description: name of the secret.
+                                maxLength: 253
+                                minLength: 1
+                                pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                type: string
+                              namespace:
+                                description: namespace in which the secret exists.
+                                  If empty, secret will looked up in local namespace.
+                                maxLength: 63
+                                minLength: 1
+                                pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                type: string
+                            required:
+                            - name
+                            type: object
+                          region:
+                            description: region is for configuring the AWS region
+                              to be used.
+                            example: ap-south-1
+                            maxLength: 50
+                            minLength: 1
+                            pattern: ^[a-z0-9-]+$
+                            type: string
+                        required:
+                        - awsCredentialsSecretRef
+                        - region
+                        type: object
+                      credConfig:
+                        description: |-
+                          credConfig holds the configmap reference containing the GCP external account credential configuration in JSON format and the key name containing the json data.
+                          For using Kubernetes cluster as the identity provider, use serviceAccountRef instead. Operators mounted serviceaccount token cannot be used as the token source, instead
+                          serviceAccountRef must be used by providing operators service account details.
+                        properties:
+                          key:
+                            description: key name holding the external account credential
+                              config.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[-._a-zA-Z0-9]+$
+                            type: string
+                          name:
+                            description: name of the configmap.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                          namespace:
+                            description: namespace in which the configmap exists.
+                              If empty, configmap will looked up in local namespace.
+                            maxLength: 63
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                            type: string
+                        required:
+                        - key
+                        - name
+                        type: object
+                      externalTokenEndpoint:
+                        description: |-
+                          externalTokenEndpoint is the endpoint explicitly set up to provide tokens, which will be matched against the
+                          credential_source.url in the provided credConfig. This field is merely to double-check the external token source
+                          URL is having the expected value.
+                        type: string
+                      serviceAccountRef:
+                        description: |-
+                          serviceAccountRef is the reference to the kubernetes ServiceAccount to be used for obtaining the tokens,
+                          when Kubernetes is configured as provider in workload identity pool.
+                        properties:
+                          audiences:
+                            description: |-
+                              Audience specifies the `aud` claim for the service account token
+                              If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity
+                              then this audiences will be appended to the list
+                            items:
+                              type: string
+                            type: array
+                          name:
+                            description: The name of the ServiceAccount resource being
+                              referred to.
+                            maxLength: 253
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                            type: string
+                          namespace:
+                            description: |-
+                              Namespace of the resource being referred to.
+                              Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                            maxLength: 63
+                            minLength: 1
+                            pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                            type: string
+                        required:
+                        - name
+                        type: object
+                    type: object
                 type: object
               projectID:
                 description: ProjectID defines which project to use to authenticate

+ 452 - 0
deploy/crds/bundle.yaml

@@ -3794,6 +3794,119 @@ spec:
                               required:
                                 - serviceAccountRef
                               type: object
+                            workloadIdentityFederation:
+                              description: GCPWorkloadIdentityFederation holds the configurations required for generating federated access tokens.
+                              properties:
+                                audience:
+                                  description: |-
+                                    audience is the Secure Token Service (STS) audience which contains the resource name for the workload identity pool and the provider identifier in that pool.
+                                    If specified, Audience found in the external account credential config will be overridden with the configured value.
+                                    audience must be provided when serviceAccountRef or awsSecurityCredentials is configured.
+                                  type: string
+                                awsSecurityCredentials:
+                                  description: |-
+                                    awsSecurityCredentials is for configuring AWS region and credentials to use for obtaining the access token,
+                                    when using the AWS metadata server is not an option.
+                                  properties:
+                                    awsCredentialsSecretRef:
+                                      description: |-
+                                        awsCredentialsSecretRef is the reference to the secret which holds the AWS credentials.
+                                        Secret should be created with below names for keys
+                                        - aws_access_key_id: Access Key ID, which is the unique identifier for the AWS account or the IAM user.
+                                        - aws_secret_access_key: Secret Access Key, which is used to authenticate requests made to AWS services.
+                                        - aws_session_token: Session Token, is the short-lived token to authenticate requests made to AWS services.
+                                      properties:
+                                        name:
+                                          description: name of the secret.
+                                          maxLength: 253
+                                          minLength: 1
+                                          pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                          type: string
+                                        namespace:
+                                          description: namespace in which the secret exists. If empty, secret will looked up in local namespace.
+                                          maxLength: 63
+                                          minLength: 1
+                                          pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                          type: string
+                                      required:
+                                        - name
+                                      type: object
+                                    region:
+                                      description: region is for configuring the AWS region to be used.
+                                      example: ap-south-1
+                                      maxLength: 50
+                                      minLength: 1
+                                      pattern: ^[a-z0-9-]+$
+                                      type: string
+                                  required:
+                                    - awsCredentialsSecretRef
+                                    - region
+                                  type: object
+                                credConfig:
+                                  description: |-
+                                    credConfig holds the configmap reference containing the GCP external account credential configuration in JSON format and the key name containing the json data.
+                                    For using Kubernetes cluster as the identity provider, use serviceAccountRef instead. Operators mounted serviceaccount token cannot be used as the token source, instead
+                                    serviceAccountRef must be used by providing operators service account details.
+                                  properties:
+                                    key:
+                                      description: key name holding the external account credential config.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[-._a-zA-Z0-9]+$
+                                      type: string
+                                    name:
+                                      description: name of the configmap.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                      type: string
+                                    namespace:
+                                      description: namespace in which the configmap exists. If empty, configmap will looked up in local namespace.
+                                      maxLength: 63
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                      type: string
+                                  required:
+                                    - key
+                                    - name
+                                  type: object
+                                externalTokenEndpoint:
+                                  description: |-
+                                    externalTokenEndpoint is the endpoint explicitly set up to provide tokens, which will be matched against the
+                                    credential_source.url in the provided credConfig. This field is merely to double-check the external token source
+                                    URL is having the expected value.
+                                  type: string
+                                serviceAccountRef:
+                                  description: |-
+                                    serviceAccountRef is the reference to the kubernetes ServiceAccount to be used for obtaining the tokens,
+                                    when Kubernetes is configured as provider in workload identity pool.
+                                  properties:
+                                    audiences:
+                                      description: |-
+                                        Audience specifies the `aud` claim for the service account token
+                                        If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity
+                                        then this audiences will be appended to the list
+                                      items:
+                                        type: string
+                                      type: array
+                                    name:
+                                      description: The name of the ServiceAccount resource being referred to.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                      type: string
+                                    namespace:
+                                      description: |-
+                                        Namespace of the resource being referred to.
+                                        Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                                      maxLength: 63
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                      type: string
+                                  required:
+                                    - name
+                                  type: object
+                              type: object
                           type: object
                         location:
                           description: Location optionally defines a location for a secret
@@ -14622,6 +14735,119 @@ spec:
                               required:
                                 - serviceAccountRef
                               type: object
+                            workloadIdentityFederation:
+                              description: GCPWorkloadIdentityFederation holds the configurations required for generating federated access tokens.
+                              properties:
+                                audience:
+                                  description: |-
+                                    audience is the Secure Token Service (STS) audience which contains the resource name for the workload identity pool and the provider identifier in that pool.
+                                    If specified, Audience found in the external account credential config will be overridden with the configured value.
+                                    audience must be provided when serviceAccountRef or awsSecurityCredentials is configured.
+                                  type: string
+                                awsSecurityCredentials:
+                                  description: |-
+                                    awsSecurityCredentials is for configuring AWS region and credentials to use for obtaining the access token,
+                                    when using the AWS metadata server is not an option.
+                                  properties:
+                                    awsCredentialsSecretRef:
+                                      description: |-
+                                        awsCredentialsSecretRef is the reference to the secret which holds the AWS credentials.
+                                        Secret should be created with below names for keys
+                                        - aws_access_key_id: Access Key ID, which is the unique identifier for the AWS account or the IAM user.
+                                        - aws_secret_access_key: Secret Access Key, which is used to authenticate requests made to AWS services.
+                                        - aws_session_token: Session Token, is the short-lived token to authenticate requests made to AWS services.
+                                      properties:
+                                        name:
+                                          description: name of the secret.
+                                          maxLength: 253
+                                          minLength: 1
+                                          pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                          type: string
+                                        namespace:
+                                          description: namespace in which the secret exists. If empty, secret will looked up in local namespace.
+                                          maxLength: 63
+                                          minLength: 1
+                                          pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                          type: string
+                                      required:
+                                        - name
+                                      type: object
+                                    region:
+                                      description: region is for configuring the AWS region to be used.
+                                      example: ap-south-1
+                                      maxLength: 50
+                                      minLength: 1
+                                      pattern: ^[a-z0-9-]+$
+                                      type: string
+                                  required:
+                                    - awsCredentialsSecretRef
+                                    - region
+                                  type: object
+                                credConfig:
+                                  description: |-
+                                    credConfig holds the configmap reference containing the GCP external account credential configuration in JSON format and the key name containing the json data.
+                                    For using Kubernetes cluster as the identity provider, use serviceAccountRef instead. Operators mounted serviceaccount token cannot be used as the token source, instead
+                                    serviceAccountRef must be used by providing operators service account details.
+                                  properties:
+                                    key:
+                                      description: key name holding the external account credential config.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[-._a-zA-Z0-9]+$
+                                      type: string
+                                    name:
+                                      description: name of the configmap.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                      type: string
+                                    namespace:
+                                      description: namespace in which the configmap exists. If empty, configmap will looked up in local namespace.
+                                      maxLength: 63
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                      type: string
+                                  required:
+                                    - key
+                                    - name
+                                  type: object
+                                externalTokenEndpoint:
+                                  description: |-
+                                    externalTokenEndpoint is the endpoint explicitly set up to provide tokens, which will be matched against the
+                                    credential_source.url in the provided credConfig. This field is merely to double-check the external token source
+                                    URL is having the expected value.
+                                  type: string
+                                serviceAccountRef:
+                                  description: |-
+                                    serviceAccountRef is the reference to the kubernetes ServiceAccount to be used for obtaining the tokens,
+                                    when Kubernetes is configured as provider in workload identity pool.
+                                  properties:
+                                    audiences:
+                                      description: |-
+                                        Audience specifies the `aud` claim for the service account token
+                                        If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity
+                                        then this audiences will be appended to the list
+                                      items:
+                                        type: string
+                                      type: array
+                                    name:
+                                      description: The name of the ServiceAccount resource being referred to.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                      type: string
+                                    namespace:
+                                      description: |-
+                                        Namespace of the resource being referred to.
+                                        Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                                      maxLength: 63
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                      type: string
+                                  required:
+                                    - name
+                                  type: object
+                              type: object
                           type: object
                         location:
                           description: Location optionally defines a location for a secret
@@ -22576,6 +22802,119 @@ spec:
                                 - clusterName
                                 - serviceAccountRef
                               type: object
+                            workloadIdentityFederation:
+                              description: GCPWorkloadIdentityFederation holds the configurations required for generating federated access tokens.
+                              properties:
+                                audience:
+                                  description: |-
+                                    audience is the Secure Token Service (STS) audience which contains the resource name for the workload identity pool and the provider identifier in that pool.
+                                    If specified, Audience found in the external account credential config will be overridden with the configured value.
+                                    audience must be provided when serviceAccountRef or awsSecurityCredentials is configured.
+                                  type: string
+                                awsSecurityCredentials:
+                                  description: |-
+                                    awsSecurityCredentials is for configuring AWS region and credentials to use for obtaining the access token,
+                                    when using the AWS metadata server is not an option.
+                                  properties:
+                                    awsCredentialsSecretRef:
+                                      description: |-
+                                        awsCredentialsSecretRef is the reference to the secret which holds the AWS credentials.
+                                        Secret should be created with below names for keys
+                                        - aws_access_key_id: Access Key ID, which is the unique identifier for the AWS account or the IAM user.
+                                        - aws_secret_access_key: Secret Access Key, which is used to authenticate requests made to AWS services.
+                                        - aws_session_token: Session Token, is the short-lived token to authenticate requests made to AWS services.
+                                      properties:
+                                        name:
+                                          description: name of the secret.
+                                          maxLength: 253
+                                          minLength: 1
+                                          pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                          type: string
+                                        namespace:
+                                          description: namespace in which the secret exists. If empty, secret will looked up in local namespace.
+                                          maxLength: 63
+                                          minLength: 1
+                                          pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                          type: string
+                                      required:
+                                        - name
+                                      type: object
+                                    region:
+                                      description: region is for configuring the AWS region to be used.
+                                      example: ap-south-1
+                                      maxLength: 50
+                                      minLength: 1
+                                      pattern: ^[a-z0-9-]+$
+                                      type: string
+                                  required:
+                                    - awsCredentialsSecretRef
+                                    - region
+                                  type: object
+                                credConfig:
+                                  description: |-
+                                    credConfig holds the configmap reference containing the GCP external account credential configuration in JSON format and the key name containing the json data.
+                                    For using Kubernetes cluster as the identity provider, use serviceAccountRef instead. Operators mounted serviceaccount token cannot be used as the token source, instead
+                                    serviceAccountRef must be used by providing operators service account details.
+                                  properties:
+                                    key:
+                                      description: key name holding the external account credential config.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[-._a-zA-Z0-9]+$
+                                      type: string
+                                    name:
+                                      description: name of the configmap.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                      type: string
+                                    namespace:
+                                      description: namespace in which the configmap exists. If empty, configmap will looked up in local namespace.
+                                      maxLength: 63
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                      type: string
+                                  required:
+                                    - key
+                                    - name
+                                  type: object
+                                externalTokenEndpoint:
+                                  description: |-
+                                    externalTokenEndpoint is the endpoint explicitly set up to provide tokens, which will be matched against the
+                                    credential_source.url in the provided credConfig. This field is merely to double-check the external token source
+                                    URL is having the expected value.
+                                  type: string
+                                serviceAccountRef:
+                                  description: |-
+                                    serviceAccountRef is the reference to the kubernetes ServiceAccount to be used for obtaining the tokens,
+                                    when Kubernetes is configured as provider in workload identity pool.
+                                  properties:
+                                    audiences:
+                                      description: |-
+                                        Audience specifies the `aud` claim for the service account token
+                                        If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity
+                                        then this audiences will be appended to the list
+                                      items:
+                                        type: string
+                                      type: array
+                                    name:
+                                      description: The name of the ServiceAccount resource being referred to.
+                                      maxLength: 253
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                      type: string
+                                    namespace:
+                                      description: |-
+                                        Namespace of the resource being referred to.
+                                        Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                                      maxLength: 63
+                                      minLength: 1
+                                      pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                      type: string
+                                  required:
+                                    - name
+                                  type: object
+                              type: object
                           type: object
                         projectID:
                           description: ProjectID defines which project to use to authenticate with
@@ -24430,6 +24769,119 @@ spec:
                         - clusterName
                         - serviceAccountRef
                       type: object
+                    workloadIdentityFederation:
+                      description: GCPWorkloadIdentityFederation holds the configurations required for generating federated access tokens.
+                      properties:
+                        audience:
+                          description: |-
+                            audience is the Secure Token Service (STS) audience which contains the resource name for the workload identity pool and the provider identifier in that pool.
+                            If specified, Audience found in the external account credential config will be overridden with the configured value.
+                            audience must be provided when serviceAccountRef or awsSecurityCredentials is configured.
+                          type: string
+                        awsSecurityCredentials:
+                          description: |-
+                            awsSecurityCredentials is for configuring AWS region and credentials to use for obtaining the access token,
+                            when using the AWS metadata server is not an option.
+                          properties:
+                            awsCredentialsSecretRef:
+                              description: |-
+                                awsCredentialsSecretRef is the reference to the secret which holds the AWS credentials.
+                                Secret should be created with below names for keys
+                                - aws_access_key_id: Access Key ID, which is the unique identifier for the AWS account or the IAM user.
+                                - aws_secret_access_key: Secret Access Key, which is used to authenticate requests made to AWS services.
+                                - aws_session_token: Session Token, is the short-lived token to authenticate requests made to AWS services.
+                              properties:
+                                name:
+                                  description: name of the secret.
+                                  maxLength: 253
+                                  minLength: 1
+                                  pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                                  type: string
+                                namespace:
+                                  description: namespace in which the secret exists. If empty, secret will looked up in local namespace.
+                                  maxLength: 63
+                                  minLength: 1
+                                  pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                                  type: string
+                              required:
+                                - name
+                              type: object
+                            region:
+                              description: region is for configuring the AWS region to be used.
+                              example: ap-south-1
+                              maxLength: 50
+                              minLength: 1
+                              pattern: ^[a-z0-9-]+$
+                              type: string
+                          required:
+                            - awsCredentialsSecretRef
+                            - region
+                          type: object
+                        credConfig:
+                          description: |-
+                            credConfig holds the configmap reference containing the GCP external account credential configuration in JSON format and the key name containing the json data.
+                            For using Kubernetes cluster as the identity provider, use serviceAccountRef instead. Operators mounted serviceaccount token cannot be used as the token source, instead
+                            serviceAccountRef must be used by providing operators service account details.
+                          properties:
+                            key:
+                              description: key name holding the external account credential config.
+                              maxLength: 253
+                              minLength: 1
+                              pattern: ^[-._a-zA-Z0-9]+$
+                              type: string
+                            name:
+                              description: name of the configmap.
+                              maxLength: 253
+                              minLength: 1
+                              pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                              type: string
+                            namespace:
+                              description: namespace in which the configmap exists. If empty, configmap will looked up in local namespace.
+                              maxLength: 63
+                              minLength: 1
+                              pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                              type: string
+                          required:
+                            - key
+                            - name
+                          type: object
+                        externalTokenEndpoint:
+                          description: |-
+                            externalTokenEndpoint is the endpoint explicitly set up to provide tokens, which will be matched against the
+                            credential_source.url in the provided credConfig. This field is merely to double-check the external token source
+                            URL is having the expected value.
+                          type: string
+                        serviceAccountRef:
+                          description: |-
+                            serviceAccountRef is the reference to the kubernetes ServiceAccount to be used for obtaining the tokens,
+                            when Kubernetes is configured as provider in workload identity pool.
+                          properties:
+                            audiences:
+                              description: |-
+                                Audience specifies the `aud` claim for the service account token
+                                If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity
+                                then this audiences will be appended to the list
+                              items:
+                                type: string
+                              type: array
+                            name:
+                              description: The name of the ServiceAccount resource being referred to.
+                              maxLength: 253
+                              minLength: 1
+                              pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+                              type: string
+                            namespace:
+                              description: |-
+                                Namespace of the resource being referred to.
+                                Ignored if referent is not cluster-scoped, otherwise defaults to the namespace of the referent.
+                              maxLength: 63
+                              minLength: 1
+                              pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+                              type: string
+                          required:
+                            - name
+                          type: object
+                      type: object
                   type: object
                 projectID:
                   description: ProjectID defines which project to use to authenticate with

+ 4 - 2
docs/api/generator/cluster.md

@@ -5,8 +5,10 @@ in the consuming `ExternalSecret`.
 
 ## Limitations
 
-With this, the generator will still create objects in the namespace in which the referencing ES lives.
-That has not changed as of now. It will change in future modifications.
+- The generator will continue to create objects in the same namespace as the referencing ExternalSecret (ES) object.
+  This behavior is subject to change in future updates.
+- The objects referenced within the ClusterGenerator must also reside in the same namespace as the ES object that
+  references them. This is due to the inherent, namespace-scoped nature of the embedded generator types.
 
 ## Example Manifest
 

+ 241 - 0
docs/api/spec.md

@@ -826,6 +826,53 @@ External Secrets meta/v1.SecretKeySelector
 </tr>
 </tbody>
 </table>
+<h3 id="external-secrets.io/v1.AwsCredentialsConfig">AwsCredentialsConfig
+</h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1.GCPWorkloadIdentityFederation">GCPWorkloadIdentityFederation</a>)
+</p>
+<p>
+<p>AwsCredentialsConfig holds the region and the Secret reference which contains the AWS credentials.</p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>region</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+<p>region is for configuring the AWS region to be used.</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>awsCredentialsSecretRef</code></br>
+<em>
+<a href="#external-secrets.io/v1.SecretReference">
+SecretReference
+</a>
+</em>
+</td>
+<td>
+<p>awsCredentialsSecretRef is the reference to the secret which holds the AWS credentials.
+Secret should be created with below names for keys
+- aws_access_key_id: Access Key ID, which is the unique identifier for the AWS account or the IAM user.
+- aws_secret_access_key: Secret Access Key, which is used to authenticate requests made to AWS services.
+- aws_session_token: Session Token, is the short-lived token to authenticate requests made to AWS services.</p>
+</td>
+</tr>
+</tbody>
+</table>
 <h3 id="external-secrets.io/v1.AzureAuthCredentials">AzureAuthCredentials
 </h3>
 <p>
@@ -2551,6 +2598,58 @@ Kubernetes meta/v1.LabelSelector
 </tr>
 </tbody>
 </table>
+<h3 id="external-secrets.io/v1.ConfigMapReference">ConfigMapReference
+</h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1.GCPWorkloadIdentityFederation">GCPWorkloadIdentityFederation</a>)
+</p>
+<p>
+<p>ConfigMapReference holds the details of a configmap.</p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>name</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+<p>name of the configmap.</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>namespace</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+<p>namespace in which the configmap exists. If empty, configmap will looked up in local namespace.</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>key</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+<p>key name holding the external account credential config.</p>
+</td>
+</tr>
+</tbody>
+</table>
 <h3 id="external-secrets.io/v1.ConjurAPIKey">ConjurAPIKey
 </h3>
 <p>
@@ -4849,6 +4948,19 @@ GCPWorkloadIdentity
 <em>(Optional)</em>
 </td>
 </tr>
+<tr>
+<td>
+<code>workloadIdentityFederation</code></br>
+<em>
+<a href="#external-secrets.io/v1.GCPWorkloadIdentityFederation">
+GCPWorkloadIdentityFederation
+</a>
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+</td>
+</tr>
 </tbody>
 </table>
 <h3 id="external-secrets.io/v1.GCPSMAuthSecretRef">GCPSMAuthSecretRef
@@ -5007,6 +5119,94 @@ If not specified, it fetches information from the metadata server</p>
 </tr>
 </tbody>
 </table>
+<h3 id="external-secrets.io/v1.GCPWorkloadIdentityFederation">GCPWorkloadIdentityFederation
+</h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1.GCPSMAuth">GCPSMAuth</a>)
+</p>
+<p>
+<p>GCPWorkloadIdentityFederation holds the configurations required for generating federated access tokens.</p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>credConfig</code></br>
+<em>
+<a href="#external-secrets.io/v1.ConfigMapReference">
+ConfigMapReference
+</a>
+</em>
+</td>
+<td>
+<p>credConfig holds the configmap reference containing the GCP external account credential configuration in JSON format and the key name containing the json data.
+For using Kubernetes cluster as the identity provider, use serviceAccountRef instead. Operators mounted serviceaccount token cannot be used as the token source, instead
+serviceAccountRef must be used by providing operators service account details.</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>serviceAccountRef</code></br>
+<em>
+<a href="https://pkg.go.dev/github.com/external-secrets/external-secrets/apis/meta/v1#ServiceAccountSelector">
+External Secrets meta/v1.ServiceAccountSelector
+</a>
+</em>
+</td>
+<td>
+<p>serviceAccountRef is the reference to the kubernetes ServiceAccount to be used for obtaining the tokens,
+when Kubernetes is configured as provider in workload identity pool.</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>awsSecurityCredentials</code></br>
+<em>
+<a href="#external-secrets.io/v1.AwsCredentialsConfig">
+AwsCredentialsConfig
+</a>
+</em>
+</td>
+<td>
+<p>awsSecurityCredentials is for configuring AWS region and credentials to use for obtaining the access token,
+when using the AWS metadata server is not an option.</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>audience</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+<p>audience is the Secure Token Service (STS) audience which contains the resource name for the workload identity pool and the provider identifier in that pool.
+If specified, Audience found in the external account credential config will be overridden with the configured value.
+audience must be provided when serviceAccountRef or awsSecurityCredentials is configured.</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>externalTokenEndpoint</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+<p>externalTokenEndpoint is the endpoint explicitly set up to provide tokens, which will be matched against the
+credential_source.url in the provided credConfig. This field is merely to double-check the external token source
+URL is having the expected value.</p>
+</td>
+</tr>
+</tbody>
+</table>
 <h3 id="external-secrets.io/v1.GcpIamAuthCredentials">GcpIamAuthCredentials
 </h3>
 <p>
@@ -7603,6 +7803,47 @@ External Secrets meta/v1.SecretKeySelector
 </tr>
 </tbody>
 </table>
+<h3 id="external-secrets.io/v1.SecretReference">SecretReference
+</h3>
+<p>
+(<em>Appears on:</em>
+<a href="#external-secrets.io/v1.AwsCredentialsConfig">AwsCredentialsConfig</a>)
+</p>
+<p>
+<p>SecretReference holds the details of a secret.</p>
+</p>
+<table>
+<thead>
+<tr>
+<th>Field</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<code>name</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+<p>name of the secret.</p>
+</td>
+</tr>
+<tr>
+<td>
+<code>namespace</code></br>
+<em>
+string
+</em>
+</td>
+<td>
+<p>namespace in which the secret exists. If empty, secret will looked up in local namespace.</p>
+</td>
+</tr>
+</tbody>
+</table>
 <h3 id="external-secrets.io/v1.SecretServerProvider">SecretServerProvider
 </h3>
 <p>

+ 1 - 1
docs/provider/google-secrets-manager.md

@@ -166,7 +166,7 @@ Finally, you can create an `ExternalSecret` for the `demo-secret` that reference
 
 #### Authorizing the Core Controller Pod
 
-Instead of managing authentication at the `SecretStore` and `ClusterSecretStore` level, you can give the [Core Controller](../api/components/) Pod's service account access to Secret Manager secrets using one of the two WIF approaches described in the previous sections.
+Instead of managing authentication at the `SecretStore` and `ClusterSecretStore` level, you can give the [Core Controller](../api/components.md) Pod's service account access to Secret Manager secrets using one of the two WIF approaches described in the previous sections.
 
 To demonstrate this approach, we'll assume you installed ESO using Helm into the `external-secrets` namespace, with `external-secrets` as the release name:
 

+ 0 - 1
hack/api-docs/Makefile

@@ -66,7 +66,6 @@ build: image generate $(SOURCES)
 	    --mount type=bind,source=$(ROOT),target=/repo \
 		--sig-proxy=true \
 		--rm \
-		--user $(UID):$(GID) \
 		--env "GIT_COMMITTER_NAME=$(shell git config user.name)" \
 		--env "GIT_COMMITTER_EMAIL=$(shell git config user.email)" \
 		$(MKDOCS_IMAGE) \

+ 3 - 2
pkg/generator/gcr/gcr.go

@@ -69,8 +69,9 @@ func (g *Generator) generate(
 		return nil, nil, fmt.Errorf(errParseSpec, err)
 	}
 	ts, err := tokenSource(ctx, esv1.GCPSMAuth{
-		SecretRef:        (*esv1.GCPSMAuthSecretRef)(res.Spec.Auth.SecretRef),
-		WorkloadIdentity: (*esv1.GCPWorkloadIdentity)(res.Spec.Auth.WorkloadIdentity),
+		SecretRef:                  (*esv1.GCPSMAuthSecretRef)(res.Spec.Auth.SecretRef),
+		WorkloadIdentity:           (*esv1.GCPWorkloadIdentity)(res.Spec.Auth.WorkloadIdentity),
+		WorkloadIdentityFederation: res.Spec.Auth.WorkloadIdentityFederation,
 	}, res.Spec.ProjectID, resolvers.EmptyStoreKind, kube, namespace)
 	if err != nil {
 		return nil, nil, err

+ 9 - 2
pkg/provider/gcp/secretmanager/auth.go

@@ -16,7 +16,6 @@ package secretmanager
 
 import (
 	"context"
-	"errors"
 	"fmt"
 
 	"golang.org/x/oauth2"
@@ -34,7 +33,7 @@ func NewTokenSource(ctx context.Context, auth esv1.GCPSMAuth, projectID, storeKi
 	}
 	wi, err := newWorkloadIdentity(ctx, projectID)
 	if err != nil {
-		return nil, errors.New("unable to initialize workload identity")
+		return nil, fmt.Errorf("unable to initialize workload identity: %w", err)
 	}
 	defer func() {
 		_ = wi.Close()
@@ -44,6 +43,14 @@ func NewTokenSource(ctx context.Context, auth esv1.GCPSMAuth, projectID, storeKi
 	if ts != nil || err != nil {
 		return ts, err
 	}
+	wif, err := newWorkloadIdentityFederation(kube, auth.WorkloadIdentityFederation, isClusterKind, namespace)
+	if err != nil {
+		return nil, fmt.Errorf("failed to initialize workload identity federation: %w", err)
+	}
+	ts, err = wif.TokenSource(ctx)
+	if ts != nil || err != nil {
+		return ts, err
+	}
 	return google.DefaultTokenSource(ctx, CloudPlatformRole)
 }
 

+ 29 - 6
pkg/provider/gcp/secretmanager/workload_identity.go

@@ -26,7 +26,7 @@ import (
 	"cloud.google.com/go/compute/metadata"
 	iam "cloud.google.com/go/iam/credentials/apiv1"
 	"cloud.google.com/go/iam/credentials/apiv1/credentialspb"
-	secretmanager "cloud.google.com/go/secretmanager/apiv1"
+	gsmapiv1 "cloud.google.com/go/secretmanager/apiv1"
 	"github.com/googleapis/gax-go/v2"
 	"golang.org/x/oauth2"
 	"google.golang.org/api/option"
@@ -57,6 +57,29 @@ const (
 	errNoProjectID    = "unable to find ProjectID in storeSpec"
 )
 
+var (
+	// defaultUniverseDomain is the domain which will be used in the STS token URL.
+	defaultUniverseDomain = "googleapis.com"
+
+	// workloadIdentitySubjectTokenType is the STS token type used in Oauth2.0 token exchange.
+	workloadIdentitySubjectTokenType = "urn:ietf:params:oauth:token-type:jwt"
+
+	// workloadIdentitySubjectTokenType is the STS token type used in Oauth2.0 token exchange with AWS.
+	workloadIdentitySubjectTokenTypeAWS = "urn:ietf:params:aws:token-type:aws4_request"
+
+	// workloadIdentityTokenGrantType is the grant type for OAuth 2.0 token exchange .
+	workloadIdentityTokenGrantType = "urn:ietf:params:oauth:grant-type:token-exchange"
+
+	// workloadIdentityRequestedTokenType is the requested type for OAuth 2.0 access token.
+	workloadIdentityRequestedTokenType = "urn:ietf:params:oauth:token-type:access_token"
+
+	// workloadIdentityTokenURL is the token service endpoint.
+	workloadIdentityTokenURL = "https://sts.googleapis.com/v1/token"
+
+	// workloadIdentityTokenInfoURL is the STS introspection service endpoint.
+	workloadIdentityTokenInfoURL = "https://sts.googleapis.com/v1/introspect"
+)
+
 // workloadIdentity holds all clients and generators needed
 // to create a gcp oauth token.
 type workloadIdentity struct {
@@ -192,7 +215,7 @@ func (w *workloadIdentity) TokenSource(ctx context.Context, auth esv1.GCPSMAuth,
 	}
 	gcpSAResp, err := w.iamClient.GenerateAccessToken(ctx, &credentialspb.GenerateAccessTokenRequest{
 		Name:  fmt.Sprintf("projects/-/serviceAccounts/%s", gcpSA),
-		Scope: secretmanager.DefaultAuthScopes(),
+		Scope: gsmapiv1.DefaultAuthScopes(),
 	}, gax.WithGRPCOptions(grpc.PerRPCCredentials(oauth.TokenSource{TokenSource: oauth2.StaticTokenSource(idBindToken)})))
 	metrics.ObserveAPICall(constants.ProviderGCPSM, constants.CallGCPSMGenerateAccessToken, err)
 	if err != nil {
@@ -277,12 +300,12 @@ func newIDBindTokenGenerator() idBindTokenGenerator {
 
 func (g *gcpIDBindTokenGenerator) Generate(ctx context.Context, client *http.Client, k8sToken, idPool, idProvider string) (*oauth2.Token, error) {
 	body, err := json.Marshal(map[string]string{
-		"grant_type":           "urn:ietf:params:oauth:grant-type:token-exchange",
-		"subject_token_type":   "urn:ietf:params:oauth:token-type:jwt",
-		"requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
+		"grant_type":           workloadIdentityTokenGrantType,
+		"subject_token_type":   workloadIdentitySubjectTokenType,
+		"requested_token_type": workloadIdentityRequestedTokenType,
 		"subject_token":        k8sToken,
 		"audience":             fmt.Sprintf("identitynamespace:%s:%s", idPool, idProvider),
-		"scope":                "https://www.googleapis.com/auth/cloud-platform",
+		"scope":                CloudPlatformRole,
 	})
 	if err != nil {
 		return nil, err

+ 424 - 0
pkg/provider/gcp/secretmanager/workload_identity_federation.go

@@ -0,0 +1,424 @@
+/*
+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 secretmanager
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"reflect"
+	"regexp"
+	"strings"
+
+	gsmapiv1 "cloud.google.com/go/secretmanager/apiv1"
+	"golang.org/x/oauth2"
+	"golang.org/x/oauth2/google/externalaccount"
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/types"
+	kclient "sigs.k8s.io/controller-runtime/pkg/client"
+
+	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+	"github.com/external-secrets/external-secrets/pkg/constants"
+	"github.com/external-secrets/external-secrets/pkg/metrics"
+)
+
+// workloadIdentityFederation holds the clients and generators needed
+// to create a gcp oauth token.
+type workloadIdentityFederation struct {
+	kubeClient       kclient.Client
+	saTokenGenerator saTokenGenerator
+	config           *esv1.GCPWorkloadIdentityFederation
+	isClusterKind    bool
+	namespace        string
+}
+
+// k8sSATokenReader holds the data for generating the federated token.
+type k8sSATokenReader struct {
+	audience         string
+	subjectTokenType string
+	saTokenGenerator saTokenGenerator
+	saAudience       []string
+	serviceAccount   types.NamespacedName
+}
+
+type awsSecurityCredentialsReader struct {
+	region                 string
+	awsSecurityCredentials *externalaccount.AwsSecurityCredentials
+}
+
+// credentialsFile is the unmarshalled representation of a credentials file.
+// sourced from https://github.com/golang/oauth2/blob/master/google/google.go#L108-L144
+// as the type is not exported.
+type credentialsFile struct {
+	Type string `json:"type"`
+
+	// Service Account fields
+	ClientEmail    string `json:"client_email"`
+	PrivateKeyID   string `json:"private_key_id"`
+	PrivateKey     string `json:"private_key"`
+	AuthURL        string `json:"auth_uri"`
+	TokenURL       string `json:"token_uri"`
+	ProjectID      string `json:"project_id"`
+	UniverseDomain string `json:"universe_domain"`
+
+	// User Credential fields
+	// (These typically come from gcloud auth.)
+	ClientSecret string `json:"client_secret"`
+	ClientID     string `json:"client_id"`
+	RefreshToken string `json:"refresh_token"`
+
+	// External Account fields
+	Audience                       string                           `json:"audience"`
+	SubjectTokenType               string                           `json:"subject_token_type"`
+	TokenURLExternal               string                           `json:"token_url"`
+	TokenInfoURL                   string                           `json:"token_info_url"`
+	ServiceAccountImpersonationURL string                           `json:"service_account_impersonation_url"`
+	ServiceAccountImpersonation    serviceAccountImpersonationInfo  `json:"service_account_impersonation"`
+	Delegates                      []string                         `json:"delegates"`
+	CredentialSource               externalaccount.CredentialSource `json:"credential_source"`
+	QuotaProjectID                 string                           `json:"quota_project_id"`
+	WorkforcePoolUserProject       string                           `json:"workforce_pool_user_project"`
+
+	// External Account Authorized User fields
+	RevokeURL string `json:"revoke_url"`
+
+	// Service account impersonation
+	SourceCredentials *credentialsFile `json:"source_credentials"`
+}
+
+type serviceAccountImpersonationInfo struct {
+	TokenLifetimeSeconds int `json:"token_lifetime_seconds"`
+}
+
+var (
+	awsSTSTokenURLRegex                 = regexp.MustCompile(`^http://(metadata\.google\.internal|169\.254\.169\.254|\[fd00:ec2::254\])/latest/meta-data/iam/security-credentials$`)
+	awsRegionURLRegex                   = regexp.MustCompile(`^http://(metadata\.google\.internal|169\.254\.169\.254|\[fd00:ec2::254\])/latest/meta-data/placement/availability-zone$`)
+	awsSessionTokenURLRegex             = regexp.MustCompile(`^http://(metadata\.google\.internal|169\.254\.169\.254|\[fd00:ec2::254\])/latest/api/token$`)
+	serviceAccountImpersonationURLRegex = regexp.MustCompile(`^https://iamcredentials\.googleapis\.com/v1/projects/-/serviceAccounts/(\S+):generateAccessToken$`)
+)
+
+const (
+	// autoMountedServiceAccountTokenPath is the kubernetes service account token filepath
+	// made available by automountServiceAccountToken option in pod spec.
+	autoMountedServiceAccountTokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token"
+
+	// externalAccountCredentialType is the external account type indicator in the credentials files.
+	externalAccountCredentialType = "external_account"
+
+	awsEnvironmentIDPrefix    = "aws"
+	awsAccessKeyIdKeyName     = "aws_access_key_id"
+	awsSecretAccessKeyKeyName = "aws_secret_access_key"
+	awsSessionTokenKeyName    = "aws_session_token"
+)
+
+func newWorkloadIdentityFederation(kube kclient.Client, wif *esv1.GCPWorkloadIdentityFederation, isClusterKind bool, namespace string) (*workloadIdentityFederation, error) {
+	satg, err := newSATokenGenerator()
+	if err != nil {
+		return nil, err
+	}
+	return &workloadIdentityFederation{
+		kubeClient:       kube,
+		saTokenGenerator: satg,
+		config:           wif,
+		isClusterKind:    isClusterKind,
+		namespace:        namespace,
+	}, nil
+}
+
+func (w *workloadIdentityFederation) TokenSource(ctx context.Context) (oauth2.TokenSource, error) {
+	if w.config == nil {
+		return nil, nil
+	}
+
+	invalidConfigErrPrefix := "invalid workloadIdentityFederation config"
+	count := 0
+	if w.config.CredConfig != nil {
+		count++
+	}
+	if w.config.ServiceAccountRef != nil {
+		count++
+	}
+	if w.config.AwsSecurityCredentials != nil {
+		count++
+	}
+	if count != 1 {
+		return nil, fmt.Errorf("%s: exactly one of credConfig, awsSecurityCredentials or serviceAccountRef must be provided", invalidConfigErrPrefix)
+	}
+	if (w.config.ServiceAccountRef != nil || w.config.AwsSecurityCredentials != nil) && w.config.Audience == "" {
+		return nil, fmt.Errorf("%s: audience must be provided, when serviceAccountRef or awsSecurityCredentials is provided", invalidConfigErrPrefix)
+	}
+
+	config, err := w.readCredConfig(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return externalaccount.NewTokenSource(ctx, *config)
+}
+
+// readCredConfig is for loading the json cred config stored in the provided configmap.
+func (w *workloadIdentityFederation) readCredConfig(ctx context.Context) (*externalaccount.Config, error) {
+	if w.config.CredConfig == nil {
+		return w.generateExternalAccountConfig(ctx, nil)
+	}
+
+	key := types.NamespacedName{
+		Name:      w.config.CredConfig.Name,
+		Namespace: w.namespace,
+	}
+	if w.isClusterKind && w.config.CredConfig.Namespace != "" {
+		key.Namespace = w.config.CredConfig.Namespace
+	}
+
+	cm := &corev1.ConfigMap{}
+	if err := w.kubeClient.Get(ctx, key, cm); err != nil {
+		return nil, fmt.Errorf("failed to fetch external acccount credentials configmap %q: %w", key, err)
+	}
+
+	credKeyName := w.config.CredConfig.Key
+	credJSON, ok := cm.Data[credKeyName]
+	if !ok {
+		return nil, fmt.Errorf("missing key %q in configmap %q", credKeyName, w.config.CredConfig.Name)
+	}
+	if credJSON == "" {
+		return nil, fmt.Errorf("key %q in configmap %q has empty value", credKeyName, w.config.CredConfig.Name)
+	}
+	credFile := &credentialsFile{}
+	if err := json.Unmarshal([]byte(credJSON), credFile); err != nil {
+		return nil, fmt.Errorf("failed to unmarshal external acccount config in %q: %w", w.config.CredConfig.Name, err)
+	}
+
+	return w.generateExternalAccountConfig(ctx, credFile)
+}
+
+func (w *workloadIdentityFederation) generateExternalAccountConfig(ctx context.Context, credFile *credentialsFile) (*externalaccount.Config, error) {
+	var config = new(externalaccount.Config)
+
+	if err := w.updateExternalAccountConfigWithCredFileValues(config, credFile); err != nil {
+		return nil, err
+	}
+	w.updateExternalAccountConfigWithSubjectTokenSupplier(config)
+	if err := w.updateExternalAccountConfigWithAWSCredentialsSupplier(ctx, config); err != nil {
+		return nil, err
+	}
+	w.updateExternalAccountConfigWithDefaultValues(config)
+	if err := validateExternalAccountConfig(config, w.config); err != nil {
+		return nil, err
+	}
+
+	return config, nil
+}
+
+func (w *workloadIdentityFederation) updateExternalAccountConfigWithCredFileValues(config *externalaccount.Config, credFile *credentialsFile) error {
+	if credFile == nil {
+		return nil
+	}
+
+	if credFile.Type != externalAccountCredentialType {
+		return fmt.Errorf("invalid credentials: 'type' field is %q (expected %q)", credFile.Type, externalAccountCredentialType)
+	}
+
+	config.Audience = credFile.Audience
+	config.SubjectTokenType = credFile.SubjectTokenType
+	config.TokenURL = credFile.TokenURLExternal
+	config.TokenInfoURL = credFile.TokenInfoURL
+	config.ServiceAccountImpersonationURL = credFile.ServiceAccountImpersonationURL
+	config.ServiceAccountImpersonationLifetimeSeconds = credFile.ServiceAccountImpersonation.TokenLifetimeSeconds
+	config.ClientSecret = credFile.ClientSecret
+	config.ClientID = credFile.ClientID
+	config.QuotaProjectID = credFile.QuotaProjectID
+	config.UniverseDomain = credFile.UniverseDomain
+
+	// disallow using token of operator serviceaccount, not everyone gets
+	// same access defined to the operator. To use operator serviceaccount
+	// once has to provide the service account reference explicitly.
+	if !reflect.ValueOf(credFile.CredentialSource).IsZero() &&
+		credFile.CredentialSource.File != autoMountedServiceAccountTokenPath {
+		config.CredentialSource = &credFile.CredentialSource
+	}
+
+	return nil
+}
+
+func (w *workloadIdentityFederation) updateExternalAccountConfigWithDefaultValues(config *externalaccount.Config) {
+	config.Scopes = gsmapiv1.DefaultAuthScopes()
+	if w.config.Audience != "" {
+		config.Audience = w.config.Audience
+	}
+	if config.SubjectTokenType == "" {
+		config.SubjectTokenType = workloadIdentitySubjectTokenType
+	}
+	if config.TokenURL == "" {
+		config.TokenURL = workloadIdentityTokenURL
+	}
+	if config.TokenInfoURL == "" {
+		config.TokenInfoURL = workloadIdentityTokenInfoURL
+	}
+	if config.UniverseDomain == "" {
+		config.UniverseDomain = defaultUniverseDomain
+	}
+}
+
+func (w *workloadIdentityFederation) updateExternalAccountConfigWithAWSCredentialsSupplier(ctx context.Context, config *externalaccount.Config) error {
+	awsCredentialsSupplier, err := w.readAWSSecurityCredentials(ctx)
+	if err != nil {
+		return err
+	}
+	if awsCredentialsSupplier != nil {
+		config.AwsSecurityCredentialsSupplier = awsCredentialsSupplier
+		config.SubjectTokenType = workloadIdentitySubjectTokenTypeAWS
+	}
+	return nil
+}
+
+func (w *workloadIdentityFederation) updateExternalAccountConfigWithSubjectTokenSupplier(config *externalaccount.Config) {
+	if w.config.ServiceAccountRef == nil {
+		return
+	}
+
+	ns := w.namespace
+	if w.isClusterKind && w.config.ServiceAccountRef.Namespace != nil {
+		ns = *w.config.ServiceAccountRef.Namespace
+	}
+	config.SubjectTokenSupplier = &k8sSATokenReader{
+		audience:         config.Audience,
+		subjectTokenType: workloadIdentitySubjectTokenType,
+		saTokenGenerator: w.saTokenGenerator,
+		saAudience:       w.config.ServiceAccountRef.Audiences,
+		serviceAccount: types.NamespacedName{
+			Name:      w.config.ServiceAccountRef.Name,
+			Namespace: ns,
+		},
+	}
+}
+
+func (w *workloadIdentityFederation) readAWSSecurityCredentials(ctx context.Context) (*awsSecurityCredentialsReader, error) {
+	awsCreds := w.config.AwsSecurityCredentials
+	if awsCreds == nil {
+		return nil, nil
+	}
+
+	key := types.NamespacedName{
+		Name:      awsCreds.AwsCredentialsSecretRef.Name,
+		Namespace: w.namespace,
+	}
+	if w.isClusterKind && awsCreds.AwsCredentialsSecretRef.Namespace != "" {
+		key.Namespace = awsCreds.AwsCredentialsSecretRef.Namespace
+	}
+	secret := &corev1.Secret{}
+	if err := w.kubeClient.Get(ctx, key, secret); err != nil {
+		return nil, fmt.Errorf("failed to fetch AwsSecurityCredentials secret %q: %w", key, err)
+	}
+
+	accessKeyID := string(secret.Data[awsAccessKeyIdKeyName])
+	secretAccessKey := string(secret.Data[awsSecretAccessKeyKeyName])
+	sessionToken := string(secret.Data[awsSessionTokenKeyName])
+	if accessKeyID == "" || secretAccessKey == "" {
+		return nil, fmt.Errorf("%s and %s keys must be present in AwsSecurityCredentials secret", awsAccessKeyIdKeyName, awsSecretAccessKeyKeyName)
+	}
+
+	return &awsSecurityCredentialsReader{
+		region: w.config.AwsSecurityCredentials.Region,
+		awsSecurityCredentials: &externalaccount.AwsSecurityCredentials{
+			AccessKeyID:     accessKeyID,
+			SecretAccessKey: secretAccessKey,
+			SessionToken:    sessionToken,
+		},
+	}, nil
+}
+
+// validateExternalAccountConfig is for validating the external_account credentials configurations, based on
+// suggestions made at https://cloud.google.com/docs/authentication/client-libraries#external-credentials.
+func validateExternalAccountConfig(config *externalaccount.Config, wif *esv1.GCPWorkloadIdentityFederation) error {
+	var errs []error
+	errs = append(errs, fmt.Errorf("invalid %s config", externalAccountCredentialType))
+
+	if config.Audience == "" {
+		errs = append(errs, fmt.Errorf("audience is empty"))
+	}
+	if config.ServiceAccountImpersonationURL != "" &&
+		!serviceAccountImpersonationURLRegex.MatchString(config.ServiceAccountImpersonationURL) {
+		errs = append(errs, fmt.Errorf("service_account_impersonation_url \"%s\" does not have expected value", config.ServiceAccountImpersonationURL))
+	}
+	if config.TokenURL != workloadIdentityTokenURL {
+		errs = append(errs, fmt.Errorf("token_url \"%s\" must match %s", config.TokenURL, workloadIdentityTokenURL))
+	}
+	if config.CredentialSource != nil {
+		errs = append(errs, validateCredConfigCredentialSource(config.CredentialSource, wif)...)
+	}
+	if len(errs) > 1 {
+		return errors.Join(errs...)
+	}
+
+	return nil
+}
+
+func validateCredConfigCredentialSource(credSource *externalaccount.CredentialSource, wif *esv1.GCPWorkloadIdentityFederation) []error {
+	var errs []error
+	// restricting the use of executables from security standpoint, since executables can't be validated.
+	if credSource.Executable != nil {
+		errs = append(errs, fmt.Errorf("credential_source.executable.command is not allowed"))
+	}
+	if credSource.File == "" && credSource.URL == "" && credSource.EnvironmentID == "" {
+		errs = append(errs, fmt.Errorf("one of credential_source.file, credential_source.url, credential_source.aws.url or credential_source_environment_id should be provided"))
+	}
+	if credSource.EnvironmentID == "" && credSource.URL != wif.ExternalTokenEndpoint {
+		errs = append(errs, fmt.Errorf("credential_source.url \"%s\" does not match with the configured %s externalTokenEndpoint", credSource.URL, wif.ExternalTokenEndpoint))
+	}
+	errs = append(errs, validateCredConfigAWSCredentialSource(credSource)...)
+
+	return errs
+}
+
+func validateCredConfigAWSCredentialSource(credSource *externalaccount.CredentialSource) []error {
+	var errs []error
+	if credSource.EnvironmentID != "" {
+		if !strings.HasPrefix(strings.ToLower(credSource.EnvironmentID), awsEnvironmentIDPrefix) {
+			errs = append(errs, fmt.Errorf("credential_source.environment_id \"%s\" must start with %s", credSource.EnvironmentID, awsEnvironmentIDPrefix))
+		}
+		if !awsSTSTokenURLRegex.MatchString(credSource.URL) {
+			errs = append(errs, fmt.Errorf("credential_source.aws.url \"%s\" does not have expected value", credSource.URL))
+		}
+		if !awsRegionURLRegex.MatchString(credSource.RegionURL) {
+			errs = append(errs, fmt.Errorf("credential_source.aws.region_url \"%s\" does not have expected value", credSource.RegionURL))
+		}
+		if credSource.IMDSv2SessionTokenURL != "" && !awsSessionTokenURLRegex.MatchString(credSource.IMDSv2SessionTokenURL) {
+			errs = append(errs, fmt.Errorf("credential_source.aws.imdsv2_session_token_url \"%s\" does not have expected value", credSource.IMDSv2SessionTokenURL))
+		}
+	}
+	return errs
+}
+
+func (r *k8sSATokenReader) SubjectToken(ctx context.Context, options externalaccount.SupplierOptions) (string, error) {
+	if options.Audience != r.audience || options.SubjectTokenType != r.subjectTokenType {
+		return "", fmt.Errorf("invalid subject token request, audience is %s(expected %s) and subject_token_type is %s(expected %s)", options.Audience, r.audience, options.SubjectTokenType, r.subjectTokenType)
+	}
+
+	resp, err := r.saTokenGenerator.Generate(ctx, r.saAudience, r.serviceAccount.Name, r.serviceAccount.Namespace)
+	metrics.ObserveAPICall(constants.ProviderGCPSM, constants.CallGCPSMGenerateSAToken, err)
+	if err != nil {
+		return "", fmt.Errorf(errFetchPodToken, err)
+	}
+
+	return resp.Status.Token, nil
+}
+
+func (a *awsSecurityCredentialsReader) AwsRegion(ctx context.Context, options externalaccount.SupplierOptions) (string, error) {
+	return a.region, nil
+}
+
+func (a *awsSecurityCredentialsReader) AwsSecurityCredentials(ctx context.Context, options externalaccount.SupplierOptions) (*externalaccount.AwsSecurityCredentials, error) {
+	return a.awsSecurityCredentials, nil
+}

+ 899 - 0
pkg/provider/gcp/secretmanager/workload_identity_federation_test.go

@@ -0,0 +1,899 @@
+/*
+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 secretmanager
+
+import (
+	"context"
+	"encoding/json"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"golang.org/x/oauth2/google/externalaccount"
+	authv1 "k8s.io/api/authentication/v1"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/types"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
+
+	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
+	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
+)
+
+type workloadIdentityFederationTest struct {
+	name              string
+	wifConfig         *esv1.GCPWorkloadIdentityFederation
+	kubeObjects       []client.Object
+	genSAToken        func(context.Context, []string, string, string) (*authv1.TokenRequest, error)
+	expectError       string
+	expectTokenSource bool
+}
+
+const (
+	testConfigMapName                  = "external-account-config"
+	testConfigMapKey                   = "config.json"
+	testServiceAccount                 = "test-sa"
+	testAudience                       = "//iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/test-pool/providers/test-provider"
+	testServiceAccountImpersonationURL = "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/test@test.iam.gserviceaccount.com:generateAccessToken"
+	testSAToken                        = "test-sa-token"
+	testAwsRegion                      = "us-west-2"
+	// below values taken from https://docs.aws.amazon.com/sdkref/latest/guide/feature-static-credentials.html
+	testAwsAccessKey = "AKIAIOSFODNN7EXAMPLE"
+	testAwsSecretKey = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
+	// below value taken from https://docs.aws.amazon.com/STS/latest/APIReference/API_GetSessionToken.html
+	testAwsSessionToken        = "AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4OlgkBN9bkUDNCJiBeb/AXlzBBko7b15fjrBs2+cTQtpZ3CYWFXG8C5zqx37wnOE49mRl/+OtkIKGO7fAE"
+	testAwsTokenFQDNURL        = "http://metadata.google.internal/latest/meta-data/iam/security-credentials"
+	testAwsRegionFQDNURL       = "http://metadata.google.internal/latest/meta-data/placement/availability-zone"
+	testAwsSessionTokenFQDNURL = "http://metadata.google.internal/latest/api/token"
+	testAwsTokenIPV4URL        = "http://169.254.169.254/latest/meta-data/iam/security-credentials"
+	testAwsRegionIPv4URL       = "http://169.254.169.254/latest/meta-data/placement/availability-zone"
+	testAwsSessionTokenIPv4URL = "http://169.254.169.254/latest/api/token"
+	testAwsTokenIPV6URL        = "http://[fd00:ec2::254]/latest/meta-data/iam/security-credentials"
+	testAwsRegionIPv6URL       = "http://[fd00:ec2::254]/latest/meta-data/placement/availability-zone"
+	testAwsSessionTokenIPv6URL = "http://[fd00:ec2::254]/latest/api/token"
+)
+
+var (
+	testNamespace = "external-secrets-tests"
+)
+
+func createValidK8sExternalAccountConfig(audience string) string {
+	config := map[string]interface{}{
+		"type":               externalAccountCredentialType,
+		"audience":           audience,
+		"subject_token_type": workloadIdentitySubjectTokenType,
+		"token_url":          workloadIdentityTokenURL,
+		"credential_source": map[string]interface{}{
+			"file": "/var/run/secrets/oidc_token",
+		},
+		"token_info_url": workloadIdentityTokenInfoURL,
+	}
+	data, _ := json.Marshal(config)
+	return string(data)
+}
+
+func createValidAWSExternalAccountConfig(audience string) string {
+	config := map[string]interface{}{
+		"type":                              externalAccountCredentialType,
+		"audience":                          audience,
+		"subject_token_type":                workloadIdentitySubjectTokenType,
+		"token_url":                         workloadIdentityTokenURL,
+		"service_account_impersonation_url": testServiceAccountImpersonationURL,
+		"credential_source": map[string]interface{}{
+			"environment_id":           "aws1",
+			"url":                      testAwsTokenIPV4URL,
+			"region_url":               testAwsRegionIPv4URL,
+			"imdsv2_session_token_url": testAwsSessionTokenIPv4URL,
+		},
+	}
+	data, _ := json.Marshal(config)
+	return string(data)
+}
+
+func createInvalidTypeExternalAccountConfig() string {
+	config := map[string]interface{}{
+		"type":     "service_account",
+		"audience": testAudience,
+	}
+	data, _ := json.Marshal(config)
+	return string(data)
+}
+
+func createInvalidK8sExternalAccountConfigWithUnallowedTokenFilePath(audience string) string {
+	config := map[string]interface{}{
+		"type":               externalAccountCredentialType,
+		"audience":           audience,
+		"subject_token_type": workloadIdentitySubjectTokenType,
+		"token_url":          workloadIdentityTokenURL,
+		"credential_source": map[string]interface{}{
+			"file": autoMountedServiceAccountTokenPath,
+		},
+		"token_info_url": workloadIdentityTokenInfoURL,
+	}
+	data, _ := json.Marshal(config)
+	return string(data)
+}
+
+func createInvalidK8sExternalAccountConfigWithUnallowedTokenURL(audience string) string {
+	config := map[string]interface{}{
+		"type":               externalAccountCredentialType,
+		"audience":           audience,
+		"subject_token_type": workloadIdentitySubjectTokenType,
+		"token_url":          "https://example.com",
+		"credential_source": map[string]interface{}{
+			"file": "/var/run/secrets/oidc_token",
+		},
+		"token_info_url": workloadIdentityTokenInfoURL,
+	}
+	data, _ := json.Marshal(config)
+	return string(data)
+}
+
+func defaultSATokenGenerator(ctx context.Context, idPool []string, namespace, name string) (*authv1.TokenRequest, error) {
+	return &authv1.TokenRequest{
+		Status: authv1.TokenRequestStatus{
+			Token: testSAToken,
+		},
+	}, nil
+}
+
+func TestWorkloadIdentityFederation(t *testing.T) {
+	tests := []*workloadIdentityFederationTest{
+		{
+			name:      "workload identity federation config is empty",
+			wifConfig: nil,
+		},
+		{
+			name: "invalid workload identity federation config without audience",
+			wifConfig: &esv1.GCPWorkloadIdentityFederation{
+				ServiceAccountRef: &esmeta.ServiceAccountSelector{
+					Name:      testServiceAccount,
+					Namespace: &testNamespace,
+					Audiences: []string{testAudience},
+				},
+			},
+			expectError: `invalid workloadIdentityFederation config: audience must be provided, when serviceAccountRef or awsSecurityCredentials is provided`,
+		},
+		{
+			name: "successful kubernetes service account token federation",
+			wifConfig: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{
+					Name:      testConfigMapName,
+					Key:       testConfigMapKey,
+					Namespace: testNamespace,
+				},
+			},
+			kubeObjects: []client.Object{
+				&corev1.ConfigMap{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      testConfigMapName,
+						Namespace: testNamespace,
+					},
+					Data: map[string]string{
+						testConfigMapKey: createValidK8sExternalAccountConfig(testAudience),
+					},
+				},
+			},
+			expectTokenSource: true,
+		},
+		{
+			name: "cred configmap configured non-existent key",
+			wifConfig: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{
+					Name:      testConfigMapName,
+					Namespace: testNamespace,
+					Key:       testConfigMapKey,
+				},
+			},
+			kubeObjects: []client.Object{
+				&corev1.ConfigMap{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      testConfigMapName,
+						Namespace: testNamespace,
+					},
+					Data: map[string]string{
+						"incorrect": createValidK8sExternalAccountConfig(testAudience),
+					},
+				},
+			},
+			expectError: `missing key "config.json" in configmap "external-account-config"`,
+		},
+		{
+			name: "cred configmap configured with wrong key name",
+			wifConfig: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{
+					Name:      testConfigMapName,
+					Key:       "wrongKey",
+					Namespace: testNamespace,
+				},
+			},
+			kubeObjects: []client.Object{
+				&corev1.ConfigMap{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      testConfigMapName,
+						Namespace: testNamespace,
+					},
+					Data: map[string]string{
+						testConfigMapKey: createValidK8sExternalAccountConfig(testAudience),
+					},
+				},
+			},
+			expectError: `missing key "wrongKey" in configmap "external-account-config"`,
+		},
+		{
+			name: "invalid cred config - invalid tokenURL",
+			wifConfig: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{
+					Name:      testConfigMapName,
+					Namespace: testNamespace,
+					Key:       testConfigMapKey,
+				},
+			},
+			kubeObjects: []client.Object{
+				&corev1.ConfigMap{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      testConfigMapName,
+						Namespace: testNamespace,
+					},
+					Data: map[string]string{
+						testConfigMapKey: createInvalidK8sExternalAccountConfigWithUnallowedTokenURL(testAudience),
+					},
+				},
+			},
+			expectError: "invalid external_account config\ntoken_url \"https://example.com\" must match https://sts.googleapis.com/v1/token",
+		},
+		{
+			name: "successful AWS federation with security credentials",
+			wifConfig: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{
+					Name:      testConfigMapName,
+					Key:       testConfigMapKey,
+					Namespace: testNamespace,
+				},
+			},
+			kubeObjects: []client.Object{
+				&corev1.ConfigMap{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      testConfigMapName,
+						Namespace: testNamespace,
+					},
+					Data: map[string]string{
+						testConfigMapKey: createValidAWSExternalAccountConfig(testAudience),
+					},
+				},
+				&corev1.Secret{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "aws-creds",
+						Namespace: testNamespace,
+					},
+					Data: map[string][]byte{
+						awsAccessKeyIdKeyName:     []byte(testAwsAccessKey),
+						awsSecretAccessKeyKeyName: []byte(testAwsSecretKey),
+						awsSessionTokenKeyName:    []byte(testAwsSessionToken),
+					},
+				},
+			},
+			expectTokenSource: true,
+		},
+		{
+			name: "external account creds configmap not present",
+			wifConfig: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{
+					Name:      testConfigMapName,
+					Key:       testConfigMapKey,
+					Namespace: testNamespace,
+				},
+			},
+			kubeObjects: []client.Object{},
+			expectError: `failed to fetch external acccount credentials configmap "external-secrets-tests/external-account-config": configmaps "external-account-config" not found`,
+		},
+		{
+			name: "creds configmap has invalid type",
+			wifConfig: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{
+					Name:      testConfigMapName,
+					Key:       testConfigMapKey,
+					Namespace: testNamespace,
+				},
+			},
+			kubeObjects: []client.Object{
+				&corev1.ConfigMap{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      testConfigMapName,
+						Namespace: testNamespace,
+					},
+					Data: map[string]string{
+						testConfigMapKey: createInvalidTypeExternalAccountConfig(),
+					},
+				},
+			},
+			expectError: `invalid credentials: 'type' field is "service_account" (expected "external_account")`,
+		},
+		{
+			name: "creds configmap has non-json data",
+			wifConfig: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{
+					Name:      testConfigMapName,
+					Key:       testConfigMapKey,
+					Namespace: testNamespace,
+				},
+			},
+			kubeObjects: []client.Object{
+				&corev1.ConfigMap{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      testConfigMapName,
+						Namespace: testNamespace,
+					},
+					Data: map[string]string{
+						testConfigMapKey: "invalid-json",
+					},
+				},
+			},
+			expectError: "failed to unmarshal external acccount config in \"external-account-config\": invalid character 'i' looking for beginning of value",
+		},
+		{
+			name: "successful with service account reference",
+			wifConfig: &esv1.GCPWorkloadIdentityFederation{
+				ServiceAccountRef: &esmeta.ServiceAccountSelector{
+					Name:      testServiceAccount,
+					Namespace: &testNamespace,
+					Audiences: []string{testAudience},
+				},
+				Audience: testAudience,
+			},
+			kubeObjects: []client.Object{
+				&corev1.ConfigMap{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      testConfigMapName,
+						Namespace: testNamespace,
+					},
+					Data: map[string]string{
+						testConfigMapKey: createInvalidK8sExternalAccountConfigWithUnallowedTokenFilePath(testAudience),
+					},
+				},
+			},
+			genSAToken: func(c context.Context, s1 []string, s2, s3 string) (*authv1.TokenRequest, error) {
+				return &authv1.TokenRequest{
+					Status: authv1.TokenRequestStatus{
+						Token: testSAToken,
+					},
+				}, nil
+			},
+			expectTokenSource: true,
+		},
+		{
+			name: "valid AWS credentials secret",
+			wifConfig: &esv1.GCPWorkloadIdentityFederation{
+				AwsSecurityCredentials: &esv1.AwsCredentialsConfig{
+					Region: testAwsRegion,
+					AwsCredentialsSecretRef: &esv1.SecretReference{
+						Name:      "aws-creds",
+						Namespace: testNamespace,
+					},
+				},
+				Audience: testAudience,
+			},
+			kubeObjects: []client.Object{
+				&corev1.ConfigMap{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      testConfigMapName,
+						Namespace: testNamespace,
+					},
+					Data: map[string]string{
+						testConfigMapKey: createValidAWSExternalAccountConfig(testAudience),
+					},
+				},
+				&corev1.Secret{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "aws-creds",
+						Namespace: testNamespace,
+					},
+					Data: map[string][]byte{
+						awsAccessKeyIdKeyName:     []byte(testAwsAccessKey),
+						awsSecretAccessKeyKeyName: []byte(testAwsSecretKey),
+					},
+				},
+			},
+		},
+		{
+			name: "non-existent AWS credentials secret",
+			wifConfig: &esv1.GCPWorkloadIdentityFederation{
+				AwsSecurityCredentials: &esv1.AwsCredentialsConfig{
+					Region: testAwsRegion,
+					AwsCredentialsSecretRef: &esv1.SecretReference{
+						Name:      "non-existent-aws-creds",
+						Namespace: testNamespace,
+					},
+				},
+				Audience: testAudience,
+			},
+			kubeObjects: []client.Object{
+				&corev1.ConfigMap{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      testConfigMapName,
+						Namespace: testNamespace,
+					},
+					Data: map[string]string{
+						testConfigMapKey: createValidAWSExternalAccountConfig(testAudience),
+					},
+				},
+			},
+			expectError: `failed to fetch AwsSecurityCredentials secret "external-secrets-tests/non-existent-aws-creds": secrets "non-existent-aws-creds" not found`,
+		},
+		{
+			name: "invalid AWS credentials - aws_access_key_id not provided",
+			wifConfig: &esv1.GCPWorkloadIdentityFederation{
+				AwsSecurityCredentials: &esv1.AwsCredentialsConfig{
+					Region: testAwsRegion,
+					AwsCredentialsSecretRef: &esv1.SecretReference{
+						Name:      "aws-creds",
+						Namespace: testNamespace,
+					},
+				},
+				Audience: testAudience,
+			},
+			kubeObjects: []client.Object{
+				&corev1.ConfigMap{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      testConfigMapName,
+						Namespace: testNamespace,
+					},
+					Data: map[string]string{
+						testConfigMapKey: createValidAWSExternalAccountConfig(testAudience),
+					},
+				},
+				&corev1.Secret{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "aws-creds",
+						Namespace: testNamespace,
+					},
+					Data: map[string][]byte{
+						awsSecretAccessKeyKeyName: []byte(testAwsSecretKey),
+					},
+				},
+			},
+			expectError: "aws_access_key_id and aws_secret_access_key keys must be present in AwsSecurityCredentials secret",
+		},
+		{
+			name: "credConfig is empty",
+			wifConfig: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: nil,
+			},
+			expectError: "invalid workloadIdentityFederation config: exactly one of credConfig, awsSecurityCredentials or serviceAccountRef must be provided",
+		},
+		{
+			name: "both credential_source in credConfig and AwsCredentialsConfig are set",
+			wifConfig: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{
+					Name:      testConfigMapName,
+					Key:       testConfigMapKey,
+					Namespace: testNamespace,
+				},
+				AwsSecurityCredentials: &esv1.AwsCredentialsConfig{
+					Region: testAwsRegion,
+					AwsCredentialsSecretRef: &esv1.SecretReference{
+						Name:      "aws-creds",
+						Namespace: testNamespace,
+					},
+				},
+			},
+			kubeObjects: []client.Object{
+				&corev1.ConfigMap{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      testConfigMapName,
+						Namespace: testNamespace,
+					},
+					Data: map[string]string{
+						testConfigMapKey: createValidAWSExternalAccountConfig(testAudience),
+					},
+				},
+				&corev1.Secret{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "aws-creds",
+						Namespace: testNamespace,
+					},
+					Data: map[string][]byte{
+						awsAccessKeyIdKeyName:     []byte(testAwsAccessKey),
+						awsSecretAccessKeyKeyName: []byte(testAwsSecretKey),
+						awsSessionTokenKeyName:    []byte(testAwsSessionToken),
+					},
+				},
+			},
+			expectError: "invalid workloadIdentityFederation config: exactly one of credConfig, awsSecurityCredentials or serviceAccountRef must be provided",
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			fakeClient := clientfake.NewClientBuilder().WithObjects(tc.kubeObjects...).Build()
+
+			fakeSATG := &fakeSATokenGen{
+				GenerateFunc: tc.genSAToken,
+			}
+			if tc.genSAToken == nil {
+				fakeSATG.GenerateFunc = defaultSATokenGenerator
+			}
+
+			wif := &workloadIdentityFederation{
+				kubeClient:       fakeClient,
+				saTokenGenerator: fakeSATG,
+				config:           tc.wifConfig,
+				isClusterKind:    true,
+				namespace:        testNamespace,
+			}
+
+			ts, err := wif.TokenSource(context.Background())
+			if tc.expectError != "" {
+				assert.Error(t, err)
+				assert.Equal(t, tc.expectError, err.Error())
+				assert.Nil(t, ts)
+			} else {
+				assert.NoError(t, err)
+				if tc.expectTokenSource {
+					assert.NotNil(t, ts)
+				}
+			}
+		})
+	}
+}
+
+func TestValidateCredConfig(t *testing.T) {
+	tests := []struct {
+		name        string
+		config      *externalaccount.Config
+		wif         *esv1.GCPWorkloadIdentityFederation
+		expectError string
+	}{
+		{
+			name: "valid kubernetes provider config",
+			config: &externalaccount.Config{
+				Audience:                       testAudience,
+				SubjectTokenType:               workloadIdentitySubjectTokenType,
+				TokenURL:                       workloadIdentityTokenURL,
+				ServiceAccountImpersonationURL: testServiceAccountImpersonationURL,
+				CredentialSource: &externalaccount.CredentialSource{
+					File: autoMountedServiceAccountTokenPath,
+				},
+			},
+			wif: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{Name: testConfigMapName},
+			},
+			expectError: "",
+		},
+		{
+			name: "valid AWS provider config with IPv6",
+			config: &externalaccount.Config{
+				Audience:                       testAudience,
+				SubjectTokenType:               workloadIdentitySubjectTokenType,
+				TokenURL:                       workloadIdentityTokenURL,
+				ServiceAccountImpersonationURL: testServiceAccountImpersonationURL,
+				CredentialSource: &externalaccount.CredentialSource{
+					EnvironmentID:         "aws1",
+					URL:                   testAwsTokenIPV6URL,
+					RegionURL:             testAwsRegionIPv6URL,
+					IMDSv2SessionTokenURL: testAwsSessionTokenIPv6URL,
+				},
+			},
+			wif: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{Name: testConfigMapName},
+			},
+			expectError: "",
+		},
+		{
+			name: "valid AWS provider config with FQDN",
+			config: &externalaccount.Config{
+				Audience:                       testAudience,
+				SubjectTokenType:               workloadIdentitySubjectTokenType,
+				TokenURL:                       workloadIdentityTokenURL,
+				ServiceAccountImpersonationURL: testServiceAccountImpersonationURL,
+				CredentialSource: &externalaccount.CredentialSource{
+					EnvironmentID:         "aws1",
+					URL:                   testAwsTokenFQDNURL,
+					RegionURL:             testAwsRegionFQDNURL,
+					IMDSv2SessionTokenURL: testAwsSessionTokenFQDNURL,
+				},
+			},
+			wif: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{Name: testConfigMapName},
+			},
+			expectError: "",
+		},
+		{
+			name: "invalid service account impersonation URL",
+			config: &externalaccount.Config{
+				Audience:                       testAudience,
+				TokenURL:                       workloadIdentityTokenURL,
+				ServiceAccountImpersonationURL: "https://invalid-url.com",
+			},
+			wif: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{Name: testConfigMapName},
+			},
+			expectError: "invalid external_account config\nservice_account_impersonation_url \"https://invalid-url.com\" does not have expected value",
+		},
+		{
+			name: "invalid token URL",
+			config: &externalaccount.Config{
+				Audience:                       testAudience,
+				TokenURL:                       "https://invalid-token-url.com",
+				ServiceAccountImpersonationURL: testServiceAccountImpersonationURL,
+			},
+			wif: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{Name: testConfigMapName},
+			},
+			expectError: "invalid external_account config\ntoken_url \"https://invalid-token-url.com\" must match https://sts.googleapis.com/v1/token",
+		},
+		{
+			name: "executable is configured",
+			config: &externalaccount.Config{
+				Audience:                       testAudience,
+				TokenURL:                       workloadIdentityTokenURL,
+				ServiceAccountImpersonationURL: testServiceAccountImpersonationURL,
+				CredentialSource: &externalaccount.CredentialSource{
+					Executable: &externalaccount.ExecutableConfig{
+						Command: "/usr/local/bin/token-issuer",
+					},
+				},
+			},
+			wif: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{Name: testConfigMapName},
+			},
+			expectError: "invalid external_account config\ncredential_source.executable.command is not allowed\none of credential_source.file, credential_source.url, credential_source.aws.url or credential_source_environment_id should be provided",
+		},
+		{
+			name: "invalid config - empty audience",
+			config: &externalaccount.Config{
+				TokenURL:                       workloadIdentityTokenURL,
+				ServiceAccountImpersonationURL: testServiceAccountImpersonationURL,
+				CredentialSource: &externalaccount.CredentialSource{
+					File: "/var/run/secrets/token",
+				},
+			},
+			wif: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{Name: testConfigMapName},
+			},
+			expectError: "invalid external_account config\naudience is empty",
+		},
+		{
+			name: "invalid config - invalid URL",
+			config: &externalaccount.Config{
+				Audience:                       testAudience,
+				TokenURL:                       workloadIdentityTokenURL,
+				ServiceAccountImpersonationURL: testServiceAccountImpersonationURL,
+				CredentialSource: &externalaccount.CredentialSource{
+					URL: "https://example.com",
+				},
+			},
+			wif: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig:            &esv1.ConfigMapReference{Name: testConfigMapName},
+				ExternalTokenEndpoint: "https://mismatch.com",
+			},
+			expectError: "invalid external_account config\ncredential_source.url \"https://example.com\" does not match with the configured https://mismatch.com externalTokenEndpoint",
+		},
+		{
+			name: "invalid config - invalid AWS config",
+			config: &externalaccount.Config{
+				Audience:                       testAudience,
+				TokenURL:                       workloadIdentityTokenURL,
+				ServiceAccountImpersonationURL: testServiceAccountImpersonationURL,
+				CredentialSource: &externalaccount.CredentialSource{
+					EnvironmentID:         "sample",
+					URL:                   "https://aws-token.com",
+					RegionURL:             "https://region.com",
+					IMDSv2SessionTokenURL: "https://session-token.com",
+				},
+			},
+			wif: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig:            &esv1.ConfigMapReference{Name: testConfigMapName},
+				ExternalTokenEndpoint: "https://mismatch.com",
+			},
+			expectError: "invalid external_account config\ncredential_source.environment_id \"sample\" must start with aws\ncredential_source.aws.url \"https://aws-token.com\" does not have expected value\ncredential_source.aws.region_url \"https://region.com\" does not have expected value\ncredential_source.aws.imdsv2_session_token_url \"https://session-token.com\" does not have expected value",
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			err := validateExternalAccountConfig(tc.config, tc.wif)
+			if tc.expectError != "" {
+				assert.Error(t, err)
+				assert.Equal(t, tc.expectError, err.Error())
+			} else {
+				assert.NoError(t, err)
+			}
+		})
+	}
+}
+
+func TestK8sSATokenReader(t *testing.T) {
+	r := &k8sSATokenReader{
+		audience:         testAudience,
+		subjectTokenType: workloadIdentitySubjectTokenType,
+		saTokenGenerator: &fakeSATokenGen{
+			GenerateFunc: defaultSATokenGenerator,
+		},
+		saAudience: []string{testAudience},
+		serviceAccount: types.NamespacedName{
+			Name:      testServiceAccount,
+			Namespace: testNamespace,
+		},
+	}
+
+	ctx := context.Background()
+
+	// Test successful token generation
+	token, err := r.SubjectToken(ctx, externalaccount.SupplierOptions{
+		Audience:         testAudience,
+		SubjectTokenType: workloadIdentitySubjectTokenType,
+	})
+	assert.NoError(t, err)
+	assert.Equal(t, testSAToken, token)
+
+	// Test invalid audience
+	_, err = r.SubjectToken(ctx, externalaccount.SupplierOptions{
+		Audience:         "invalid-audience",
+		SubjectTokenType: workloadIdentitySubjectTokenType,
+	})
+	assert.Error(t, err)
+	assert.Equal(t,
+		`invalid subject token request, audience is invalid-audience(expected //iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/test-pool/providers/test-provider) and subject_token_type is urn:ietf:params:oauth:token-type:jwt(expected urn:ietf:params:oauth:token-type:jwt)`,
+		err.Error())
+
+	// Test invalid subject token type
+	_, err = r.SubjectToken(ctx, externalaccount.SupplierOptions{
+		Audience:         testAudience,
+		SubjectTokenType: "invalid-type",
+	})
+	assert.Error(t, err)
+	assert.Equal(t,
+		`invalid subject token request, audience is //iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/test-pool/providers/test-provider(expected //iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/test-pool/providers/test-provider) and subject_token_type is invalid-type(expected urn:ietf:params:oauth:token-type:jwt)`,
+		err.Error())
+}
+
+func TestAWSSecurityCredentialsReader(t *testing.T) {
+	r := &awsSecurityCredentialsReader{
+		region: testAwsRegion,
+		awsSecurityCredentials: &externalaccount.AwsSecurityCredentials{
+			AccessKeyID:     testAwsAccessKey,
+			SecretAccessKey: testAwsSecretKey,
+			SessionToken:    testAwsSessionToken,
+		},
+	}
+
+	ctx := context.Background()
+	options := externalaccount.SupplierOptions{}
+
+	// Test region retrieval
+	region, err := r.AwsRegion(ctx, options)
+	assert.NoError(t, err)
+	assert.Equal(t, testAwsRegion, region)
+
+	// Test credentials retrieval
+	creds, err := r.AwsSecurityCredentials(ctx, options)
+	assert.NoError(t, err)
+	assert.Equal(t, testAwsAccessKey, creds.AccessKeyID)
+	assert.Equal(t, testAwsSecretKey, creds.SecretAccessKey)
+	assert.Equal(t, testAwsSessionToken, creds.SessionToken)
+}
+
+func TestReadCredConfig(t *testing.T) {
+	tests := []struct {
+		name        string
+		config      *esv1.GCPWorkloadIdentityFederation
+		kubeObjects []client.Object
+		expectError string
+	}{
+		{
+			name: "cred configmap has empty data",
+			config: &esv1.GCPWorkloadIdentityFederation{
+				CredConfig: &esv1.ConfigMapReference{
+					Name:      testConfigMapName,
+					Namespace: testNamespace,
+					Key:       testConfigMapKey,
+				},
+			},
+			kubeObjects: []client.Object{
+				&corev1.ConfigMap{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      testConfigMapName,
+						Namespace: testNamespace,
+					},
+					Data: map[string]string{
+						testConfigMapKey: "",
+					},
+				},
+			},
+			expectError: `key "config.json" in configmap "external-account-config" has empty value`,
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			fakeClient := clientfake.NewClientBuilder().WithObjects(tc.kubeObjects...).Build()
+
+			wif := &workloadIdentityFederation{
+				kubeClient:       fakeClient,
+				saTokenGenerator: &fakeSATokenGen{GenerateFunc: defaultSATokenGenerator},
+				config:           tc.config,
+				isClusterKind:    false,
+				namespace:        testNamespace,
+			}
+
+			ctx := context.Background()
+			_, err := wif.readCredConfig(ctx)
+
+			if tc.expectError != "" {
+				assert.Error(t, err)
+				assert.Equal(t, tc.expectError, err.Error())
+			} else {
+				assert.NoError(t, err)
+			}
+		})
+	}
+}
+
+func TestGenerateExternalAccountConfig(t *testing.T) {
+	wif := &esv1.GCPWorkloadIdentityFederation{
+		CredConfig: &esv1.ConfigMapReference{
+			Name:      testConfigMapName,
+			Namespace: testNamespace,
+		},
+		AwsSecurityCredentials: &esv1.AwsCredentialsConfig{
+			Region: testAwsRegion,
+			AwsCredentialsSecretRef: &esv1.SecretReference{
+				Name:      "aws-creds",
+				Namespace: testNamespace,
+			},
+		},
+		Audience: testAudience,
+	}
+
+	kubeObjects := []client.Object{
+		&corev1.Secret{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "aws-creds",
+				Namespace: testNamespace,
+			},
+			Data: map[string][]byte{
+				awsAccessKeyIdKeyName:     []byte(testAwsAccessKey),
+				awsSecretAccessKeyKeyName: []byte(testAwsSecretKey),
+				awsSessionTokenKeyName:    []byte(testAwsSessionToken),
+			},
+		},
+	}
+
+	fakeClient := clientfake.NewClientBuilder().WithObjects(kubeObjects...).Build()
+
+	wifInstance := &workloadIdentityFederation{
+		kubeClient:       fakeClient,
+		saTokenGenerator: &fakeSATokenGen{GenerateFunc: defaultSATokenGenerator},
+		config:           wif,
+		isClusterKind:    false,
+		namespace:        testNamespace,
+	}
+
+	ctx := context.Background()
+	credFile := &credentialsFile{
+		Type:                           externalAccountCredentialType,
+		Audience:                       testAudience,
+		SubjectTokenType:               workloadIdentitySubjectTokenType,
+		TokenURLExternal:               workloadIdentityTokenURL,
+		ServiceAccountImpersonationURL: testServiceAccountImpersonationURL,
+	}
+
+	config, err := wifInstance.generateExternalAccountConfig(ctx, credFile)
+	assert.NoError(t, err)
+	assert.NotNil(t, config)
+	assert.NotNil(t, config.AwsSecurityCredentialsSupplier)
+	assert.Equal(t, testAudience, config.Audience)
+}

+ 18 - 0
tests/__snapshot__/clustergenerator-v1alpha1.yaml

@@ -67,6 +67,22 @@ spec:
             audiences: [] # minItems 0 of type string
             name: string
             namespace: string
+        workloadIdentityFederation:
+          audience: string
+          awsSecurityCredentials:
+            awsCredentialsSecretRef:
+              name: string
+              namespace: string
+            region: "ap-south-1"
+          credConfig:
+            key: string
+            name: string
+            namespace: string
+          externalTokenEndpoint: string
+          serviceAccountRef:
+            audiences: [] # minItems 0 of type string
+            name: string
+            namespace: string
       projectID: string
     githubAccessTokenSpec:
       appID: string
@@ -251,6 +267,8 @@ spec:
           name: string
           namespace: string
           type: "Secret" # "Secret", "ConfigMap"
+        checkAndSet:
+          required: true
         forwardInconsistent: true
         headers: {}
         namespace: string

+ 19 - 0
tests/__snapshot__/clustersecretstore-v1.yaml

@@ -272,6 +272,7 @@ spec:
       - key: string
         value: string
         version: string
+      validationResult: 1
     fortanix:
       apiKey:
         secretRef:
@@ -294,6 +295,22 @@ spec:
             audiences: [] # minItems 0 of type string
             name: string
             namespace: string
+        workloadIdentityFederation:
+          audience: string
+          awsSecurityCredentials:
+            awsCredentialsSecretRef:
+              name: string
+              namespace: string
+            region: "ap-south-1"
+          credConfig:
+            key: string
+            name: string
+            namespace: string
+          externalTokenEndpoint: string
+          serviceAccountRef:
+            audiences: [] # minItems 0 of type string
+            name: string
+            namespace: string
       location: string
       projectID: string
     github:
@@ -718,6 +735,8 @@ spec:
         name: string
         namespace: string
         type: "Secret" # "Secret", "ConfigMap"
+      checkAndSet:
+        required: true
       forwardInconsistent: true
       headers: {}
       namespace: string

+ 16 - 0
tests/__snapshot__/gcraccesstoken-v1alpha1.yaml

@@ -16,4 +16,20 @@ spec:
         audiences: [] # minItems 0 of type string
         name: string
         namespace: string
+    workloadIdentityFederation:
+      audience: string
+      awsSecurityCredentials:
+        awsCredentialsSecretRef:
+          name: string
+          namespace: string
+        region: "ap-south-1"
+      credConfig:
+        key: string
+        name: string
+        namespace: string
+      externalTokenEndpoint: string
+      serviceAccountRef:
+        audiences: [] # minItems 0 of type string
+        name: string
+        namespace: string
   projectID: string

+ 19 - 0
tests/__snapshot__/secretstore-v1.yaml

@@ -272,6 +272,7 @@ spec:
       - key: string
         value: string
         version: string
+      validationResult: 1
     fortanix:
       apiKey:
         secretRef:
@@ -294,6 +295,22 @@ spec:
             audiences: [] # minItems 0 of type string
             name: string
             namespace: string
+        workloadIdentityFederation:
+          audience: string
+          awsSecurityCredentials:
+            awsCredentialsSecretRef:
+              name: string
+              namespace: string
+            region: "ap-south-1"
+          credConfig:
+            key: string
+            name: string
+            namespace: string
+          externalTokenEndpoint: string
+          serviceAccountRef:
+            audiences: [] # minItems 0 of type string
+            name: string
+            namespace: string
       location: string
       projectID: string
     github:
@@ -718,6 +735,8 @@ spec:
         name: string
         namespace: string
         type: "Secret" # "Secret", "ConfigMap"
+      checkAndSet:
+        required: true
       forwardInconsistent: true
       headers: {}
       namespace: string

+ 2 - 0
tests/__snapshot__/vaultdynamicsecret-v1alpha1.yaml

@@ -104,6 +104,8 @@ spec:
       name: string
       namespace: string
       type: "Secret" # "Secret", "ConfigMap"
+    checkAndSet:
+      required: true
     forwardInconsistent: true
     headers: {}
     namespace: string