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.
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
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: trueon 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
concurrencyand 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.