Using OIDC to integrate GitHub Actions with AWS
Table of Contents
Recently I came across a quick read by Ryan Cormack where he described how he integrated Github Actions with AWS using CDK and OIDC. It was a great overview and piqued some interest from me to learn more. After some additional reading of the Github documentation I knew it was the way to go for deploying this blog website.
Up until now, I’ve been using the Hugo Github action by peaceiris to deploy changes to S3 on merge to the main branch. Since the action needs to authenticate with AWS to upload the files and invalidate the CloudFront distribution, it required setting a long lived IAM User Access Key and Secret in the secrets section of the repository and specifying them as build step environment variables. Long lived tokens are never a great solution so by integrating with OIDC I’ve eliminated the need for those tokens. Fortunately the Hugo cli and the configuration files make the deployment rather simple and it natively consumed the tokens generated by the OIDC integration.
The setup is very straightforward by walking through Ryan’s blog post and the Github documentation. Here were my steps.
1. Configure the IDP #
The AWS environment for this blog is very straightforward so I didn’t feel the need to create a CDK project to configure the IDP in AWS like Ryan did. I did that step manually and took less than 5 minutes by following both the Github and AWS documentation.
2. Create and IAM role with the proper permission policy #
I already had an IAM policy with the proper permissions attached to my IAM User so all I needed to do was create an IAM Role and attach that policy. You will need to set the proper conditions on the trust policy.
Here is the example from the Github documentation:
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:octo-org/octo-repo:ref:refs/heads/octo-branch"
}
}
For this trust policy I’m following the principle of least privileges and chose be very specific in the condition statement. I maintained the StringEquals
on my repo definition rather than using a StringLike
and the only difference in my policy is the path to my org, repo, and branch.
3. Github Action Permissions #
Grant the proper permissions to the Github action in the workflow yaml file.
permissions:
id-token: write # This is required for requesting the JWT
contents: read # This is required for actions/checkout
4. Add a Credential Build Step #
Add a build step to your workflow yaml file to trigger the OIDC flow to obtain the tokens. Here I’m specifying the role created in step 2 and the default region.
- name: configure aws credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::123456789001:role/github-actions-deployment-role
aws-region: us-east-1
5. Hugo Deploy Step without Access Key and Secret Environment Variables #
In my Github action workflow document, I already had a build step to deploy to S3. I left the same run command and just removed the env definition which retrieved the long lived tokens from Github secrets.
- name: Deploy to S3
run: hugo deploy --force --maxDeletes -1 --invalidateCDN
6. Delete the IAM User #
Since you don’t need the IAM User anymore, don’t forget to delete it. You don’t want to have unused tokens floating around so make sure you clean up!
Summary #
So it is pretty simple to configure and the bonus of not having to worry about long lived tokens is just another bonus!