AWS with Terraform Tutorial: AWS VPC (4)
How to Create, and Manage AWS VPCs with Terraform #
How to configure and use the Terraform aws_vpc resource block to create and manage AWS VPCs.
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 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.
Prerequisites #
Read the previous sections of the tutorial, listed in the series index at the end of this page.
Terraform AWS Configuration Plan Definition #
Previous sections of this AWS with Terraform guide have covered basic information about Terraform and AWS. Now it is time to create a Terraform Plan.
In an empty directory, create a file named terraform-aws-tutorial.tf with the following two blocks:
# Copyright (C) 2018 - 2023 IT Wonder Lab (https://www.itwonderlab.com)
#
# This software may be modified and distributed under the terms
# of the MIT license. See the LICENSE file for details.
# -------------------------------- WARNING --------------------------------
# IT Wonder Lab's best practices for infrastructure include modularizing
# Terraform/OpenTofu configuration.
# In this example, we define everything in a single file.
# See other tutorials for best practices at itwonderlab.com
# -------------------------------- WARNING --------------------------------
#-----------------------------------------
# Define Terrraform Providers and Backend
#-----------------------------------------
terraform {
required_version = "> 1.5"
required_providers {
aws = {
source = "aws"
version = "~> 5.0"
}
}
}
#-----------------------------------------
# Provider: AWS
#-----------------------------------------
provider "aws" {
profile = "ditwl_infradmin"
default_tags {
tags = {
environment = "pro"
cost_center = "sales-department"
}
}
}
The first block defines the Terraform version and the required AWS Terraform provider, specifying the version and the provider (none, Hashicorp, or OpenTofu).
The second block configures the AWS Terraform provider by specifying "ditwl_infradmin" as the AWS CLI profile to use for authentication and a list of tags and values that will be added by default to all the resources created with Terraform.
The AWS CLI profile includes the access key, secret access key, account ID, and the AWS region.
How to create an AWS VPC with Terraform #
The first element that should be created is a VPC.
The VPC is created in the region specified while configuring the AWS Terraform provider (therefore the one defined by the AWS CLI profile "ditwl_infradmin"). This example uses the region us-east-1, located in Northern Virginia, United States.
VPC definition using Terraform, add the following block to the file terraform-aws-tutorial.tf:
# VPC, CIDR Block: 172.21.0.0/19
resource "aws_vpc" "ditlw-vpc" {
cidr_block = "172.21.0.0/19" #172.21.0.0 - 172.21.31.254
tags = {
Name = "ditlw-vpc"
tool = "Terraform"
}
}
The Terraform aws_vpc resource block creates a VPC with a network CIDR of 172.21.0.0/19 and the tags Name = "ditlw-vpc" and tool = "Terraform". Additionally the default tags environment = "pro" and cost_center = "sales-department" defined at the AWS Provider block will be automatically added by Terraform.
Other configuration options are available but not needed for a basic VPC.
The VPC properties can be referenced in the Terraform plan using the resource type (aws_vpc), assigned name (ditlw-vpc), and the exported attribute, for example:
- ID of the VPC:
aws_vpc.ditlw-vpc.id - Amazon Resource Name (ARN) of VPC:
aws_vpc.ditlw-vpc.arn - Default route table id:
aws_vpc.ditlw-vpc.default_route_table_id
The Tag Name and the resource name can be different but the best practice is to keep the same name.
The VPC ID will be used in the next sections as a parameter to create the AWS Subnets and the Default Routing Table.
Run the Terraform Plan #
Terraform configuration plans can be applied iteratively as new infrastructure needs to be added, modified, or destroyed.
Decide between using Terraform or OpenTofu and using the same tool during all the tutorial sections. You can switch tools to test Terraform and OpenTofu compatibility. The code is compatible with both tools and during the tutorial, OpenTofu will be used to run all commands.
Open a command line shell in the directory where the file terraform-aws-tutorial.tf is located, and run the Terraform or OpenTofu init, plan, and apply commands:
Init using OpenTofu #
The init command needs to be run once to download and initialize the required providers and lock files.
$ tofu init
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.0"...
- Installing hashicorp/aws v5.32.1...
- Installed hashicorp/aws v5.32.1 (signed, key ID 0C0AF313E5FD9F80)
Providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://opentofu.org/docs/cli/plugins/signing/
OpenTofu has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that OpenTofu can guarantee to make the same selections by default when
you run "tofu init" in the future.
OpenTofu has been successfully initialized!
You may now begin working with OpenTofu. Try running "tofu plan" to see
any changes that are required for your infrastructure. All OpenTofu commands
should now work.
If you ever set or change modules or backend configuration for OpenTofu,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary
Plan using OpenTofu #
Run tofu plan to generate and review the execution plan. Check each line and value to make sure that corresponds to the desired change. In this case, a VPC will be created (as shown with the + sign) and only a few of its initial properties have been specified (the cidr_block and the tags), with the rest of the properties using default provider values or being known after creation.
$ tofu plan
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_vpc.ditlw-vpc will be created
+ resource "aws_vpc" "ditlw-vpc" {
+ arn = (known after apply)
+ cidr_block = "172.21.0.0/19"
+ default_network_acl_id = (known after apply)
+ default_route_table_id = (known after apply)
+ default_security_group_id = (known after apply)
+ dhcp_options_id = (known after apply)
+ enable_dns_hostnames = (known after apply)
+ enable_dns_support = true
+ enable_network_address_usage_metrics = (known after apply)
+ id = (known after apply)
+ instance_tenancy = "default"
+ ipv6_association_id = (known after apply)
+ ipv6_cidr_block = (known after apply)
+ ipv6_cidr_block_network_border_group = (known after apply)
+ main_route_table_id = (known after apply)
+ owner_id = (known after apply)
+ tags = {
+ "Name" = "ditlw-vpc"
+ "tool" = "Terraform"
}
+ tags_all = {
+ "Name" = "ditlw-vpc"
+ "cost_center" = "sales-department"
+ "environment" = "pro"
+ "tool" = "Terraform"
}
}
Plan: 1 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.
Apply the changes using OpenTofu #
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
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_vpc.ditlw-vpc will be created
+ resource "aws_vpc" "ditlw-vpc" {
+ arn = (known after apply)
+ cidr_block = "172.21.0.0/19"
+ default_network_acl_id = (known after apply)
+ default_route_table_id = (known after apply)
+ default_security_group_id = (known after apply)
+ dhcp_options_id = (known after apply)
+ enable_dns_hostnames = (known after apply)
+ enable_dns_support = true
+ enable_network_address_usage_metrics = (known after apply)
+ id = (known after apply)
+ instance_tenancy = "default"
+ ipv6_association_id = (known after apply)
+ ipv6_cidr_block = (known after apply)
+ ipv6_cidr_block_network_border_group = (known after apply)
+ main_route_table_id = (known after apply)
+ owner_id = (known after apply)
+ tags = {
+ "Name" = "ditlw-vpc"
+ "tool" = "Terraform"
}
+ tags_all = {
+ "Name" = "ditlw-vpc"
+ "cost_center" = "sales-department"
+ "environment" = "pro"
+ "tool" = "Terraform"
}
}
Plan: 1 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_vpc.ditlw-vpc: Creating...
aws_vpc.ditlw-vpc: Creation complete after 5s [id=vpc-0bed1f6c715e9a909]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed
Review the result, it should be 1 (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]
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.
You can modify the cost_center tag, add a new one (owner = "IT Wonder Lab"), and then run tofu plan or tofu apply again. This way, OpenTofu will adjust the VPC, ensuring that the necessary changes in AWS align with the Terraform code.
This example demonstrates an in-place update, where the infrastructure is modified without the need to destroy and recreate it. Be aware that some changes require infrastructure destruction (destroy and create).
$ 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:
~ update in-place
OpenTofu will perform the following actions:
# aws_vpc.ditlw-vpc will be updated in-place
~ resource "aws_vpc" "ditlw-vpc" {
id = "vpc-0bed1f6c715e9a909"
~ tags = {
"Name" = "ditlw-vpc"
- "cost_center" = "sales-department" -> null
"tool" = "Terraform"
}
~ tags_all = {
~ "cost_center" = "sales-department" -> "marketing-department"
+ "owner" = "IT Wonder Lab"
# (3 unchanged elements hidden)
}
# (14 unchanged attributes hidden)
}
Plan: 0 to add, 1 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_vpc.ditlw-vpc: Modifying... [id=vpc-0bed1f6c715e9a909]
aws_vpc.ditlw-vpc: Modifications complete after 5s [id=vpc-0bed1f6c715e9a909]
Apply complete! Resources: 0 added, 1 changed, 0 destroyed
Terraform shows an in-place update that:
- Removes (-) the tag “cost_center” from “sales-department” to null:
- "cost_center" = "sales-department" -> null - Changes (~) the tags_all (a default tag defined at the AWS Provider level) “cost_center” from “sales-department” to “marketing-department”:
~ "cost_center" = "sales-department" -> "marketing-department" - And, adds (+) a new tag “owner” with the value “IT Wonder Lab”:
+ "owner" = "IT Wonder Lab"
Common Questions About AWS VPC #
What IP range should be used for a VPC? #
When planning your Virtual Private Cloud (VPC) network CIDR (Classless Inter-Domain Routing), consider the following:
- Size: Choose a CIDR block size that provides enough IP addresses for your resources but avoids wasting address space.
- Subnetting: Plan your subnets within the VPC wisely, considering the number of subnets needed, their size, and the future scalability.
- Overlap Avoidance: Ensure there’s no overlap with other networks to prevent routing issues. It’s common to avoid using the same CIDR block as other networks you might connect to.
- Future Growth: Plan for future growth and expansion by choosing a CIDR block that allows for additional subnets and addresses.
- Reserved Addresses: Each subnet reserves a few IP addresses for AWS use:
- Network address (first IP,
.0): the base network address. - VPC router (second IP,
.1): reserved for the VPC router. - DNS server (third IP,
.2): reserved for the Amazon DNS server. - Future use (fourth IP,
.3): reserved by AWS for future use. - Broadcast address (last IP): reserved, although broadcast is not supported in a VPC.
- Additional Addresses for AWS services. For example, Amazon EKS (see the EKS tutorial) needs to have at least 6 IP addresses available but at least 16 IPs are recommended.
- Network address (first IP,
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.
How many VPCs do you need? #
The number of VPCs and most importantly the services that each VPC provides have an impact on the cost of the Cloud.
Data Transfer Costs for Common Architectures :
- Data transfer over VPC Peering connections is free within the same Availability Zone (AZ)
- Data transfer over a VPC Peering connection that crosses Availability Zones is charged.
- In RDS Multi-AZ replication between the primary and standby instances does not incur additional data transfer charges, but access from EC2 instances to the RDS instances in different availability zones does.
For small companies, consider each VPC as a data center with its own network, security and costs. Start with one VPC per environment (or one for production and one for the rest) and add more only when there is a reason, such as isolation, compliance or different accounts.
Next Steps #
Continue with AWS Subnets, or see the full series index.