Lesson 08 Terraform Basics + Remote State
Theme:

Homework 08 — Terraform Basics + Remote State

Lesson 08 · Cloud Infrastructure & DevOps · Three tasks

These three tasks extend the Terraform module from the lab. Each one introduces a real-world pattern you will use again in Module 4 and beyond. Start with the lab’s VM running and state already in S3 before attempting any task.

Task 1 — Add a Cloudflare DNS A record via Terraform

After the lab’s terraform apply, you manually pointed a DNS A record at the Elastic IP. Replace that manual step with code.

  1. Add the cloudflare/cloudflare provider (version ~> 4.0) to required_providers in versions.tf.
  2. Add a provider "cloudflare" {} block that reads its API token from the CLOUDFLARE_API_TOKEN environment variable (no inline token).
  3. Add a data "cloudflare_zone" source that looks up your zone by name (e.g. example.com), controlled by a new var.cf_zone variable.
  4. Add a cloudflare_record resource that creates an A record for var.domain pointing at aws_eip.vm.public_ip with a 60-second TTL.
  5. Run terraform init && terraform apply to wire the full provision-and-route pipeline in one command.

✓ Self-check: terraform apply from a cold baseline creates the VM, EIP, and DNS record in one run. dig +short urls.example.com returns the EIP within 60 seconds of apply completing. curl -fsS https://urls.example.com/healthz returns {"status":"ok"}.

Task 2 — Tighten SSH to your IP only

The lab’s security group opens port 22 to 0.0.0.0/0. This is a significant attack surface: any host on the internet can attempt SSH authentication. Narrow it to your current public IP.

  1. Add the hashicorp/http provider (version ~> 3.0) to required_providers.
  2. Add a data "http" "myip" data source that fetches https://ipv4.icanhazip.com.
  3. Add a variable "ssh_admin_cidr" with an empty string default.
  4. Add a local that uses trimspace(data.http.myip.response_body)/32 when var.ssh_admin_cidr is empty, and the variable value otherwise.
  5. Replace the 0.0.0.0/0 in the SSH ingress rule with local.effective_admin_cidr.
  6. Run terraform init && terraform apply.
  7. Document your findings in a new file cloud-devops/sample-app/terraform/SECURITY.md checked into your fork.

✓ Self-check: nmap -p 22 <public_ip> from a different network shows “filtered”; from your home network (or any IP in ssh_admin_cidr) shows “open”. SECURITY.md explains what was changed and why.

Task 3 — Two environments via workspaces

Terraform workspaces let you maintain multiple independent state slots from the same .tf files — useful for dev and prod instances of the same service.

  1. Modify the tags map on aws_instance.vm to include Name = "url-shortener-${terraform.workspace}" and Env = terraform.workspace.
  2. Create a dev workspace and apply with the default t3.micro:
    terraform workspace new dev
    terraform apply
  3. Create a prod workspace and apply with t3.small:
    terraform workspace new prod
    terraform apply -var instance_type=t3.small
  4. Confirm both instances exist simultaneously. Then tear both down:
    terraform workspace select dev && terraform destroy
    terraform workspace select prod && terraform destroy

✓ Self-check: terraform workspace list shows dev, prod, and default. The AWS console shows two running instances tagged url-shortener-dev and url-shortener-prod with different instance types. The S3 bucket contains state at env:/dev/prod/terraform.tfstate and env:/prod/prod/terraform.tfstate.

View solutions →