Terraform – Managing AWS VPC – Creating Private Subnets

Andrei Maksimov

Andrei Maksimov

5
(1)

In the previous article (Terraform recipe – Managing AWS VPC – Creating Public Subnet), we’ve used Terraform to create a VPC, Internet Gateway, and Route Table to form Public Subnet. If you missed it, we strongly encourage you to read it first. This article continues Terraform article series and covers the management of NAT-ed and Fully Isolated Private Subnets.

But if you’re looking only for code snippets, please, feel free to use the VPC declaration from the next section. It already contains everything you need to move forward.

You may find a complete example of the project in our GitHub repo.

VPC with the public subnet

Here’s a complete example from the previous article:

resource "aws_vpc" "my_vpc" {
  cidr_block       = "10.0.0.0/16"
  enable_dns_hostnames = true

  tags = {
    Name = "My VPC"
  }
}

resource "aws_subnet" "public" {
  vpc_id     = aws_vpc.my_vpc.id
  cidr_block = "10.0.0.0/24"
  availability_zone = "us-east-1a"

  tags = {
    Name = "Public Subnet"
  }
}

resource "aws_internet_gateway" "my_vpc_igw" {
  vpc_id = aws_vpc.my_vpc.id

  tags = {
    Name = "My VPC - Internet Gateway"
  }
}

resource "aws_route_table" "my_vpc_us_east_1a_public" {
    vpc_id = aws_vpc.my_vpc.id

    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = aws_internet_gateway.my_vpc_igw.id
    }

    tags = {
        Name = "Public Subnet Route Table."
    }
}

resource "aws_route_table_association" "my_vpc_us_east_1a_public" {
    subnet_id = aws_subnet.public.id
    route_table_id = aws_route_table.my_vpc_us_east_1a_public.id
}

resource "aws_security_group" "allow_ssh" {
  name        = "allow_ssh_sg"
  description = "Allow SSH inbound connections"
  vpc_id = aws_vpc.my_vpc.id

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port       = 0
    to_port         = 0
    protocol        = "-1"
    cidr_blocks     = ["0.0.0.0/0"]
  }

  tags = {
    Name = "allow_ssh_sg"
  }
}

resource "aws_instance" "my_instance" {
  ami           = "ami-0ac019f4fcb7cb7e6"
  instance_type = "t2.micro"
  key_name = "Lenovo T410"
  vpc_security_group_ids = [ aws_security_group.allow_ssh.id ]
  subnet_id = aws_subnet.public.id
  associate_public_ip_address = true

  tags = {
    Name = "My Instance"
  }
}

NAT-ed Private Subnet

Instances launched in this subnet will be able to communicate with any services within VPC and go to the Internet using the special AWS service NAT Gateway.

AWS recommends using this type of network if you’re running, for example, a public-facing web application, and you don’t want to make your back-end servers publicly accessible. A typical example is a multi-tier website, with web servers in a public subnet and database servers in a private subnet. You can set up security and routing so that the web servers can communicate with the database servers.

Here’s how the infrastructure looks like:

Terraform-recipe-Managing-AWS-VPC-Public-and-Private-NAT-Subnet

To extend our VPC with this NAT-ed Private network, we need to create the following resources:

  • VPC NAT Gateway.
  • Subnet.
  • Route Table with the route to VPC NAT Gateway.
  • Association between Route Table and Subnet.

Let’s begin from Subnet, by declaring additional aws_subnet resource:

resource "aws_subnet" "nated" {
  vpc_id     = aws_vpc.my_vpc.id
  cidr_block = "10.0.1.0/24"
  availability_zone = "us-east-1a"

  tags = {
    Name = "NAT-ed Subnet"
  }
}

Now let’s create NAT Gateway in a public subnet by declaring aws_nat_gateway and aws_eip.

You can not launch NAT Gateway without Elastic IP address associated with it, that’s why aws_eip required:

resource "aws_eip" "nat_gw_eip" {
  vpc = true
}

resource "aws_nat_gateway" "gw" {
  allocation_id = aws_eip.nat_gw_eip.id
  subnet_id     = aws_subnet.public.id
}

Now we need to create Main Route Table by declaring additional already known for you resources aws_route_table and associate it with our NAT-ed Subnet (aws_route_table_association):

resource "aws_route_table" "my_vpc_us_east_1a_nated" {
    vpc_id = aws_vpc.my_vpc.id

    route {
        cidr_block = "0.0.0.0/0"
        nat_gateway_id = aws_nat_gateway.gw.id
    }

    tags = {
        Name = "Main Route Table for NAT-ed subnet"
    }
}

resource "aws_route_table_association" "my_vpc_us_east_1a_nated" {
    subnet_id = aws_subnet.nated.id
    route_table_id = aws_route_table.my_vpc_us_east_1a_nated.id
}

Now we’re ready to create private servers in our Private NAT-ed Subnet and they will have access to the Internet, but will not be visible from the Internet.

I guess you may do it using the instructions from the previous article.

Fully Isolated Private Subnet

Instances launched in this subnet will be able to communicate with instances within VPC, but will not be able to go to the Internet.

This type of network is commonly used when you need to connect your organization network to the AWS cloud and want more strict control of network boundaries. Or, you do not want to give some of your servers access to the Internet.

Here’s how the infrastructure looks like:

Terraform - Managing AWS VPC - Private NATed and Private Fully Isolated Subnets

To implement a fully isolated Private Subnet we need to create the following resources:

  • Subnet.
  • Route Table.
  • Association between Route Table and Subnet.

Let’s start from Subnet:

resource "aws_subnet" "private" {
  vpc_id     = aws_vpc.my_vpc.id
  cidr_block = "10.0.2.0/24"
  availability_zone = "us-east-1a"

  tags = {
    Name = "Isolated Private Subnet"
  }
}

Next, we need to create an additional Route Table with no routes declaration and associate it with our private Subnet:

resource "aws_route_table" "my_vpc_us_east_1a_private" {
    vpc_id = aws_vpc.my_vpc.id

    tags = {
        Name = "Local Route Table for Isolated Private Subnet"
    }
}

resource "aws_route_table_association" "my_vpc_us_east_1a_private" {
    subnet_id = aws_subnet.private.id
    route_table_id = aws_route_table.my_vpc_us_east_1a_private.id
}

Summary

In this article, you’ve learned how to create different types of AWS Private Subnets in your environment and the differences between them.

We hope, this article has been helpful for you! If so, please, help us to spread it to the world!

Stay tuned!

How useful was this post?

Click on a star to rate it!

As you found this post useful...

Follow us on social media!

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?

Top rated Udemy Courses to improve you career

Subscribe to our updates

Like this article?

Share on facebook
Share on Facebook
Share on twitter
Share on Twitter
Share on linkedin
Share on Linkdin
Share on pinterest
Share on Pinterest

Want to be an author of another post?

We’re looking for skilled technical authors for our blog!

Leave a comment

If you’d like to ask a question about the code or piece of configuration, feel free to use https://codeshare.io/ or a similar tool as Facebook comments are breaking code formatting.