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 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.

Terraform Basics, AWS Basics, Terraform AWS Provider, AWS VPC, AWS Subnets, AWS Internet Gateway, AWS NAT Gateway, AWS Routing Tables, AWS Security Groups, AWS Key Pairs, AWS AMIs, AWS EC2 Instances, AWS RDS, AWS Route 53 (DNS), AWS Auto Scaling, AWS Load Balancers, Terraform AWS & Ansible, Terraform Modules, Terraform Backends, Terraform Tools, Terraform CI/CD.

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 VPC

  1. Prerequisites

    Read previous sections of the tutorial: AWS with Terraform Tutorial

  2. Terraform AWS Configuration Plan Definition

    Previous sections of the Tutorial have covered basic information about Terraform, AWS Cloud, and the Terraform AWS Provider. Now it is time to create a Terraform Plan.

  3. How to create AWS VPCs with Terraform

    The first element that should be created in an AWS Terraform Plan is the VPC.

  4. Run the Terraform Plan

    Init, plan, and apply the Terraform plan to create a VPC in AWS.

  5. Common Questions About AWS VPC

    What IP range should be used for a VPC? How many VPCs do you need?

  6. Next Steps

    Other tutorials for creating infrastructure in AWS using Terraform.

Prerequisites

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 North Virginia, United States.

ITWL Tutorials AWS Terraform Essentials VPC

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 at the same location as the terraform-aws-tutorial.tf the file 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 be 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): This is the base network address and is reserved.
    • VPC Router (Second IP): The second IP address is reserved for the VPC router.
    • DNS Server (Third IP): The third IP address is reserved for the Amazon DNS server.
    • Reserved for Future Use (Last IP): The last IP address in the subnet is reserved for future use.
    • Additional Addresses for AWS services. For example, AWS Elastic Kubernetes Services needs to have at least 6 IP addresses available but at least 16 IPs are recommended.

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

Next Steps

This tutorial series is a work in progress and will have these sections:

Terraform Basics, AWS Basics, Terraform AWS Provider, AWS VPC, AWS Subnets, AWS Internet Gateway, AWS NAT Gateway, AWS Routing Tables, AWS Security Groups, AWS Key Pairs, AWS AMIs, AWS EC2 Instances, AWS RDS, AWS Route 53 (DNS), AWS Auto Scaling, AWS Load Balancers, Terraform AWS & Ansible, Terraform Modules, Terraform Backends, Terraform Tools, Terraform CI/CD.

AWS with Terraform: The Essential Guide: Sections

Leave a Reply

Your email address will not be published. Required fields are marked *


Related Cloud Tutorials

Securing your Infrastructure: Encrypting Terraform State Files with OpenTofu
Using the Terraform aws_route53_delegation_set, aws_route53_zone, and aws_route53_record resource blocks to configure DNS in AWS.
Using the Terraform aws_db_instance resource block to configure, launch, and secure RDS instances.
How to use the Terraform aws_instance resource block to configure, launch, and secure EC2 instances.
How to configure and use the Terraform aws_ami data source block to find and use AWS AMIs as templates (root volume snapshot with operating system and applications) for EC2 instances.
Javier Ruiz Cloud and SaaS Expert

Javier Ruiz

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?

linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram