Deploying to AWS using GitHub Actions via OpenID Connect [OIDC]

Deploying to AWS using GitHub Actions via OpenID Connect [OIDC]

Learn how to use GitHub Actions and OIDC for safe AWS deployment.

·

6 min read

In today's fast-paced development landscape, implementing secure, automated CI/CD pipelines is crucial for efficient software delivery. Traditionally, deploying to AWS using GitHub Actions required creating an IAM user (service account) with key credentials (Access Key and Secret Key).

These credentials would then be stored in GitHub as secrets to enable the Actions workflow. However, this approach posed significant security risks. The stored secrets could remain valid indefinitely, often exceeding the recommended 90-day rotation period for credentials.

If compromised, especially if the credentials have elevated permissions, then malicious actors could exploit them to deploy unauthorized resources like crypto miners or access sensitive data, leading to severe security breaches.

With the integration of GitHub Actions and OpenID Connect (OIDC), deploying resources to AWS will become more secure. This publication walks you through deploying an S3 bucket to AWS using GitHub Actions and OIDC.


What Is OpenID Connect (OIDC)?

OIDC allows GitHub Actions to securely authenticate with AWS without relying on long-lived access keys. Instead, it leverages temporary credentials granted via an identity provider (IdP) trust relationship between AWS and GitHub.

This approach:

  • Reduces the risk of credential exposure.

  • Simplifies authentication management.

  • Facilitates least-privilege access with short-lived tokens.


Prerequisites:

  1. An AWS account with IAM permission to create S3 Bucket.

  2. Basic understanding of creating an AWS IAM role and its functionality.

  3. Basic understanding of GitHub Actions.

  4. Basic Understanding of OIDC OpenID Connector

  5. GitHub repository for your project. Here is my Repository for this project


NOTE:

I’ve outlined two methods for configuring the OIDC Identity provider and connecting it to an IAM role in AWS. The first involves using the Management console, while the second involves utilizing a cloud-formation template provided in the subsequent steps below.


Step 1: Configure AWS OIDC Identity Provider

Create an Identity Provider in AWS:

  • Log into AWS Management Console:

  • Go to the IAM Service:

  • Select Identity Providers:

  • Click on Add Provider

  • Choose OpenID Connect, then add Provider Url and Audience. By default, this information is the same for everyone, as GitHub/AWS provides it.

For the provider URL: Use https://token.actions.githubusercontent.com

For the Audience Use sts.amazonaws.com

Create an IAM Role for GitHub Actions:

Now that we've set up the Identity provider, we’ll create an IAM role with the specific permissions we want our GitHub action to have. We’ll also specify the name of the GitHub repository to which the role will grant permission. Finally, we’ll link the Identity provider to the IAM role we created.

  • Click to open the created identity provider

  • Click on the Assign Role button at the right corner of the screen

Chose Create a new role

Select “Web identity” as the trusted entity type. Then, fill out the form fields:

- GitHub organization

- GitHub repository

Click on NEXT.

  • Attached the required permission. In our use case, we will attach S3 full access permission.

  • Click on NEXT.

Provide the role name and description, and then click on Create role.


Using CloudFormation for Configuring OIDC Identity Provider in AWS

  • Open the CloudFormation Template File in this Repository

  • Access the CloudFormation YAML file

Update Role Name

  • Look for the section defining the IAM role in the template

  • Modify the RoleName property to match the desired role name.

Parameters:
  RoleName:
    Type: String
    Default: "YourUpdatedRoleName"
    Description: Name of the IAM role to be created

Update Repository Name

  • Locate the parameter, resource, or property specifying the repository name.

  • Replace it with the appropriate repository name.

# GitHub repository name in format owner/repo
  RepoName:
    Type: String
    Default: "YourUpdatedRepoName"
    Description: GitHub repository name in format owner/repo

Save the Changes

  • Save the modified CloudFormation file locally.

Deploy the CloudFormation Template

  • Use the AWS Management Console, AWS CLI, or AWS SDKs to deploy the template.

You have successfully deployed your CloudFormation stack! Everything is now set up, and your resources should be ready to use. 🎯


Step 2: Write Your GitHub Actions Workflow

