Safeguard
Security Guides•

Deploy Terraform from CI with OIDC instead of stored cloud keys

OIDC lets a CI job get short-lived cloud credentials instead of storing keys as secrets. How the trust works and why the subject condition matters.

Safeguard Security Team
3 min read

With OpenID Connect, a CI job asks the cloud provider for a short-lived credential at run time, so you do not store long-lived cloud keys as pipeline secrets. The trust policy must restrict which repository, branch or environment can assume the role. A loose subject condition is the main way this setup goes wrong.

The old pattern and its problem

Many Terraform pipelines hold an access key pair as a repository secret. That key does not expire, works from anywhere, and is exposed to anyone who can run a workflow, edit one, or compromise a dependency that runs in the job. Rotating it is a manual chore that tends to be forgotten.

How OIDC changes it

GitHub's documentation says you set up an OIDC trust with your cloud provider and have workflows request credentials at runtime, so you do not duplicate long-lived credentials as secrets. Each job gets an automatically generated OIDC token. The cloud provider checks the token's subject and other claims against conditions you preconfigured on the role's trust definition, then issues a short-lived access token that is valid for a single job.

AWS's IAM guidance agrees in principle: workloads outside AWS, including managed CI platforms, can still use temporary credentials, for example through the AssumeRoleWithWebIdentity API with a token from an identity provider configured in your account.

The part that matters: the subject claim

The sub claim identifies the workflow. GitHub's example subject is repo:octo-org/octo-repo:environment:prod, which ties access to a specific repository and environment. The tighter your condition, the fewer workflows can assume the role.

Practical rules:

  • Match the full subject, not a wildcard on the organization.
  • Use separate roles for plan and apply. A plan role can be read only.
  • Tie the apply role to a protected environment so approvals gate it.
  • Never share one role between production and development pipelines.

GitHub also notes newer repositories use an immutable subject format that includes owner and repository IDs. Check which format yours uses before writing the condition.

The page I fetched did not cover the workflow permission setting needed to request the token, so check GitHub's OIDC reference for that detail.

Plan versus apply roles

JobRole permissionsTrigger
Plan on pull requestRead only, plus state readPull requests
ApplyWrite for the stack's resourcesProtected branch and environment approval

Pull requests from forks should not get a role at all.

Migration steps

  1. Create the identity provider and role in a test account.
  2. Scope the trust to one repository and environment.
  3. Switch one pipeline and confirm the stored key is no longer used.
  4. Delete the old key and revoke its permissions.
  5. Repeat per pipeline, then add a check that no access key secrets remain.

Quick check

Does OIDC remove the need for any secret?

For cloud credentials, largely yes. You may still need secrets for other services, such as a package registry.

What is the most common OIDC mistake?

A trust condition that is too wide on the subject claim, which lets more workflows than intended assume the role.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.