All Articles

Deploying to AWS using Github Actions

Deploying a web application has never been easier with the powerful combination of GitHub Actions and AWS. In this guide, we’ll walk through setting up AWS OIDC (OpenID Connect), using the configure-aws-credentials action, and deploy a small Gatsby project to AWS S3, followed by creating a CloudFront invalidation. This setup is really helpful in creating a secure environment, as leveraging trusted roles means credentials don’t have to be used at all. This very site is deployed using confiuration very close to the below tutorial.

Table of Contents

  1. Introduction
  2. Prerequisites
  3. Setting Up AWS OIDC
  4. Configuring GitHub Actions
  5. Deploying
  6. Security Considerations
  7. Conclusion

Introduction

GitHub Actions is an excellent CI/CD tool that allows you to automate your workflow directly from your GitHub repository. AWS S3 and CloudFront are robust services for hosting and delivering static web apps. This tutorial will show how to automate deployment directly from Github.

Prerequisites

Before we start, ensure you have the following:

  • An AWS account
  • A GitHub repository with any static website project
  • Basic understanding of GitHub Actions and AWS services

Setting Up AWS OIDC

AWS OpenID Connect (OIDC) allows GitHub Actions to securely authenticate with AWS without requiring long-lived AWS credentials.

Step 1: Create an IAM Role for GitHub Actions

  1. Go to the IAM console in AWS.
  2. Create a new role and select the “Web Identity” option.
  3. Choose “GitHub” as the identity provider.
  4. Add the following condition to the trust relationship policy:
    "Condition": {
      "StringEquals": {
        "token.actions.githubusercontent.com:sub": "repo:<your-github-username>/<your-repo-name>:ref:refs/heads/<branch-name>"
      }
    }
  5. Attach policies that grant necessary permissions, such as AmazonS3FullAccess and CloudFrontFullAccess.

Step 2: Configure the Role

  1. Copy the Role ARN (Amazon Resource Name).
  2. Add the Role ARN to your GitHub repository secrets as AWS_ROLE_ARN.

Configuring GitHub Actions

Create a .github/workflows/deploy.yml file in your repository with the following configuration:

name: Deploy Static Website to AWS

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    permissions:
      id-token: write
      contents: read

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

      - name: Install dependencies
        run: npm install

      - name: Build static site
        run: npm run build

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

      - name: Deploy
        run: |
            aws s3 cp ./public s3://your-s3-bucket-name --recursive
            aws cloudfront create-invalidation --distribution-id your-distribution-id --paths "/*"

Of note here, the id-token: write is required to request a jwt token from github. There is also a common pitfall working with forks: by default, github will not pass secrets to PRs opened from forks. This is for good reason, as open source projects could have secrets compromised by a bad actor simply opening a PR. However, in most team settings, fork owners are known and can be trusted, but this is a decision you’ll need to make forself. To configure Github to send secrets to PRs from forks, navigate to organization settings, actions, security, and the “Fork pull request workflows in private repositories section.” Check the appropriate choices there.

Deploy

The aws s3 cp command in the GitHub Actions workflow copies your built static website from the public directory to your S3 bucket. And then it’s straightforward to create an invlidation for your cloudfront distro. Not that the path value of /* will invalidate cached objects. You may be able to tailor this to keep some objects in cache.

Step-by-Step Breakdown

  1. Checkout code: Pulls the latest code from your repository.
  2. Install dependencies: Installs all the necessary dependencies for your static website project.
  3. Build static site: Generates the static files for your site.
  4. Configure AWS credentials: Uses the OIDC token to assume the specified IAM role.
  5. Deploy: Uploads the static files to your S3 bucket, and creates the Cloudfront invalidation

Command Breakdown

  • aws cloudfront create-invalidation --distribution-id your-distribution-id --paths "/*"

This command invalidates all files in your CloudFront distribution, ensuring users receive the latest content.

Security Considerations

Using OIDC with GitHub Actions enhances security by eliminating the need for long-lived AWS credentials. Here’s why this configuration is secure:

  1. Short-lived credentials: The OIDC tokens are short-lived, reducing the risk of credential exposure.
  2. Scoped permissions: The IAM role grants only the necessary permissions for deployment, following the principle of least privilege.
  3. Conditional access: The trust policy limits access to specific GitHub repositories and branches, adding an extra layer of security.

Conclusion

By following this guide, you’ve set up a secure and efficient deployment pipeline for your static project using GitHub Actions and AWS. This integration not only simplifies your workflow but also leverages the security benefits of AWS OIDC. Happy deploying!

Feel free to ask any questions or share your deployment experiences with me!

Published May 26, 2024

Thoughts on about software, tech, leadership, food and ceramics.