PRACTITIONER GUIDE | IDENTITY SECURITY
Practitioner Guide14 min read

Workload Identity Federation: Eliminating Static Credentials in CI/CD Pipelines

~1h
Maximum lifetime of WIF-issued credentials vs. static keys that are often never rotated
0
Credentials to store in CI/CD secrets when using WIF -- OIDC token exchange requires only a role ARN or pool ID, not a secret
Subject claim
OIDC token field that can be restricted by repository name, branch, environment, and job context to prevent token reuse across workflows
80%+
Reduction in exposed static cloud credentials achievable by migrating GitHub Actions and GitLab CI to OIDC-based WIF

SponsoredRetool

Retool's new app builder is where AI-generated code ships safely

Building apps with AI is easy. Getting them to production safely is another story.

Start building for free today

Static cloud credentials in CI/CD pipelines are one of the highest-risk credential patterns in most organizations. An AWS access key ID stored in GitHub Secrets is a 365-day threat surface: it is valid until rotated, often shared across workflows, and can be exfiltrated by a malicious dependency or a compromised developer account. Workload Identity Federation via OIDC eliminates static credentials entirely -- GitHub Actions or GitLab CI/CD presents a short-lived OIDC token to AWS or GCP, which exchanges it for a temporary role credential valid for 15-60 minutes. This guide covers the AWS and GCP implementation, GitHub and GitLab workflow changes, subject claim conditions that prevent cross-repo token reuse, and the audit process for finding and replacing existing static credentials.

Configure AWS for GitHub Actions OIDC

The AWS side requires an OIDC identity provider, an IAM role with a trust policy, and trust conditions that restrict which GitHub repository and branch can assume the role.

Create the GitHub OIDC identity provider in AWS IAM

In AWS IAM, go to Identity Providers and create an OpenID Connect provider. Set the provider URL to `https://token.actions.githubusercontent.com` and the audience to `sts.amazonaws.com`. AWS fetches the provider's public key automatically from the OIDC discovery endpoint. This provider registration tells AWS: 'Trust OIDC tokens signed by GitHub Actions.' Create this provider once per AWS account -- all repository-specific restrictions are enforced via IAM role trust policy conditions, not by creating separate providers.

Create an IAM role with a scoped trust policy

Create an IAM role for your CI/CD use case (e.g., `github-actions-deploy-prod`) with a trust policy specifying the OIDC provider and a condition on the sub claim: `StringLike: {token.actions.githubusercontent.com:sub: repo:myorg/myrepo:ref:refs/heads/main}`. Use StringLike (not StringEquals) if you need to allow multiple branches with a wildcard. Attach only the IAM policies the CI/CD workflow actually needs -- not AdministratorAccess. A deployment workflow typically needs specific S3 write permissions or ECS deploy permissions, not full account access.

Update the GitHub Actions workflow to use OIDC

Add `permissions: id-token: write` at the job level to grant the workflow permission to request an OIDC token. Replace any `aws-actions/configure-aws-credentials@v1` steps using static key secrets with `aws-actions/configure-aws-credentials@v4` using `role-to-assume: arn:aws:iam::<account-id>:role/github-actions-deploy-prod` and `aws-region: us-east-1`. Remove `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` references from the workflow file entirely. Test with a dry-run deployment to confirm the OIDC exchange works before revoking the static keys.

Add environment-based restrictions for production roles

For IAM roles that deploy to production environments, configure the GitHub Actions deployment environment and add an environment claim condition to the trust policy: `StringEquals: {token.actions.githubusercontent.com:sub: repo:myorg/myrepo:environment:production}`. Create the 'production' environment in the GitHub repository settings with required reviewers and protection rules. Now, even if a developer modifies the workflow, they cannot assume the production IAM role without an approved deployment to the production environment.

Configure Google Cloud WIF for GitHub Actions

GCP Workload Identity Federation uses a Workload Identity Pool and Provider to establish trust with the GitHub OIDC endpoint.

Create a Workload Identity Pool

In GCP IAM, create a Workload Identity Pool: `gcloud iam workload-identity-pools create github-actions --project=<project-id> --location=global --display-name='GitHub Actions Pool'`. The pool is the container that holds one or more identity providers. Create one pool per external system (one for GitHub, one for GitLab if both are used).

