
August 17, 2026
9 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
Storing long-term AWS access keys in repository secrets is a security liability that most teams accept out of habit rather than necessity. When you configure CI/CD pipelines for production systems, the standard approach of pasting AWS_ACCESS_KEY_ID into GitHub Secrets creates permanent credentials that can leak through logs, forks, or compromised workflows. The correct solution in 2026 is to deploy to AWS from GitHub Actions with OIDC (No Keys), replacing static secrets with ephemeral tokens issued directly by AWS STS based on cryptographic proof of workflow identity.
aws-actions/configure-aws-credentials action with the role-to-assume parameter instead of access keys.Why should you deploy to AWS from GitHub Actions with OIDC (No Keys) instead of access keys?
The fundamental problem with long-term IAM user credentials is their persistence. An access key generated today remains valid indefinitely until manually rotated or deleted. In my experience maintaining deployment infrastructure for legal-tech portals and eCommerce platforms, I have seen these keys accidentally committed to git history, exposed in pull request checks on public forks, or left active long after a developer departed. Even with strict secret scanning, the window between exposure and detection is often enough for automated scanners to find and abuse them.
OpenID Connect (OIDC) federation eliminates this entire class of risk by removing the credential entirely. Instead of GitHub possessing a secret that grants access to AWS, GitHub possesses only a signed JWT assertion about the current workflow run. AWS validates this signature against GitHub's public JWKS endpoint and issues temporary credentials scoped to exactly what the trust policy allows. These credentials expire automatically, typically within an hour, and cannot be reused outside the specific workflow context that requested them.
Beyond security, OIDC simplifies operational overhead. There are no rotation schedules to maintain, no IAM users to provision for each repository, and no risk of a single leaked key compromising multiple environments. For agencies managing dozens of client projects, as I do with Laravel applications deployed across shared infrastructure, this reduction in credential management complexity compounds significantly across the portfolio.
How do you configure the AWS IAM Identity Provider for GitHub OIDC?
The first step in setting up OIDC federation is creating an IAM Identity Provider resource in AWS that trusts GitHub's token issuer. This is a one-time configuration per AWS account, not per repository. You can create this via the console, but infrastructure-as-code is strongly preferred for reproducibility and auditability.
Terraform configuration for the identity provider
This Terraform resource defines GitHub as a trusted OIDC provider. The client_id_list must contain exactly sts.amazonaws.com, which is the audience value GitHub uses when minting tokens for AWS. The URL points to GitHub's fixed OIDC issuer endpoint.
resource "aws_iam_openid_connect_provider" "github" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = [
"6938fd4d98bab03faadb97b34396831e3780aea1",
"1c58a3a8518e8759bf075b76b750d4f2df264fcd"
]
} The thumbprint_list contains the SHA-1 fingerprints of GitHub's signing certificates. Including both the current and previous thumbprints ensures continuity during certificate rotations without downtime. AWS uses these to validate the JWT signature before accepting any token. Never omit this field or use placeholder values; the trust relationship will silently fail validation.
Verifying the provider configuration
After applying, confirm the provider exists and has the correct audience:
aws iam get-open-id-connect-provider \
--open-id-connect-provider-arn arn:aws:iam::YOUR_ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com If you manage multiple AWS accounts through an organization, create this provider in each target account. It cannot be shared across accounts via RAM or cross-account references because the trust evaluation happens at the STS level within the receiving account.
What trust policy conditions secure the IAM role for GitHub Actions?
Creating the identity provider alone grants nothing. You must create an IAM role with a trust policy that explicitly restricts which GitHub workflows can assume it. This is where most misconfigurations occur. A trust policy that only checks the provider URL without additional conditions effectively grants any GitHub repository in the world permission to assume your role.
Production-ready trust policy template
This trust policy restricts assumption to the main branch of a specific repository. Adjust the ref condition for environment branches or tag-based deployments.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:your-org/your-repo:ref:refs/heads/main"
}
}
}
]
} The StringLike operator with the sub claim is critical. The sub claim contains the full workflow context including repository, branch, environment, and actor. Using StringEquals here would require matching the exact string including the job ID, which changes every run. StringLike with the prefix pattern matches all runs on the specified branch regardless of the trailing job identifier.
Environment-scoped roles for multi-stage deployments
For projects with staging and production environments, create separate IAM roles with different ref or environment conditions. GitHub's OIDC token includes the environment name when a workflow job specifies one:
"token.actions.githubusercontent.com:sub": "repo:your-org/your-repo:environment:production" This prevents a staging deployment workflow from assuming the production role even if someone modifies the workflow file. On cloud-hosted projects where staging and production share an AWS account, this separation is essential for preventing accidental cross-environment deployments.
How do you write the GitHub Actions workflow to assume the OIDC role?
With the AWS side configured, the workflow needs three elements: the id-token: write permission, the aws-actions/configure-aws-credentials action with role-to-assume, and no access key inputs whatsoever.
Complete workflow example for Laravel deployment
This workflow deploys a Laravel application using Deployer 7 after authenticating via OIDC. Note the explicit permissions block at the job level — this is mandatory.
name: Deploy to Production
on:
push:
branches: [main]
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-24.04
environment: production
steps:
- uses: actions/checkout@v4
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::ACCOUNT_ID:role/GitHubActionsDeployRole
aws-region: ap-south-1
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
tools: composer:v2, deployer
- name: Deploy with Deployer
run: dep deploy production The aws-actions/configure-aws-credentials@v4 action handles the entire OIDC exchange internally. It fetches the JWT from GitHub's internal endpoint, calls AssumeRoleWithWebIdentity, and exports the resulting temporary credentials as environment variables for subsequent steps. You never see or handle the token directly.
Common permission errors and fixes
The most frequent failure mode is forgetting id-token: write. Without it, the credentials action cannot request the JWT and fails with an opaque "Could not load credentials" error. Setting permissions at the workflow level applies to all jobs; setting them at the job level provides finer control. Always prefer job-level permissions to follow least privilege.
Another common issue is specifying aws-access-key-id alongside role-to-assume. The action prioritizes static credentials when present, silently bypassing OIDC. Remove all key-related inputs to ensure OIDC is actually used. Audit existing workflows for leftover key references from pre-OIDC configurations.
How does OIDC compare to other AWS authentication methods for CI/CD?
Understanding the trade-offs between authentication approaches helps justify the migration effort to stakeholders who may be comfortable with existing key-based setups.
| Criteria | Long-Term Access Keys | OIDC Federation | IAM User + Rotation Script |
|---|---|---|---|
| Credential lifetime | Indefinite until manual deletion | 15–60 minutes, auto-expires | Varies, typically 30–90 days |
| Leak impact | Full access until detected and rotated | Limited to single workflow run | Full access until next rotation cycle |
| Rotation burden | Manual or custom automation required | None — automatic by design | Custom scripts, cron jobs, monitoring |
| Repository scope enforcement | Impossible — keys are bearer tokens | Native via trust policy conditions | Impossible — keys are bearer tokens |
| Multi-environment isolation | Separate IAM users per environment | Separate roles with branch/environment conditions | Separate IAM users per environment |
| Setup complexity | Low initial, high ongoing | Moderate initial, near-zero ongoing | High initial, high ongoing |
| Audit trail granularity | CloudTrail shows IAM user, not workflow | CloudTrail includes repo, branch, actor, run ID | CloudTrail shows IAM user, not workflow |
OIDC wins on every dimension except initial setup complexity, and that complexity is front-loaded and solved once per account. For teams already using infrastructure-as-code, the Terraform or CloudFormation templates take perhaps thirty minutes to write and apply. The ongoing savings in rotation automation, incident response, and compliance audits dwarf that investment.
For Nepal-based teams working with international clients, OIDC also simplifies compliance conversations. When a client's security team asks how you manage cloud credentials, demonstrating that no long-term secrets exist in your CI/CD system is far more convincing than explaining your rotation schedule. This matters increasingly for building trust with global customers who evaluate vendor security posture before engagement.
Secure your AWS deployments now
Migrating to OIDC federation is a bounded, well-understood task that permanently eliminates an entire category of credential risk. The AWS IAM Identity Provider takes five minutes to create. The trust policy requires careful thought about branch and environment scoping but is straightforward once the condition syntax is understood. The workflow change is a single parameter swap. If you are still storing AWS access keys in GitHub Secrets in 2026, prioritize this migration before your next feature sprint. For teams needing hands-on implementation support for CI/CD pipelines, AWS infrastructure, or Laravel deployment automation, reach out to discuss your project.

