DEV Community

Cover image for Accessing AWS in Github Actions Using OIDC
Tobiloba Ogundiyan
Tobiloba Ogundiyan

Posted on • Originally published at linkedin.com

Accessing AWS in Github Actions Using OIDC

In CI/CD pipelines, the normal way to access AWS resources for deployment is to generate long-lived access keys in IAM and store those keys in the repository, but this approach has the following flaws:

  • The keys are long-lived and if they ever leak, an attacker can use them to access your AWS account.

  • The same static keys get reused across many jobs and branches, so it is hard to trace which workflow actually did what.

  • Rotating or expiring those keys requires a manual process, so they usually stay active way longer than they should.

OpenID Connect (OIDC), an identity layer on top of OAuth 2.0, solves this by letting GitHub Actions request short-lived, on-demand credentials from AWS using a trusted federation instead of storing static keys. This approach gives the following benefits:

  • No long-lived secrets in the repo. There are no hardcoded AWS access keys in GitHub at all.

  • Short-lived credentials. AWS only issues temporary credentials for that specific job, and they expire automatically after the job finishes.

  • Fine-grained access. You can scope which repo, branch, or even workflow is allowed to assume a specific IAM role.

  • Auditability. In CloudTrail, you can see exactly which workflow assumed which role, so it’s easier to trace changes.

  • Lower blast radius. If one repo is compromised, it can’t reuse credentials from another repo or environment.

Prerequisites

In this article, we will configure AWS to trust GitHub via OIDC, create an IAM role with read-only access to S3, and let a GitHub Actions workflow assume that role. You will need these resources to proceed:

An AWS account with the following permissions:


 iam:CreateOpenIDconnectProvider
 iam:CreateRole
 iam:PutRolePolicy or attached managed policies
For less hassle, a root account should do.
Enter fullscreen mode Exit fullscreen mode
  • Create a new GitHub repository in your account and name it aws-oidc. Leave it empty for now with no code and no workflow. I also created a repo for this article here: github.com/t0gun/aws-oidc. We will add the workflow file later after we configure AWS.

High-Level Architecture

Below is the high-level flow of how GitHub uses OIDC to get temporary credentials for our Actions runner.

Tobiloba Ogundiyan High level overview of OIDC with github actions and AWS

At a high level, the workflow runner requests an OIDC token, AWS STS verifies it against the trust policy, and then returns short-lived credentials that match the IAM role we created. Now let’s build this step by step.

Step 1: Add GitHub as an OIDC identity provider in AWS

You can either use the management console or the AWS CloudShell (CLI) to do this.

Using the AWS Management Console:

  • Open the IAM console and in the left navigation choose Identity Providers.

  • Once you are in that pane, proceed to add a provider, for the provider type choose OpenID connect.

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

  • For the "Audience": Use sts.amazonaws.com

  • Save

At this point, AWS now trusts the GitHub OIDC provider.

Using the AWS CLI:

Paste this in the CloudShell:

aws iam create-open-id-connect-provider \
  --url "https://token.actions.githubusercontent.com" \
  --client-id-list "sts.amazonaws.com" \
  --thumbprint-list "6938fd4d98bab03faadb97b34396831e3780aea1"
Enter fullscreen mode Exit fullscreen mode

The --client-id-list value is what the audience must be, and the thumbprint is GitHub’s root CA fingerprint. We can also confirm if it has been added using:

aws iam list-open-id-connect-providers
Enter fullscreen mode Exit fullscreen mode

You should receive a response of your ARN (Amazon Resource Name) similar to this:

