Multi-Cloud Identity Federation: Connecting AWS, Azure, and GCP Without Shared Secrets
OIDC federation, workload identity, GitHub Actions OIDC setup across all three clouds, cross-cloud trust patterns, and eliminating every long-lived credential.
Long-Lived Credentials Are the Problem
In 2024, the Cybersecurity and Infrastructure Security Agency (CISA) reported that compromised cloud credentials were the initial access vector in over 60 percent of cloud-related security incidents. Static access keys, service account JSON files stored in CI/CD secrets, and shared credentials pasted into environment variables remain the most common way attackers gain access to cloud environments. The solution has been available for years, but adoption has been slow because identity federation feels complex and the documentation across clouds is fragmented.
Identity federation eliminates long-lived credentials by establishing trust relationships between identity providers and cloud platforms. Instead of storing an AWS access key in GitHub Actions, your CI/CD pipeline requests a short-lived token from AWS by presenting a signed JWT from GitHub's OIDC provider. AWS verifies the token, checks the claims against your trust policy, and issues temporary credentials that expire in minutes to hours. No secrets to rotate, no credentials to leak, no access keys sitting in a repository's settings page.
This guide walks through the concrete implementation patterns for identity federation across AWS, Azure, and GCP, with specific focus on CI/CD pipelines, cross-cloud service-to-service access, and the elimination of every long-lived credential in your infrastructure.
How OIDC Federation Works
OpenID Connect (OIDC) federation is the foundation for modern cloud identity. The mechanism is straightforward once you understand the four participants.
- The identity provider (IdP) issues signed tokens that assert the identity of the caller. GitHub Actions, GitLab CI, Azure AD, Google Cloud, and AWS are all OIDC providers.
- The cloud platform (the relying party) trusts the IdP and accepts tokens signed by it. You configure this trust by registering the IdP's issuer URL and specifying which token claims are allowed.
- The workload (your CI/CD job, application, or service) requests a token from the IdP, then presents it to the cloud platform in exchange for temporary credentials.
- The trust policy defines which tokens from the IdP are accepted and what permissions they receive. This is where you constrain access to specific repositories, branches, or environments.
The security of this model depends entirely on the specificity of your trust policy. A trust policy that accepts any token from GitHub Actions is almost as dangerous as a static credential -- any repository in any GitHub organization could assume the role. A well-crafted trust policy restricts access to a specific organization, repository, branch, and workflow.
AWS: OIDC Identity Provider + IAM Roles
AWS implements OIDC federation through IAM Identity Providers and IAM Roles with trust policies. Here is the setup for GitHub Actions.
Step 1: Create the OIDC Identity Provider
In IAM, create an Identity Provider with the provider type "OpenID Connect." Set the provider URL to https://token.actions.githubusercontent.com and the audience to sts.amazonaws.com. AWS will fetch the provider's JWKS (JSON Web Key Set) to verify token signatures. You only need one IdP per AWS account per GitHub instance, regardless of how many repositories will use it.
Step 2: Create an IAM Role with a Trust Policy
Create an IAM role with a trust policy that specifies the OIDC provider as a trusted principal. The critical part is the condition block, which restricts which GitHub tokens can assume the role.
A minimal trust policy condition checks the sub claim, which contains the repository and branch information in the format repo:org/repo-name:ref:refs/heads/branch-name. For example, to restrict access to the main branch of a specific repository: StringEquals: "token.actions.githubusercontent.com:sub": "repo:my-org/my-repo:ref:refs/heads/main".
You can also restrict by environment: repo:my-org/my-repo:environment:production. This is more granular than branch restrictions because GitHub environments support required reviewers, wait timers, and deployment protection rules.
The wildcard sub claim trap
Never use StringLike with a broad wildcard like repo:my-org/* in your trust policy unless you are absolutely certain that every repository in your organization should be able to assume this role. A developer creating a new repository in your org would automatically get access. Use StringEquals with explicit repository names, or at minimum restrict to specific branches and environments.
Step 3: Configure the GitHub Actions Workflow
In your workflow, add permissions: id-token: write at the job level, then use the aws-actions/configure-aws-credentials action with role-to-assume set to your IAM role's ARN. The action handles the OIDC token request and STS AssumeRoleWithWebIdentity call automatically. The resulting credentials are injected as environment variables for subsequent steps.
The temporary credentials have a default duration of 1 hour, configurable up to the role's maximum session duration (default 1 hour, maximum 12 hours). For most CI/CD pipelines, the default is sufficient. If your deployment takes longer than an hour, increase the role's max session duration rather than extending the default.
Build IAM permission boundaries for federated rolesAzure: Federated Identity Credentials
Azure implements OIDC federation through Federated Identity Credentials on Azure AD applications or user-assigned managed identities. The concept is the same as AWS -- establish trust with an external IdP and exchange tokens for temporary credentials -- but the configuration model is different.
Setting Up GitHub OIDC with Azure
Create an Azure AD application registration (or use an existing one). Under Certificates & secrets, add a Federated credential. Set the issuer to https://token.actions.githubusercontent.com, the subject identifier to the repository and branch pattern (e.g., repo:my-org/my-repo:ref:refs/heads/main), and the audience to api://AzureADTokenExchange.
Assign the application an Azure RBAC role on the resources it needs access to. For Terraform deployments, this is typically Contributor on the target resource group or subscription. For read-only operations, use Reader.
In your GitHub Actions workflow, use the azure/login action with client-id, tenant-id, and subscription-id parameters. Note that you do not provide a client secret -- the OIDC token replaces it entirely.
User-Assigned Managed Identities
Azure also supports federated credentials on user-assigned managed identities, which is preferable to application registrations for several reasons. Managed identities are Azure resources that can be governed by Azure Policy, appear in resource group views, and support Azure RBAC natively. Application registrations live in Azure AD, are governed by different policies, and require separate RBAC assignments.
The configuration is identical: create a user-assigned managed identity, add a federated credential pointing to your OIDC provider, and assign RBAC roles. The only difference is that you use the managed identity's client ID in your workflow configuration.
GCP: Workload Identity Federation
GCP's Workload Identity Federation is the most flexible implementation of OIDC federation across the three major clouds. It supports attribute mapping and attribute conditions that let you create fine-grained access policies based on any claim in the OIDC token.
Workload Identity Pool and Provider
Create a Workload Identity Pool (a logical container for external identities) and a Workload Identity Provider within it. For GitHub Actions, set the issuer URL to https://token.actions.githubusercontent.com. Configure attribute mappings to map OIDC token claims to Google Cloud attributes:
google.subjectmaps toassertion.sub(required)attribute.repositorymaps toassertion.repositoryattribute.repository_ownermaps toassertion.repository_ownerattribute.refmaps toassertion.ref
Then set an attribute condition to restrict which tokens are accepted: assertion.repository_owner == "my-org". You can combine conditions: assertion.repository_owner == "my-org" && assertion.ref == "refs/heads/main".
Service Account Impersonation
After authenticating through the Workload Identity Pool, the external identity needs to impersonate a GCP service account to access resources. Grant the roles/iam.workloadIdentityUser role on the service account to the external identity, with a principal set filter that restricts which federated identities can impersonate it.
The principal format is: principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/attribute.repository/my-org/my-repo. This ensures that only tokens from the specific repository can impersonate the service account.
GCP attribute conditions are powerful
GCP's attribute conditions support Common Expression Language (CEL), which lets you write sophisticated access rules. For example, you can restrict access to specific GitHub environments, require certain workflow names, or even check the actor who triggered the workflow. This level of granularity is not available in AWS or Azure trust policies without custom Lambda authorizers or Azure Policy.
Cross-Cloud Federation: Service-to-Service Access
Identity federation is not just for CI/CD. You can use the same mechanism for cross-cloud service-to-service communication, eliminating shared credentials between cloud environments.
AWS to GCP: Using AWS STS Tokens with GCP Workload Identity
A service running on AWS (EC2, ECS, Lambda) can access GCP resources without storing a GCP service account key. Configure a Workload Identity Pool provider in GCP that trusts AWS as an OIDC provider. The AWS service uses its IAM role credentials to request an OIDC-compatible token from AWS STS, then exchanges it for GCP credentials through the Workload Identity Pool.
The GCP client libraries handle this exchange automatically when configured with a credential configuration file that specifies the AWS source. Your application code does not change -- it uses the standard GCP client library, which transparently handles the token exchange.
Azure to AWS: Using Azure AD Tokens with AWS STS
A service running on Azure with a managed identity can access AWS resources by assuming an IAM role through OIDC federation. Create an OIDC provider in AWS that trusts Azure AD (issuer URL: https://login.microsoftonline.com/TENANT_ID/v2.0). The Azure service requests a token from the managed identity endpoint, then exchanges it for AWS temporary credentials using STS AssumeRoleWithWebIdentity.
This pattern is particularly useful for organizations migrating between clouds or running workloads across multiple providers. Your Azure-hosted API can read from an S3 bucket or write to a DynamoDB table without any AWS access keys stored in Azure Key Vault.
GCP to Azure: Using Google ID Tokens with Azure AD
Google Cloud services can authenticate to Azure using federated identity credentials on an Azure AD application. The GCP service requests an ID token from the metadata server, and Azure AD validates it against the federated credential configuration. This enables scenarios like a Cloud Run service calling an Azure Function or a GKE workload accessing Azure Blob Storage.
Eliminating Every Long-Lived Credential
The goal is not just to federate CI/CD pipelines. The goal is to eliminate every long-lived credential in your infrastructure. Here is a systematic approach.
Phase 1: Audit Existing Credentials
Start by finding every long-lived credential in your environment. On AWS, run aws iam list-access-keys for every IAM user and check the CreateDate. Any access key older than 90 days is a risk. On Azure, check application registrations for client secrets with long expiry dates. On GCP, list all service account keys with gcloud iam service-accounts keys list and flag any user-managed keys.
Phase 2: Federate CI/CD Pipelines
This is the highest-value migration. CI/CD systems like GitHub Actions, GitLab CI, CircleCI, and Bitbucket Pipelines all support OIDC tokens. Migrate each pipeline to use OIDC federation instead of stored access keys. This typically takes 30 to 60 minutes per pipeline and requires no application code changes.
Phase 3: Federate Cross-Cloud Access
Replace any stored credentials used for cross-cloud access with federation. A common example is a GCP service account JSON key stored in AWS Secrets Manager so that an AWS Lambda function can access BigQuery. Replace this with a Workload Identity Pool that trusts AWS, and the Lambda function uses its IAM role to get GCP credentials on demand.
Phase 4: Eliminate Service Account Keys
On GCP, enable the Organization Policy constraint iam.disableServiceAccountKeyCreation to prevent new service account keys from being created. On AWS, create an SCP that denies iam:CreateAccessKey for all users except break-glass accounts. On Azure, set short expiry periods on application secrets and require federated credentials for new applications.
The break-glass exception
You need at least one non-federated authentication method for emergency access. If your OIDC provider (GitHub, GitLab, Azure AD) has an outage, you need a way to access your cloud accounts. Maintain one or two break-glass IAM users with MFA-protected console access and access keys stored in a physical safe or hardware security module. These accounts should have CloudTrail alerts that fire on any usage.
Common Implementation Mistakes
Mistake 1: Overly Broad Trust Policies
A trust policy that accepts any token from token.actions.githubusercontent.com without a subject condition lets any GitHub repository in the world assume your role. Always constrain the sub claim to your organization, repository, and preferably branch or environment.
Mistake 2: Not Testing Token Claims
Before configuring your trust policy, print the actual OIDC token in a test workflow and examine its claims. The format of the sub claim varies by CI/CD provider and has changed in past updates. Do not assume -- verify. In GitHub Actions, you can decode the token with: curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL" | jq -r '.value' | cut -d. -f2 | base64 -d | jq.
Mistake 3: Using Maximum Session Duration
Setting the session duration to 12 hours because "deployments sometimes take a while" defeats the purpose of short-lived credentials. If an OIDC token is somehow intercepted, the resulting credentials should expire as quickly as possible. Use the shortest duration that works for your pipeline -- typically 15 to 30 minutes for simple deployments and 1 to 2 hours for complex ones.
Mistake 4: Ignoring Audience Restrictions
The audience (aud) claim in an OIDC token specifies the intended recipient. AWS expects sts.amazonaws.com, Azure expects api://AzureADTokenExchange, and GCP uses the Workload Identity Pool URL. Always validate the audience in your trust configuration to prevent token reuse across unintended targets.
The End State
When identity federation is fully implemented, your infrastructure has zero stored credentials that could be leaked, compromised, or forgotten in a developer's laptop. Every authentication is based on short-lived tokens that are scoped to specific actions and expire in minutes. Your CI/CD pipelines are immune to credential rotation failures because there are no credentials to rotate. Cross-cloud access is auditable through token exchange logs on both sides. And your security team can sleep better knowing that the most common attack vector -- compromised credentials -- has been eliminated from your infrastructure.
The implementation effort is modest relative to the security improvement. A team of two engineers can federate all CI/CD pipelines and cross-cloud access for a medium-sized organization in two to three weeks. The ongoing maintenance cost is essentially zero because there are no credentials to rotate or secrets to manage. If you have not started this migration, make it your next infrastructure priority.
Try These Tools
Written by CloudToolStack Team
Cloud architects with 15+ years of production experience across AWS, Azure, GCP, and OCI. We build free tools and write practical guides to help engineers navigate multi-cloud infrastructure.
Disclaimer: This article is for informational purposes. Cloud services and pricing change frequently; always verify with official provider documentation. AWS, Azure, GCP, and OCI are trademarks of their respective owners.