GitHub Actions: CI/CD Workflows From First Run to Secure Deployments · Pipelines, Deployments and Security

Deployments: Environments, Approvals and OIDC

Deploy through protected environments with required reviewers, and authenticate to the cloud with short-lived OIDC tokens instead of stored keys.

Create a free account to save this page, take notes and track your progress. Sign in

What you'll build

A deployment workflow that goes to staging automatically and to production only after a reviewer approves, using temporary AWS credentials obtained through OpenID Connect.

The idea

Environments (Settings → Environments) name deployment targets. A job with environment: production gets:

  • Protection rules: required reviewers, a wait timer, and branch restrictions.
  • Environment secrets and variables that only that job can read.
  • A deployment history with the live URL.

Stored cloud keys are long-lived and can leak. OIDC removes them: GitHub issues each job a short-lived signed token, and the cloud provider (configured to trust your repository, branch or environment) exchanges it for temporary credentials. The job needs the permission id-token: write.

The code

Staging, then production behind approval, using OIDC
name: Deploy
on:
  push:
    branches: [main]

permissions:
  id-token: write
  contents: read

jobs:
  staging:
    runs-on: ubuntu-latest
    environment:
      name: staging
      url: https://staging.example.com
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/deploy-staging
          aws-region: us-east-1
      - run: ./deploy.sh staging

  production:
    needs: staging
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://www.example.com
    concurrency:
      group: production
      cancel-in-progress: false
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/deploy-production
          aws-region: us-east-1
      - run: ./deploy.sh production

Output

actionlint: no problems found
workflow: Deploy
triggers: push (branches: main)
jobs, in the order they run:
  staging: runs on ubuntu-latest | 3 step(s) | environment staging
  production: runs on ubuntu-latest | 3 step(s) | after staging | environment production

Run this on your computer — see “Get Started” for setup.

The production job pauses at "Waiting for review" until an approver accepts; its role can be limited on the AWS side to tokens from the production environment only.

Common mistakes

  • Forgetting id-token: write. The login action then fails with a message about requesting a token.
  • A trust policy that is too broad. Restrict the cloud role to your repository and, ideally, the environment or branch.
  • cancel-in-progress: true on deployments. Cancelling a half-finished deploy can leave a broken release.
  • Putting production secrets at repository level. Every workflow could read them; use environment secrets.

Key points

  • Environments add approvals, scoped secrets and deployment history.
  • OIDC gives temporary cloud credentials with no stored keys.
  • Serialize deployments with concurrency and never cancel one midway. Further reading: GitHub Docs.

Practice questions

What advantage does OIDC have over storing a cloud access key as a secret?

Answer

No long-lived credential exists to leak or rotate. The cloud provider issues temporary credentials per job and can restrict them to a specific repository, branch or environment.

Which permission must the job have to use OIDC?

Answer

id-token: write, so the job can request an OIDC token from GitHub.

Open in the app to mark lessons complete, take notes and track your progress.

Was this page helpful?