Terraform Cloud Project Bootcamp with Andrew Brown — 2.5.0 Deploying to Terratowns

Gwen Leigh
6 min readOct 16, 2023

--

This article is part of my Terraform journey with Terraform Bootcamp by Andrew Brown and Andrew Bayko with Chris Williams and Shala.

My wild career adventure into Cloud Computing continues with Andrews, and I highly, highly recommend you to come join us if you are interested. Check out Andrews’ free youtube learning contents. You can also buy some paid courses here to support their good cause.

Agenda

Video here: 2 5 0 Deploying to Terratowns

Issue #52 Goals

  • ✅ 1) Test our custom provider, to work with the production server.

Workflow

1. Deploy to Missingo

In the previous episode, we were testing the environment locally in Gitpod workspace. Now we want to deploy our terratown_homes to actual TerraTown. The town Missingo is a test town for campers to test-deploy our homes. Let’s do this.

The first thing we do is to update the URL endpoint for the terratowns provider in main.tf.

provider "terratowns" {
- endpoint = "http://localhost:4567/api"
+ endpoint = "https://terratowns.cloud/api"
user_uuid = "e328f4ab-b99f-421c-84c9-4ccea042c7d1"
token = "9b49b3fb-b8e9-483c-b703-97ba88eef8e0"
}

Then we replace the mock user_uuid and token with our own. You can find your own User UUID in the access token on ExamPro.co website.

  • user_uuid: click on your profile circle at the top-right corner.
  • token: from that circle, you have the top-down menu. Click on Settings. Then you will have the Vending Machine option. There, you can generate your own access token.
# main.tf

provider "terratowns" {
endpoint = "https://terratowns.cloud/api"
user_uuid = "your-own-uuid"
token = "your-own-token-from-vending-machine"
}
Where to find your UUID
Get a token from the vending machine

Then we are switching to the test town “missingo”.

resource "terratowns_home" "home" {
name = "Nomadiachi's nomadic life"
description = <<DESCRIPTION
Mariachi works nomadically so popping in and checking out here and there.
Pictures of some memorable moments, quick snapshots of days in and days out.
Come join my nomadinary journey? :D
DESCRIPTION
# domain_name = module.terrahouse_aws.cloudfront_url
domain_name = "3fdq3gz.cloudfront.net"
- town = "the-nomad-pad"
+ town = "missingo"
content_version = 2
}

We rebuild our custom provider then test it out. Now run:

./bin/build_provider
terraform init
terraform apply

Now it’s running.

2. Serve the content

If you click on the terratowns_home in Missingo, however, the content is not served. We have to do more configuration to get it served up. So we tear down the infrastructure. Run: terraform destroy (6:19).

First, we want to mask the environmental variables using terraform variables in provider in main.tf.

provider "terratowns" {
- endpoint = "http://localhost:4567/api"
- user_uuid = "e328f4ab-b99f-421c-84c9-4ccea042c7d1"
- token = "9b49b3fb-b8e9-483c-b703-97ba88eef8e0"
+ endpoint = var.terratowns_endpoint
+ user_uuid = var.teacherseat_user_uuid
+ token = var.terratowns_access_token
}

Add the following to terraform.tfvars at root.

terraform_endpoint="https://terratowns.cloud/api"

We take out the mock url and bring back the CloudFront domain_name in resource home.

resource "terratowns_home" "home" {
name = "Nomadiachi's nomadic life"
...
+ domain_name = module.terrahouse_aws.cloudfront_url
- domain_name = "4fdq3gz.cloudfront.net"
town = "missingo"
content_version = 1
}

For security best practices, we want to store the user_uuid and access_token as env variables and call them from main.tf. The way to let terraform know of the locally stored env variables is to name the env variables headed by “TF_VAR”.

export TF_VAR_terratowns_access_token="access-token-from-vending"
gp env TF_VAR_terratowns_access_token="access-token-from-vending"
export TF_VAR_teacherseat_user_uuid="uuid-from-exampro"
gp env TF_VAR_teacherseat_user_uuid="uuid-from-exampro"

Run terraform apply.

