How to configure and use the Terraform aws_subnet
resource block to create and manage AWS Subnets inside a VPC. AWS Subnets are a subdivision of the IP Network assigned to the VPC.
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: AWS Subnets
Read previous sections of the tutorial: AWS with Terraform Tutorial
Terraform AWS Configuration Plan Definition
Previous sections of the Tutorial have covered basic information about Terraform, AWS Cloud, the Terraform AWS Provider, and the VPC. Now it is time to create the VPC Subnets.
How to Create an AWS Subnet with Terraform
AWS Subnets are a subdivision of the IP Network assigned to the VPC.
Plan, and apply the Terraform plan to create Subnets in AWS.
Common Questions About AWS VPC
What IP range should be used for a VPC? How many VPCs do you need?
Other tutorials for creating infrastructure in AWS using Terraform.
Read previous sections of the tutorial:
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.
It is time to create the Subnets. Keep adding Terraform blocks to the terraform-aws-tutorial.tf
created in previous sections.
AWS Subnets are a subdivision of the IP Network assigned to the VPC. In the AWS with Terraform: The Essential Guide (4/21) – AWS VPC section the VPC was created and can now be used as an input to other Terraform blocks.
Use a CIDR Calculator to divide the VPC IP Network into the desired subnets.
Each subnet is assigned to one availability zone (us-east-1a, us-east-1b, us-east-1c, ...) in the chosen region (us-east-1).
Additionally, a subnet can be configured as public or private:
Subnet definition using Terraform, add the following block to the file terraform-aws-tutorial.tf
:
# Av. Zone: A, Env: PRO, Type: PUBLIC, Code: 00, CIDR Block: 172.21.0.0/23 resource "aws_subnet" "ditwl-sn-za-pro-pub-00" { vpc_id = aws_vpc.ditlw-vpc.id cidr_block = "172.21.0.0/23" #172.21.0.0 - 172.21.1.255 map_public_ip_on_launch = true availability_zone = "us-east-1a" tags = { Name = "ditwl-sn-za-pro-pub-00" } }
The Terraform aws_subnet resource block creates a Subnet, named ditwl-sn-za-pro-pub-00
, inside the VPC created in the previous tutorial, using its Terraform reference aws_vpc.ditlw-vpc.id
.
The Subnet has the following properties:
cidr_block = "172.21.0.0/23"
map_public_ip_on_launch = true
(Assigns public IPV4 addresses to instances launched inside the Subnet)availability_zone = "us-east-1a"
Name = "ditwl-sn-za-pro-pub-00"
Use the same values for the Terraform name and the Tag Name and follow a company wide naming standard and pattern to easily identify the resource across companies, products, projects, and clouds.
ditwl-sn-za-pro-pub-00
stands for:
Learn more about AWS and Terraform Naming Best Practices.
Add 3 more subnet blocks to the file terraform-aws-tutorial.tf
:
# Av. Zone: A, Env: PRO, Type: PRIVATE, Code: 02, CIDR Block: 172.21.2.0/23 resource "aws_subnet" "ditwl-sn-za-pro-pri-02" { vpc_id = aws_vpc.ditlw-vpc.id cidr_block = "172.21.2.0/23" #172.21.2.0 - 172.21.3.255 map_public_ip_on_launch = false availability_zone = "us-east-1a" tags = { Name = "ditwl-sn-za-pro-pri-02" } } # Av. Zone: B, Env: PRO, Type: PUBLIC, Code: 04, CIDR Block: 172.21.4.0/23 resource "aws_subnet" "ditwl-sn-zb-pro-pub-04" { vpc_id = aws_vpc.ditlw-vpc.id cidr_block = "172.21.4.0/23" #172.21.4.0 - 172.21.5.255 map_public_ip_on_launch = true availability_zone = "us-east-1b" tags = { Name = "ditwl-sn-zb-pro-pub-04" } } # Av. Zone: B, Env: PRO, Type: PRIVATE, Code: 06, CIDR Block: 172.21.6.0/23 resource "aws_subnet" "ditwl-sn-zb-pro-pri-06" { vpc_id = aws_vpc.ditlw-vpc.id cidr_block = "172.21.6.0/23" #172.21.6.0 - 172.21.7.255 map_public_ip_on_launch = false availability_zone = "us-east-1b" tags = { Name = "ditwl-sn-zb-pro-pri-06" } }
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 corresponds to the desired change. The VPC was already created in the previous Terraform execution so now only the new subnets will be created.
As you can see the order of creation of the subnets is not the same as the order in which they are defined in the file terraform-aws-tutorial.tf
, this is correct and doesn't have an impact as each subnet is independent from the others.
Terraform generates a dependency graph to understand the order in which resources should be created or modified. It helps determine the relationships and dependencies between different resources defined in your Terraform configuration. This ensures that resources are created or modified in the correct order to maintain a consistent infrastructure state. Sometimes Terraform or the provider can't generate accurate dependency relations and require additional configuration using the depends_on
Meta-Argument (to be documented in other tutorial sections).
$ tofu plan aws_vpc.ditlw-vpc: Refreshing state... [id=vpc-0bed1f6c715e9a909] 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_subnet.ditwl-sn-za-pro-pri-02 will be created + resource "aws_subnet" "ditwl-sn-za-pro-pri-02" { + arn = (known after apply) + assign_ipv6_address_on_creation = false + availability_zone = "us-east-1a" + availability_zone_id = (known after apply) + cidr_block = "172.21.2.0/23" + enable_dns64 = false + enable_resource_name_dns_a_record_on_launch = false + enable_resource_name_dns_aaaa_record_on_launch = false + id = (known after apply) + ipv6_cidr_block_association_id = (known after apply) + ipv6_native = false + map_public_ip_on_launch = false + owner_id = (known after apply) + private_dns_hostname_type_on_launch = (known after apply) + tags = { + "Name" = "ditwl-sn-za-pro-pri-02" } + tags_all = { + "Name" = "ditwl-sn-za-pro-pri-02" + "cost_center" = "marketing-department" + "environment" = "pro" + "owner" = "IT Wonder Lab" } + vpc_id = "vpc-0bed1f6c715e9a909" } # aws_subnet.ditwl-sn-za-pro-pub-00 will be created + resource "aws_subnet" "ditwl-sn-za-pro-pub-00" { + arn = (known after apply) + assign_ipv6_address_on_creation = false + availability_zone = "us-east-1a" + availability_zone_id = (known after apply) + cidr_block = "172.21.0.0/23" + enable_dns64 = false + enable_resource_name_dns_a_record_on_launch = false + enable_resource_name_dns_aaaa_record_on_launch = false + id = (known after apply) + ipv6_cidr_block_association_id = (known after apply) + ipv6_native = false + map_public_ip_on_launch = true + owner_id = (known after apply) + private_dns_hostname_type_on_launch = (known after apply) + tags = { + "Name" = "ditwl-sn-za-pro-pub-00" } + tags_all = { + "Name" = "ditwl-sn-za-pro-pub-00" + "cost_center" = "marketing-department" + "environment" = "pro" + "owner" = "IT Wonder Lab" } + vpc_id = "vpc-0bed1f6c715e9a909" } # aws_subnet.ditwl-sn-zb-pro-pri-06 will be created + resource "aws_subnet" "ditwl-sn-zb-pro-pri-06" { + arn = (known after apply) + assign_ipv6_address_on_creation = false + availability_zone = "us-east-1b" + availability_zone_id = (known after apply) + cidr_block = "172.21.6.0/23" + enable_dns64 = false + enable_resource_name_dns_a_record_on_launch = false + enable_resource_name_dns_aaaa_record_on_launch = false + id = (known after apply) + ipv6_cidr_block_association_id = (known after apply) + ipv6_native = false + map_public_ip_on_launch = false + owner_id = (known after apply) + private_dns_hostname_type_on_launch = (known after apply) + tags = { + "Name" = "ditwl-sn-zb-pro-pri-06" } + tags_all = { + "Name" = "ditwl-sn-zb-pro-pri-06" + "cost_center" = "marketing-department" + "environment" = "pro" + "owner" = "IT Wonder Lab" } + vpc_id = "vpc-0bed1f6c715e9a909" } # aws_subnet.ditwl-sn-zb-pro-pub-04 will be created + resource "aws_subnet" "ditwl-sn-zb-pro-pub-04" { + arn = (known after apply) + assign_ipv6_address_on_creation = false + availability_zone = "us-east-1b" + availability_zone_id = (known after apply) + cidr_block = "172.21.4.0/23" + enable_dns64 = false + enable_resource_name_dns_a_record_on_launch = false + enable_resource_name_dns_aaaa_record_on_launch = false + id = (known after apply) + ipv6_cidr_block_association_id = (known after apply) + ipv6_native = false + map_public_ip_on_launch = true + owner_id = (known after apply) + private_dns_hostname_type_on_launch = (known after apply) + tags = { + "Name" = "ditwl-sn-zb-pro-pub-04" } + tags_all = { + "Name" = "ditwl-sn-zb-pro-pub-04" + "cost_center" = "marketing-department" + "environment" = "pro" + "owner" = "IT Wonder Lab" } + vpc_id = "vpc-0bed1f6c715e9a909" } Plan: 4 to add, 0 to change, 0 to destroy. ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Note: You didn't use the -out option to save this plan, so OpenTofu can't guarantee to take exactly these actions if you run "tofu apply" now.
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] 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_subnet.ditwl-sn-za-pro-pri-02 will be created + resource "aws_subnet" "ditwl-sn-za-pro-pri-02" { ... + vpc_id = "vpc-0bed1f6c715e9a909" } # aws_subnet.ditwl-sn-za-pro-pub-00 will be created + resource "aws_subnet" "ditwl-sn-za-pro-pub-00" { ... + vpc_id = "vpc-0bed1f6c715e9a909" } # aws_subnet.ditwl-sn-zb-pro-pri-06 will be created + resource "aws_subnet" "ditwl-sn-zb-pro-pri-06" { ... + vpc_id = "vpc-0bed1f6c715e9a909" } # aws_subnet.ditwl-sn-zb-pro-pub-04 will be created + resource "aws_subnet" "ditwl-sn-zb-pro-pub-04" { ... + vpc_id = "vpc-0bed1f6c715e9a909" } Plan: 4 to add, 0 to change, 0 to destroy. 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_subnet.ditwl-sn-za-pro-pub-00: Creating... aws_subnet.ditwl-sn-za-pro-pri-02: Creating... aws_subnet.ditwl-sn-zb-pro-pub-04: Creating... aws_subnet.ditwl-sn-zb-pro-pri-06: Creating... aws_subnet.ditwl-sn-zb-pro-pri-06: Creation complete after 2s [id=subnet-0f5662bd40a070e55] aws_subnet.ditwl-sn-za-pro-pri-02: Creation complete after 2s [id=subnet-096bf79e4bab2e1c4] aws_subnet.ditwl-sn-za-pro-pub-00: Still creating... [10s elapsed] aws_subnet.ditwl-sn-zb-pro-pub-04: Still creating... [10s elapsed] aws_subnet.ditwl-sn-za-pro-pub-00: Creation complete after 13s [id=subnet-07753bf540026684d] aws_subnet.ditwl-sn-zb-pro-pub-04: Creation complete after 13s [id=subnet-0d34cee7300e9fa45] Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
Review the result, it should be 4 (resource) added, 0 changed, 0 destroyed
.
You can now run tofu plan
or tofu apply
again to check that OpenTofu has not found any new changes to apply.
$ tofu plan aws_vpc.ditlw-vpc: Refreshing state... [id=vpc-0bed1f6c715e9a909] aws_subnet.ditwl-sn-zb-pro-pri-06: Refreshing state... [id=subnet-0f5662bd40a070e55] aws_subnet.ditwl-sn-za-pro-pub-00: Refreshing state... [id=subnet-07753bf540026684d] 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] No changes. Your infrastructure matches the configuration. OpenTofu has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
Check using the AWS web Console that the Subnets have been created:
If you don't see the Subnets check on the right top corner that the Region is N. Virginia that corresponds to us-east-1.
The number of subnets you create in each Virtual Private Cloud (VPC) depends on your specific requirements and network architecture. However, it's a common practice to have at least two subnets in each VPC: one public and one private.
Consider factors like security, isolation, and scalability. Additional subnets may be created for specific purposes, like separating application tiers or isolating sensitive data.
As long as the VPC is created with a large CIDR block that has remaining sub-blocks for future use, you can add subnets later as needed.
When planning your Virtual Private Cloud (VPC) network CIDR (Classless Inter-Domain Routing) and its Subnets, consider the following:
Peering or VPNs: If you plan to connect VPCs or use VPNs, ensure that the CIDR blocks don't overlap with other clouds, existing VPCs, on-premises data centers, and LAN networks.
Private IP addresses are free to use but proper planning is required for routing across the organization.
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?