This guide will help you securely deploy a static web application (e.g., Next.js, Vite) to an AWS S3 bucket using GitHub Actions and an IAM Role.
Step 1: Create an IAM Role in AWS
- Log in to the AWS Management Console and navigate to IAM > Roles.
- Click Create Role.
- Select Web Identity as the trusted entity type.
- Under Identity Provider, choose
token.actions.githubusercontent.com
. If it doesn’t exist:- Click Create Provider.
- Set Provider Type to OpenID Connect.
- Enter
token.actions.githubusercontent.com
as the Provider URL. - Set sts.amazonaws.com as the Audience.
- Click Save.
- Return to the Create Role screen, select
token.actions.githubusercontent.com
, and confirm sts.amazonaws.com as the audience. -
Add Permissions: Choose a policy like
AdministratorAccess
(for simplicity) or a custom policy with least privilege for production. - Set Trust Policy: Ensure the policy matches the following (replace placeholders with your values):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<AWS_ACCOUNT_ID>:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:<GITHUB_USERNAME>/<REPO_NAME>:ref:refs/heads/<BRANCH_NAME>"
}
}
}
]
}
-
Name the Role (e.g.,
GitHubActionsRole
) and click Create Role.
Step 2: Configure GitHub Repository Secrets
- Go to your GitHub repository.
- Navigate to Settings > Secrets and Variables > Actions.
- Add the following secrets:
-
AWS_ROLE_ARN
: The ARN of the IAM role (e.g.,arn:aws:iam::<AWS_ACCOUNT_ID>:role/GitHubActionsRole
). -
AWS_REGION
: Your AWS region (e.g.,us-east-1
). -
S3_BUCKET
: The name of your S3 bucket (e.g.,my-app-bucket
).
-
Step 3: Create a GitHub Actions Workflow
- In your repository, create a file at
.github/workflows/deploy.yml
. - Add the following YAML configuration to automate the deployment to S3:
name: Deploy to S3
on:
push:
branches:
- main
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Verify AWS Role Assumption
run: aws sts get-caller-identity
- name: Install Dependencies
run: npm install
- name: Build Application
run: npm run build
- name: Deploy Next.js to S3
run: |
if [ -d "out" ]; then
echo "✅ Found 'out/' directory (Next.js export). Deploying..."
aws s3 sync out/ s3://${{ secrets.S3_BUCKET }}/ --delete --cache-control "public, max-age=0, must-revalidate"
else
echo "❌ 'out/' directory not found. Build may have failed."
exit 1
fi
- name: Deploy Vite to S3
run: |
if [ -d "dist" ]; then
echo "✅ Found 'dist/' directory (Vite). Deploying..."
aws s3 sync dist/ s3://${{ secrets.S3_BUCKET }}/ --delete --cache-control "public, max-age=0, must-revalidate"
else
echo "❌ 'dist/' directory not found. Build may have failed."
exit 1
fi
Explanation of the Workflow
-
Trigger: The workflow is triggered when a push is made to the
main
branch. - Permissions: Grants access to the GitHub OIDC token and repository contents.
-
Steps:
-
Checkout code: Uses
actions/checkout
to pull the latest code. -
Configure AWS Credentials: Uses
aws-actions/configure-aws-credentials
to authenticate using the IAM role. - Verify Role Assumption: Confirms that the AWS role has been assumed successfully.
-
Install Dependencies: Runs
npm install
to install the necessary packages. -
Build Application: Executes
npm run build
to generate the production build. -
Deploy to S3: Syncs the build output (either
out/
for Next.js ordist/
for Vite) to the S3 bucket, ensuring the removal of outdated files and setting proper cache headers.
-
Checkout code: Uses
Notes
-
Replace placeholders: Ensure that you replace
<AWS_ACCOUNT_ID>
,<GITHUB_USERNAME>
,<REPO_NAME>
, and<BRANCH_NAME>
with your actual values. -
Least-privilege policy: For production environments, use a least-privilege IAM policy instead of
AdministratorAccess
. - S3 static website hosting: If you’re serving the app directly from S3, make sure your S3 bucket is configured for static website hosting.
Top comments (0)