How to configure and use the Terraform aws_route_table
, aws_route
, and aws_main_route_table_association
resource blocks to create and manage AWS Routing Tables.
Welcome to our tutorial series where we dive into cloud infrastructure deployment using Terraform or OpenTofu on AWS. In this series, the fundamentals are shown, guiding you through the process of minimizing resource usage and simplifying the deployment complexities associated with cloud infrastructure. This tutorial series is a work in progress.
This comprehensive OpenTofu and Terraform tutorial guides you step-by-step through creating infrastructure in AWS using Terraform.
Infrastructure as Code (IaC) helps maintain consistency, enables version control, enhances collaboration among teams, allows for easier replication of environments, streamlines the deployment and management of infrastructure boosting efficiency, and reducing errors in managing complex systems.
How to start building AWS infrastructure with Terraform: Routing Tables
Read previous sections of the tutorial: AWS with Terraform Tutorial
An AWS routing table is a set of rules that defines how network traffic is directed within a Virtual Private Cloud (VPC). It contains a list of routes, each specifying a destination and the target for the traffic.
Routing Diagram: List of Routes Needed
A diagram with the services and intended connections helps design the routing tables.
Terraform AWS Configuration Plan Definition
Previous sections of the Tutorial have covered basic information about Terraform, AWS Cloud, the Terraform AWS Provider, VPC, Subnets, Internet Gateway, and NAT Gateway. In this section, the Routing Tables needed to use the Gateways are presented.
How to create an AWS Routing Table with Terraform
Terraform has two different ways to define a Routing Table and its routes. In-line routes where the routes are included in the Routing Table block and Routing Table with outside route association when the routing table is created in a block and the rules are added in different blocks.
Plan, and apply the Terraform plan to create the Routing Tables in AWS.
Destroying AWS Infrastructure with Terraform
Removing infrastructure from Terraform Configuration and the Cloud.
Common Questions About AWS Routing Tables
Can I have multiple routing tables in a VPC?, What is the main purpose of the default route in a routing table?, ...
Other tutorials for creating infrastructure in AWS using Terraform.
Read previous sections of the tutorial:
An AWS routing table is a set of rules that defines how network traffic is directed within a Virtual Private Cloud (VPC). It contains a list of routes, each specifying a destination and the target for the traffic.
When a VPC is created, AWS creates a default routing table. For our VPC the AWS default routing table can be seen at the AWS Console.
We will not use this Routing table as it is not Terraform managed but we will explore its configuration:
This existing Routing Table is currently configured as Main but since it wasn't created with Terraform we will add a new Terraform-managed Main Routing Table for the VPC.
A diagram with the services and intended connections helps design the routing tables.
The needs for the tutorial are:
The diagram shows 3 routing tables, using red for ditwl-rt-pub-main
and green for the ditwl-rt-priv-za
and ditwl-rt-priv-zb
:
List of Routing Tables:
Name | Availability Zone | Visibility | Routing Table |
---|---|---|---|
ditwl-sn-za-pro-pub-00 | us-east-1a | Public | VPC default (ditwl-rt-pub-main) |
ditwl-sn-za-pro-pri-02 | us-east-1a | Private | ditwl-rt-priv-za |
ditwl-sn-zb-pro-pub-04 | us-east-1b | Public | VPC default (ditwl-rt-pub-main) |
ditwl-sn-zb-pro-pri-06 | us-east-1b | Private | ditwl-rt-priv-zb |
Previous sections of this AWS with Terraform guide have covered basic information about Terraform and AWS and have configured and used the AWS Terraform provider to create a VPC, four subnets, one Internet Gateway, and two NAT Gateways.
It is time to create the Routing Tables and the routes to use the Internet Gateway and the NAT Gateways.
Keep adding Terraform blocks to the terraform-aws-tutorial.tf
created in previous sections.
Terraform has two different ways to define a Routing Table and its routes.
The in-line routes approach works better for small routing tables and the one with outside route association is better suited for routing tables with many routes. It is not possible to mix in the same routing table both approaches but each routing table can use one or another in the same Terraform configuration.
A new routing table named ditwl-rt-pub-main
is created and using in-line routes a route from CIDR block 0.0.0.0 to the Internet Gateway is created referencing it by its ID using the Terraform name and the id property aws_internet_gateway.ditwl-ig.id
.
Once the routing table has been created it is configured as Main for the VPC using the Terraform resource aws_main_route_table_association
and specifying the ID of the VPC and the ID of the newly created routing table using its Terraform resource, name, and property.
Add the following block to the file terraform-aws-tutorial.tf
:
# Routing table for public subnet (access to the Internet) # Using in-line routes resource "aws_route_table" "ditwl-rt-pub-main" { vpc_id = aws_vpc.ditlw-vpc.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.ditwl-ig.id } tags = { Name = "ditwl-rt-pub-main" } } # Set new main_route_table as main resource "aws_main_route_table_association" "ditwl-rta-default" { vpc_id = aws_vpc.ditlw-vpc.id route_table_id = aws_route_table.ditwl-rt-pub-main.id }
These routing tables are defined using the outside route association approach, each routing table is created in a block with no routes.
The Routing table is assigned to its corresponding subnet using a Terraform resource block aws_route_table_association
.
Each routing rule is added in an independent block using the aws_route
and specifying the ID of the routing table where the rule will be added.
# Routing table for private subnet in Availability Zone A # Using standalone routes resources resource "aws_route_table" "ditwl-rt-priv-za" { vpc_id = aws_vpc.ditlw-vpc.id tags = { Name = "ditwl-rt-priv-za" } } # Route Access to the Internet through NAT (Av. Zone A) resource "aws_route" "ditwl-r-rt-priv-za-ngw-za" { route_table_id = aws_route_table.ditwl-rt-priv-za.id destination_cidr_block = "0.0.0.0/0" gateway_id = aws_nat_gateway.ditwl-ngw-za-pub.id } # Routing Table Association for Subnet ditwl-sn-za-pro-pri-02 resource "aws_route_table_association" "ditwl-rta-za-pro-pri-02" { subnet_id = aws_subnet.ditwl-sn-za-pro-pri-02.id route_table_id = aws_route_table.ditwl-rt-priv-za.id } # Routing table for private subnet in Availability Zone B # Using standalone routes resources resource "aws_route_table" "ditwl-rt-priv-zb" { vpc_id = aws_vpc.ditlw-vpc.id tags = { Name = "ditwl-rt-priv-zb" } } # Routing Table Association for Subnet ditwl-sn-zb-pro-pri-06 resource "aws_route_table_association" "ditwl-rta-zb-pro-pri-06" { subnet_id = aws_subnet.ditwl-sn-zb-pro-pri-06.id route_table_id = aws_route_table.ditwl-rt-priv-zb.id } # Route Access to the Internet through NAT (Av. Zone B) resource "aws_route" "ditwl-r-rt-priv-zb-ngw-zb" { route_table_id = aws_route_table.ditwl-rt-priv-zb.id destination_cidr_block = "0.0.0.0/0" gateway_id = aws_nat_gateway.ditwl-ngw-zb-pub.id }
Open a command line shell at the same location where the terraform-aws-tutorial.tf file is located, and, run the Terraform or OpenTofu plan, and apply the commands.
Run tofu plan
to generate and review the execution plan. Check each line and value to make sure that it corresponds to the desired change.
Terraform will refresh the state comparing it with the Cloud resources and produce a plan for the resources that need to be created, updated, or destroyed.
In the past section of the tutorial, the NAT Gateways and the EIP were created and destroyed (by commenting its definition in the Terraform configuration file) to reduce cost while developing the infrastructure definition. Now Terraform will create the NAT Gateways, the EIPs, and the Routing tables.
Uncomment the NAT Gateways and the EIP as the Routing Tables reference those resources and run the Terraform plan:
$ tofu plan aws_vpc.ditlw-vpc: Refreshing state... [id=vpc-0bed1f6c715e9a909] aws_internet_gateway.ditwl-ig: Refreshing state... [id=igw-033b206763b59357e] aws_subnet.ditwl-sn-za-pro-pri-02: Refreshing state... [id=subnet-096bf79e4bab2e1c4] aws_subnet.ditwl-sn-za-pro-pub-00: Refreshing state... [id=subnet-07753bf540026684d] aws_subnet.ditwl-sn-zb-pro-pub-04: Refreshing state... [id=subnet-0d34cee7300e9fa45] aws_subnet.ditwl-sn-zb-pro-pri-06: Refreshing state... [id=subnet-0f5662bd40a070e55] OpenTofu used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create OpenTofu will perform the following actions: # aws_eip.ditwl-eip-ngw-za will be created + resource "aws_eip" "ditwl-eip-ngw-za" { ... } # aws_eip.ditwl-eip-ngw-zb will be created + resource "aws_eip" "ditwl-eip-ngw-zb" { ... } # aws_main_route_table_association.ditwl-rta-default will be created + resource "aws_main_route_table_association" "ditwl-rta-default" { ... + vpc_id = "vpc-0bed1f6c715e9a909" } # aws_nat_gateway.ditwl-ngw-za-pub will be created + resource "aws_nat_gateway" "ditwl-ngw-za-pub" { ... } # aws_nat_gateway.ditwl-ngw-zb-pub will be created + resource "aws_nat_gateway" "ditwl-ngw-zb-pub" { ... } # aws_route.ditwl-r-rt-priv-za-ngw-za will be created + resource "aws_route" "ditwl-r-rt-priv-za-ngw-za" { + destination_cidr_block = "0.0.0.0/0" ... } # aws_route.ditwl-r-rt-priv-zb-ngw-zb will be created + resource "aws_route" "ditwl-r-rt-priv-zb-ngw-zb" { + destination_cidr_block = "0.0.0.0/0" ... } # aws_route_table.ditwl-rt-priv-za will be created + resource "aws_route_table" "ditwl-rt-priv-za" { ... } # aws_route_table.ditwl-rt-priv-zb will be created + resource "aws_route_table" "ditwl-rt-priv-zb" { ... } # aws_route_table.ditwl-rt-pub-main will be created + resource "aws_route_table" "ditwl-rt-pub-main" { ... } # aws_route_table_association.ditwl-rta-za-pro-pri-02 will be created + resource "aws_route_table_association" "ditwl-rta-za-pro-pri-02" { + id = (known after apply) + route_table_id = (known after apply) + subnet_id = "subnet-096bf79e4bab2e1c4" } # aws_route_table_association.ditwl-rta-zb-pro-pri-06 will be created + resource "aws_route_table_association" "ditwl-rta-zb-pro-pri-06" { + id = (known after apply) + route_table_id = (known after apply) + subnet_id = "subnet-0f5662bd40a070e55" } Plan: 12 to add, 0 to change, 0 to destroy.
Run tofu apply
to generate and apply the execution plan. OpenTofu will generate a new plan and ask for confirmation before applying the changes. Review again the changes and answer yes or no to apply the changes in AWS.
$ tofu apply aws_vpc.ditlw-vpc: Refreshing state... [id=vpc-0bed1f6c715e9a909] aws_internet_gateway.ditwl-ig: Refreshing state... [id=igw-033b206763b59357e] aws_subnet.ditwl-sn-za-pro-pri-02: Refreshing state... [id=subnet-096bf79e4bab2e1c4] aws_subnet.ditwl-sn-zb-pro-pub-04: Refreshing state... [id=subnet-0d34cee7300e9fa45] aws_subnet.ditwl-sn-za-pro-pub-00: Refreshing state... [id=subnet-07753bf540026684d] aws_subnet.ditwl-sn-zb-pro-pri-06: Refreshing state... [id=subnet-0f5662bd40a070e55] OpenTofu used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create OpenTofu will perform the following actions: # aws_eip.ditwl-eip-ngw-za will be created .... Do you want to perform these actions? OpenTofu will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes aws_route_table.ditwl-rt-priv-za: Creating... aws_route_table.ditwl-rt-priv-zb: Creating... aws_eip.ditwl-eip-ngw-zb: Creating... aws_eip.ditwl-eip-ngw-za: Creating... aws_route_table.ditwl-rt-pub-main: Creating... aws_eip.ditwl-eip-ngw-za: Creation complete after 3s [id=eipalloc-0256d8e1eae1e7774] aws_nat_gateway.ditwl-ngw-za-pub: Creating... aws_eip.ditwl-eip-ngw-zb: Creation complete after 3s [id=eipalloc-0ad38a8c4f37daa52] aws_nat_gateway.ditwl-ngw-zb-pub: Creating... aws_route_table.ditwl-rt-priv-zb: Creation complete after 3s [id=rtb-003e3066aad95d701] aws_route_table_association.ditwl-rta-zb-pro-pri-06: Creating... aws_route_table.ditwl-rt-priv-za: Creation complete after 4s [id=rtb-04c95397c69600c18] aws_route_table_association.ditwl-rta-za-pro-pri-02: Creating... aws_route_table_association.ditwl-rta-za-pro-pri-02: Creation complete after 1s [id=rtbassoc-06395ca838c6dfa8a] aws_route_table.ditwl-rt-pub-main: Creation complete after 6s [id=rtb-05cbe56c02830be54] aws_main_route_table_association.ditwl-rta-default: Creating... aws_route_table_association.ditwl-rta-zb-pro-pri-06: Creation complete after 4s [id=rtbassoc-06c8ede0cd3cbc25f] aws_main_route_table_association.ditwl-rta-default: Creation complete after 3s [id=rtbassoc-0c3f227acd4563a24] aws_nat_gateway.ditwl-ngw-za-pub: Still creating... [10s elapsed] aws_nat_gateway.ditwl-ngw-zb-pub: Still creating... [10s elapsed] aws_nat_gateway.ditwl-ngw-za-pub: Still creating... [20s elapsed] aws_nat_gateway.ditwl-ngw-zb-pub: Still creating... [20s elapsed] aws_nat_gateway.ditwl-ngw-za-pub: Still creating... [30s elapsed] aws_nat_gateway.ditwl-ngw-zb-pub: Still creating... [30s elapsed] aws_nat_gateway.ditwl-ngw-za-pub: Still creating... [40s elapsed] aws_nat_gateway.ditwl-ngw-zb-pub: Still creating... [40s elapsed] aws_nat_gateway.ditwl-ngw-za-pub: Still creating... [50s elapsed] aws_nat_gateway.ditwl-ngw-zb-pub: Still creating... [50s elapsed] aws_nat_gateway.ditwl-ngw-za-pub: Still creating... [1m0s elapsed] aws_nat_gateway.ditwl-ngw-zb-pub: Still creating... [1m0s elapsed] aws_nat_gateway.ditwl-ngw-za-pub: Still creating... [1m10s elapsed] aws_nat_gateway.ditwl-ngw-zb-pub: Still creating... [1m10s elapsed] aws_nat_gateway.ditwl-ngw-za-pub: Still creating... [1m20s elapsed] aws_nat_gateway.ditwl-ngw-zb-pub: Still creating... [1m20s elapsed] aws_nat_gateway.ditwl-ngw-za-pub: Still creating... [1m30s elapsed] aws_nat_gateway.ditwl-ngw-zb-pub: Still creating... [1m30s elapsed] aws_nat_gateway.ditwl-ngw-zb-pub: Creation complete after 1m31s [id=nat-0066c29e6212c63d9] aws_route.ditwl-r-rt-priv-zb-ngw-zb: Creating... aws_route.ditwl-r-rt-priv-zb-ngw-zb: Creation complete after 4s [id=r-rtb-003e3066aad95d7011080289494] aws_nat_gateway.ditwl-ngw-za-pub: Still creating... [1m40s elapsed] aws_nat_gateway.ditwl-ngw-za-pub: Still creating... [1m50s elapsed] aws_nat_gateway.ditwl-ngw-za-pub: Still creating... [2m0s elapsed] aws_nat_gateway.ditwl-ngw-za-pub: Creation complete after 2m4s [id=nat-09d7641d934f5afc2] aws_route.ditwl-r-rt-priv-za-ngw-za: Creating... aws_route.ditwl-r-rt-priv-za-ngw-za: Creation complete after 3s [id=r-rtb-04c95397c69600c181080289494] Apply complete! Resources: 12 added, 0 changed, 0 destroyed.
Review the result, it should be 12 (resource) added, 0 changed, 0 destroyed
.
The route associations ditwl-r-rt-priv-za-ngw-za
and ditwl-r-rt-priv-zb-ngw-zb
, were created after the Route Tables as Terraform was able to automatically determine the relationships and dependencies between the resources.
Check using the AWS web Console that the Route Tables have been created:
ditwl-sn-za-pro-pri-02
:Click on the Public IPs to navigate to the EIP console and see its properties.
There is no cost for having Routing Tables but there is a cost for running NAT gateways and EIPs.
AWS charges for Inter-regional data transfer and data transfer to the Internet.
Yes, a VPC can have multiple routing tables, but each subnet can only be associated with one routing table at a time.
The default route (0.0.0.0/0) is typically used for directing traffic to an internet gateway, allowing instances in the subnet to access the internet.
Yes, you can modify existing routes in a routing table to update the target or make other adjustments.
Routes with more specific CIDR blocks take precedence over less specific ones. The most specific route that matches the destination is used.
If there is no matching route, the traffic is not routed, and communication to the destination will fail.
This tutorial series is a work in progress and will have these sections:
AWS with Terraform: The Essential Guide: Sections
IT Wonder Lab tutorials are based on the diverse experience of Javier Ruiz, who founded and bootstrapped a SaaS company in the energy sector. His company, later acquired by a NASDAQ traded company, managed over €2 billion per year of electricity for prominent energy producers across Europe and America. Javier has over 25 years of experience in building and managing IT companies, developing cloud infrastructure, leading cross-functional teams, and transitioning his own company from on-premises, consulting, and custom software development to a successful SaaS model that scaled globally.
Are you looking for cloud automation best practices tailored to your company?