CI workload identity: replace copied cloud keys with scoped claims
Reason about OIDC trust, token audience, job identity, and short-lived cloud credentials.
On this page
Key takeaways
- A signed CI identity token is useful only when the cloud trust policy constrains its claims.
- Short lifetime reduces exposure but does not make an overprivileged job harmless.
First principles
Many build pipelines need a cloud identity to publish an artifact, read a package, or deploy a service. A static access key stored in CI settings is a long-lived bearer credential: anyone who obtains it may use it until it is revoked or expires under the provider's own rules. It can be copied into logs, caches, forked-job contexts, or developer machines. Rotating it is a separate operational chore, so forgotten keys tend to live longer than intended.
Workload identity federation replaces that shared secret with a trust exchange. The CI platform issues a signed OpenID Connect token describing a job. A cloud identity provider validates the issuer and signature, checks claims such as audience and subject, and returns or vends a short-lived credential for a role. The job proves who it is for this run; it does not embed the cloud's long-term signing key. Exact exchange APIs differ between providers, but the security decision always depends on which issuer and claims the trust policy accepts.
The subject claim should be narrow enough to represent the intended repository, branch, environment, or deployment identity. Trusting every job from an organization is usually broader than needed. An audience prevents a token minted for one relying party from being replayed at another that accepts a different audience. The provider should also limit the resulting role to the actions the job needs. A tightly scoped token that can still delete every production account is not least privilege.
Separate build and deploy identities. A pull request from untrusted code may need to run tests but should not receive deployment credentials. A release workflow can publish an immutable artifact, while an environment-protected deployment job obtains a different role after approval. This boundary is meaningful only if untrusted code cannot modify the trusted workflow, impersonate the protected environment, or extract the token through a step that runs with privileged context.
Runnable example
The following shell sequence is a provider-neutral checklist expressed as commands to inspect the job environment. Real CI systems expose different variable names and claim formats. Do not print the token itself: it is a bearer credential. A safe diagnostic reports only the expected issuer, audience, and subject after verification by the provider-side trust configuration.
set -eu
test -n "${CI_REPOSITORY:-}" || { echo 'missing repository identity' >&2; exit 1; }
test -n "${CI_REF:-}" || { echo 'missing ref identity' >&2; exit 1; }
printf 'requesting scoped workload credential for %s at %s\n' "$CI_REPOSITORY" "$CI_REF"
The secure exchange itself belongs in the platform's supported OIDC action or SDK integration, not a home-grown JWT decoder. The cloud side must verify the token cryptographically and match the exact issuer, audience, and subject constraints. The job should request the smallest role and session duration needed, avoid exposing the token to unrelated steps, and ensure credentials are masked and never written to build artifacts.
Contextual failure case
A team removes a stored cloud key and enables federated login, then grants the trust policy to every branch in the repository. A contributor opens a pull request that changes a test script. The workflow executes it with the same identity as the release job, so the script requests a valid cloud token and publishes an unreviewed artifact. No long-lived key was stolen, but the trust boundary still allowed untrusted code to act as production.
Another mistake is validating repository but not ref or environment. A token from a feature branch may then match the same trust rule as a release tag. Conversely, overly brittle claim matching can break legitimate deploys when a platform changes subject formatting. Treat claims as an explicit contract: document which repository, workflow, ref, environment, audience, and role are accepted, and test both allowed and denied cases. Use a separate test identity when exploring a new trust rule.
Short-lived credentials reduce the window for replay after a token escapes. They do not stop an attacker who controls a currently running job from using the permission during its valid interval. Secretless is not permissionless. Review job provenance, branch protection, required review, action pinning, artifact immutability, and deployment approvals alongside the token policy.
Verification
Create a matrix of expected identities: a protected release job should be accepted; a pull request from a fork, an unprotected branch, a different repository, and an incorrect audience should be rejected. Inspect the cloud audit event for the federated principal, role, session expiry, and source claims. Ensure logs redact token contents. Confirm the role cannot perform unrelated actions by testing denied operations in a disposable account.
For deployments, verify that the artifact digest approved in one stage is the same digest deployed later; rebuilding at deploy time weakens the provenance chain. Reproducible builds and artifact promotion explains why identity and artifact identity must be considered together. Record trust-policy changes as code and review them with the same care as firewall or production-role changes.
Exercise
Draft a trust policy for one repository with two jobs: tests on any branch and production deployment only from a protected release environment. List the claims each job must present and the distinct cloud actions each role can perform. Then write negative tests for a forked pull request and a release workflow with the wrong audience. Explain how an attacker who can change the workflow file might cross the boundary and which branch protections prevent that path.
Safety and caveats
OIDC claim names and token-exchange flows are platform- and provider-specific. Verify them against the actual signed claims and current provider documentation before deployment; do not trust environment variables as proof of identity. Never paste tokens into a decoder website or chat. Short credential lifetimes, approval controls, and scoped roles are defense in depth, not substitutes for protecting the workflow and its source code.