Skip to main content

Article

Complete Guide: Secure GitHub Actions & AWS Integration with OIDC

10 min read
Complete Guide: Secure GitHub Actions & AWS Integration with OIDC

Complete Guide: Secure GitHub Actions & AWS Integration with OIDC

What We're Building

Instead of storing AWS secrets in GitHub (which is risky), we'll set up a secure trust relationship where GitHub Actions can directly assume an AWS role and get temporary credentials automatically.

The Magic: No secrets stored anywhere, yet GitHub Actions gets full AWS administrator access!


Understanding the Key Concepts First

What is OIDC?

OpenID Connect (OIDC) is like a digital passport system for applications.

Think of it this way:

  • You have a GitHub Actions workflow (the traveler)
  • AWS is like a country you want to visit
  • OIDC is the passport verification system
  • Instead of carrying a physical passport (secrets), you get a temporary visa (token) that proves who you are

What is an Identity Provider?

An Identity Provider is like a trusted government that issues passports.

In our case:

  • GitHub is the Identity Provider (issues tokens)
  • AWS trusts GitHub to verify identities
  • When GitHub says "this workflow is legitimate," AWS believes it

What is IAM Role?

An IAM Role is like a job position with specific permissions.

Instead of giving a person direct access, you create a role (like "Administrator") and let people temporarily "wear that hat" when they need those permissions.


Step-by-Step Implementation

Step 1: Create OIDC Identity Provider in AWS

This step tells AWS: "I trust GitHub Actions to send me identity tokens."

  1. Navigate to AWS Console

    • Go to AWS Console → IAM
  2. Add Identity Provider

    • Click "Identity providers" in the left sidebar
    • Click "Add provider"
  3. Configure Provider

    Provider Type: OpenID Connect
    Provider URL: https://token.actions.githubusercontent.com
    Audience: sts.amazonaws.com
    
  4. Why these values?

    • Provider URL: This is GitHub's official OIDC endpoint
    • Audience: This tells AWS that the tokens are meant for AWS STS (Security Token Service)
  5. Click "Add provider"

Step 2: Create IAM Role for GitHub Actions

This creates the "job position" that GitHub Actions will assume.

  1. Start Role Creation

    • Go to IAM → Roles → Create Role
  2. Choose Trust Type

    • Select "Web identity" (because GitHub Actions is a web service)
  3. Configure Web Identity

    • Identity provider: Select the GitHub OIDC provider you just created
    • Audience: sts.amazonaws.com
  4. What's happening here?

    • We're telling AWS: "Only tokens from GitHub's OIDC provider can use this role"
    • The audience ensures the token was meant for AWS

Step 3: Attach Administrator Permissions

This gives the role full AWS access (be careful with this in production!).

  1. Attach Policy

    • Search for AdministratorAccess
    • Select it and click Next
  2. Name Your Role

    • Role name: GitHubActionsAdminRole (you can give any name)
    • Add description: "Role for GitHub Actions with admin access"
  3. Create Role

Step 4: Fine-tune the Trust Policy (Important!)

The default trust policy might be too broad. Let's make it more secure.

  1. Edit Trust Policy

    • Go to your new role → Trust relationshipsEdit trust policy
  2. Replace with this secure version:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Federated": "arn:aws:iam::YOUR_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_GITHUB_USERNAME/YOUR_REPO_NAME:*"
            }
          }
        }
      ]
    }
    
  3. Replace placeholders:

    • YOUR_ACCOUNT_ID: Your AWS account ID (find it in top-right corner)
    • YOUR_GITHUB_USERNAME: Your GitHub username
    • YOUR_REPO_NAME: Your repository name
  4. Why this trust policy?

    • Federated: Points to our OIDC provider
    • StringEquals: Ensures token is for AWS
    • StringLike: Only allows your specific repository to use this role

GitHub Actions Workflow Configuration

Now let's create the workflow that uses this setup.

