Automate an AWS Hub-and-Spoke Network
Deploy, troubleshoot, and validate a Transit Gateway network with Terraform.
Introduction
30 Second Summary
A network diagram can look convincing while one missing connection quietly blocks traffic. A trail of console clicks also gives you little proof that you can rebuild the same design.
In this project, you will automate a two-spoke network around a central AWS Transit Gateway with Terraform. You will prove that a missing route blocks traffic before your code restores connectivity in both directions.
What You'll Build
Picture showing someone a network test in Amazon VPC Reachability Analyzer move from Not reachable to Reachable after one Terraform route change.
By the end of this project, you'll have:
- A repeatable deployment you can run to create two private VPC spokes around one central hub.
- Clear failure evidence showing that the first network design is Not reachable because its spoke routes are missing.
- Bidirectional proof showing that both network paths are Reachable after Terraform applies the symmetric routes.
- Secret Mission: An optional challenge to push your skills further.
Are There Any Prerequisites?
You need a Windows computer plus an AWS employer sandbox that permits network resource creation. The project guides you through the local tool setup before deployment.
Before We Start
This is your moment to commit to an automation-first AWS networking project before the hands-on work begins. You will build a repeatable hub-and-spoke network that demonstrates infrastructure as code, troubleshooting, validation, and cost-aware cleanup.
Set Up the Windows Automation Workstation
Console-only network changes are difficult to reproduce. An automation workstation gives every deployment the same starting point.
In this step, you will install Terraform CLI 1.16.5 to turn your network design into repeatable configuration.
The AWS CLI connects that workflow to your employer sandbox. Its identity check proves which account receives your future commands.
Visual Studio Code provides the editor for your configuration files. Windows PowerShell provides the command line for every check.
In this step, get ready to:
- Install Terraform CLI 1.16.5 on the Windows PATH.
- Prepare AWS CLI version 2 for authenticated sandbox access.
- Install Visual Studio Code with command-line access.
Install Terraform CLI 1.16.5
The Windows PATH lists the folders that PowerShell searches for executable files. Adding the Terraform folder lets you run terraform.exe from any location.
- Press the Windows key to open search.
- Type PowerShell into the search box.
- Press Enter to open Windows PowerShell.
- Check your current Terraform state by running this command:
terraform -version
What does this command check?
- The command asks PowerShell to find Terraform through the Windows PATH.
- The result tells you whether the required release is ready or needs installation.
✔️ I see version 1.16.5
Your Terraform installation already matches the project. That is one part of your automation toolchain ready.
ⓧ I see an older version
An older Terraform executable is taking precedence on your PATH. Replacing that executable gives the project its required release.
- Open the official Terraform install page in your browser.
- Choose the AMD64 Windows download if your computer uses an x64 processor.
- Choose the ARM64 Windows download if your computer uses an Arm-based processor.
- Download Terraform 1.16.5.
- Extract the downloaded archive.
- Replace the existing terraform.exe in its current PATH folder.
Why replace the existing executable?
Windows uses the first matching executable it finds on the PATH. Replacing the current file prevents PowerShell from continuing to launch the older release.
- Close the current PowerShell window.
- Press the Windows key to open search.
- Type PowerShell into the search box.
- Press Enter to open a fresh PowerShell window.
- Confirm the replacement by running this command:
terraform -version
What should this confirm?
Terraform should now report version 1.16.5. The fresh PowerShell window reads the latest PATH state.
Still seeing the older version?
Another folder may contain an older copy of terraform.exe. Remove that older copy from the search order or replace it with the required release.
Help me find why Windows PowerShell still launches an older Terraform version.
ⓧ Command not found
Terraform needs a dedicated folder that Windows can search. You will add that folder to your user PATH.
- Open the official Terraform install page in your browser.
- Choose the AMD64 Windows download if your computer uses an x64 processor.
- Choose the ARM64 Windows download if your computer uses an Arm-based processor.
- Download Terraform 1.16.5.
- Extract the archive into a new C:\Terraform folder.
Windows hides the user PATH editor behind several dialogs. The next clicks add the folder without changing the existing entries.
- Press the Windows key to open search.
- Type Environment Variables into the search box.
- Select Edit the system environment variables from the results.
The System Properties window now gives you access to the user-level search path.
- Click Environment Variables.
- Select Path under the user variables for your account.
- Click Edit.
- Click New.
- Enter C:\Terraform.
- Confirm the new entry with OK.
The Terraform folder is now part of your user PATH.
- Close the current PowerShell window.
- Press the Windows key to open search.
- Type PowerShell into the search box.
- Press Enter to open a fresh PowerShell window.
- Confirm the installation by running this command:
terraform -version
What should this confirm?
Terraform should report version 1.16.5. This proves that PowerShell can find the executable through your user PATH.
Terraform still not found?
Confirm that terraform.exe sits directly inside C:\Terraform. Confirm that your user Path contains the folder path instead of the executable path.
Help me diagnose why Terraform is not available from a fresh Windows PowerShell window.
Install and authenticate AWS CLI version 2
The AWS CLI gives your terminal an authenticated route into the employer sandbox. The identity check keeps future infrastructure changes tied to the intended account.
- Check your current AWS CLI state by running this command:
aws --version
What does this command check?
- The command asks PowerShell to find the AWS CLI installation.
- The result identifies the installed major version when the command is available.
✔️ I see version 2
Your AWS CLI already has the required major version. The local command is ready for sandbox authentication.
ⓧ I see an older version
- Install AWS CLI version 2 for your current Windows user by running this command:
irm https://awscli.amazonaws.com/v2/install.ps1 | iex
What does this command do?
PowerShell downloads the official AWS CLI installer script. The script installs version 2 for the current Windows user.
- Close the current PowerShell window.
- Press the Windows key to open search.
- Type PowerShell into the search box.
- Press Enter to open a fresh PowerShell window.
- Confirm the updated installation by running this command:
aws --version
What should this confirm?
The AWS CLI output should identify major version 2.
AWS CLI update failed?
A company network policy may block the installer download. Your employer may also require software installation through a managed catalog.
Help me diagnose an AWS CLI version 2 installation failure on my employer-managed Windows computer.
ⓧ Command not found
- Install AWS CLI version 2 for your current Windows user by running this command:
irm https://awscli.amazonaws.com/v2/install.ps1 | iex
What does this command do?
PowerShell downloads the official AWS CLI installer script. The script installs version 2 for the current Windows user.
- Close the current PowerShell window.
- Press the Windows key to open search.
- Type PowerShell into the search box.
- Press Enter to open a fresh PowerShell window.
- Confirm the installation by running this command:
aws --version
What should this confirm?
The AWS CLI output should identify major version 2. The fresh PowerShell window can now find the command.
AWS CLI still not found?
Close every PowerShell window after installation. A terminal that stayed open keeps its old PATH state.
Help me diagnose why AWS CLI version 2 is not available in a fresh Windows PowerShell window.
Authentication is the sensitive part of this setup. Your employer-approved sign-in flow keeps credentials outside the project files.
Sandbox authentication differs between employers. Choose the path that matches the method your employer provides.
IAM Identity Center
AWS IAM Identity Center uses a browser sign-in to connect the CLI to an approved account. The configuration wizard asks for values supplied by your employer.
- Start the IAM Identity Center configuration wizard by running this command:
aws configure sso
What happens during configuration?
The AWS CLI collects your employer-provided sandbox settings. It opens a browser so you can complete the approved sign-in flow.
- Enter the sandbox details supplied by your employer.
- Complete the browser sign-in with your employer account.
- Return to PowerShell after the browser confirms access.
- Verify the selected sandbox identity by running this command:
aws sts get-caller-identity
What should this prove?
AWS should return identity details for the selected employer sandbox. This proves that the CLI has authenticated access without exposing a credential.
Identity check failed?
Repeat the employer sign-in flow if the browser session expired. Confirm that you selected the intended sandbox account during configuration.
Help me diagnose why AWS CLI cannot return my employer sandbox identity after IAM Identity Center configuration.
Another employer-approved method
Some sandboxes use a managed terminal session or another company authentication process. Follow the method supplied by your employer before testing the identity.
- Complete the employer-approved sandbox authentication process.
- Verify the selected sandbox identity by running this command:
aws sts get-caller-identity
What should this prove?
AWS should return identity details for the selected employer sandbox. The result confirms that future commands target an authenticated account.
Sandbox identity unavailable?
Confirm that your employer authentication session is active. Ask the sandbox administrator which approved sign-in method applies to your account.
Help me identify why AWS CLI cannot return my employer sandbox identity.
Install Visual Studio Code and verify the workstation
The Visual Studio Code User setup adds the editor command to your Windows PATH. A fresh PowerShell window proves that every tool is available from one command line.
The first check opens the current PowerShell folder when Visual Studio Code is already installed. Match the result to the appropriate tab.
- Check whether the editor command is ready by running this command:
code .
What does this command check?
The command asks Windows to launch Visual Studio Code. The dot tells the editor to open the current PowerShell folder.
✔️ Visual Studio Code opens
Visual Studio Code is already installed with command-line access. Close the editor before completing the final verification.
ⓧ Command not found
- Open the official Visual Studio Code Windows setup guide in your browser.
- Download the User setup installer for Windows.
- Run the downloaded installer.
- Accept the installer defaults.
- Complete the installation.
- Close the current PowerShell window.
- Press the Windows key to open search.
- Type PowerShell into the search box.
The User setup adds Visual Studio Code to the PATH for new terminal sessions.
- Press Enter to open a fresh PowerShell window.
Visual Studio Code installation blocked?
An employer-managed computer may restrict downloaded installers. Use the company software catalog if Visual Studio Code is available there.
Help me install the Visual Studio Code User setup on an employer-managed Windows computer.
The final command opens the current folder in Visual Studio Code. The other commands leave their verification results visible in PowerShell.
Before you run the final check, which tool do you expect PowerShell to verify first?
- Verify the complete automation workstation by running these commands in the fresh PowerShell window:
terraform -version
aws --version
aws sts get-caller-identity
code .
What should you see?
- Terraform reports version 1.16.5.
- The AWS CLI output identifies major version 2.
- AWS returns the selected employer sandbox identity.
- Visual Studio Code opens the current PowerShell folder.
One of the final checks failed?
A failed version command usually means the current PowerShell window has an older PATH state. Close every terminal window before opening a new one.
Help me diagnose which part of my Windows automation workstation verification is failing.
Your Windows workstation can now edit infrastructure code and authenticate to the sandbox. Next up, you will deploy an intentionally incomplete hub-and-spoke network.
Deploy the Incomplete Hub-and-Spoke Network
Your Windows automation workstation is ready. Now you need a real network that can be reproduced from code instead of a diagram that only describes the design.
In this step, you will use Terraform to deploy two private VPCs around an AWS Transit Gateway. The first deployment deliberately omits the inter-spoke routes so you can test the incomplete design in the next step.
In this step, get ready to:
- Create the local Terraform project files.
- Initialize and validate the Terraform configuration.
- Deploy the incomplete network and capture its output identifiers.
Create and initialize the project
The aws-tgw-lab folder keeps the configuration in one predictable location. Visual Studio Code then opens that folder as your workspace.
- Return to the fresh PowerShell window from the previous step.
- Create the aws-tgw-lab folder on your Desktop by running these commands:
New-Item -Path "$HOME\Desktop\aws-tgw-lab" -ItemType Directory
Set-Location -Path "$HOME\Desktop\aws-tgw-lab"
code .
What do these commands do?
- The first command creates the aws-tgw-lab folder on your Desktop.
- The second command moves PowerShell into that folder.
- The final command opens the current folder in Visual Studio Code.
- Confirm that Visual Studio Code opens with aws-tgw-lab shown as the workspace folder.
Folder or editor did not open?
Check that the PowerShell path ends with aws-tgw-lab. If the editor command fails, restart PowerShell so the Visual Studio Code entry on your Windows PATH refreshes.
Ask for help with the exact output you see: Help me troubleshoot why my aws-tgw-lab folder or Visual Studio Code workspace did not open from PowerShell.
This project separates provider settings from network resources and outputs. That structure makes each part easier to review before Terraform creates anything.
- Return to the PowerShell window from earlier.
- Create the three configuration files by running this command:
New-Item -Path terraform.tf, main.tf, outputs.tf -ItemType File
What does this command do?
The command creates terraform.tf, main.tf, and outputs.tf inside aws-tgw-lab.
- Return to the Explorer sidebar in Visual Studio Code.
- Confirm that terraform.tf, main.tf, and outputs.tf are listed.
- Confirm that routes.tf is absent.
Files missing from the Explorer?
Confirm that PowerShell was inside aws-tgw-lab when you created the files. Refresh the Explorer sidebar if the files exist on disk but are not listed.
Ask for help locating the files: Help me find the Terraform files I created from PowerShell.
The first configuration pins the tool versions and the deployment region. Exact pins keep future runs tied to Terraform 1.16.5 and AWS Provider 6.67.0.
- Select terraform.tf in the Explorer sidebar.
- Add the provider configuration by copying this code into the file:
terraform {
required_version = "= 1.16.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "= 6.67.0"
}
}
}
provider "aws" {
region = "us-east-2"
}
What does this configuration do?
- The Terraform constraint requires CLI version 1.16.5.
- The provider block selects hashicorp/aws version 6.67.0.
- The AWS provider targets us-east-2, which is US East (Ohio).
- Save terraform.tf.
- Confirm that the file tab no longer shows an unsaved-change indicator.
Provider configuration looks different?
Check every quote and closing brace against the code block. Confirm that the region is us-east-2.
Ask for a configuration comparison: Help me compare my terraform.tf file with the required provider configuration.
Terraform must download the pinned AWS provider before it can understand the AWS resource blocks. Initialization also prepares this folder for validation and deployment.
- Return to PowerShell.
- Initialize the aws-tgw-lab configuration by running:
terraform init
What does this command do?
Terraform initializes the folder and downloads the provider selected in terraform.tf. This prepares the configuration for local validation.
The provider download can keep the terminal busy on its first run. When initialization completes, Terraform reports that the working directory is ready.
Initialization failed?
Confirm that PowerShell is inside the Desktop aws-tgw-lab folder. A provider download failure can also point to an employer network restriction.
Ask for help with the initialization output: Help me troubleshoot my terraform init failure.
Define the incomplete network
The network starts with two private address spaces. Each spoke receives one subnet that can attach to the central Transit Gateway.
- Select main.tf in the Explorer sidebar.
- Add the two VPC resources by copying this code into the file:
resource "aws_vpc" "spoke_a" {
cidr_block = "10.10.0.0/16"
tags = {
Name = "tgw-lab-spoke-a"
}
}
resource "aws_vpc" "spoke_b" {
cidr_block = "10.20.0.0/16"
tags = {
Name = "tgw-lab-spoke-b"
}
}
What do these resources do?
- Spoke A uses the private address range 10.10.0.0/16.
- Spoke B uses the separate private address range 10.20.0.0/16.
- The tags give both VPCs recognizable names in AWS.
- Save main.tf.
- Confirm that both aws_vpc blocks remain visible in the file.
VPC blocks showing errors?
Check that each VPC block has one opening brace and one matching closing brace. Confirm that the CIDR ranges match the code block exactly.
Ask for help with the VPC definitions: Help me find the syntax problem in my two aws_vpc blocks.
- Place the subnet resources below the VPC resources in main.tf by copying this code:
resource "aws_subnet" "spoke_a" {
vpc_id = aws_vpc.spoke_a.id
cidr_block = "10.10.1.0/24"
tags = {
Name = "tgw-lab-spoke-a-subnet"
}
}
resource "aws_subnet" "spoke_b" {
vpc_id = aws_vpc.spoke_b.id
cidr_block = "10.20.1.0/24"
tags = {
Name = "tgw-lab-spoke-b-subnet"
}
}
How do the subnets fit in?
- Each subnet references the ID of its matching VPC.
- Spoke A uses 10.10.1.0/24.
- Spoke B uses 10.20.1.0/24.
- Save main.tf.
- Validate the VPC and subnet definitions by running this command in PowerShell:
terraform validate
What does validation check?
Terraform checks the configuration syntax and internal references. A valid result confirms that both subnet references resolve to declared VPC resources.
Terraform reports that the configuration is valid. You have now completed the first checkable slice of the network.
Validation reports a problem?
Use the filename and line number in the validation output to locate the issue. Check the resource names against aws_vpc.spoke_a.id and aws_vpc.spoke_b.id.
Ask for help reading the validation result: Help me understand my Terraform validation error after adding the VPCs and subnets.
Each spoke also needs a route table associated with its subnet. These route tables intentionally contain no inter-spoke route resources.
- Place the route table resources below the subnet resources in main.tf by copying this code:
resource "aws_route_table" "spoke_a" {
vpc_id = aws_vpc.spoke_a.id
tags = {
Name = "tgw-lab-spoke-a-rt"
}
}
resource "aws_route_table" "spoke_b" {
vpc_id = aws_vpc.spoke_b.id
tags = {
Name = "tgw-lab-spoke-b-rt"
}
}
resource "aws_route_table_association" "spoke_a" {
subnet_id = aws_subnet.spoke_a.id
route_table_id = aws_route_table.spoke_a.id
}
resource "aws_route_table_association" "spoke_b" {
subnet_id = aws_subnet.spoke_b.id
route_table_id = aws_route_table.spoke_b.id
}
What do these resources do?
- Each route table belongs to its matching VPC.
- Each association assigns the matching route table to one private subnet.
- The absence of an inter-spoke route preserves the intended gap for later analysis.
- Save main.tf.
- Confirm that the file contains two route tables and two subnet associations.
Route table references showing errors?
Check that each association references the subnet and route table from the same spoke. A swapped resource name can connect the wrong pair.
Ask for help checking the references: Help me verify my route table and subnet association references.
The central hub accepts an attachment from each spoke. Default association and propagation let the Transit Gateway route table learn the attached VPC networks.
- Place the hub and Spoke A attachment below the route table associations in main.tf by copying this code:
resource "aws_ec2_transit_gateway" "hub" {
description = "Hub for the Terraform network validation lab"
default_route_table_association = "enable"
default_route_table_propagation = "enable"
tags = {
Name = "tgw-lab-hub"
}
}
resource "aws_ec2_transit_gateway_vpc_attachment" "spoke_a" {
subnet_ids = [aws_subnet.spoke_a.id]
transit_gateway_id = aws_ec2_transit_gateway.hub.id
vpc_id = aws_vpc.spoke_a.id
transit_gateway_default_route_table_association = true
transit_gateway_default_route_table_propagation = true
tags = {
Name = "tgw-lab-spoke-a-attachment"
}
}
How does the hub connect Spoke A?
- The Transit Gateway provides the central hub.
- Default association places the attachment in the default Transit Gateway route table.
- Default propagation advertises the Spoke A VPC route through that table.
- Save main.tf.
- Confirm that the Spoke A attachment references the Spoke A subnet and VPC.
Hub attachment references look wrong?
Check that the attachment references aws_subnet.spoke_a.id and aws_vpc.spoke_a.id. Confirm that both default Transit Gateway settings use true.
Ask for help checking the hub attachment: Help me verify my Transit Gateway and Spoke A attachment configuration.
- Place the Spoke B attachment below the Spoke A attachment in main.tf by copying this code:
resource "aws_ec2_transit_gateway_vpc_attachment" "spoke_b" {
subnet_ids = [aws_subnet.spoke_b.id]
transit_gateway_id = aws_ec2_transit_gateway.hub.id
vpc_id = aws_vpc.spoke_b.id
transit_gateway_default_route_table_association = true
transit_gateway_default_route_table_propagation = true
tags = {
Name = "tgw-lab-spoke-b-attachment"
}
}
How does Spoke B join the hub?
The second attachment connects the Spoke B subnet and VPC to the same Transit Gateway. Its propagation setting advertises the Spoke B network through the Transit Gateway route table.
- Save main.tf.
- Validate the route tables and hub attachments by running this command in PowerShell:
terraform validate
What does this check prove?
A valid result confirms that both attachments reference declared subnets, VPCs, and the central Transit Gateway. It also confirms that the route table associations are internally consistent.
Terraform reports that the configuration is valid. The hub now has two complete attachment definitions in code.
Attachment validation failed?
Compare the spoke suffix on every subnet and VPC reference. Check that both attachment blocks reference aws_ec2_transit_gateway.hub.id.
Ask for help with the failing reference: Help me diagnose my Terraform validation error for the Transit Gateway attachments.
Reachability Analyzer needs endpoints with scoped traffic rules. The security groups permit TCP port 443 only between the two spoke address ranges.
- Place the two security groups below the Transit Gateway attachments in main.tf by copying this code:
resource "aws_security_group" "spoke_a" {
name_prefix = "tgw-lab-spoke-a-"
description = "Allow the scoped Reachability Analyzer path"
vpc_id = aws_vpc.spoke_a.id
tags = {
Name = "tgw-lab-spoke-a-sg"
}
}
resource "aws_security_group" "spoke_b" {
name_prefix = "tgw-lab-spoke-b-"
description = "Allow the scoped Reachability Analyzer path"
vpc_id = aws_vpc.spoke_b.id
tags = {
Name = "tgw-lab-spoke-b-sg"
}
}
Why use one security group per spoke?
Each security group belongs to its spoke VPC. Separate groups let the configuration express each direction of the scoped test traffic.
- Save main.tf.
- Confirm that each security group references its matching VPC.
Security group blocks showing errors?
Check the vpc_id value in each block. Spoke A must reference Spoke A while Spoke B must reference Spoke B.
Ask for help comparing the blocks: Help me check my two Terraform security group resources.
- Place the ingress rules below the security groups in main.tf by copying this code:
resource "aws_vpc_security_group_ingress_rule" "spoke_a_from_b" {
security_group_id = aws_security_group.spoke_a.id
cidr_ipv4 = aws_vpc.spoke_b.cidr_block
from_port = 443
ip_protocol = "tcp"
to_port = 443
}
resource "aws_vpc_security_group_ingress_rule" "spoke_b_from_a" {
security_group_id = aws_security_group.spoke_b.id
cidr_ipv4 = aws_vpc.spoke_a.cidr_block
from_port = 443
ip_protocol = "tcp"
to_port = 443
}
What do the ingress rules allow?
- Spoke A accepts TCP port 443 from the Spoke B address range.
- Spoke B accepts TCP port 443 from the Spoke A address range.
- Save main.tf.
- Confirm that each ingress rule uses the opposite VPC CIDR as its source.
Ingress directions seem reversed?
Read each resource name as destination from source. The spoke_a_from_b rule belongs to Spoke A and references the Spoke B CIDR.
Ask for help tracing the direction: Help me verify the source and destination logic in my ingress rules.
- Place the egress rules below the ingress rules in main.tf by copying this code:
resource "aws_vpc_security_group_egress_rule" "spoke_a_to_b" {
security_group_id = aws_security_group.spoke_a.id
cidr_ipv4 = aws_vpc.spoke_b.cidr_block
from_port = 443
ip_protocol = "tcp"
to_port = 443
}
resource "aws_vpc_security_group_egress_rule" "spoke_b_to_a" {
security_group_id = aws_security_group.spoke_b.id
cidr_ipv4 = aws_vpc.spoke_a.cidr_block
from_port = 443
ip_protocol = "tcp"
to_port = 443
}
What do the egress rules allow?
- Spoke A can send TCP port 443 traffic toward the Spoke B address range.
- Spoke B can send TCP port 443 traffic toward the Spoke A address range.
- Save main.tf.
- Validate the security group definitions by running this command in PowerShell:
terraform validate
What does this check prove?
A valid result confirms that every security group rule references an existing group and VPC. It also confirms that the port and protocol arguments are structurally valid.
Terraform reports that the configuration is valid. The analysis traffic now has symmetric security group permissions.
Security rule validation failed?
Check the resource type on each block. Ingress blocks use aws_vpc_security_group_ingress_rule while egress blocks use aws_vpc_security_group_egress_rule.
Ask for help with the exact rule error: Help me diagnose my Terraform security group rule validation error.
Two unattached network interfaces provide stable endpoints for configuration analysis. Their private IP addresses sit inside the spoke subnets.
- Place the network interfaces below the security group rules in main.tf by copying this code:
resource "aws_network_interface" "spoke_a" {
subnet_id = aws_subnet.spoke_a.id
private_ips = ["10.10.1.10"]
security_groups = [aws_security_group.spoke_a.id]
tags = {
Name = "tgw-lab-spoke-a-eni"
}
}
resource "aws_network_interface" "spoke_b" {
subnet_id = aws_subnet.spoke_b.id
private_ips = ["10.20.1.10"]
security_groups = [aws_security_group.spoke_b.id]
tags = {
Name = "tgw-lab-spoke-b-eni"
}
}
Why create network interfaces?
Each network interface gives Reachability Analyzer a source or destination inside a spoke. This avoids creating compute instances solely for network validation.
- Save main.tf.
- Confirm that each interface references the subnet and security group from the same spoke.
Network interface references showing errors?
Check that 10.10.1.10 belongs to the Spoke A subnet. Check that 10.20.1.10 belongs to the Spoke B subnet.
Ask for help checking the endpoint definitions: Help me verify my two Terraform network interface resources.
Terraform outputs expose the deployed identifiers you need for later analysis. Descriptive output names keep you from searching through the AWS console for each resource.
- Select outputs.tf in the Explorer sidebar.
- Add the three output definitions by copying this code into the file:
output "transit_gateway_id" {
description = "ID of the central Transit Gateway"
value = aws_ec2_transit_gateway.hub.id
}
output "spoke_a_network_interface_id" {
description = "Source network interface for the A-to-B analysis"
value = aws_network_interface.spoke_a.id
}
output "spoke_b_network_interface_id" {
description = "Destination network interface for the A-to-B analysis"
value = aws_network_interface.spoke_b.id
}
What do these outputs expose?
- The transit_gateway_id output identifies the central hub.
- The spoke_a_network_interface_id output identifies the forward-path source.
- The spoke_b_network_interface_id output identifies the forward-path destination.
- Save outputs.tf.
- Format all three Terraform files by running this command in PowerShell:
terraform fmt
What does formatting do?
Terraform rewrites configuration files into its recommended layout. Consistent spacing makes the planned infrastructure easier to review.
- Run the final configuration validation with this command:
terraform validate
What does the final validation prove?
Terraform checks all three files as one configuration. A valid result confirms that the outputs resolve to resources declared in main.tf.
Terraform reports that the configuration is valid. Your complete incomplete-network definition is ready to deploy.
Formatting or validation failed?
Confirm that all three files are saved. Follow the filename and line number in the validation output to find a missing brace or mistyped resource reference.
Ask for help with the final check: Help me fix my final Terraform formatting or validation problem.
✔️ Awesome, I've got everything!
Great. Confirm that terraform.tf, main.tf, and outputs.tf are saved before you deploy.
ⓧ I'd like to double check the full code
terraform {
required_version = "= 1.16.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "= 6.67.0"
}
}
}
provider "aws" {
region = "us-east-2"
}
resource "aws_vpc" "spoke_a" {
cidr_block = "10.10.0.0/16"
tags = {
Name = "tgw-lab-spoke-a"
}
}
resource "aws_vpc" "spoke_b" {
cidr_block = "10.20.0.0/16"
tags = {
Name = "tgw-lab-spoke-b"
}
}
resource "aws_subnet" "spoke_a" {
vpc_id = aws_vpc.spoke_a.id
cidr_block = "10.10.1.0/24"
tags = {
Name = "tgw-lab-spoke-a-subnet"
}
}
resource "aws_subnet" "spoke_b" {
vpc_id = aws_vpc.spoke_b.id
cidr_block = "10.20.1.0/24"
tags = {
Name = "tgw-lab-spoke-b-subnet"
}
}
resource "aws_route_table" "spoke_a" {
vpc_id = aws_vpc.spoke_a.id
tags = {
Name = "tgw-lab-spoke-a-rt"
}
}
resource "aws_route_table" "spoke_b" {
vpc_id = aws_vpc.spoke_b.id
tags = {
Name = "tgw-lab-spoke-b-rt"
}
}
resource "aws_route_table_association" "spoke_a" {
subnet_id = aws_subnet.spoke_a.id
route_table_id = aws_route_table.spoke_a.id
}
resource "aws_route_table_association" "spoke_b" {
subnet_id = aws_subnet.spoke_b.id
route_table_id = aws_route_table.spoke_b.id
}
resource "aws_ec2_transit_gateway" "hub" {
description = "Hub for the Terraform network validation lab"
default_route_table_association = "enable"
default_route_table_propagation = "enable"
tags = {
Name = "tgw-lab-hub"
}
}
resource "aws_ec2_transit_gateway_vpc_attachment" "spoke_a" {
subnet_ids = [aws_subnet.spoke_a.id]
transit_gateway_id = aws_ec2_transit_gateway.hub.id
vpc_id = aws_vpc.spoke_a.id
transit_gateway_default_route_table_association = true
transit_gateway_default_route_table_propagation = true
tags = {
Name = "tgw-lab-spoke-a-attachment"
}
}
resource "aws_ec2_transit_gateway_vpc_attachment" "spoke_b" {
subnet_ids = [aws_subnet.spoke_b.id]
transit_gateway_id = aws_ec2_transit_gateway.hub.id
vpc_id = aws_vpc.spoke_b.id
transit_gateway_default_route_table_association = true
transit_gateway_default_route_table_propagation = true
tags = {
Name = "tgw-lab-spoke-b-attachment"
}
}
resource "aws_security_group" "spoke_a" {
name_prefix = "tgw-lab-spoke-a-"
description = "Allow the scoped Reachability Analyzer path"
vpc_id = aws_vpc.spoke_a.id
tags = {
Name = "tgw-lab-spoke-a-sg"
}
}
resource "aws_security_group" "spoke_b" {
name_prefix = "tgw-lab-spoke-b-"
description = "Allow the scoped Reachability Analyzer path"
vpc_id = aws_vpc.spoke_b.id
tags = {
Name = "tgw-lab-spoke-b-sg"
}
}
resource "aws_vpc_security_group_ingress_rule" "spoke_a_from_b" {
security_group_id = aws_security_group.spoke_a.id
cidr_ipv4 = aws_vpc.spoke_b.cidr_block
from_port = 443
ip_protocol = "tcp"
to_port = 443
}
resource "aws_vpc_security_group_ingress_rule" "spoke_b_from_a" {
security_group_id = aws_security_group.spoke_b.id
cidr_ipv4 = aws_vpc.spoke_a.cidr_block
from_port = 443
ip_protocol = "tcp"
to_port = 443
}
resource "aws_vpc_security_group_egress_rule" "spoke_a_to_b" {
security_group_id = aws_security_group.spoke_a.id
cidr_ipv4 = aws_vpc.spoke_b.cidr_block
from_port = 443
ip_protocol = "tcp"
to_port = 443
}
resource "aws_vpc_security_group_egress_rule" "spoke_b_to_a" {
security_group_id = aws_security_group.spoke_b.id
cidr_ipv4 = aws_vpc.spoke_a.cidr_block
from_port = 443
ip_protocol = "tcp"
to_port = 443
}
resource "aws_network_interface" "spoke_a" {
subnet_id = aws_subnet.spoke_a.id
private_ips = ["10.10.1.10"]
security_groups = [aws_security_group.spoke_a.id]
tags = {
Name = "tgw-lab-spoke-a-eni"
}
}
resource "aws_network_interface" "spoke_b" {
subnet_id = aws_subnet.spoke_b.id
private_ips = ["10.20.1.10"]
security_groups = [aws_security_group.spoke_b.id]
tags = {
Name = "tgw-lab-spoke-b-eni"
}
}
output "transit_gateway_id" {
description = "ID of the central Transit Gateway"
value = aws_ec2_transit_gateway.hub.id
}
output "spoke_a_network_interface_id" {
description = "Source network interface for the A-to-B analysis"
value = aws_network_interface.spoke_a.id
}
output "spoke_b_network_interface_id" {
description = "Destination network interface for the A-to-B analysis"
value = aws_network_interface.spoke_b.id
}
Apply the network and capture its outputs
A Terraform apply turns the configuration into AWS resources. The plan gives you one final chance to confirm that the change matches the intended incomplete design.
Paid resources start here
This apply creates two paid Transit Gateway attachments. The US East (Ohio) example rate is $0.05 per VPC attachment per hour.
Each partial attachment-hour is billed as a full hour. The cleanup section removes these resources when you finish.
Before you run the apply, which types of network resources do you expect Terraform to add from the configuration you just validated?
- Create the execution plan by running this command:
terraform apply
What happens during apply?
Terraform compares the configuration with the empty AWS environment. It presents the proposed resource additions before making any change.
- Review the plan for the two VPCs and their supporting resources.
- Confirm that the plan includes one Transit Gateway.
- Confirm that the plan includes two Transit Gateway VPC attachments.
- Confirm that the plan does not include a routes.tf file or inter-spoke VPC routes.
- Enter yes when the confirmation prompt appears.
AWS creates the resources while PowerShell remains attached to the apply. Keep the terminal open until Terraform reports that the apply completed.
Apply failed or permission was denied?
Confirm that the AWS CLI still uses the intended employer sandbox identity. A denial for Transit Gateway or networking resources means the sandbox role needs the corresponding permissions.
Ask for help without sharing credentials: Help me diagnose my Terraform apply failure in an AWS employer sandbox.
The apply completes with the AWS resources under Terraform management. That is the deployment milestone: your two spokes now attach to one central hub.
Before you inspect the outputs, which three identifiers do you expect Terraform to display from outputs.tf?
- Display the deployed identifiers by running this command:
terraform output
What should the outputs represent?
- One value identifies the central Transit Gateway.
- One value identifies the Spoke A network interface.
- One value identifies the Spoke B network interface.
PowerShell displays transit_gateway_id, spoke_a_network_interface_id, and spoke_b_network_interface_id with their deployed AWS resource IDs.
- Record the Transit Gateway output as your Transit Gateway ID.
- Record the Spoke A output as your Spoke A network interface ID.
- Record the Spoke B output as your Spoke B network interface ID.
Outputs missing or empty?
Confirm that the apply completed successfully. Check that outputs.tf is saved and that PowerShell is still inside aws-tgw-lab.
Ask for help with the output state: Help me troubleshoot missing Terraform outputs after apply.
Your repeatable hub-and-spoke network is deployed with the intended routing gap intact. Next, you will use Reachability Analyzer to prove what a successful infrastructure deployment still cannot guarantee.
Prove the Missing Route
Your hub-and-spoke network is deployed. However, a successful resource deployment only proves that AWS accepted the configuration.
Amazon VPC Reachability Analyzer can test the configuration between your two spokes without sending packets. This gives you evidence of the current path before you change the network design.
In this step, get ready to:
- Retrieve both network interface IDs from the existing Terraform outputs.
- Create a Reachability Analyzer path for TCP port 443.
- Inspect the completed analysis to identify the blocking configuration.
Collect the path endpoints
A Reachability Analyzer path needs a source endpoint. It also needs a destination endpoint.
The existing outputs expose stable IDs for both network interfaces. You will use those IDs to define the exact path under test.
- Switch back to the Windows PowerShell terminal in Visual Studio Code.
- Locate spoke_a_network_interface_id in the existing Terraform output.
- Record its value here: your Spoke A network interface ID.
- Locate spoke_b_network_interface_id in the existing Terraform output.
- Record its value here: your Spoke B network interface ID.
Outputs no longer visible?
- Use your PowerShell history to rerun the output command from the previous step.
- Confirm that the terminal is still inside the aws-tgw-lab folder.
Help me find the Terraform network interface outputs.
Create the A-to-B analysis
Reachability Analyzer builds a model from your network configuration. It checks whether the selected source has a valid path to the selected destination.
Creating the analysis costs $0.10. You only need one run in this step.
- Open the AWS Network Manager console in your browser.
- Complete your employer-approved sandbox sign-in if prompted.
- Choose Reachability Analyzer in the console navigation.
- Choose Create and analyze path.
- Set the path source to your Spoke A network interface ID.
- Set the path destination to your Spoke B network interface ID.
- Select TCP as the protocol.
- Enter 443 as the port.
Before you create the analysis, predict whether the current path can reach Spoke B.
- Start the analysis by choosing Create and analyze path.
- Wait for the analysis to complete.
You will see Not reachable for the A-to-B path. That visible shortfall is the intended baseline.
You now have the evidence: the deployed resources exist while the tested network path still fails.
Analysis does not complete?
- Confirm that the source matches your Spoke A network interface ID.
- Confirm that the destination matches your Spoke B network interface ID.
- Ask your sandbox administrator for permission to create Reachability Analyzer paths if the console blocks the action.
Help me troubleshoot an incomplete Reachability Analyzer analysis.
Inspect the blocking configuration
The path status tells you whether connectivity exists. The analysis explanation identifies the configuration responsible for the result.
Before you inspect the evidence, predict whether routing or security will be named as the blocker.
- Open the completed path by choosing its Path ID.
- Inspect Reachability status.
- Inspect Explanations.
- Review the blocking component under Details.
The completed analysis shows Not reachable under Reachability status. Explanations identifies the route configuration as the blocking component.
The scoped security group rules already allow TCP port 443. The evidence isolates the missing spoke route as the cause.
Why does the path stop?
AWS Transit Gateway learns the attached VPC routes through propagation. The Spoke A VPC route table still needs a route for 10.20.0.0/16 that points traffic toward the hub.
The source subnet has no configured next hop for Spoke B. Reachability Analyzer exposes that break before any packets are sent.
Seeing a different blocker?
- Compare the path source with your Spoke A network interface ID.
- Compare the path destination with your Spoke B network interface ID.
- Confirm that the path scope uses TCP port 443.
Help me understand why my analysis identifies a different blocker.
Your Terraform files remain unchanged. Next, you will add symmetric routes to test how the analysis responds.
Add Symmetric Routes and Validate Connectivity
Your earlier Amazon VPC Reachability Analyzer analysis proved that the deployed network exists. It also exposed the missing spoke route that blocks traffic.
Attachments on an AWS Transit Gateway do not give each VPC route table a destination for the other spoke. Each spoke needs an explicit route through the hub.
In this step, you will use Terraform to add both route directions. You will then validate each direction separately.
In this step, get ready to:
- Define symmetric routes between the two VPC spokes.
- Apply the route change through Terraform.
- Validate connectivity separately in both traffic directions.
Add the symmetric route resources
Symmetric routing gives each spoke a path toward the other spoke. Both routes use the Transit Gateway as their next hop.
- In Visual Studio Code, create routes.tf inside the aws-tgw-lab folder using the file creation control in the file sidebar.
- Add the route from Spoke A to Spoke B by pasting this code into routes.tf:
resource "aws_route" "spoke_a_to_b" {
route_table_id = aws_route_table.spoke_a.id
destination_cidr_block = aws_vpc.spoke_b.cidr_block
transit_gateway_id = aws_ec2_transit_gateway.hub.id
depends_on = [
aws_ec2_transit_gateway_vpc_attachment.spoke_a,
aws_ec2_transit_gateway_vpc_attachment.spoke_b
]
}
What Does This Route Do?
- The route belongs to the Spoke A route table.
- The destination is the Spoke B VPC CIDR.
- The Transit Gateway acts as the next hop.
- The explicit dependency waits for both VPC attachments before creating the route.
- Save routes.tf.
- Confirm the first route is structurally valid by running this command in the PowerShell terminal from earlier:
terraform validate
What Does This Check?
The command checks the Terraform files for valid syntax. It also checks references between the route and your existing resources.
Terraform reports that the configuration is valid. This confirms that the first route can resolve the existing route table, VPC, Transit Gateway, and attachments.
Does the First Route Fail Validation?
Confirm that routes.tf sits inside aws-tgw-lab. Check each resource reference against the code above.
Ask for help with the exact validation output: Why does my first Terraform route fail validation?
- Add the reverse route from Spoke B to Spoke A below the first resource:
resource "aws_route" "spoke_b_to_a" {
route_table_id = aws_route_table.spoke_b.id
destination_cidr_block = aws_vpc.spoke_a.cidr_block
transit_gateway_id = aws_ec2_transit_gateway.hub.id
depends_on = [
aws_ec2_transit_gateway_vpc_attachment.spoke_a,
aws_ec2_transit_gateway_vpc_attachment.spoke_b
]
}
How Does the Reverse Route Work?
- The route belongs to the Spoke B route table.
- The destination is the Spoke A VPC CIDR.
- The Transit Gateway carries traffic toward Spoke A.
- The same attachment dependencies preserve a predictable creation order.
- Save routes.tf.
- Confirm that both route resources are structurally valid by running:
terraform validate
What Does the Second Check Prove?
Terraform now evaluates both route resources as one configuration. A successful result confirms that the two directions use valid existing references.
You will see Terraform report a valid configuration. Your file now expresses the complete symmetric routing intent.
Does Validation Fail After the Second Route?
Check that the second resource uses aws_route_table.spoke_b.id as its route table. Confirm that its destination uses aws_vpc.spoke_a.cidr_block.
Ask for help checking the reverse references: Why does my symmetric Terraform route configuration fail validation?
Use these tabs to confirm that routes.tf contains both complete route resources.
✔️ Awesome, I've got everything!
Your routes.tf file now defines the A-to-B route and the B-to-A route.
ⓧ I'd like to double check the full code
- Compare your complete routes.tf file with this reference:
resource "aws_route" "spoke_a_to_b" {
route_table_id = aws_route_table.spoke_a.id
destination_cidr_block = aws_vpc.spoke_b.cidr_block
transit_gateway_id = aws_ec2_transit_gateway.hub.id
depends_on = [
aws_ec2_transit_gateway_vpc_attachment.spoke_a,
aws_ec2_transit_gateway_vpc_attachment.spoke_b
]
}
resource "aws_route" "spoke_b_to_a" {
route_table_id = aws_route_table.spoke_b.id
destination_cidr_block = aws_vpc.spoke_a.cidr_block
transit_gateway_id = aws_ec2_transit_gateway.hub.id
depends_on = [
aws_ec2_transit_gateway_vpc_attachment.spoke_a,
aws_ec2_transit_gateway_vpc_attachment.spoke_b
]
}
Format and apply the route change
Terraform turns the new route definitions into a reviewed infrastructure change. Formatting keeps the file consistent before validation checks the complete configuration.
- Format the Terraform files by running:
terraform fmt
What Does Formatting Change?
Terraform reformats the configuration files to its recommended style. This keeps spacing consistent without changing the routing intent.
Terraform returns control to PowerShell after formatting the files. Your route definitions are ready for the final configuration check.
- Validate the formatted configuration by running:
terraform validate
What Does Final Validation Cover?
Terraform checks every configuration file inside aws-tgw-lab. The check now includes both route resources.
You will see Terraform report a valid configuration. This confirms that the new file fits the deployed network definition.
- Predict which Terraform resources the plan will add before running the next command.
- Prepare the symmetric route change by running:
terraform apply
What Does This Apply Do?
Terraform compares the new route resources with the existing state. It then presents an execution plan for approval.
The expected plan adds aws_route.spoke_a_to_b and aws_route.spoke_b_to_a.
- Review the plan for exactly two route additions.
- Enter yes when the plan retains the existing VPCs, Transit Gateway, and attachments.
That is the routing fix deployed. Both aws_route resources now exist in Terraform state.
Does the Apply Show Unexpected Changes?
Do not approve a plan that replaces the existing VPCs or Transit Gateway. Return to routes.tf and compare its references with the full-file check.
If the sandbox denies route creation, request permission to manage VPC routes. Help me understand why my Terraform route apply failed in an AWS sandbox.
Validate both traffic directions
Reachability Analyzer evaluates only forward traffic for a TCP path that traverses a Transit Gateway route table. A separate reverse path provides evidence that the routing design works in both directions.
- Switch back to the Reachability Analyzer page from earlier.
- Select the existing A-to-B path.
- Predict whether the previous route blocker remains after the Terraform apply.
- Choose Analyze path.
You will see Reachability status change to Reachable. The analysis displays the route through the Transit Gateway.
What Changed in the Forward Path?
The security group rules still permit the scoped TCP traffic on port 443. The new VPC route removes the configuration blocker identified by the earlier analysis.
Your original failed path now proves the effect of one controlled infrastructure change.
- Choose Create and analyze path.
- Set the source to the network interface named tgw-lab-spoke-b-eni.
- Set the destination to the network interface named tgw-lab-spoke-a-eni.
- Select TCP as the protocol.
- Enter 443 as the destination port.
- Predict whether the reverse direction will follow the Transit Gateway route successfully.
- Choose Create and analyze path.
You will see the B-to-A path report Reachable. Its shortest route passes through the Transit Gateway.
- Return to the Reachability Analyzer path list.
You will see Reachable results for both A-to-B and B-to-A. Your symmetric routing design now has evidence in each direction.
Does Either Path Remain Not Reachable?
Open Explanations for the failed analysis. Confirm whether the blocker points to routing or another network component.
Check that the source and destination network interfaces are reversed for the B-to-A path. Help me diagnose a Reachability Analyzer path that remains Not reachable after adding symmetric routes.
Secret mission
Turn Connectivity into an Isolation Control
Remove the two Terraform route resources while keeping the hub-and-spoke foundation deployed. Then reanalyze a saved path to prove that declarative routing policy can intentionally isolate the spokes.
Clean Up Your Resources
Clean Up Your Resources
Your two AWS Transit Gateway attachments keep accruing hourly charges while the lab remains deployed. Decide whether to keep the isolated network, remove only the cloud resources, or remove the cloud resources plus the local files.
Cost warning
Each VPC attachment costs $0.05 per hour in US East (Ohio). Two attachments therefore cost $0.10 per hour.
Each partial attachment hour is billed as a full hour. Each new Amazon VPC Reachability Analyzer analysis costs $0.10.
- Choose the Pause or Delete option below to stop the attachment charges.
Resources you used:
- Terraform-managed spoke resources: two VPCs, two private subnets, two route tables, and two route table associations.
- Terraform-managed traffic controls: two security groups, four TCP port 443 rules, and two network interfaces.
- Terraform-managed hub resources: one AWS Transit Gateway and two Transit Gateway VPC attachments.
- Reachability Analyzer resources: two saved paths and their analyses.
- Local files: the aws-tgw-lab folder containing terraform.tf, main.tf, outputs.tf, and the local Terraform state.
Keep everything running
No action needed. Choose this if you want to demonstrate the network's declarative isolation policy again.
- Retain the deployed AWS network for future analysis.
- Keep the aws-tgw-lab folder so Terraform can continue managing the same state.
- Budget for the continuing $0.10 hourly charge from the two Transit Gateway VPC attachments.
Pause - I'll come back to this later
This option removes every cloud resource that can continue charging. Your local Terraform configuration stays ready for another deployment.
- Return to Reachability Analyzer in the AWS Network Manager console from earlier.
- Select one saved path from the path list.
- Choose Actions.
- Choose Delete path.
- Confirm Delete path.
- Repeat the deletion for the remaining saved path.
Good. The path list no longer contains the two lab paths. Their analyses were deleted with them.
- In Visual Studio Code, start a PowerShell terminal for the open aws-tgw-lab folder.
- Begin deprovisioning the Terraform-managed AWS resources by running this command:
terraform destroy
What does this command remove?
- This operation deprovisions every object managed by the current Terraform configuration.
- The local .tf files remain in aws-tgw-lab.
- The local Terraform state also remains in the folder.
- Review the destruction plan.
- Confirm that the plan targets only resources from the aws-tgw-lab configuration.
- Enter yes to approve the destruction.
- Wait for Terraform to report that the operation completed successfully.
That closes the meter on this lab. The Transit Gateway attachments and remaining network stack are gone.
Terraform cannot finish the destroy?
- Confirm that both saved Reachability Analyzer paths were deleted before retrying.
- Reauthenticate with the employer-approved sandbox method if your AWS session has expired.
- Ask for help diagnosing the destroy failure.
Your cloud resources are removed. The reusable files remain in aws-tgw-lab for your next deployment.
Delete - I don't want to use this again
This option removes the cloud stack plus the local project folder. You finish with no lab resources left in AWS or on your computer.
- Return to Reachability Analyzer in the AWS Network Manager console from earlier.
- Select one saved path from the path list.
- Choose Actions.
- Choose Delete path.
- Confirm Delete path.
- Repeat the deletion for the remaining saved path.
The two lab paths disappear from the path list. Their saved analyses are removed at the same time.
- In Visual Studio Code, start a PowerShell terminal for the open aws-tgw-lab folder.
- Begin deprovisioning the Terraform-managed AWS resources by running this command:
terraform destroy
What does this command remove?
- This operation deprovisions every object managed by the current Terraform configuration.
- The local .tf files remain until you delete the folder.
- The local Terraform state also remains until you delete the folder.
- Review the destruction plan.
- Confirm that the plan targets only resources from the aws-tgw-lab configuration.
- Enter yes to approve the destruction.
- Wait for Terraform to report that the operation completed successfully.
The billable infrastructure is now cleared. Terraform has removed the Transit Gateway attachments and the remaining network stack.
Terraform cannot finish the destroy?
- Confirm that both saved Reachability Analyzer paths were deleted before retrying.
- Reauthenticate with the employer-approved sandbox method if your AWS session has expired.
- Ask for help diagnosing the destroy failure.
Save anything you need first
Deleting aws-tgw-lab permanently removes the reusable configuration and local Terraform state.
- Copy any configuration or notes you want to retain to another folder.
- Close Visual Studio Code.
- Use File Explorer to locate the aws-tgw-lab folder that was open in Visual Studio Code.
- Delete the aws-tgw-lab folder.
- Confirm that aws-tgw-lab no longer appears in File Explorer.
Everything from the lab is now cleared. No project cloud resources or local configuration files remain.
Nice Work!
Nice Work!
You did it! You built a two-spoke network around a central AWS Transit Gateway with Terraform.
You've learned how to:
- Built a repeatable hub-and-spoke network with two private VPC spokes connected to a central Transit Gateway.
- Used Amazon VPC Reachability Analyzer to expose a missing route after Terraform reported a successful deployment.
- Added symmetric routing through infrastructure as code. Proved that the path was reachable in both directions.
- Secret Mission: Removed both spoke routes as a declarative policy change. Confirmed that the network enforced intentional isolation while preserving the VPCs and Transit Gateway attachments.
Ready to quiz yourself?