Skip to main content
Terraform challenge · Intermediate

Fix the Network Module

A Terraform module for a VPC and its subnets broke in a refactor: it does not validate, its subnets overlap and it accepts any input. Fix it until its tests and random plans pass, with no AWS account.

60minutes
5graded checks

The situation

Every team builds its VPC with the platform team's network module. Last sprint someone refactored it, and it has not worked since: terraform validate fails, and the private subnet of one availability zone still overlaps the public subnet of the next.

Subnets are created with count, so when a team removed eu-west-1a from a test stack, Terraform wanted to destroy and recreate every subnet. Nothing checks the inputs: last month someone created a VPC with a public /8 range. And a team that passed its own Name tag gave every resource in its VPC that one name.

Your task

  • Validate the inputs: name (3 to 20 lowercase letters, digits and hyphens), environment (dev, staging or prod), vpc_cidr (a private IPv4 block from /16 to /24) and azs (2 to 4 different AZs in one region, ending in a to f).
  • Create aws_vpc.this with DNS support and DNS hostnames, and one public and one private subnet per AZ, keyed by the AZ name.
  • Split the VPC into 16 blocks. The AZ letter picks the public subnet's block (a is 0, f is 5), and the private subnet is 8 blocks higher, wherever the AZ is in the list.
  • Tag every resource with the caller's tags plus Name, Environment, ManagedBy and, on subnets, Tier. The module's values win.
  • Output the VPC ID, and maps from AZ to subnet ID and subnet CIDR block. The module has only aws_vpc and aws_subnet resources, may not read files or configure the AWS provider, and reads only id, cidr_block, availability_zone and vpc_id from its resources.

What the grader checks

CheckPasses when
Formatted and validThe module has only variable, locals, resource (aws_vpc and aws_subnet) and output blocks, reads no files or paths, calls no provider functions, and reads only id, cidr_block, availability_zone and vpc_id from its resources. terraform init works with no network and only the AWS provider, terraform validate passes, and terraform fmt has nothing to change in main.tf, variables.tf and outputs.tf.
The module's tests passterraform test passes every run in tests/network.tftest.hcl, with a mock AWS provider. One run gives the VPC and subnets known IDs to check the outputs and that every subnet is in the VPC.
Inputs are validatedFor every input rule in the brief, a random value that breaks it (20 in all) is rejected by a variable validation rule, and three random sets of good inputs plan without errors.
Subnets for random inputsFor three random sets of good inputs, the plan has aws_vpc.this with DNS turned on, and one public and one private subnet per AZ in that VPC, keyed by AZ name, with the range the AZ letter picks. The outputs map AZs to subnet ranges and IDs, checked with random mocked IDs in a test written for each run.
TagsIn the same plans, the VPC and every subnet have the caller's tags plus Name, Environment, ManagedBy and, on subnets, Tier from the module, and the module's values win.

When a check fails, the grader's comment says what it saw, not how to fix it.

Files you may change

  • challenges/fix-the-network-module/main.tf
  • challenges/fix-the-network-module/variables.tf
  • challenges/fix-the-network-module/outputs.tf

A pull request that changes any other file, including the tests or the workflows, is not graded.

Hints

Start with what Terraform tells you

Run terraform validate and read each error. It names the file and the line.

count or for_each

Resources created with count are known by their position in the list, so removing the first AZ shifts every other subnet. Resources created with for_each are known by their key.

From AZ letter to block number

Look at substr(), index() and cidrsubnet() in the Terraform function documentation.

Validation rules that do not crash

cidrhost() fails on a value that is not a CIDR block. can() turns that failure into false. A variable can have more than one validation block, each with its own error message.

Which tag wins

merge() keeps the value from the last map that has the key.

Test it locally

From the challenge folder, with Terraform 1.11 or later. You do not need an AWS account: the tests use a mock provider.

terraform init
terraform validate
terraform fmt -check
terraform test

Submit

  1. Fork The-DevOps-Daily/challenges and create a branch.
  2. Commit your changes to the files listed above, and nothing else.
  3. Open a pull request against main in The-DevOps-Daily/challenges.
  4. Read the grader's comment. If a check fails, push another commit to the same branch and it grades again.
  5. When every check passes, the PR gets the passed label and is closed. It is never merged, and your pass is usually counted on this page within a few minutes.
How grading stays honest

The workflow takes the tests and the grader from the repository's main branch and copies only the files above out of your PR. Your code runs in a container or a throwaway kind cluster, and some inputs are random at grading time. A second workflow checks the result against your PR's real commit before it comments.

Learn the basics first

More challenges

All challenges