Chapter 20Lesson 01~200 minutes

OpenID Connect, Cloud Federation, Trust Policies, and Secretless Deployment: Core Concepts and Mental Model

Chapter 19 governed who may enter a deployment environment. Chapter 20 removes the assumption that the approved job must hold a long-lived cloud key. Instead, the job proves its workload identity to GitHub, the provider validates narrow claims, and temporary authority exists only long enough to perform the authorized operation.

OIDCFederationClaimsLeast privilegeTrust policy

Learning objectives

  • Explain the difference between GitHub's OIDC identity token and a cloud access credential.
  • Trace issuer, audience, subject, repository/workflow/ref/environment claims through a trust decision.
  • Explain exactly what id-token: write grants—and what it does not grant.
  • Design narrow trust policies around the identity that is actually expected to deploy.
  • Preserve run, revision, runner, claim-policy, credential-lifetime, and provider-audit evidence.

1. The practical problem: long-lived keys outlive the run that needed them

Chapter 19 separated a deployment target from the branch that produced it. The next problem is credential lifetime. A repository secret containing a cloud access key can remain valid for weeks or months, while the deployment job that needed it might run for only a few minutes. If the secret is copied, exposed in another system, or simply forgotten during rotation, the credential survives the workflow run and can be used outside the evidence chain that authorized the deployment.

OpenID Connect changes the model. Instead of storing a cloud password in GitHub, an eligible job asks GitHub for a short-lived identity assertion. The cloud provider verifies that assertion against a preconfigured trust policy and, only if the claims match, returns a temporary provider credential. This separates identity from authorization: GitHub proves what workload is asking; the provider decides what that workload may receive.

2. Mental model: identity assertion → provider authorization → temporary credential

Read the chain in order. An event selects a workflow revision and creates a run. A deployment job reaches the point where it needs cloud identity. The job must have id-token: write, which permits it to request a JWT from GitHub's OIDC issuer. The JWT carries an issuer, audience, subject, timestamps, and GitHub-specific claims. The provider validates signature, issuer, audience, time bounds, and its own trust conditions. Only then does the provider issue a short-lived credential for a narrowly scoped role or service account. That credential is used for the deployment action and then expires.

Causal path: GitHub workload identity to provider authorization
flowchart TD
A[Event + exact source SHA] --> B[Workflow job]
B --> C[id-token: write]
C --> D[GitHub OIDC JWT]
D --> E[Provider validates issuer audience subject and claims]
E -->|match| F[Short-lived provider credential]
E -->|mismatch| G[Denied federation request]
F --> H[Scoped deployment/API call]
H --> I[Provider audit record + target evidence]
F --> J[Credential expires]

No arrow should be skipped. id-token: write does not jump directly to cloud permissions. A valid GitHub-signed JWT does not mean the provider must accept it. A successful token exchange does not prove the deployment changed the intended target. Each transition has separate evidence.

3. Keep the state layers separate

Layer State to record What it proves
Event / revision event, ref, GITHUB_SHA, run ID, attempt Which source and workflow run requested identity
Workflow configuration job-level permissions, environment, reusable-workflow reference What GitHub configuration was evaluated
GitHub identity issuer, audience, subject, repository/workflow/ref/environment claims What workload GitHub asserted
Provider trust role/service-account identity and exact claim conditions Which GitHub identities the provider is willing to trust
Provider credential temporary session identity and expiry—not the secret value Which temporary authority was issued
Deployment target identity, immutable artifact/digest, provider audit/deployment record What authorized side effect actually occurred

A useful incident record can therefore say: “run 412, attempt 1, source SHA X, production environment, expected subject Y, AWS role Z, temporary session issued at time T, deployment changed target Q.” It should never need the raw OIDC JWT or temporary credential value.

4. id-token: write is token-minting permission, not cloud write access

GitHub requires id-token: write at workflow or job scope before a job can request an OIDC token. The word write is easy to misread: it does not grant write access to repository contents, GitHub APIs, AWS, Azure, or Google Cloud. It only enables the OIDC token request mechanism for that job.

jobs:
  deploy:
    runs-on: ubuntu-24.04
    environment: production
    permissions:
      contents: read
      id-token: write
    steps:
      - run: echo "Cloud authorization still depends on provider trust."

Prefer job-level permission when only the deployment job needs federation. A build or lint job normally has no reason to mint an identity token. Narrowing the permission makes the trust boundary visible during review.

5. The three claims every federation design starts with

The issuer (iss) identifies GitHub's OIDC issuer: https://token.actions.githubusercontent.com. The audience (aud) identifies the intended token consumer and is provider-specific. The subject (sub) is the main workload identity string used by many trust policies. GitHub also exposes useful claims such as repository_id, repository_owner_id, workflow_ref, workflow_sha, job_workflow_ref, job_workflow_sha, ref, environment, run_id, run_attempt, and runner_environment.

