It's the moment of truth! In this chapter, you will build your first real infrastructure with Terraform, putting together everything you've learned: the AWS services from Part II and the Terraform language from Part III. We start with the foundation of any architecture: a VPC with subnets. Remember the concepts from Chapter 6, which you will now write in code.

What we are going to build

Throughout the chapter, we will set up a simple but complete architecture:

┌──────────── VPC (10.0.0.0/16) ────────────┐
│                                            │
│   ┌─ Public subnet (10.0.1.0/24) ─┐        │
│   │   (our server will go here)    │       │
│   └───────────────────────────────┘        │
│                                            │
│   + Internet Gateway (gateway to internet) │
│   + Route Table (routes)                   │
└────────────────────────────────────────────┘

In this subchapter, we create the VPC, a subnet, and basic internet connectivity. In the following ones, we will add the server, the firewall, the IP, and the outputs.

Step 1: Configure the provider

Every project starts by configuring the AWS provider (remember subchapter 11.1). We create a file, for example main.tf:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "eu-west-1"   # Ireland (choose your region, Chapter 3)
}

Step 2: Create the VPC

The VPC is our private network (remember subchapter 6.1). With a range of 10.0.0.0/16:

resource "aws_vpc" "principal" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "mi-primera-vpc"
  }
}
  • cidr_block defines the address range (subchapter 6.1).
  • The enable_dns_* options allow resources to have DNS names (useful for the server to have a name).
  • tags gives a human-readable name to the resource (it's highly recommended to tag everything).

Step 3: Create a public subnet

Inside the VPC, we create a subnet (subchapter 6.2). We place it in a specific availability zone:

resource "aws_subnet" "publica" {
  vpc_id                  = aws_vpc.principal.id    # ← reference to the VPC
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "eu-west-1a"
  map_public_ip_on_launch = true                    # automatic public IP

  tags = {
    Name = "subred-publica"
  }
}

Notice vpc_id = aws_vpc.principal.id: it's a reference (subchapter 10.3). We tell the subnet "you belong to the VPC I created before." This creates the dependency: Terraform knows it must create the VPC first.

map_public_ip_on_launch = true makes resources in this subnet automatically receive a public IP, part of what makes it "public."

Step 4: Create the Internet Gateway

For the subnet to be truly public, it needs a gateway to the internet (subchapter 6.3):

resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.principal.id

  tags = {
    Name = "mi-igw"
  }
}

This creates the Internet Gateway and connects it to our VPC.

Step 5: Create the Route Table and associate it

The Internet Gateway alone is not enough: you have to tell the subnet to use that gateway to access the internet. This is done with a route table (subchapter 6.4):

resource "aws_route_table" "publica" {
  vpc_id = aws_vpc.principal.id

  route {
    cidr_block = "0.0.0.0/0"                       # all internet
    gateway_id = aws_internet_gateway.igw.id       # goes out through the IGW
  }

  tags = {
    Name = "rt-publica"
  }
}

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

This is exactly what we saw in subchapter 6.4: the route 0.0.0.0/0 → Internet Gateway is what makes the subnet public. The route_table_association connects the table to our subnet.

The result

With these five steps, you have a functional network:

✓ VPC (10.0.0.0/16)
✓ Public subnet (10.0.1.0/24) in eu-west-1a
✓ Internet Gateway connected
✓ Route Table that sends internet traffic through the IGW
✓ Association of the table to the subnet

If you now run terraform init and terraform plan (subchapter 11.4), you would see something like:

Plan: 5 to add, 0 to change, 0 to destroy.
  + aws_vpc.principal
  + aws_subnet.publica
  + aws_internet_gateway.igw
  + aws_route_table.publica
  + aws_route_table_association.publica

And with terraform apply (typing yes), Terraform would create the entire network in the correct order automatically, thanks to the references between resources.

The power of this: you just defined a complete network in a few lines of text. You can reuse, version in Git, and recreate this same configuration as many times as you want (remember the problems of manual provisioning from Chapter 9). And if you delete it with destroy, it disappears cleanly.

What you should remember

  • Every architecture starts with the network: VPC + subnets + connectivity.
  • The steps: configure the provider, create the VPC, the subnet, the Internet Gateway, the Route Table, and its association.
  • References (aws_vpc.principal.id) connect resources and create dependencies, so Terraform creates them in the correct order.
  • The route 0.0.0.0/0 to the Internet Gateway is what makes the subnet public (just as we saw in Chapter 6, now in code).
  • Tag (tags) all your resources with readable names: it's a good practice.

In the next subchapter, we will put an EC2 server inside this public subnet.

Cloud, AWS & Terraform — From Zero to Expert

Chapter 1 · What is cloud computing

Chapter 2 · The cloud market and major providers

Chapter 3 · Regions, availability zones and edge

Chapter 4 · Compute: EC2

Chapter 5 · Storage: S3

Chapter 6 · Networking: VPC

Chapter 7 · Identity and access: IAM

Chapter 8 · Managed databases

Chapter 9 · Why Infrastructure as Code

Chapter 10 · HCL: the Terraform language

Chapter 11 · Providers and state

Chapter 12 · Your first real infrastructure in Terraform

Chapter 13 · Load balancing and auto scaling

Chapter 14 · Serverless with Lambda

Chapter 15 · Messaging and events

Chapter 16 · Content delivery and DNS

Chapter 17 · Containers on AWS

Chapter 18 · Modules: reuse and composition

Chapter 19 · Workspaces and environment management

Chapter 20 · Remote backends and locking

Chapter 21 · Infrastructure testing

Chapter 22 · Terraform in CI/CD

Chapter 23 · Defense in depth

Chapter 24 · Observability: logs, metrics and traces

Chapter 25 · Cost optimization

Chapter 26 · High availability and disaster recovery

Chapter 27 · AWS Well-Architected Framework

Chapter 28 · Serverless architectures at scale

Chapter 29 · Data platforms on AWS

Chapter 30 · Multi-account and landing zones

Chapter 31 · Platform Engineering and Internal Developer Platform

Chapter 32 · Relevant AWS certifications

Chapter 33 · Projects to consolidate what you've learned

Chapter 34 · Resources and community

© Copyright 2024. All rights reserved