Automating AWS deployments through GitHub Actions can save time and reduce manual work. A workflow can build an application, run tests, create a deployment package, and update AWS resources whenever code is merged into a branch.
The challenge is managing AWS credentials securely. A common approach is to store an AWS access key ID and secret access key in GitHub repository secrets. The workflow retrieves those credentials and uses them to authenticate with AWS.
Although this approach can work, long-lived access keys create an additional security risk. They can remain valid for months or years unless they are rotated or revoked. If credentials are exposed through a compromised workflow, misconfigured repository, or unauthorized access, an attacker may be able to use them outside GitHub Actions.
OpenID Connect (OIDC) offers a different approach. GitHub Actions can request a short-lived identity token, and AWS Security Token Service (STS) can exchange that token for temporary AWS credentials after validating the workflow's identity.
This article explains how to configure GitHub Actions to access AWS using OIDC, how to restrict permissions, and how to troubleshoot common authentication problems.
What Is OIDC Authentication?
OpenID Connect is an identity layer built on OAuth 2.0. In a GitHub Actions deployment, it allows the workflow to prove its identity to AWS without storing a permanent AWS access key in GitHub.
The process works as follows:
A GitHub Actions job starts and requests an OIDC token from GitHub.
GitHub issues a signed token containing identity information about the workflow.
The AWS security token service validates the token against the configured identity provider and IAM role trust policy.
AWS returns temporary credentials for the IAM role.
The workflow uses those temporary credentials to perform authorized AWS operations.
<box border radius="lg" padding={3} gap={2}> <box background="surface-secondary" radius="md" padding={3} align="center"> GitHub Actions
<text size="sm" color="secondary">Requests an OIDC identity token</text>
</box> <box align="center"> <icon name="arrow-down" size="lg" color="secondary" /> </box> <box border radius="md" padding={3} align="center"> AWS STS
<text size="sm" color="secondary">Validates the token and IAM trust policy</text>
</box> <box align="center"> <icon name="arrow-down" size="lg" color="secondary" /> </box> <box background="surface-secondary" radius="md" padding={3} align="center"> Temporary AWS credentials
<text size="sm" color="secondary">Allow only the actions granted by the IAM role</text>
</box> </box>
The workflow does not need a permanent AWS secret key. Temporary credentials expire automatically, reducing the risk associated with credentials that remain valid indefinitely.
However, OIDC does not remove the need for access control. If the IAM role has excessive permissions, a compromised workflow can still perform unauthorized operations while its credentials remain valid.
Step 1: Create an IAM OIDC Identity Provider
AWS must trust GitHub's OIDC identity provider before a workflow can assume an IAM role.
In the AWS Management Console, open IAM and navigate to Identity providers. Add an OpenID Connect provider with these values:
The audience identifies the intended recipient of the token. The standard AWS credentials action uses sts.amazonaws.com for this purpose.
If your AWS account already has the GitHub OIDC provider configured, you do not need to create another one. Verify that its provider URL and audience are correct.
The identity provider establishes trust in GitHub's token issuer. The IAM role trust policy will determine which workflow identities are permitted to assume a particular role.
Step 2: Create an IAM Role for GitHub Actions
Create an IAM role that the workflow can assume. Select web identity as the trusted entity and choose the GitHub OIDC provider.
For a deployment that runs only from the main branch of a repository named my-org/my-app, a trust policy can restrict access to that repository and branch.
Replace the example account and repository details with your actual values.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:my-org/my-app:ref:refs/heads/main"
}
}
}
]
}
The account ID, organization, and repository in this example are placeholders.
The aud condition restricts the token's audience. The sub condition restricts which GitHub Actions identity can assume the role.
This is important because trusting GitHub's identity provider alone is not enough. Without appropriate conditions, the role may be available to more workflow identities than intended.
If your workflow uses GitHub Environments, the subject claim can have a different format, such as one identifying an environment instead of a branch. Match the trust policy to the actual token claims produced by your workflow.
Also consider the implications of reusable workflows, pull requests, and other branches. Grant access only to the identities that genuinely need to deploy.
Step 3: Grant the Role Only the Required AWS Permissions
The trust policy controls who can assume the role. The role's permissions policy controls what that identity can do after assuming it.
For example, a workflow that deploys an application to Amazon S3 may need permission to upload files to a specific bucket. A workflow deploying to ECS will require a different set of permissions.
Avoid attaching broad administrator access simply to make the workflow succeed.
For an S3 deployment, a policy might grant access only to the deployment bucket and its objects:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::my-app-deployment-bucket"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::my-app-deployment-bucket/*"
}
]
}
This example is suitable only for the relevant S3 operations. The DeleteObject permission is necessary only if the deployment process removes objects. Add permissions only when the chosen deployment method requires them.
A real deployment may also need permissions for CloudFront invalidation, ECS service updates, Lambda deployments, or other AWS services. Define those permissions separately and scope their resources as narrowly as possible.
Step 4: Configure GitHub Actions Permissions
GitHub Actions must be allowed to request an OIDC token. Add the id-token: write permission to the workflow or the specific job that needs AWS access.
For example:
name: Deploy to AWS
on:
push:
branches:
- main
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsDeployRole
aws-region: ap-south-1
- name: Verify AWS identity
run: aws sts get-caller-identity
The account ID, role name, and AWS region are examples. Replace them with your deployment configuration.
The id-token: write permission allows the job to request an OIDC token. It does not grant direct write access to AWS resources. AWS authorization still depends on the role trust policy and permissions policy.
The aws-actions/configure-aws-credentials action exchanges the GitHub identity token for temporary AWS credentials and makes them available to AWS tooling in the job.
The aws sts get-caller-identity command is a useful verification step. It displays the AWS identity associated with the current credentials without requiring broad access to deployment resources.
For production, review and pin third-party actions according to your organization's supply-chain security policy. Using a verified full commit SHA for actions provides stronger protection against unexpected changes than relying only on a mutable version tag.
Step 5: Add Your Actual Deployment Commands
Once the workflow can assume the role, add the build and deployment steps for your application.
For example, a static site might be built and copied to S3:
- name: Install dependencies
run: npm ci
- name: Build application
run: npm run build
- name: Deploy to S3
run: |
aws s3 sync dist/ \
s3://my-app-deployment-bucket \
--delete
These steps assume that the project uses npm and produces a dist/ directory. Change the commands to match your application's build process.
The --delete option removes destination files that are not present in the local build output. Use it only when that behavior is intended and the destination contains files managed by this deployment.
The IAM role must include all permissions required by the deployment commands. In this example, that includes listing the bucket, uploading objects, and deleting objects if --delete is used.
For a containerized application, the workflow might instead build an image, push it to Amazon ECR, and update an ECS service. The same OIDC authentication pattern applies, but the permissions and deployment steps will be different.
Step 6: Remove Long-Lived AWS Keys
After OIDC authentication works and the deployment has been tested, remove the old AWS access key ID and secret access key from GitHub repository or environment secrets if they are no longer required.
Also review whether the old IAM user or access key is used by other systems. Do not revoke a key blindly if it supports another production workflow. Identify its consumers, migrate them, and then disable or delete the obsolete credentials.
If an access key may have been exposed, follow your incident response process rather than waiting for an ordinary migration window.
The goal is to eliminate unnecessary long-lived credentials without breaking unrelated systems.
Common OIDC Authentication Errors
Not authorized to perform sts
This usually indicates a mismatch between the GitHub token and the IAM role's trust policy.
Check the AWS account ID, role ARN, provider ARN, audience condition, and subject condition. Confirm that the workflow's repository, branch, or environment matches the policy.
Incorrect audience
The role trust policy expects the token audience to match the configured value. For the standard AWS credentials action, that is typically sts.amazonaws.com.
Check the action configuration and IAM condition if the token is rejected.
Missing id-token permission
Without id-token: write, the workflow cannot request the GitHub OIDC token needed for authentication.
Set the permission at the workflow or job level, and make sure the deployment job actually receives it.
Authentication succeeds but deployment fails
Successful role assumption does not mean every AWS operation is authorized.
Review the role's permissions policy, resource ARNs, bucket policies, service-specific restrictions, and any organization-level controls. Grant only the additional permissions that the deployment actually needs.
Workflow uses an environment-specific subject
If a job references a GitHub Environment, its token subject may identify that environment instead of the branch. A branch-only trust policy may then reject the request.
Inspect the actual token claims using an approved diagnostic approach that does not expose the token itself. Update the trust policy to match the intended deployment identity and retain appropriate restrictions.
Security Best Practices
Use a dedicated IAM role for each deployment purpose rather than sharing a highly privileged role across unrelated applications.
Restrict the trust policy to the required repository and branch or GitHub Environment. Protect deployment branches with appropriate repository rules and reviews.
Keep the permissions policy limited to the required AWS actions and resources. Avoid storing OIDC tokens or temporary credentials in logs, artifacts, or application configuration.
Finally, monitor role usage and deployment activity. OIDC removes the need for permanent AWS keys in GitHub Actions, but a compromised repository or workflow can still misuse the permissions granted to its role.
Conclusion
GitHub Actions can deploy to AWS without storing long-lived AWS access keys. With OIDC, GitHub provides a short-lived identity token, AWS validates that identity against an IAM role trust policy, and the workflow receives temporary credentials.
The essential steps are to configure the GitHub identity provider, create a narrowly scoped IAM role, grant id-token: write to the deployment job, configure the AWS credentials action, and test the resulting identity before deploying.
When combined with restrictive trust conditions, least-privilege permissions, protected deployment branches, and careful action pinning, OIDC makes AWS deployment authentication easier to manage and reduces the risks associated with permanent credentials.
Join the conversation! Your thoughts help the community grow.