Add GitHub as an OIDC provider to the pool

Add the GitHub OIDC provider: `gcloud iam workload-identity-pools providers create-oidc github --project=<project-id> --location=global --workload-identity-pool=github-actions --issuer-uri=https://token.actions.githubusercontent.com --attribute-mapping=google.subject=assertion.sub,attribute.repository=assertion.repository --attribute-condition=assertion.repository_owner=='myorg'`. The attribute condition restricts the pool to tokens from your GitHub organization -- anyone with a public GitHub repository cannot assume roles in your GCP project.

Grant the pool permission to impersonate a service account

Bind the Workload Identity pool to a GCP service account: `gcloud iam service-accounts add-iam-policy-binding deploy-sa@<project>.iam.gserviceaccount.com --role=roles/iam.workloadIdentityUser --member=principalSet://iam.googleapis.com/projects/<project-number>/locations/global/workloadIdentityPools/github-actions/attribute.repository/myorg/myrepo`. This restricts impersonation to tokens from the specific repository -- not all repositories in your organization.

Use google-github-actions/auth in the workflow

In the GitHub Actions workflow, replace static GCP service account key steps with `google-github-actions/auth@v2` using `workload_identity_provider` set to the pool provider resource name and `service_account` set to the service account email. Remove any `GOOGLE_CREDENTIALS` or `GCP_SA_KEY` secrets from the workflow. Subsequent steps use `google-github-actions/setup-gcloud` or the standard gcloud CLI with the federated credentials automatically picked up from the environment.

Free daily briefing

Briefings like this, every morning before 9am.

Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.

Audit and Replace Existing Static Credentials

WIF adoption without removing existing static keys leaves the credential risk in place. Audit and revoke systematically.

Inventory all static credentials in use

Run `aws iam generate-credential-report && aws iam get-credential-report` to see all IAM users with active access keys. Filter for keys that have been used in the past 30 days and cross-reference with your known service accounts. For GCP, list all service account keys per project: `gcloud iam service-accounts keys list --iam-account=<sa-email> --filter=keyType:USER_MANAGED`. Any user-managed key is a static credential -- managed keys (created by Google) rotate automatically.

Search CI/CD configuration for static credential references

Search GitHub Secrets for known patterns: in the GitHub org settings, audit which repositories have secrets named AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, GCP_SA_KEY, GOOGLE_CREDENTIALS, or similar. For each, check whether the consuming workflow has already been migrated to OIDC. For secrets still in use, create a migration ticket with a deadline -- leaving static keys in place after WIF is deployed is the most common mistake teams make.

Revoke static keys after confirming OIDC works

Do not revoke static keys until you have confirmed OIDC authentication works in at least one successful CI/CD run. After confirming, deactivate the key first (AWS `update-access-key --status Inactive`, GCP key disable) and monitor for 48 hours. If nothing breaks, delete the key. Deactivation before deletion gives you a fast rollback path if something was missed. Update your credential inventory documentation to mark the key as decommissioned.

The bottom line

Workload Identity Federation via OIDC is the correct credential model for CI/CD pipelines -- short-lived tokens scoped to specific repositories and branches, no secrets to store or rotate, and automatic expiration that limits the damage window of any token capture. The migration effort is a one-time workflow change and OIDC provider setup per cloud account. The ongoing benefit is elimination of the most commonly exploited credential class in cloud breaches: long-lived access keys committed to code, stored in logs, or extracted from build artifacts.

Frequently asked questions

What is the security advantage of WIF over static service account keys?

Static keys (AWS access key IDs, GCP service account JSON keys) are long-lived credentials that do not expire. If leaked (via git commit, log output, build artifact, misconfigured S3 bucket), they remain valid until manually detected and rotated. WIF tokens expire in minutes to hours -- if a WIF token is captured from a workflow's environment, the attack window is the token's remaining lifetime, not indefinite. WIF also eliminates the key management burden: no keys to rotate, no rotation reminders, no key inventory audits.

What is an OIDC trust policy and why does the subject claim matter?