{
    "OpenIDConnectProviderList": [
        {
            "Arn": "arn:aws:iam::555055555555:oidc-provider/token.actions.githubusercontent.com"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Create the IAM Role for GitHub Actions

Now that AWS trusts GitHub as an OIDC identity provider, we need to create an IAM role that GitHub Actions can assume. This role does two things:

  • Defines the trust policy: which repo and branch are allowed to assume it

  • Defines the permissions: what that workflow is actually allowed to do in AWS

For this demo, we will give only S3 ReadOnly access so we can test the setup. For simplicity we will only use the AWS management console to create this role.

Using the AWS Console:

  • In the IAM console, go to “Roles” and click “Create role.”

  • For trusted entity type, choose “Web identity.”

  • For identity provider, select the GitHub provider you created in Step 1 token.actions.githubusercontent.com and the audience sts.amazonaws.com

  • For GitHub organization / user: set this to your GitHub username (for example, t0gun).

  • For Github Respository: Use the repo you created for this, aws-oidc.

  • We should leave the branch as is *, this gives us flexibility to run our jobs from any branch.

  • Attach permissions. For demo, attach AmazonS3ReadOnlyAccess.

  • Name the role something like github-oidc-deploy-role and save it.

  • Copy the Role ARN. We will use that in the GitHub Actions workflow.

Now open the role, check trust relationships and open the trust policy it should look this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::555066115752: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:t0gun/aws-oidc:*"
                    ]
                }
            }
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode
  • Principal.Federated is the OIDC provider we created in Step 1.

  • Action is sts:AssumeRoleWithWebIdentity, which is how GitHub asks AWS for short-lived credentials.

  • aud must match sts.amazonaws.com, so AWS knows this request is meant for STS.

  • sub is basically “who is calling.” In this case we’re allowing any branch from the repo t0gun/aws-oidc.

For example, if you only want to allow the main branch to assume this role, you can tighten the trust policy by replacing the sub condition with:

"token.actions.githubusercontent.com:sub": "repo:t0gun/aws-oidc:ref:refs/heads/main"
Enter fullscreen mode Exit fullscreen mode

This means only workflows running from the main branch of t0gun/aws-oidc will get credentials. All other branches will be denied.

Step 3: Create the Github Actions Workflow

Now we will create a Github Actions workflow in the aws-oidc repo that:

  • Requests temporary credentials from AWS using OIDC

  • Assumes the IAM role we just created

  • Runs an AWS command to prove it works

Clone your repo locally, create a file inside the repo at .github/workflows/oidc-test.yml with this content:

name: oidc-test

on:  
  workflow_dispatch  

permissions:
  id-token: write    # required for OIDC
  contents: read     # allow checkout

jobs:
  aws-access-test:
    runs-on: ubuntu-latest

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

      - name: Configure AWS credentials using OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: {your own arn role here}
          role-session-name: github-actions-session
          aws-region: us-east-1 # or any region you work in

      - name: Verify AWS identity
        run: |
          aws sts get-caller-identity
          aws s3 ls
Enter fullscreen mode Exit fullscreen mode

Here are the important parts:

permission.id-token: write (this is what allows the workflow to request the OIDC token from github).

  • configure-aws-credentials@v4: This action calls sts:AssumeRoleWithWebIdentity behind the scenes. It uses the trust policy you defined in IAM

  • role-to-assume: This must match the Role ARN from the role you just created in Step 2.

  • aws sts get-caller-identity: This prints which IAM role the job is currently using. You should see your role name here, not root and not an IAM user.

  • aws s3 ls: This should work because you attached AmazonS3ReadOnlyAccess. If STS or the trust policy is broken, this will fail.

After you commit this file, push it to GitHub. Since the workflow is triggered with workflow_dispatch, you need to run it manually in the Actions tab.When it finishes successfully, you’ve proved OIDC is working and GitHub Actions got temporary AWS credentials with no long-lived access keys stored in the repo.after running mine here are the results from the image below

Tobiloba Ogundiyan github actions runner logs

If pipeline fails please feel free to review the steps and also check out my own aws-oidc public repo.

Conclusion

This setup removes long-lived AWS keys from your CI/CD pipeline and replaces them with short-lived, scoped credentials issued on demand through OIDC. You get least privilege, auditability, and no shared secrets across repos. This is the baseline for doing secure delivery in AWS with GitHub Actions, and it’s what I expect teams to be doing in 2025.

Top comments (0)