Create the Workflow File

  1. Select any of your repo.

  2. Create .github/workflows/deploy-ec2.yml:

name: Deploy EC2 via GitHub Actions with OIDC

# When should this workflow run?
on:
  workflow_dispatch:  # Allows manual trigger from GitHub UI

# Define the job
jobs:
  deploy:
    runs-on: ubuntu-latest  # Use Ubuntu virtual machine
    
    # CRITICAL: These permissions are required for OIDC
    permissions:
      id-token: write    # Allows requesting OIDC token
      contents: read     # Allows reading repository contents
    
    steps:
      # Step 1: Get the code
      - name: Checkout code
        uses: actions/checkout@v4
      
      # Step 2: Get AWS credentials using OIDC (THE MAGIC HAPPENS HERE)
      - name: Configure AWS credentials using OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::<Account-id>:role/<Role-Name>
          aws-region: us-east-1
      
      # Step 3: Use AWS CLI with the temporary credentials
      - name: Launch EC2 instance
        run: |
          echo "Launching EC2 instance..."
          aws ec2 run-instances \
            --image-id ami-0c02fb55956c7d316 \
            --count 1 \
            --instance-type t2.micro \
            --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=GitHubOIDCTest}]' \
            --key-name <key-pair-name> \
            --security-groups default

Understanding Each Line

Workflow Trigger

on:
  workflow_dispatch:
  • workflow_dispatch: Allows you to manually run this workflow from GitHub's web interface
  • You could also use push, pull_request, or schedule triggers

Job Configuration

jobs:
  deploy:
    runs-on: ubuntu-latest
  • jobs: A workflow can have multiple jobs
  • deploy: Name of our job (you can choose any name)
  • runs-on: Specifies the virtual machine type

Critical Permissions

permissions:
  id-token: write
  contents: read

This is crucial for OIDC to work!

  • id-token: write: Allows GitHub to generate and send OIDC tokens
  • contents: read: Allows reading files from your repository

Steps Breakdown

Step 1: Checkout Code

- name: Checkout code
  uses: actions/checkout@v4
  • Downloads your repository code to the virtual machine
  • @v4: Version of the checkout action

Step 2: OIDC Authentication (The Magic)

- name: Configure AWS credentials using OIDC
  uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: arn:aws:iam::<Account-id>:role/<Role-Name>
    aws-region: us-east-1

Step 3: Use AWS CLI

- name: Launch EC2 instance
  run: |
    echo "Launching EC2 instance..."
    aws ec2 run-instances \
      --image-id ami-0c02fb55956c7d316 \
      --count 1 \
      --instance-type t2.micro \
      --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=GitHubOIDCTest}]' \
      --key-name <key-pair-name> \
      --security-groups default

Breaking down the EC2 command:

  • aws ec2 run-instances: Launch EC2 instances
  • --image-id: The AMI (Amazon Machine Image) to use
  • --count 1: Launch 1 instance
  • --instance-type t2.micro: Size of the instance
  • --tag-specifications: Add tags to identify the instance
  • --key-name <key-pair-name>: SSH key pair for connecting to instance
  • --security-groups default: Security group (firewall rules)

Replace these placeholders

Replace the following placeholders in your GitHub Actions workflow file:

Placeholder Replace with
<Account-id> Your AWS Account ID (e.g. 123456789012)
<Role-Name> Name of the IAM Role you created (e.g. GitHubActionsAdminRole)
key-pair-name Name of an EC2 Key Pair already created in AWS
ami-0c02fb55956c7d316 Amazon Linux 2 AMI for us-east-1 (can be used as-is if your region matches)

How to Find These

🔹 AWS Account ID

  • Sign in to AWS Console
  • Click your account name (top-right) → Account
  • Copy the 12-digit AWS Account ID

🔹 IAM Role Name

  • Go to AWS Console → IAMRoles
  • Find the role you created for GitHub OIDC
  • Copy the role name

🔹 Key Pair Name

  • Go to AWS Console → EC2Key Pairs
  • Use an existing key pair name or create a new one
  • Remember to download the .pem file if you create a new one

🔹 AMI ID

  • The default ami-0c02fb55956c7d316 is for Amazon Linux 2 in us-east-1
  • If using another region, you can find a suitable AMI in the EC2 Launch Wizard or AWS AMI catalog

What happens behind the scenes:

  1. GitHub Actions requests an OIDC token from GitHub
  2. The token contains information about the workflow, repository, and run
  3. This action sends the token to AWS
  4. AWS verifies the token against the trust policy
  5. AWS returns temporary credentials (valid for ~1 hour)
  6. These credentials are automatically available to subsequent steps

How It All Works Together

The Flow

  1. You trigger the workflow (manually or via push/PR)
  2. GitHub Actions starts a virtual machine
  3. GitHub generates an OIDC token containing workflow metadata
  4. AWS receives the token and verifies it against the trust policy
  5. AWS provides temporary credentials to the workflow
  6. Your workflow uses these credentials to perform AWS operations
  7. Credentials automatically expire after ~1 hour

Security Benefits

  • No secrets stored anywhere
  • Credentials are temporary (auto-expire)
  • Specific to your repository (trust policy restriction)
  • Full audit trail (CloudTrail logs all actions)

Customization Options

Modify for Your Repository

  1. Update the role ARN in the workflow file:

    role-to-assume: arn:aws:iam::YOUR_ACCOUNT_ID:role/GitHubActionsAdminRole
    
  2. Update the trust policy with your repository details:

    "token.actions.githubusercontent.com:sub": "repo:YOUR_USERNAME/YOUR_REPO:*"
    

Different Trigger Options

# Trigger on push to main branch
on:
  push:
    branches: [ main ]

# Trigger on pull request
on:
  pull_request:
    branches: [ main ]

# Trigger on schedule (daily at 9 AM)
on:
  schedule:
    - cron: '0 9 * * *'

Different AWS Operations

Replace the EC2 launch command with any AWS CLI command:

# Deploy to S3
- name: Deploy to S3
  run: |
    aws s3 cp ./dist s3://my-bucket/ --recursive

# Update Lambda function
- name: Update Lambda
  run: |
    aws lambda update-function-code \
      --function-name my-function \
      --zip-file fileb://function.zip

Troubleshooting Common Issues

Error: "Unable to assume role"

  • Check: Role ARN is correct in workflow file
  • Check: Trust policy has correct repository name
  • Check: OIDC provider is properly configured

Error: "Token validation failed"

  • Check: permissions.id-token: write is set in workflow
  • Check: Audience is sts.amazonaws.com in both places

Error: "Access denied"

  • Check: Role has necessary permissions (AdministratorAccess or whatever you are working/need for)
  • Check: Trust policy conditions are met

Conclusion

You've successfully set up a secure, secret-free integration between GitHub Actions and AWS! This approach is:

  • More secure than storing secrets
  • Easier to manage (no credential rotation)
  • More auditable (full CloudTrail logs)
  • Scalable (works across multiple repositories)

The key insight is that instead of storing long-lived secrets, we're using short-lived, dynamically generated tokens that prove the identity of our GitHub Actions workflow to AWS.


📚 Additional Resources

Official Documentation

Security Best Practices

Advanced Topics

🌟 Explore More AWS Content

📖 Related Reading

Loved this secure integration guide? Take your AWS skills to the next level with cost monitoring and automation:

💰 How to Build an Automated AWS Resource Monitor
Build a smart system that tracks your AWS resources and sends hourly notifications to prevent surprise bills

✨ What you'll learn:

  • 🔔 Automated email alerts for running resources
  • 📊 Cost optimization strategies
  • ⚡ Lambda-powered monitoring system

Happy Reading & Building!
Share:

Continue Reading

Explore more articles on similar topics