DEV Community

Cover image for Stop Using AWS Access Keys in GitHub Actions: The OIDC Guide You Need
Ali Zgheib
Ali Zgheib

Posted on • Edited on

Stop Using AWS Access Keys in GitHub Actions: The OIDC Guide You Need

Overview

OpenID Connect (OIDC) allows your GitHub Actions workflows to access resources in Amazon Web Services (AWS) without storing long-lived AWS credentials as GitHub secrets. Whether you're deploying Lambda functions, updating S3 buckets, managing EC2 instances, or using any AWS service, this guide shows you how to transition from using AWS access keys to OIDC authentication.

Why OIDC Instead of Access Keys?

Access Keys (Traditional Method):

  • ❌ Long-lived credentials that never expire
  • ❌ Must be rotated manually
  • ❌ If leaked, remain valid until manually revoked
  • ❌ Stored as GitHub secrets

OIDC (Modern Method):

  • ✅ Short-lived tokens that expire automatically
  • ✅ No credentials to rotate
  • ✅ Tokens are automatically invalidated after use
  • ✅ Fine-grained access control with trust policies

Prerequisites

Before proceeding, ensure you have:

  • An AWS account with IAM permissions
  • A GitHub repository
  • Basic understanding of IAM roles and policies

Step 1: Add GitHub OIDC Provider to AWS

  1. Navigate to the IAM Console in AWS
  2. Go to Identity providersAdd provider
  3. Select OpenID Connect
  4. Configure the provider:
    • Provider URL: https://token.actions.githubusercontent.com
    • Audience: sts.amazonaws.com
  5. Click Add provider

Step 2: Create IAM Role with Trust Policy

Navigate to IAMRolesCreate role to begin.

Step 1: Select Trusted Entity

  1. Select Web identity as the trusted entity type
  2. Configure the identity provider using the dropdowns:
    • Identity provider: Select token.actions.githubusercontent.com from the dropdown
    • Audience: Select sts.amazonaws.com from the dropdown
    • GitHub organization: Enter your organization or personal username (e.g., AliZgheib)
    • GitHub repository (optional): Enter * to allow all repositories, or specify a specific repo name
    • GitHub branch (optional): Enter * to allow all branches, or specify a specific branch like main
  3. Click Next

Tip: Using * for repository and branch gives you flexibility, but for better security, specify exact repository and branch names in production.

Step 2: Add Permissions

Attach the necessary permissions for your deployment based on what AWS services you're using:

Common AWS Services:

  • Lambda & API Gateway: AWSLambdaFullAccess, AmazonAPIGatewayAdministrator
  • S3: AmazonS3FullAccess
  • EC2: AmazonEC2FullAccess
  • ECS/Fargate: AmazonECS_FullAccess
  • CloudFormation/CDK/Terraform: CloudFormationFullAccess
  • General deployments: IAMFullAccess (or more restricted custom policy)

Note: In production, create a custom policy with least-privilege permissions specific to your needs.

Click Next to continue.

Step 3: Name, Review, and Create

  1. Name the role: Enter a descriptive name (e.g., GitHubToAWSOIDC)
  2. Description (optional): Add a description like "Role for GitHub Actions to deploy to AWS via OIDC"
  3. Review:
    • Step 1: Select trusted entities: Verify your GitHub org/repo settings
    • Step 2: Add permissions: Verify the policies you attached
    • Step 3: Add tags (optional): Add tags if needed for organization
  4. Click Create role

Copy the Role ARN

After the role is created successfully, find and copy the Role ARN (e.g., arn:aws:iam::123456789012:role/GitHubToAWSOIDC). You'll need this for the next step.

Understanding the Trust Policy (Reference)

