Keyless AWS Deployments from GitHub Actions with OIDC
10 Feb, 2026
Until recently, I configured my CI/CD pipelines the same way: create an IAM user, generate access keys, paste them into GitHub’s secrets, and ignore the security advice about long-lived credentials. OIDC seemed to be yet another complicated authentication acronym, until I decided to give it a go one day, just to discover that it was pretty simple and ingenious.
Since 2021, GitHub Actions supports OpenID Connect (OIDC) — a protocol that lets your workflows request short-lived AWS credentials on the fly, with no stored secrets at all. GitHub proves its identity to AWS, AWS hands back temporary credentials, and they expire after the job finishes.
This post walks through the full setup with Terraform, using the same module that deploys this site.
How It Works
The integration relies on five components:
GitHub Actions workflow → requests credentials during a run.
GitHub OIDC provider → issues signed identity tokens (JWTs).
AWS IAM OIDC provider resource → tells AWS which OIDC provider URL to trust and stores the TLS thumbprint used to verify the provider’s TLS certificate. (For GitHub: https://token.actions.githubusercontent.com)
IAM Role Trust Policy → defines which principal may assume the role, which action is allowed (sts:AssumeRoleWithWebIdentity), and which token claims (repo, branch, etc.) must match.
AWS STS → validates the token and issues temporary credentials.
Configuration (One-Time Setup)
To enable OIDC between AWS and GitHub:
Create an IAM OIDC provider
Register GitHub’s OIDC issuer URL in your AWS account, establishing GitHub as a trusted identity source.
Create an IAM role for GitHub
Define an IAM role with a trust policy that allows sts:AssumeRoleWithWebIdentity for requests signed by GitHub’s OIDC provider and restricted to specific claim-based conditions (repository, branch, environment, etc.).
Configure the GitHub workflow
Enable OIDC token permissions (id-token: write) and configure the AWS credentials step to assume the IAM role using OIDC.
Runtime flow
The GitHub Action requests an OIDC token from GitHub’s OIDC provider.
The provider returns a signed JWT containing claims (issuer, audience, repository, branch, etc.).
The GitHub Action calls sts:AssumeRoleWithWebIdentity and passes the JWT.
STS verifies the token signature using the configured IAM OIDC provider, checks expiration and issuer, then evaluates the role’s trust policy conditions.
If everything matches, STS issues short-lived AWS credentials scoped to that role.
No passwords or long-lived secrets are stored anywhere. Access is granted based on cryptographic verification of signed tokens, explicit trust configuration, and claim-based authorization rules.
Advantages
Using OIDC provides several important benefits:
No long-lived AWS credentials
No access keys are stored in GitHub. Each workflow run receives short-lived, automatically expiring credentials.
Reduced blast radius
Credentials are scoped to a specific IAM role with tightly controlled permissions and typically expire within one hour.
Fine-grained, claim-based access control
Access can be restricted to specific repositories, branches, or environments using IAM trust policy conditions — eliminating the need for separate IAM users or distributed access keys.
Simpler management and governance
Access is controlled through IAM roles rather than per-repository IAM users. Repository and role context are visible in audit logs, improving traceability and oversight.
No access key lifecycle management
There are no static credentials to secure, distribute, rotate, or revoke.
Improved security posture
Eliminates the risk associated with leaked static secrets.
Best Practices
Restrict by repository and branch
Never allow a wildcard sub condition like repo:org/*. Restrict access to the exact repository and branch (or environment) that requires it.
Limit role permissions strictly
The IAM role should grant only the minimum permissions required, scoped to the resources relevant to the repository, applying the principle of least privilege.
Use short session durations
Keep STS session duration just short enough for the deployment to finish.
Separate roles per environment
Use different IAM roles for dev, staging, and production to prevent accidental privilege escalation.
Avoid mixing static credentials and OIDC
Do not keep legacy access keys in repository secrets once OIDC is enabled.
Technical Deep Dive
Using Terraform to configure OIDC between AWS and GitHub
OIDC Provider
This tells AWS to trust tokens signed by GitHub. Only one OIDC provider resource is allowed per AWS Account for the same URL.
url — GitHub’s token endpoint. AWS fetches the public keys from here to verify JWT signatures.
client_id_list — The intended audience. GitHub tokens set aud to sts.amazonaws.com by default.
thumbprint_list — Certificate thumbprint for the OIDC endpoint. Terraform requires this field, but AWS no longer validates this for providers with a publicly trusted CA, so we use a dummy value to satisfy tarraform’s field validation requirements without needing a real thumbprint.
You only need one of these per AWS account, regardless of how many repos use it.
IAM Role with Trust Policy
This is where access control happens. The trust policy defines which GitHub repos can assume the role:
The sub claim contains the repo, branch, and trigger context. The wildcard :* allows any branch — you can tighten this to :ref:refs/heads/main if you only want production deployments to have access.
Permissions
Attach policies to the role based on what the workflow needs. Here’s an example with S3 deployment:
After terraform apply, grab the role ARN from the outputs and store it as a GitHub Actions secret:
output "github_secrets_summary" { value = { AWS_ROLE_ARN = module.github_oidc.github_actions_role_arn }}
AWS_ROLE_ARN is the only “secret” involved. We’ll store it in GitHub secrets, but there is no harm if it leaks as authentication happens through OIDC token exchange at runtime.
The GitHub Actions Side
With the infrastructure in place, the workflow side is minimal. Two things are required:
id-token: write permission — lets the runner request an OIDC token from GitHub.
aws-actions/configure-aws-credentials — handles the token exchange with STS.
Note: When defining permissions at the top level, all default permissions are disabled. We must explicitly add contents: read so that actions/checkout can fetch the code.
Wrapping Up
OIDC federation between GitHub and AWS is one of those rare changes that improves security and simplifies operations. The Terraform module is ~50 lines, the workflow change is 5 lines, and you permanently eliminate long-lived credentials from your deployment pipeline.
The full Terraform module and workflow files referenced in this post are part of the infrastructure repo that runs this site.