As you probably know, this website is based on an amazing static website generator Hugo. I’ve been more than happy ever since I switched to it more than two years ago.
In the beginning, I deployed website directly from my local machine to the S3 and then invalidated Cloudfront cache as described in the article. This has been working well, but I had to automate it.
Website is in Git and sometimes when I’d do something to it I would build and deploy the website, but sometimes forget to push to Git (as we all do, right? :-) ). This was especially tricky when certain edits were done on the desktop, and I realized I have a typo, misspelling or could have phrased something better while at my laptop and not at home. Who wants that kind of hassle…
Anyhow, I decided to force myself to build and deploy only once things are pushed to Git, and to ensure that I had to have build and deploy setup configured there.
Github Actions
There’s nothing much fancy here, quite simple, monolith build and deploy process:
name: Deploy website to AWS S3
on:
push:
branches:
- main
workflow_dispatch:
# Required for Auth to AWS
permissions:
contents: read
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these deployments to complete.
concurrency:
group: "aws"
cancel-in-progress: false
defaults:
run:
shell: bash
jobs:
build:
runs-on: ubuntu-latest
env:
HUGO_VERSION: SOMEVERSION
steps:
- name: Install Hugo CLI
run: |
wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
&& sudo dpkg -i ${{ runner.temp }}/hugo.deb
- name: Checkout
uses: actions/checkout@v3
with:
submodules: recursive
fetch-depth: 0
- name: Build with Hugo
run: |
hugo
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-region: MYREGION
role-to-assume: arn:aws:iam::MYAWSID:role/MYROLETOPUBLISHTOS3ANDINVALIDATECLOUDFRONTCACHE
role-session-name: Github_to_AWS_via_OIDC
- name: Deploy
run: |
hugo deploy
So basically process consists of:
- spin up Ubuntu container
- download hugo.deb and install it
- checkout repository
- hugo
- login to AWS
- hugo deploy
Authenticating to AWS
Interesting part to you might be how I authenticate to AWS. Instead of using static credentials I’m using OIDC provider in AWS. Once I created token.actions.githubusercontent.com
provider under Identity providers I created the role which we’re using in Github Actions above.
Role is created with following trust policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::MYAWSACCOUNT: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:ivantomica/MYREPOSITORY:*"
}
}
}
]
}
I could have restricted actions further, and specify that only main branch can authenticate to the AWS, but I wanted to have some freedom there for further experimentation.
This Role also has 2 policies attached to it:
- policy to invalidate cloudfront distribution cache
- policy to write to s3 bucket
And policies are as follows.
Cloudfront policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "cloudfront:CreateInvalidation",
"Resource": "arn:aws:cloudfront::MYAWSACCOUNT:distribution/MYCLOUDFRONTDISTRIBUTIONID"
}
]
}
S3 policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObjectVersion",
"s3:ListBucket",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::mys3bucket",
"arn:aws:s3:::mys3bucket/*"
]
}
]
}
Conclusion
Voila, that’s it, nothing else required to automatically publish new version of the webiste every time I change something and push to Git. Whole Github Actions build/deploy process takes around 20 seconds which is quite fast by my standards.