Terraform 101: Creating Secure Subnets in Your VPC
Tags: terraform, aws, infrastructureascode, tutorial
Published: 2024-04-25 12:11:37

Welcome to Part 2 of the series: [Terraform for Beginners](https://dev.to/ananyadasgupta/series/27114)

Previously, we learned how to create a VPC in AWS using Terraform. In this blog, we'll learn about subnets and how to create them using Terraform.

## What is a subnet?
According to AWS documentation,

> A subnet is a range of IP addresses in your VPC. You can create AWS resources, such as EC2 instances, in specific subnets.

Here's a breakdown of the key aspects of a subnet:

- Segmentation: Subnets allow you to partition your VPC into isolated units. This enhances security by restricting resources within one subnet from directly accessing resources in another subnet by default. If needed, you can configure specific routing rules to allow controlled communication between subnets.

- Placement: You can create multiple subnets within your VPC, each with its own CIDR block (a range of IP addresses). When launching resources like EC2 instances within your VPC, you can specify their subnet. This placement determines their network access and security posture.

- Public vs. Private: A common practice involves creating two main types of subnets:
       - Public Subnet: Resources placed in a public subnet have direct access to the internet. This allows them to receive inbound traffic from the internet and potentially send outbound traffic. Public subnets are suitable for resources like web servers that need to be accessed publicly.
       - Private Subnet: Resources in a private subnet don't have direct internet access by default. This improves security for resources that don't require exposure to the internet. However, if these resources need controlled outbound access (e.g., downloading updates), you can leverage a NAT Gateway (Network Address Translation Gateway) to provide it.

Let's look at the architecture diagram.

![Architecture Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k8uh6kwmya6z04113iot.png)

We have to create a public and private subnet inside the vpc we created in the previous blog. 

## Prerequisites
Complete the tutorial for creating a vpc as we will continue from there.
You can check out the tutorial [here](https://dev.to/ananyadasgupta/terraform-for-newbs-launching-a-simple-aws-backend-welcome-to-the-series-jh)

## Terraform Code to create Subnet in AWS

Step 1: In your vpc.tf file copy and paste the following piece of code:

```
resource "aws_subnet" "public_subnet" {
  for_each                = var.public_subnet
  vpc_id                  = aws_vpc.vpc.id
  cidr_block              = each.value.cidr_block
  availability_zone       = each.value.availability_zone
  map_public_ip_on_launch = true
  tags = {
    Name         = "${var.env}-${local.project}-${each.key}"
    CreatedByTer = true
  }
}

resource "aws_subnet" "private_subnet" {
  for_each          = var.private_subnet
  vpc_id            = aws_vpc.vpc.id
  cidr_block        = each.value.cidr_block
  availability_zone = each.value.availability_zone
  tags = {
    Name          = "${var.env}-${local.project}-${each.key}"
    CreatedByTer  = true
  }
}
```
_Explanation_:

- _for_each_ allows you to create multiple subnets with varying configurations based on the data provided in the variables named _public_subnet_ and _private_subnet_.

- _cidr_block = each.value.cidr_block_. 
    - This line defines the CIDR block for the subnets. However, it uses a dynamic approach by referencing each.value.cidr_block. This suggests that _var.public_subnet_ and _var.private_subnet_ is a map or list containing key-value pairs where the key is used for iteration (each.key) and the value (each.value) contains a nested object with a cidr_block key. This allows you to define multiple CIDR blocks for different subnets within the loop.

- _availability_zone = each.value.availability_zone_
    - Similar to the cidr_block, this line defines the availability zone for the subnets using a dynamic reference to the availability_zone key within the nested objects. This allows you to distribute your resources across zones for redundancy.

- _map_public_ip_on_launch_
    - This line sets the map_public_ip_on_launch attribute to true or false. When set to true, any EC2 instances launched within that subnet will automatically receive a public IP address, allowing them to be accessed directly from the internet.
Similarly, when set to false, the instances will not be assigned a public IP during creation.

You will get an error as we have not yet created the _public_subnet_ and _private_subnet_ variables.

Step 2: In your variables.tf file copy and paste the following code:

```
variable "public_subnet" {
  type        = map(any)
  description = "Public Subnets to be created"
}
variable "private_subnet" {
  type        = map(any)
  description = "Private Subnets to be created"
}
```
_Explanation_:

- This code block defines two Terraform variables named "public_subnet" and "private_subnet". It specifies that the variables will hold a collection of data in the form of a map.

-  While 'any' allows for flexibility, using more specific data types within the map can improve code readability and catch potential errors during configuration.

Step 3: In your terraform.tfvars file copy and paste the following code block

```
public_subnet = {
  public-subnet-1 = {
    cidr_block        = "10.0.101.0/24"
    availability_zone = "ap-south-1a"
  }
}
private_subnet = {
  private-subnet-1 = {
    cidr_block        = "10.0.1.0/24"
    availability_zone = "ap-south-1a"
  }
}
```
_Explanation_:

- The value of the _public_subnet_ and _private_subnet_ variables are defined here.

- This configuration defines the above variables as _map of a map_.

- _public-subnet-1_ is the name of the first child map of the variable _public_subnet_. It consists of two key-value pairs:
    - _cidr_block specifies_ the CIDR range for the subnet
    - _availability_zone_ specifies the AWS availability zone the subnet will reside in. Here we are creating the subnet in the _Mumbai _region.

- Similarly, _private-subnet-1_ is the name of the first child of the variable _private_subnet_. It consists of the same key-value pairs.

## Deploy infrastructure to AWS

Follow the steps [here](https://dev.to/ananyadasgupta/terraform-for-newbs-launching-a-simple-aws-backend-welcome-to-the-series-jh) to deploy the changes to AWS.

Congratulations! You have successfully created subnets in AWS using terraform.

Up next: Internet Gateway! Stay tuned. 👋