Obviously, terraform doesn’t know where to find the values. We have to modify the terraform variable names identical to the exported variable names (excluding TF_VAR_ in front).

# variables.tf

- variable "user_uuid" {
+ variable "teacherseat_user_uuid" {
type = string
}

In fact, we have to add all the variables that we are going to secure so add the following three to your variables.tf at root.

provider "terratowns" {
endpoint = var.terratowns_endpoint
user_uuid = var.teacherseat_user_uuid
token = var.terratowns_access_token
}
# variables.tf

variable "terratowns_endpoint" {
type = string
}

variable "teacherseat_user_uuid" {
description = "Your own user uuid from teacherseat."
type = string
}

variable "terratowns_access_token" {
description = "Your own access token generated by the vending machine from teacherseat."
type = string
}

Andrew wants to see if referencing variables works correctly. We run terraform apply. If successful, destroy the infrastructure right after.

Now, bring back the old infrastructure module.terrahouse_aws.

module "terrahouse_aws" {
source = "./modules/terrahouse_aws"
user_uuid = var.teacherseat_user_uuid
bucket_name = var.bucket_name
index_html_filepath = var.index_html_filepath
error_html_filepath = var.error_html_filepath
content_version = var.content_version
assets_path = var.assets_path
}

Run terraform init and terraform apply. It’s not going to work as the value for assets_path is missing.

Add assets_path to the module terrahouse_aws.

module "terrahouse_aws" {
source = "./modules/terrahouse_aws"
user_uuid = var.teacherseat_user_uuid
bucket_name = var.bucket_name
index_html_filepath = var.index_html_filepath
error_html_filepath = var.error_html_filepath
content_version = var.content_version
+ assets_path = var.assets_path
}

3. Bucket name & Security Best practices

There are security concerns regarding the bucket_name. During our Terraform bootcamp, it happened that someone took Andrew’s bucket name which he had been using throughout the videos. As every AWS S3 bucket name has to be unique throughout the world, this causes problems on Andrew’s end. Now he wants to have the bucket_name randomly generated so this name conflict doesn’t happen again.

module "terrahouse_aws" {
source = "./modules/terrahouse_aws"
user_uuid = var.teacherseat_user_uuid
- bucket_name = var.bucket_name
index_html_filepath = var.index_html_filepath
error_html_filepath = var.error_html_filepath
content_version = var.content_version
assets_path = var.assets_path
}

Then comment out the entire bucket_name variable in variables.tf.

# variable "bucket_name" {
# description = "The name of the S3 bucket"
# type = string

# validation {
# condition = (
# length(var.bucket_name) >= 3 && length(var.bucket_name) <= 63 &&
# can(regex("^[a-z0-9][a-z0-9-.]*[a-z0-9]$", var.bucket_name))
# )
# error_message = "The bucket name must be between 3 and 63 characters, start and end with a lowercase letter or number, and can contain only lowercase letters, numbers, hyphens, and dots."
# }
# }

Now that we removed the bucket_name variable, we have to change the parts where this variable is referenced.

resource "aws_cloudfront_origin_access_control" "default" {
- name = "OAC ${var.bucket_name}"
- description = "Origin Access Controls for Static Website Hosting ${var.bucket_name}"
+ name = "OAC ${aws_s3_bucket.website_bucket.bucket}"
+ description = "Origin Access Controls for Static Website Hosting ${aws_s3_bucket.website_bucket.bucket}"
origin_access_control_origin_type = "s3"
signing_behavior = "always"
signing_protocol = "sigv4"
}

resource "aws_cloudfront_distribution" "s3_distribution" {
...
enabled = true
is_ipv6_enabled = true
- comment = "Static website hosting for: ${var.bucket_name}"
+ comment = "Static website hosting for: ${aws_s3_bucket.website_bucket.bucket}"
default_root_object = "index.html"

Then terraform apply. My terrahome is up and running on the test town Missingo!

📑 Notes

  • Every bucket name in AWS S3 must be globally unique. Otherwise this will lead to a bucket name conflict.

Resources

Bootcamp

--

--

Gwen Leigh

Cloud Engineer to be. Actively building my profile, network and experience in the cloud space. .