Static Website

Recently, I decided to renew my silentYak blog and recreate it as a static website built using Zola and deployed to S3 with CloudFront. These are the ultra-brief cliff notes on what to do in case you want to set up something similar for yourself.

  • Create the source code Q (example) of the blog using Zola.
  • Create the GitHub repository S hosting the source code Q of the blog.
  • Create a private S3 bucket B to which artifacts will be published.
  • Create a hosted zone H in Route 53 for your domain M.
  • Update your domain registrar to use Route 53’s nameservers for domain M.
  • Wait for the hosted zone H in Route 53 to become authoritative.
  • Request a new certificate X for your domain M from AWS Certificate Manager (ACM) in us-east-1 (CloudFront has this constraint on AWS region).
  • Create domain verification (TXT) records in hosted zone H as prompted by ACM.
  • Wait for the requested certificate X to be issued.
  • Create a CloudFront function F to redirect to index.html files correctly (example).
  • Create a CloudFront distribution D with certificate X, “Viewer Request” function F, and alternate domain name M (not optional).
  • Update hosted zone H to create A and AAAA aliases for distribution D.
  • Update S3 bucket B‘s access permissions to authorize CloudFront distribution D.
  • Create an OpenID Connect identity provider C to represent GitHub Actions.
  • Create an IAM policy P (see below) for allowing access to S3 and CloudFront.
  • Create an IAM role R for publishing artifacts.
  • Associate the IAM policy P with the IAM role R.
  • Associate a trust policy T (see below) with role R for GitHub Actions.
  • Generate a GitHub Actions workflow file W (example) to build and publish artifacts.
  • Commit the GitHub Actions workflow file W to the GitHub repository S.
Example IAM Policy P
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:DeleteObject",
                "cloudfront:CreateInvalidation"
            ],
            "Resource": [
                "arn:aws:s3:::silentyak-com-website-assets/*",
                "arn:aws:s3:::silentyak-com-website-assets",
                "arn:aws:cloudfront::965356658022:distribution/E2JDATP1TDIY9S"
            ]
        }
    ]
}
Example Trust Policy T
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::965356658022: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:rri/silentYak:ref:refs/heads/main"
                }
            }
        }
    ]
}

That’s all for today, folks! 🖖