In AWS, a trust policy on an IAM role specifies which OIDC provider tokens the role will accept and under what conditions. The subject (sub) claim in the GitHub Actions OIDC token contains context like `repo:org/repo:ref:refs/heads/main:environment:production`. An AWS trust policy condition that requires `token.actions.githubusercontent.com:sub` to match `repo:myorg/myrepo:ref:refs/heads/main` means ONLY workflows running from the main branch of that specific repository can assume that role. Without this restriction, any repository in the organization could assume the role.

How do you configure AWS for GitHub Actions OIDC?

Three steps: (1) Create an IAM OIDC identity provider with URL `https://token.actions.githubusercontent.com` and audience `sts.amazonaws.com`. (2) Create an IAM role with a trust policy allowing the OIDC provider with conditions on the sub claim restricting it to specific repositories and branches. (3) In the GitHub Actions workflow, add `permissions: id-token: write` and use the `aws-actions/configure-aws-credentials` action with `role-to-assume` set to the role ARN. No secrets needed in the workflow -- the OIDC token exchange happens automatically.

Does Workload Identity Federation work with GitLab CI/CD?

Yes. GitLab CI/CD provides an OIDC token via the `CI_JOB_JWT_V2` variable (or the newer `id_tokens` configuration for job-level tokens). Configure AWS with a GitLab OIDC identity provider pointing to your GitLab instance URL. The sub claim format for GitLab is `project_path:group/project:ref_type:branch:ref:main`. Create IAM trust conditions that restrict assumption to specific project paths and branches using the sub claim. GitLab also supports GCP WIF with its OIDC token for keyless Google Cloud deployments.

Can you restrict WIF tokens to specific GitHub environments?

Yes. GitHub Actions OIDC tokens include an `environment` claim when the workflow step runs with a deployment environment configured. The sub claim format becomes `repo:org/repo:environment:production` when an environment is specified. Add a trust policy condition requiring the environment claim to equal 'production' for IAM roles that should only be assumable from production deployments. This prevents a development workflow from assuming a production IAM role even if it runs in the same repository.

How do you find and replace existing static credentials in GitHub Actions workflows?

Search your workflow files for patterns indicating static credential usage: `grep -r 'AWS_ACCESS_KEY_ID\|GOOGLE_CREDENTIALS\|GCP_SA_KEY\|AWS_SECRET_ACCESS_KEY' .github/workflows/`. For each match, check if the value is stored in GitHub Secrets. Then check whether the corresponding IAM users or GCP service accounts with key-based authentication still have active keys by auditing AWS IAM credential reports (`aws iam generate-credential-report`) or GCP service account key inventory (`gcloud iam service-accounts keys list --iam-account=<SA>`). Revoke keys after confirming OIDC replacement is working.

What is the difference between GitHub OIDC and GitHub App authentication?

GitHub OIDC tokens authenticate the workflow run itself to external cloud providers (AWS, GCP, Azure). GitHub App authentication authenticates the workflow to GitHub's own APIs (to create issues, comment on PRs, push commits) using an installation access token derived from a private key. For cloud resource access, use OIDC. For GitHub API actions within workflows that require elevated permissions (like pushing to a protected branch), use a GitHub App installation token. The two are complementary and often both appear in the same workflow.

Sources & references

  1. GitHub Actions OIDC Documentation
  2. AWS IAM OIDC Identity Providers
  3. Google Cloud Workload Identity Federation

Free resources

25
Free download

Critical CVE Reference Card 2025–2026

25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.

No spam. Unsubscribe anytime.

Free download

Ransomware Incident Response Playbook

Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.

No spam. Unsubscribe anytime.

Free newsletter

Get threat intel before your inbox does.

50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.

Unsubscribe anytime. We never sell your data.

Eric Bang
Author

Founder & Cybersecurity Evangelist, Decryption Digest

Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.

Black Hat Giveaway

Win a $2,495 Black Hat pass.

Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.

Joins Decryption Digest daily briefing. Unsubscribe anytime.

Giveaway: Black Hat USA 2026 Full-Access Pass ($2,495 value)

Details →
Daily Briefing

Subscribe to enter the giveaway

Every subscriber is automatically entered. You also get daily threat intel every morning: zero-days, ransomware, and nation-state campaigns. Free. No spam.

Already subscribed? You're already entered.

Giveaway

Win a $2,495 Black Hat USA 2026 pass.