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.
The whole process includes three sections:
- Infrastructure as Code: Define AWS infrastructure as code using Terraform.
- Website Static Content: Create index.html and 404.html files as the website static content.
- 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
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
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
...
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
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
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.
Here is the detail steps:
All content in S3 bucket:
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.
- http://bucket-name.s3-website-Region.amazonaws.com
- http://bucket-name.s3-website.Region.amazonaws.com
You can visit your website from browser now. Add path after the endpoint that doesn't exist, an 404 page is returned.
Correct URL:
Incorrect URL:
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)