Safeguard
Security Guides•

GitHub Actions to AWS with OIDC: no stored access keys

Use OpenID Connect so GitHub Actions gets short-lived AWS credentials. See the setup, the permissions needed and the trust policy condition to include.

Safeguard Security Team
3 min read

GitHub Actions can authenticate to AWS with OpenID Connect, so you store no long-lived AWS keys as secrets. GitHub issues a token for each job, AWS exchanges it for temporary credentials for a role you choose, and a condition on the role's trust policy decides which repositories may assume it.

The flow

According to GitHub's documentation, the pieces are:

  1. In IAM, add GitHub's OIDC provider, token.actions.githubusercontent.com, with sts.amazonaws.com as the audience.
  2. Create an IAM role that trusts that provider.
  3. In the workflow, the aws-actions/configure-aws-credentials action sends the job's token to AWS and receives temporary credentials for the role named in role-to-assume.

No access key or secret key is saved in GitHub. The credentials exist for the length of the job.

Workflow permissions

The job needs id-token: write so it can request the OIDC token. GitHub points out that this does not give write access to any resources. It only lets the workflow request and use the token. Permissions like contents: read for checkout are set separately.

permissions:
  id-token: write
  contents: read

The condition you must not skip

The role's trust policy should check the sub claim, using the key token.actions.githubusercontent.com:sub. GitHub says you must define at least one condition so untrusted repositories cannot request tokens for your cloud resources.

A condition can match:

  • A single branch, in the form repo:octo-org/octo-repo:ref:refs/heads/octo-branch.
  • A single environment, in the form repo:octo-org/octo-repo:environment:prod.

Using StringLike with wildcards is broader and permits more sources. Keep wildcards narrow and know exactly what they match.

Without a condition, the trust relationship may allow tokens from any repository on GitHub to assume your role. That is the most common mistake with this setup.

New repository format

GitHub notes that repositories created after July 15, 2026, or those that opt in, put immutable owner and repository IDs in the sub claim. If your trust policy matches names, check it against the format your repositories actually emit.

Hardening further

  • Use GitHub environments, and protect them with deployment rules, then bind the role to the environment claim. A production deploy role then requires an approved environment.
  • Create separate roles for separate jobs, for example one that only pushes images and one that deploys. Give each the minimum IAM permissions.
  • Keep role session credentials short. They are temporary by design.
  • Log role assumptions and alert on assumption from unexpected repositories.

Migrating from stored keys

  1. Create the provider and role.
  2. Change one low-risk workflow to use OIDC and confirm it works.
  3. Move other workflows over one at a time.
  4. Delete the old access keys and the GitHub secrets that held them. Deactivate first if you want a safety net, then delete.
  5. Add a repository scan to catch any new static credentials.

Quick check

Does OIDC remove the need for IAM permissions?

No. The role still needs a permissions policy. OIDC only changes how the workflow proves who it is.

What if two repositories need the same role?

List both repositories explicitly in the trust condition, rather than using a broad wildcard.

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.