Trust the smallest stable identity that matches the intended deployment. A provider policy that accepts “any repository in my organization” is broader than a policy that accepts one repository, one environment, and an expected reusable deployment workflow. When provider capabilities allow it, immutable repository and owner IDs are stronger anchors than names that can be renamed or reused.

2026 subject-format change. GitHub repositories created after July 15, 2026 use an immutable default sub format containing owner and repository IDs. Repositories created earlier retain the previous name-based format unless they opt in; renames/transfers can also move a repository to the immutable format. Do not paste a trust-policy subject from an old tutorial. Inspect the repository's actual OIDC configuration and design the provider trust condition to match it.

6. Branch, pull-request, and environment subjects are different identities

Without an environment, a branch-oriented subject identifies the repository plus the triggering ref. A pull-request run has a pull-request subject form. When the job references an environment, the environment becomes the subject context. That is why Chapter 19 matters: a production environment can become part of the workload identity rather than relying only on a mutable branch name.

Name-based legacy examples:
repo:acme-labs/widget-api:ref:refs/heads/main
repo:acme-labs/widget-api:pull_request
repo:acme-labs/widget-api:environment:production

Synthetic immutable-format example used in this chapter:
repo:acme-labs@100200300/widget-api@400500600:environment:production

Those are identity examples, not universal copy-paste values. The learner's repository might use another format or customized subject configuration. The operating rule is to verify the actual claim first, then bind the provider to that claim.

7. Reusable deployment workflows add another useful identity

Chapter 16 treated reusable workflows as versioned contracts. OIDC exposes job_workflow_ref and job_workflow_sha for jobs that execute through a reusable workflow. That lets a provider require not only “this repository and environment,” but also “this approved central deployment workflow.” It is a powerful way to make a golden deployment path enforceable outside GitHub.

The called workflow still cannot elevate token permissions beyond the caller chain. If the caller does not make OIDC available as required by the current same-organization/cross-organization rules, the called workflow cannot manufacture that permission. The cloud trust policy remains a second independent authorization boundary.

8. Short-lived does not mean unbounded

The GitHub-issued OIDC JWT itself is intentionally short-lived. The provider then controls the lifetime and privileges of the credential it returns. AWS STS sessions, Microsoft Entra access tokens, and Google Cloud federated/impersonated credentials have different lifetime controls. A design should record the configured lifetime and request only what the deployment needs.

Expiration limits blast radius, but it does not remove the need for least privilege. A five-minute administrator credential can still do enormous damage. Federation improves secret lifecycle; authorization policy still determines impact.

9. Read-only inspection before any provider change

# Local source identity
git rev-parse HEAD
git status --short

# Read the workflow permissions and environment before dispatch
grep -n -E 'permissions:|id-token:|environment:|uses:' \
  .github/workflows/oidc-production.yml

# Runtime evidence that is safe to print
printf 'run_id=%s\nattempt=%s\nsha=%s\nref=%s\n' \
  "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" "$GITHUB_SHA" "$GITHUB_REF"

Do not print ACTIONS_ID_TOKEN_REQUEST_TOKEN, a raw JWT, cloud access tokens, or provider credential files. If claim inspection is required in production, prefer a provider/tooling feature that reports non-secret claim fields, or decode only an explicitly synthetic token in a local lab.

10. Why this matters in DevOps

Federation aligns credential lifetime with automation lifetime. It also gives the cloud provider a verifiable workload identity that can be correlated with a GitHub run, exact revision, environment, and reusable workflow. That improves rotation burden, revocation response, auditability, and separation between build and deployment jobs.

The production invariant is not “OIDC is enabled.” It is: the exact authorized workload can mint a GitHub identity assertion, the provider accepts only the intended claim set, the resulting credential is short-lived and least-privileged, the exact verified artifact is deployed, and both GitHub and provider evidence point to the same operation.

11. Lesson summary

  • id-token: write allows a job to request an OIDC JWT; it does not grant cloud authorization.
  • The provider verifies issuer, audience, subject/claims, and its own trust policy before issuing temporary credentials.
  • Repository, workflow, ref, environment, and immutable IDs are separate identity dimensions.
  • GitHub's 2026 immutable default subject format means old name-only tutorials cannot be treated as universal.
  • Short lifetime reduces credential exposure but does not replace least-privilege provider permissions.
Next lesson

OpenID Connect, Cloud Federation, Trust Policies, and Secretless Deployment: Guided Hands-On Workflow

Continue with the next lesson to build on the current concepts, evidence, security boundaries, and operational practices.

Knowledge check

Why is id-token: write not equivalent to cloud write access?

A repository was created in August 2026. Should you assume its subject is repo:ORG/REPO:environment:production?

What evidence should be retained instead of a raw JWT?

Why can an environment strengthen OIDC trust?

A provider accepts a GitHub JWT but deployment still fails. Which boundary should you inspect next?

Official references and version notes

Version-sensitive GitHub Actions and provider behavior in this lesson was rechecked on 2026-09-10. Re-verify current OIDC subject format, provider trust syntax, action release SHAs, plan/visibility constraints, and temporary-credential lifetimes before production use.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.