Secrets, Environments & OIDC
IntermediateGitHub Actions Secrets store sensitive values encrypted at rest. Environments add deployment protection rules with manual approval gates. OIDC enables keyless authentication to cloud providers.
Overview
Pipeline security is often the weakest link in a deployment chain. GitHub Actions provides multiple layers of protection: Secrets are encrypted and injected as environment variables, never appearing in logs. Environments (staging, production) add required reviewers, deployment branch restrictions, and wait timers before release. OIDC (OpenID Connect) eliminates the most dangerous practice — storing long-lived cloud credentials in secrets — by using short-lived tokens issued per workflow run. Understanding secrets scoping (repo vs environment vs organisation) determines which pipelines can access which credentials.
Secrets Management
GitHub secrets are encrypted at rest and masked in logs. Understanding the three scopes (repository, environment, organisation) controls which workflows can access which credentials.
# Three secret scopes:
# 1. Repository secrets: available to all workflows in the repo
# Settings → Secrets and variables → Actions → New repository secret
# Name: DB_PASSWORD, Value: mysecretpassword
# 2. Environment secrets: only available to jobs using that environment
# Settings → Environments → staging → Add secret
# Only jobs with 'environment: staging' can access these secrets
# Use for environment-specific credentials (staging DB vs prod DB)
# 3. Organization secrets: shared across repos in the org
# Org Settings → Secrets → Specify which repos can access
# Using secrets in a workflow:
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # unlocks production environment secrets
steps:
- name: Deploy
env:
DB_PASSWORD: ${{ secrets.DB_PASSWORD }} # repo secret
PROD_API_KEY: ${{ secrets.PROD_API_KEY }} # env secret (production)
ORG_REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }} # org secret
run: ./deploy.sh
# Built-in secrets (no setup needed):
# secrets.GITHUB_TOKEN → auto-created per workflow run, scoped to the repo
# permissions: packages: write → push images
# permissions: pull-requests: write → comment on PRs
# permissions: contents: write → push tags, create releases
# Secret masking in logs:
run: echo "Password is ${{ secrets.DB_PASSWORD }}"
# Output: Password is *** ↠automatically maskedEnvironments & Deployment Protection
GitHub Environments add approval gates, branch restrictions, and wait timers to deployment jobs — the standard way to require human sign-off before production deployments.
# Configure environments in: Settings → Environments
# Staging environment:
# - Required reviewers: none (auto-deploy)
# - Deployment branches: develop, main
# Production environment:
# - Required reviewers: @team-lead, @senior-engineer (both must approve)
# - Deployment branches: main only
# - Wait timer: 10 minutes (cooling-off period)
# Using environments in a workflow:
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging # auto-deploys (no approval required)
steps:
- run: ./deploy.sh staging
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment:
name: production
url: https://myapp.com # shown on deployment page
# ↠pauses here until required reviewers approve in GitHub UI
steps:
- run: ./deploy.sh production
# The deployment flow:
# 1. deploy-staging runs automatically
# 2. deploy-production starts, sees 'environment: production'
# 3. GitHub sends review request to @team-lead and @senior-engineer
# 4. They see a "Review deployments" button in GitHub UI
# 5. Upon approval, deploy-production continues
# 6. Upon rejection, pipeline fails with "Deployment was rejected"
# Deployment history visible at: repo → Actions → EnvironmentsGITHUB_TOKEN Permissions & Security Hardening
The auto-generated GITHUB_TOKEN follows the principle of least privilege when configured correctly. Hardening pipelines prevents supply chain attacks and privilege escalation.
# Restrict GITHUB_TOKEN to minimum required permissions
# Default is "permissive" (read/write for most scopes)
# Best practice: set to "restricted" at org level, grant per-workflow
# At workflow level (applies to all jobs):
permissions:
contents: read # read repo contents (needed for checkout)
packages: write # push Docker images to GHCR
pull-requests: write # comment on PRs
# Everything not listed = no access
# At job level (overrides workflow level):
jobs:
build:
permissions:
contents: read
packages: write
# Jobs without packages:write cannot push images
test:
permissions:
contents: read
# Security hardening checklist:
# 1. Pin third-party actions to commit SHA (not floating tags)
# ⌠uses: actions/checkout@v4 # tag can be moved
# ✅ uses: actions/checkout@11bd71901ebe57b00494f17e4d4c82d38b8db80 # pinned SHA
# 2. Never print secrets to logs
# ⌠run: echo ${{ secrets.API_KEY }}
# ✅ use the secret in env: block, not directly in run:
# 3. Set permissions to minimum at workflow and job level
# 4. Restrict environment access to protected branches only
# 5. Use dependabot to auto-update action versions
# .github/dependabot.yml:
# version: 2
# updates:
# - package-ecosystem: "github-actions"
# directory: "/"
# schedule: { interval: "weekly" }Key Points to Remember
- 1Three secret scopes: repository (all workflows), environment (only jobs using that env), organisation (shared across repos).
- 2Environment protection rules add required reviewers and branch restrictions before production deployments.
- 3GITHUB_TOKEN is auto-created per run — grant only necessary permissions (permissions: block).
- 4Pin third-party actions to commit SHAs to prevent supply chain attacks via moved tags.
- 5OIDC eliminates long-lived cloud credentials stored in secrets — use it for AWS, GCP, and Azure.
- 6Environments have their own secret store — staging and production can have different DB credentials.
Interview Questions
Sign in to ask AriaWhat is the difference between repository secrets and environment secrets?
How do you require human approval before a production deployment in GitHub Actions?
Ask Aria about Secrets, Environments & OIDC
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.