DEV Community

Camille He
Camille He

Posted on

AWS S3 Bucket Website Hosting using Terraform

In previous blog Deploy Terraform resources to AWS using GitHub Actions via OIDC, I explained how to configure OpenID Connect within GitHub Actions workflows to authenticate with AWS, then demonstrated the process using a very simple Actions workflow that lists all buckets in my AWS account.  As I mentioned, the common use case in real world is we define AWS infrastructure as code, provision AWS resources automatically and manage these cloud infrastructure in GitHub.

In this article, I’ll go one step further. Use GitHub Actions workflow to provision and manage a S3 website using S3 website static hosting feature. The S3 bucket related AWS infrastructure is defined using Terraform. The website content and Terraform code are saved in GitHub. Any code change will trigger a new workflow build automatically to sync its infrastructure status in AWS. After done, your website can be available through bucket static website endpoint from browser.

arch-diagrm

The whole process includes three sections:

  1. Infrastructure as Code: Define AWS infrastructure as code using Terraform.
  2. Website Static Content: Create index.html and 404.html files as the website static content.
  3. GitHub Actions workflow: Create workflow to provision AWS infrastructure to AWS.

Let's get started.

Prerequisites

1. Select Tools

Terraform: I choose Terraform to provision and manage AWS infrastructure. You can use any other tools as you want, such as CloudFormation, CDK etc. The core concept is the same. Define your cloud infrastructure as code.
GitHub: Manage source code in a version control system, such as GItHub, Bitbucket, AWS CodeCommit, or Gitlab, etc.
GitHub Actions: CICD pipeline management tool, such as GitHub Actions, Jenkins, Bitbucket pipeline, AWS CodeBuild, etc.

2. Create Terraform Backend S3 Bucket

As Terraform uses persisted state data to keep track of the resources it manages, we use a backend to store state remotely. S3 bucket is commonly used to save the state of Terraform infrastructure in AWS. You can create a S3 bucket manually from AWS console, Click on Create bucket button, enter a meaningful bucket name, to make it simple, just keep all configuration as default, and click Create bucket.

The bucket name will be used in Step 3 workflow environment variable TF_BACKEND_S3_BUCKET.

3. Attach Policy on Deployment IAM Role

Remember we created a dedicated IAM role for deployment named GitHubAction-AssumeRoleWithAction in previous blog. In order to provision all AWS infrastructure that we used in this demo, you should add polices on the role. The easiest way is to attach an AWS managed policy AmazonS3FullAccess which grants full access to all buckets in your AWS account.

After done, move to coding part. You can find the sample code from GitHub repo: https://github.com/camillehe1992/demo-for-aws-deployment-via-oidc

Step 1. Infrastructure as Code

I use Terraform to define all AWS infrastructure as code, so that AWS resources can be provisioned automatically through Actions workflow and be managed in GitHub. I won’t dive into the Terraform code, as that's not in the scope. All terraform related files are in terraform directory as below.

└── terraform
    ├── local.tf
    ├── main.tf
    ├── mime.json
    ├── outputs.tf
    ├── prod.tfvars
    ├── providers.tf
    └── variables.tf
Enter fullscreen mode Exit fullscreen mode

Step 2. Website Static Content

 
Now, let’s prepare our demo website content. In public directory, create index.html, 404.html and image files. All the files in the directory are uploaded to S3 bucket as the website static content.

├── public
│   ├── 404.html
│   ├── images
│   │   ├── coffee.jpg
│   │   └── dogs.jpg
│   └── index.html
Enter fullscreen mode Exit fullscreen mode

Step 3. GitHub Actions Workflow

I created a new Actions workflow named deploy.yaml in .github/workflows directory.

├── .github
│   └── workflows
│       ├── deploy.yaml
│       └── get-started.yaml
...
Enter fullscreen mode Exit fullscreen mode

Comparing with get-started.yaml workflow, Here are main updates:

  • Add new environment variables in env block and configure these variables in GitHub Settings -> Secrets and variables -> Variable -> repository variable.
env:
  ...
  TF_BACKEND_S3_BUCKET: ${{ vars.TF_BACKEND_S3_BUCKET }}
  ENVIRONMENT: prod
  NICKNAME: demo-for-aws-deployment-via-oidc
Enter fullscreen mode Exit fullscreen mode

add-variable

TF_BACKEND_S3_BUCKET: the S3 bucket name of Terraform state files.
ENVIRONMENT: is part of Terraform backend S3 object key. Meanwhile, it's used as the suffix of website bucket name.
NICKNAME: is part of Terraform backend S3 object key.

  • Add three steps in job block after authentication:
      - name: Terraform init
        working-directory: terraform
        run: |
          terraform init -reconfigure \
            -backend-config="bucket=$TF_BACKEND_S3_BUCKET" \
            -backend-config="region=$AWS_REGION" \
            -backend-config="key=$NICKNAME/prod/$AWS_REGION/terraform.tfstate"
      # An exit code of 0 indicated no changes, 1 a terraform failure, 2 there are pending changes.
      - name: Terraform plan
        id: tf-plan
        working-directory: terraform
        run: |
          export exitcode=0

          terraform plan \
            -var-file=$ENVIRONMENT.tfvars -detailed-exitcode -no-color -out tfplan || export exitcode=$?

          echo "exitcode=$exitcode" >> $GITHUB_OUTPUT

          if [ $exitcode -eq 1 ]; then
            echo Terraform Plan Failed!
            exit 1
          else
            exit 0
          fi
      # Apply the pending changes
      - name: Terraform apply
        if: ${{ steps.tf-plan.outputs.exitcode == 2 }}
        working-directory: terraform
        run: |
          terraform apply -auto-approve tfplan -no-color
Enter fullscreen mode Exit fullscreen mode

Steps:
Terraform init: Run terraform init CLI with backend configuration
Terraform plan: Run terraform plan CLI to generate a plan.
Terraform apply: Run terraform apply CLI to apply the plan if there is pending change on it.

Commit and push to remote. A new workflow appears in Actions -> workflow named Deploy Static Website with running build.

deploy-workflow

Here is the detail steps:

deploy-workflow-detail-steps

All content in S3 bucket:

s3-objects

You can find the website_endpoint from the end of Terraform apply logs. Or go to AWS console, find your website bucket -> Properties. Scroll to the bottom of the page, then you will find the Bucket website endpoint. Depending on your Region, your Amazon S3 website endpoint follows one of these two formats.

You can visit your website from browser now. Add path after the endpoint that doesn't exist, an 404 page is returned.

Correct URL:

coffee-page

Incorrect URL:

404-page

Summary

You should know how to provision and manage AWS infrastructure using GitHub and Terraform. Now you can provision more AWS services or even other Cloud infrastructure as you want following the same methodology.

References

https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteHosting.html

Thanks for reading!

Top comments (0)