Skip to content

PATTERN Cited by 2 sources

Short-lived OIDC credentials in CI

Problem: CI workflows need credentials to talk to cloud providers (AWS, GCP, Azure), package registries (PyPI, npm), and even GitHub itself. Storing Personal Access Tokens, GitHub App private keys, or long-lived cloud API keys as repo secrets creates an arbitrary-blast-radius leak surface: anyone who exfiltrates the secret can use it from anywhere, for its full lifetime, as any identity.

Pattern: Use OIDC identity federation to exchange a short-lived JWT for a scoped, time-bounded credential per-job. No credential at rest; no credential after job exit.

Shape

  1. CI platform acts as an OIDC IdP (GitHub Actions exposes ACTIONS_ID_TOKEN_REQUEST_* env vars).
  2. Job obtains an OIDC token bearing claims like sub, aud, repo, workflow, ref.
  3. Token is presented to a broker that trusts the CI platform's IdP.
  4. Broker validates claims (via StringLike/StringEquals trust-policy matching), issues a scoped, short-lived credential.
  5. Job uses the credential; it expires without rotation.

Canonical instantiations

GitHub Actions → AWS

aws-actions/configure-aws-credentials action calls sts.AssumeRoleWithWebIdentity against an IAM Role whose trust policy names the GitHub OIDC IdP and matches sub on repo:ORG/REPO:ref:refs/heads/BRANCH. patterns/oidc-role-assumption-for-cross-cloud-auth is the dedicated pattern for the AWS side; this pattern is the CI side.

GitHub Actions → GitHub

Long-lived PATs and GitHub App private keys stored in repo secrets are the legacy; octo-sts and dd-octo-sts-action are the OIDC-exchange replacements.

GitHub Actions → PyPI

PyPI Trusted Publishing accepts OIDC tokens from known IdPs (GitHub Actions, GitLab CI) and issues ephemeral publish tokens scoped to the workflow.

Fly.io Machines → AWS

Fly.io operates its own OIDC IdP (oidc.fly.io) that issues JWTs to Fly Machines; AWS IAM trust policies scope role assumption via sub prefix matching (see sources/2024-06-19-flyio-aws-without-access-keys).

What it buys you

  1. No long-lived credential at rest in repo secrets.
  2. Per-job scope — different workflow = different identity = different trust policy match.
  3. Auto-rotation — every job gets a fresh token.
  4. Time bounds — typical ≤ 1 hour, often tighter.
  5. Fail-closed posture — if the IdP is unreachable, jobs fail rather than falling back to a long-lived secret.

What it doesn't buy you

  • Protection against malicious workflows with legitimate OIDC claims. If a malicious PR can get an OIDC token whose claims match a trust policy, the token is usable. Trust-policy design (sub prefix matching to match only main branch, only ref:refs/tags/*, etc.) is the control.
  • Protection against compromised dependencies. Third-party GitHub Actions pinned to floating tags can still exfiltrate OIDC tokens at runtime. patterns/org-wide-github-rulesets hardening + commit pinning + audit are needed here.

Seen in

  • sources/2026-03-09-datadog-when-an-ai-agent-came-knocking — Datadog cites this pattern as one of its SDLC-security initiatives: "Building an adaptation of octo-sts by chainguard for the dd-octo-sts-action GitHub action, allowing our workflows to dynamically generate minimally scoped, short-lived GitHub credentials at runtime through Open ID Connect (OIDC) identity federation to deprecate long-lived and overscoped GitHub Personal Access Tokens (PATs) and GitHub Apps in workflows."
  • sources/2024-06-19-flyio-aws-without-access-keys — Fly.io → AWS disclosure of the same pattern at a different substrate.
Last updated · 200 distilled / 1,178 read