Introduction: What is Workload Identity Federation?
Workload Identity Federation (WIF) allows workloads running in Google Cloud (e.g., GKE pods) to securely access AWS resources (like S3) without storing static AWS credentials. Instead of using long-lived access keys, GCP workloads exchange Google identity tokens for temporary AWS credentials via AWS STS (Security Token Service)
Use Case
- A pod running on Google Kubernetes Engine (GKE) needs to:
- List S3 buckets
- Download/upload files to Amazon S3
Without:
- Storing AWS credentials (no aws_access_key_id or secret_access_key in config)
High-Level Steps
- Enable Workload Identity Federation in GCP
- Create an AWS IAM OIDC Provider to trust GCP
- Create an AWS IAM Role for GCP workloads
- Create a Workload Identity Pool in GCP
- Create a Workload Identity Provider in GCP
- Map the GCP Service Account to the AWS IAM Role
- Test Authentication from GCP to AWS

Step-by-step guide: Enable Workload Identity Federation in GCP
Check if Workload Identity Federation is enabled:
$ gcloud container clusters describe CLUSTER_NAME \
--project=YOUR_PROJECT_ID \
--location=GKE_REGION \
--format="value(workloadIdentityConfig.workloadPool)"
Example:
$ gcloud container clusters describe mgr-main-sbx \
--project=mgr-product-sbx \
--location=europe-west1 \
--format="value(workloadIdentityConfig.workloadPool)"
Output:
mgr-product-sbx.svc.id.goog
If it is not enabled, run:
$ gcloud container clusters update CLUSTER_NAME \
--workload-pool=YOUR_PROJECT_ID.svc.id.goog \
--project=YOUR_PROJECT_ID \
--location=GKE_REGION
Create an AWS IAM OIDC Provider to Trust GCP
To create the provider:
$ aws iam create-open-id-connect-provider \
--url https://sts.googleapis.com \
--client-id-list sts.amazonaws.com \
--thumbprint-list 08745487ghdud7e7eh1f2a07e452f36f6
Verify the OIDC Provider is created:
$ aws iam list-open-id-connect-providers
Create a GCP Service Account for AWS Access
Create GCP Service Account (poc-gcp-to-aws-sa@mgr-product-sbx.iam.gserviceaccount.com) and create a key for this SA:
$ gcloud iam service-accounts create poc-gcp-to-aws-sa --project=YOUR_PROJECT_ID --display-name="GCP to AWS Service Account"
Example:
$ gcloud iam service-accounts create poc-gcp-to-aws-sa \ --project=mgr-product-sbx \ --display-name="GCP to AWS Service Account" --role="roles/iam.serviceAccountTokenCreator"
Give SA permissions to get/create tokens!
Get a Token for Testing
$ gcloud auth activate-service-account --key-file=mgr-product-sbx-24aa6b13e9a7.json
$ TOKEN=$(gcloud auth print-identity-token --impersonate-service-account=poc-gcp-to-aws-sa@mgr-product-sbx.iam.gserviceaccount.com)
$ echo $TOKEN | jq -R 'split(".") | .[1] | @base64d | fromjson'
Create an AWS IAM Role Trusted by GCP
Create file poc-trust-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {"Federated": "accounts.google.com"},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"accounts.google.com:aud": "<azp-value>",
"accounts.google.com:oaud": "<aud-value>",
"accounts.google.com:sub": "<sub-value>"
}
}
}
]
}
For “aud“, “oaud“ and “sub“ use the output from SA TOKEN.
accounts.google.com:oaud condition key matches the aud (AUDIENCE) field on the Google ID token.
accounts.google.com:aud condition key matches the azp (AUTHORIZED_PARTY) field on the Google ID token.
accounts.google.com:sub condition key matches the sub (SUBJECT) field on the Google ID token.
Create the AWS role
$ aws iam create-role \
--role-name GCPWorkloadIAMRole \
--assume-role-policy-document file://poc-trust-policy.json
Assigning policy “AmazonS3ReadOnlyAccess“ to this role (for the test later).
Create a Workload Identity Pool in GCP
Configure Workload Identity Federation
$ gcloud iam workload-identity-pools create "POOL_NAME" \
--project=YOUR_PROJECT_ID \
--location="global" \
--display-name="AWS Workload Identity Pool"
Example:
$ gcloud iam workload-identity-pools create "poc-aws-pool" --project=mgr-product-sbx --location="global" --display-name="AWS Workload Identity Pool"
Create a Workload Identity Provider in GCP
This connects the pool to AWS.
$ gcloud iam workload-identity-pools providers create-oidc "PROVIDER_NAME" \
--project=PROJECT_NAME \
--location="global" \
--workload-identity-pool="POOL_NAME" \
--display-name="AWS OIDC Provider" \
--issuer-uri="https://sts.amazonaws.com" \
--allowed-audiences="sts.amazonaws.com" \
--attribute-mapping="google.subject=assertion.sub,google.groups=assertion.groups"
Example:
$ gcloud iam workload-identity-pools providers create-oidc "aws-provider"
--project=mgr-product-sbx
--location="global"
--workload-identity-pool="poc-aws-pool"
--display-name="AWS OIDC Provider"
--issuer-uri="https://sts.amazonaws.com"
--allowed-audiences="sts.amazonaws.com"
--attribute-mapping="google.subject=assertion.sub,google.groups=assertion.groups"
The output will be:
projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/poc-aws- pool/providers/aws-provider
Bind the GCP Service Account to AWS Role
Allow Workloads to Assume This Service Account
$ gcloud iam service-accounts add-iam-policy-binding \
poc-gcp-to-aws-sa@YOUR_PROJECT_ID.iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_NAME/subject/arn:aws:iam::AWS_ACCOUNT_ID:role/ROLE_NAME"
Examaple:
$ gcloud iam service-accounts add-iam-policy-binding poc-gcp-to-aws-sa@mgr-product-sbx.iam.gserviceaccount.com
--role roles/iam.workloadIdentityUser
--member "principal://iam.googleapis.com/projects/960144414359/locations/global/workloadIdentityPools/poc-aws-pool/subject/arn:aws:iam::211125558983:role/GCPWorkloadIAMRole"
Test the Integration
$ gcloud auth activate-service-account --key-file=mgr-product-sbx-e284c02e086c.json
TOKEN=$(gcloud auth print-identity-token --impersonate-service-account=poc-gcp-to-aws-sa@mgr-product-sbx.iam.gserviceaccount.com)
$ echo $TOKEN | jq -R 'split(".") | .[1] | @base64d | fromjson'
$ aws sts assume-role-with-web-identity --role-arn "arn:aws:iam::211125558983:role/GCPWorkloadIAMRole" --role-session-name "gcp-session" --web-identity-token "$TOKEN" --query 'Credentials'
Output should looks something like:

export AWS_ACCESS_KEY_ID=”YOUR_ACCESS_KEY_ID”
export AWS_SECRET_ACCESS_KEY=”YOUR_SECRET_ACCESS_KEY”
export AWS_SESSION_TOKEN=”YOUR_SESSION_TOKEN”
Test S3 Access
$ aws s3 ls
Output:
2024-11-09 07:19:45 baseline-tfstates-211125558983
2024-11-09 07:37:41 billing-export-211125558983
2024-11-20 13:12:19 gar-credential-provider-test
$ aws iam list-roles
Output:
An error occurred (AccessDenied) when calling the ListRoles operation: User: arn:aws:sts::211125558983:assumed-role/GCPWorkloadIAMRole/gcp-session is not authorized to perform: iam:ListRoles on resource: arn:aws:iam::211125558983:role/ because no identity-based policy allows the iam:ListRoles action
Result: Secure AWS Access from GCP Without Storing Keys
This setup lets GCP workloads like GKE pods access AWS securely, without ever managing or embedding long-lived secrets. With Workload Identity Federation, you ensure:
- Strong cross-cloud identity
- Better security posture
- Simplified credential lifecycle