In the below repository, you’ll find the GitHub action workflow and a readme file that explains how the GitHub action works and how to create your own.

Workflow Code

Create a new file .github/workflows/s3-deploy.yml in your repository with the following content:

name: Deploy AWS S3 Bucket with OIDC authentication

on:
  push

env:
  AWS_REGION : "us-east-1"
  AWS_ROLE_TO_ASSUME: "arn:aws:iam::{YOUR-AWS-ACCOUNT-ID}:role/github-actions-s3-oidc-role-dev"
  REPOSITORY_NAME: "${{ github.actor }}"
  BUCKET_NAME: "${{ github.actor }}-oidc-test-bucket"

permissions:
      id-token: write   # This is required for requesting the JWT
      contents: read    # This is required for actions/checkout

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ env.AWS_ROLE_TO_ASSUME }}
          role-session-name: s3-deploy-action-session
          aws-region: ${{ env.AWS_REGION }}

      - name: Check if bucket exists
        id: check_bucket
        run: |
          if aws s3api head-bucket --bucket ${{ env.BUCKET_NAME }} 2>/dev/null; then
            echo "Bucket ${{ env.BUCKET_NAME }} already exists"
            echo "bucket_exists=true" >> $GITHUB_OUTPUT
          else
            echo "Bucket ${{ env.BUCKET_NAME }} does not exist"
            echo "bucket_exists=false" >> $GITHUB_OUTPUT
          fi

      - name: Create S3 bucket
        if: steps.check_bucket.outputs.bucket_exists == 'false'
        run: |
          aws s3api create-bucket \
            --bucket ${{ env.BUCKET_NAME }} \
            --region ${{ env.AWS_REGION }} \
            $(if [ "${{ env.AWS_REGION }}" != "us-east-1" ]; then echo "--create-bucket-configuration LocationConstraint=${{ env.AWS_REGION }}"; fi)

          echo "Configuring bucket settings..."

          aws s3api put-bucket-versioning \
            --bucket ${{ env.BUCKET_NAME }} \
            --versioning-configuration Status=Enabled

          aws s3api put-bucket-encryption \
            --bucket ${{ env.BUCKET_NAME }} \
            --server-side-encryption-configuration '{
              "Rules": [
                {
                  "ApplyServerSideEncryptionByDefault": {
                    "SSEAlgorithm": "AES256"
                  }
                }
              ]
            }'

      - name: Configure bucket public access
        if: steps.check_bucket.outputs.bucket_exists == 'false'
        run: |
          aws s3api put-public-access-block \
            --bucket ${{ env.BUCKET_NAME }} \
            --public-access-block-configuration \
              "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"

Workflow Overview

The workflow triggers on every push and performs the following operations:

  1. Authenticates with AWS using OIDC

  2. Check if the specified S3 bucket exists

  3. Creates a new bucket if it doesn't exist

  4. Configures bucket security settings and encryption

Configuration Requirements

AWS IAM Role Setup

You need to replace the AWS_ROLE_TO_ASSUME environment variable with your IAM role ARN. Your role ARN should look similar to:

arn:aws:iam::{YOUR-AWS-ACCOUNT-ID}:role/github-actions-s3-oidc-role-dev

Step 3: Test the Workflow

  1. Commit and push the changes to your main branch.

  2. Go to the Actions tab in your GitHub repository to monitor the workflow execution.

  3. Verify the S3 bucket creation in the AWS Management Console.


Key Benefits of Using OIDC with GitHub Actions

  • Enhanced Security: Eliminates the need for long-term AWS credentials in GitHub Secrets.

  • Scalability: Easily manage permissions for multiple repositories.

  • Cost-Effective: Automates deployment without additional infrastructure.

Conclusion

By leveraging GitHub Actions with OIDC, you can build secure, streamlined CI/CD pipelines to deploy resources like S3 buckets to AWS. This setup not only reduces complexity but also ensures your workflows adhere to modern security best practices.

Next Steps

Try extending this workflow to deploy additional AWS resources, such as Lambda functions or DynamoDB tables, and explore the power of GitHub Actions in simplifying cloud deployments.

Congratulations! 🎉 and feel free to share your thoughts or ask questions about this guide! 🚀