AWS automatically generates a trust policy based on your selections. Here's what it looks like:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Principal": {
                "Federated": "arn:aws:iam::YOUR_ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
            },
            "Condition": {
                "StringEquals": {
                    "token.actions.githubusercontent.com:aud": [
                        "sts.amazonaws.com"
                    ]
                },
                "StringLike": {
                    "token.actions.githubusercontent.com:sub": [
                        "repo:YOUR_ORG/*"
                    ]
                }
            }
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Key elements:

  • token.actions.githubusercontent.com:aud: Ensures the token is intended for AWS STS
  • token.actions.githubusercontent.com:sub: Restricts access based on your GitHub org/repo/branch selections
    • repo:YOUR_ORG/* means any repository under your organization, any branch

Note: For most use cases, the trust policy generated by AWS from the UI is sufficient. You can manually edit it later if you need more specific control (e.g., specific repository, branch, or environment restrictions).

Step 3: Add GitHub Repository Secret

  1. Go to your GitHub repository
  2. Navigate to SettingsSecrets and variablesActions
  3. Add a new repository secret:
    • Name: AWS_ROLE_ARN
    • Value: Your IAM role ARN (e.g., arn:aws:iam::123456789012:role/GitHubToAWSOIDC)

Step 4: Update GitHub Actions Workflow

Update your .github/workflows/deploy.yml to use OIDC instead of access keys:

Before (Access Keys):

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Configure AWS Credentials (Access Keys)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
Enter fullscreen mode Exit fullscreen mode

After (OIDC):

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write   # Required for requesting the JWT
      contents: read    # Required for actions/checkout

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Configure AWS Credentials (OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: us-east-1
Enter fullscreen mode Exit fullscreen mode

Key Changes:

  1. Added permissions block:

    • id-token: write allows GitHub to create a JWT token
    • contents: read allows checking out the repository
  2. Replaced credentials:

    • Removed aws-access-key-id and aws-secret-access-key
    • Added role-to-assume with the IAM role ARN
  3. Updated step name: Changed from "Access Keys" to "OIDC" for clarity

Step 5: Clean Up Old Secrets (Optional)

After confirming OIDC works successfully, remove the old access key secrets:

  1. Go to SettingsSecrets and variablesActions
  2. Delete AWS_ACCESS_KEY_ID
  3. Delete AWS_SECRET_ACCESS_KEY

Important: Delete these secrets only after verifying OIDC authentication works!

Complete Workflow Example

Here's a complete workflow example deploying to AWS (this example uses Serverless Framework, but the OIDC configuration works with any deployment tool):

name: Deploy Lambda to AWS

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '22'

      - name: Configure AWS Credentials (OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: us-east-1

      - name: Install dependencies
        run: npm install

      - name: Deploy to AWS
        run: npx serverless deploy --verbose
Enter fullscreen mode Exit fullscreen mode

Testing the Setup

  1. Commit and push your changes to the main branch
  2. Navigate to Actions tab in your GitHub repository
  3. Monitor the workflow run
  4. Verify the "Configure AWS Credentials (OIDC)" step succeeds

Troubleshooting

If your deployment fails, the most common issue is insufficient permissions. Ensure your IAM role has all the necessary permissions for the AWS services you're deploying to. If you're using granular (least-privilege) permissions instead of the full access policies, you may need to add specific permissions based on the error messages in your GitHub Actions logs.

Security Best Practices

  1. Use specific conditions: Restrict the trust policy to specific branches or environments
  2. Least privilege permissions: Attach only the minimum required permissions to the IAM role
  3. Monitor usage: Enable AWS CloudTrail to audit role assumptions
  4. Regular reviews: Periodically review and update trust policies
  5. Use environments: For production deployments, use GitHub environments with protection rules

Comparison Summary

Feature Access Keys OIDC
Credential lifetime Permanent Temporary
Rotation required Yes No
Secrets to manage 2 per AWS account 1 per IAM role
Security risk if leaked High Low
Setup complexity Simple Moderate

Conclusion

By switching from AWS access keys to OIDC, you've improved your deployment security by:

  • Eliminating long-lived credentials
  • Reducing secret management overhead
  • Implementing fine-grained access control
  • Following AWS and GitHub security best practices

The initial setup requires more configuration, but the long-term security and maintenance benefits make OIDC the recommended approach for production deployments.

Additional Resources


Have you made the switch to OIDC? Share your experience in the comments below! 👇

Top comments (0)