Secrets, Variables, and OIDC¶
Overview¶
Place non-secret configuration in variables, scope secrets correctly (repository, environment, organisation), and outline OpenID Connect (OIDC) so jobs obtain short-lived cloud credentials without long-lived access keys.
Pipelines need configuration and credentials. GitHub provides configuration variables (vars.*) and secrets (secrets.*) at repository, organisation, and environment scopes. Production Cloud and DevOps teams prefer OIDC federation to AWS, Azure, or Google Cloud: GitHub mints a JWT for the job; the cloud trusts that JWT and returns temporary credentials. That removes static keys from the Actions UI.
This is a core tutorial in Module 5 · Secrets & Variables of the REBASH Academy GitHub Actions for Cloud & DevOps Engineers series — written for Cloud, DevOps, Platform, and SRE engineers.
Prerequisites¶
- Workflow Syntax: Matrix and Reusable Workflows
- Optional: an AWS, Azure, or Google Cloud sandbox for a live OIDC exchange later
Learning Objectives¶
By the end of this tutorial, you will be able to:
- Choose
varsvssecretsvs YAMLenvfor a setting - Scope secrets to repository, organisation, and environments
- Restrict deploy jobs with
environment:and protection rules - Describe OIDC trust (issuer, subject, audience) to a cloud role
- Request
id-token: writeonly when federating
Architecture¶
This topic’s control points and relationships are shown below.
Theory¶
What it is¶
Variables are non-secret key/value pairs you set in the GitHub UI (or via API) and read as ${{ vars.NAME }}. They suit regions, image names, and feature flags you are willing to show in logs. Secrets are encrypted values injected as ${{ secrets.NAME }} (and often mapped into env: for tools that expect environment variables). GitHub redacts secret values that appear in logs when they match known secret strings — redaction is log hygiene, not a security boundary against a malicious workflow.
Scopes:
| Scope | Typical use |
|---|---|
| Repository | App-specific tokens for that repo |
| Organisation | Shared non-prod tooling credentials (limit carefully) |
Environment (environment: production) | Deploy secrets + required reviewers / wait timers |
Environments attach protection rules: required reviewers, wait timers, and branch restrictions. A job that declares environment: production only receives that environment’s secrets after gates pass.
OIDC (OpenID Connect) replaces long-lived cloud keys. You grant permissions: id-token: write, the job requests a JWT, and a cloud-specific action (for example aws-actions/configure-aws-credentials) exchanges it for temporary credentials. Trust policies bind claims such as sub (repository, ref, environment) so a feature-branch job cannot assume the production role.
Why it matters¶
Leaked long-lived keys in CI are a top breach path. Feature-branch jobs that see production database passwords violate least privilege. Organisation-wide secrets amplify blast radius when any repo can run arbitrary workflow code. OIDC plus environment-scoped secrets is the modern baseline for DevSecOps: non-secrets in vars or YAML, secrets narrowly scoped, cloud access via short-lived tokens tied to repo:ref:environment claims. Auditors can reason about who could have deployed from workflow history and cloud CloudTrail / Activity logs together.
How it works¶
- Prefer YAML
env:andvars.*for non-secret config (AWS_REGION, chart name). - Store secrets in the UI at the narrowest scope that works; prefer environment secrets for production deploys.
- Mark production jobs with
environment:and enable protection rules on that environment. - For cloud API access: create an identity provider trust for
token.actions.githubusercontent.com, map subject conditions, and grant the jobid-token: writewith minimal other permissions. - Exchange the JWT at job start; use credentials; never
echothem; rely on token expiry.
You can author the workflow without a live cloud account — the OIDC job demonstrates permissions and structure. Wire the cloud role when you have a sandbox.
Key concepts and comparisons¶
| Mechanism | Good for | Limit |
|---|---|---|
YAML env | Defaults in Git | Visible to all readers |
vars.* | Non-secret ops knobs | Not for passwords |
| Repo secret | Simple integrations | Available to all workflows in repo |
| Environment secret | Production deploys | Needs environment: on the job |
| Org secret | Shared platform tooling | Broad blast radius if overused |
| OIDC to cloud | Temporary cloud API access | Needs cloud IdP + claim conditions |
| Anti-pattern | Prefer |
|---|---|
AWS_ACCESS_KEY_ID in repo secrets forever | OIDC role assumption |
| Same production secret on all branches | Environment + protected branches |
echo ${{ secrets.X }} for debugging | Masked logs; temporary elevated support access |
Common pitfalls¶
- Believing redaction means secrets cannot leave the job — malicious steps can still exfiltrate over the network.
- Forgetting
id-token: write(and overly broadpermissions: write-allas a “fix”). - Trusting
pull_request_targetwith secrets — a separate, dangerous pattern; avoid until you study it carefully. - Organisation secrets available to all repositories including forks of public templates without review.
- Storing entire
.envfiles as one secret with no rotation owner.
Hands-on Lab¶
Create a workspace for this tutorial.
mkdir -p ~/rebash-github-actions/module-05/.github/workflows && cd ~/rebash-github-actions/module-05/.github/workflows
Focus: separate vars/secrets and author an OIDC-ready job (file-only)
Step 1 – Checklist + OIDC workflow¶
mkdir -p .github/workflows
cat > oidc-checklist.md << 'EOF'
- [ ] vars for non-secrets (DEMO_REGION)
- [ ] environment: staging for deploy secrets
- [ ] permissions: contents: read, id-token: write on OIDC jobs
- [ ] cloud trust on sub claim (repo + ref + environment)
- [ ] never echo secrets
EOF
```yaml
# .github/workflows/secrets-and-oidc.yml
name: Secrets and OIDC
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
show-config:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Non-secret configuration
env:
DEMO_REGION: ${{ vars.DEMO_REGION }}
run: |
test -f oidc-checklist.md
echo "DEMO_REGION=${DEMO_REGION:-unset}"
staging-shape:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: staging
permissions:
contents: read
id-token: write
steps:
- name: OIDC-ready placeholder
run: echo "Add aws-actions/configure-aws-credentials when cloud trust exists"
Persist a macros-safe copy without expressions for local tree checks:¶
cat > .github/workflows/secrets-and-oidc.yml << 'EOF' name: Secrets and OIDC on: [workflow_dispatch] permissions: contents: read jobs: show-config: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: test -f oidc-checklist.md staging-shape: runs-on: ubuntu-latest environment: staging permissions: contents: read id-token: write steps: - run: echo "OIDC-ready job has id-token: write" EOF
### Step 2 – File-only validation
```bash
grep -E 'id-token: write|environment: staging' .github/workflows/secrets-and-oidc.yml
test -f oidc-checklist.md
Final step – Cleanup note¶
Validation¶
- Lab commands run under
~/rebash-github-actions/module-05/.github/workflows/ - You can explain each Theory section in your own words
- You used modern tooling where it applies to this topic
- You can describe one production failure mode for this topic
Code Walkthrough¶
Production practice for Secrets, Variables, and OIDC always combines:
- Inspect before you change (status, plan, logs, dry-run)
- Prefer reversible, documented changes (Git, IaC, drop-ins, version pins)
- Capture evidence (command output, pipeline logs) for handovers
- Prefer current tools and APIs over legacy shortcuts
- Least privilege — escalate credentials only when required
Keep runbooks short enough to follow under pressure. Automate checks; keep humans for judgement.
Security Considerations¶
- Treat credentials and tokens for github-actions as privileged — never commit them
- Prefer short-lived auth (OIDC, roles, SSO) over long-lived keys
- Validate blast radius before apply/deploy/delete operations
- Restrict who can approve production changes
- Collect audit logs; limit who can read sensitive traces
Common Mistakes¶
Believing redaction means secrets cannot leave the job — malicious steps can still exfiltr
Validate assumptions against the Theory section and official docs before changing production.
Forgetting id-token: write (and overly broad permissions: write-all as a “fix”).
Lab shortcuts (open security groups, admin roles, skip approvals) must not ship unchanged.
Changing production without a rollback path
Always know how to revert (previous artefact, prior release, state rollback, DNS failback).
Best Practices¶
- Encode Secrets, Variables, and OIDC changes as code and review them in pull requests
- Pin versions (images, modules, actions, provider plugins)
- Separate environments with clear promotion gates
- Alert on symptoms with runbooks attached
- Destroy lab resources; tag everything with owner and expiry where possible
Troubleshooting¶
| Symptom | Likely cause | Fix |
|---|---|---|
| Auth / permission denied | Wrong identity, policy, or scope | Check caller identity, roles, and least-privilege policies |
| Timeout / no route | Network, DNS, security group, or endpoint | Trace path, DNS, and allow-lists before retrying |
| Drift / unexpected plan | Manual change or wrong state/workspace | Reconcile desired vs actual; avoid click-ops on managed resources |
| Pipeline/job red | Flaky step, cache, or missing secret | Read failing step logs; bisect recent workflow/config changes |
| Cost spike | Idle load balancer, NAT, oversized compute | Inventory billable resources; stop/delete labs promptly |
Summary¶
Secrets, Variables, and OIDC is essential for Cloud and DevOps engineers working with github-actions. Practise the lab until the inspection and change path is muscle memory, then continue the track.
Interview Questions¶
- Difference between vars and secrets?
- OIDC cloud login fails — which trust settings do you inspect?
- Why use environments for production secrets?
- What does id-token write enable?
- Why avoid pull_request_target with secrets?
Sample answer — question 2
Validate GitHub OIDC subject claims against the cloud IAM trust policy. Missing id-token write or wrong audience is frequent.
Sample answer — question 4
Prefer OIDC short-lived roles over long-lived cloud keys in repository secrets.