OIDC: Deploy to the Cloud Without Long-Lived Secrets

Swap static cloud keys for short-lived OIDC tokens that GitHub mints per run and the cloud verifies.

Storing an AWS access key or a GCP service-account JSON as a repository secret works, but it is a standing liability: the credential is long-lived, powerful, and one leak away from disaster. OpenID Connect (OIDC) removes it entirely.

How it works

  1. GitHub mints a short-lived, signed OIDC token for the workflow run, describing the repo, branch, and environment.
  2. Your cloud provider is configured to trust GitHub's OIDC issuer and to accept tokens matching specific claims (e.g. repo:acme/app:ref:refs/heads/main).
  3. The cloud exchanges that token for temporary credentials scoped to a role β€” valid for minutes, not forever.

What you need

  • permissions: id-token: write on the job so it may request the token.
  • A trust policy / workload-identity binding on the cloud side that pins your repo and branch.
  • The provider's login action (e.g. aws-actions/configure-aws-credentials) with a role ARN instead of keys.

Example

Example Β· yaml
name: Deploy to AWS
on:
  push:
    branches: [main]

permissions:
  id-token: write    # required to request the OIDC token
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      # No AWS keys anywhere β€” assume a role via OIDC
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/gh-deploy
          aws-region: us-east-1
      - run: aws s3 sync ./dist s3://my-bucket --delete

When to use it

  • A team configures AWS OIDC federation so GitHub Actions can deploy to ECS using short-lived tokens instead of storing long-lived AWS access keys as secrets.
  • A developer connects GitHub Actions to Google Cloud using Workload Identity Federation so no service-account JSON key is ever stored in GitHub.
  • A security engineer removes all long-lived cloud credentials from GitHub secrets after enabling OIDC, reducing the attack surface for secret leaks.

More examples

Assume AWS IAM role with OIDC

The id-token: write permission allows the runner to request a JWT; configure-aws-credentials exchanges it for temporary AWS credentials.

Example Β· yaml
permissions:
  id-token: write
  contents: read

steps:
  - uses: actions/checkout@v4
  - uses: aws-actions/configure-aws-credentials@v4
    with:
      role-to-assume: arn:aws:iam::123456789:role/github-actions-deploy
      aws-region: us-east-1
  - run: aws s3 sync dist/ s3://my-bucket/

Authenticate to GCP with Workload Identity

The auth action exchanges the GitHub OIDC token for a GCP access token bound to the specified service account, with no JSON key needed.

Example Β· yaml
permissions:
  id-token: write
  contents: read

steps:
  - uses: google-github-actions/auth@v2
    with:
      workload_identity_provider: projects/123/locations/global/workloadIdentityPools/github/providers/github
      service_account: [email protected]
  - uses: google-github-actions/deploy-cloudrun@v2
    with:
      service: my-api
      image: gcr.io/my-project/my-api:latest

Configure AWS trust policy for OIDC

This IAM trust policy allows only workflows running on the main branch of the specific repository to assume the role, scoping access precisely.

Example Β· json
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "Federated": "arn:aws:iam::123456789:oidc-provider/token.actions.githubusercontent.com"
    },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
      "StringEquals": {
        "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
        "token.actions.githubusercontent.com:sub": "repo:org/repo:ref:refs/heads/main"
      }
    }
  }]
}

Discussion

  • Be the first to comment on this lesson.
OIDC: Deploy to the Cloud Without Long-Lived Secrets β€” GitHub | SoundsCode