Criando uma VPC com subnets publicas e privadas para cada AZ com Terraform
Tags: aws, terraform, devops, tutorial
Published: 2023-07-22 13:03:57

## Série EKS Cluster Production Ready
Esse post faz parte de uma série onde iremos construir a infraestrutura completa de um cluster Kubernetes no EKS pronto para produção. O primeiro passo para realizarmos isso é a criação de uma VPC.

### Recursos que serão criados nesse tutorial

1. Uma VPC
2. Uma subnet privada **para cada Availability Zone** na região escolhida
3. Uma subnet publica **para cada Availability Zone** na região escolhida
4. Um Internet Gateway 
5. Uma Route Table para rotear o tráfego das subnets publicas para a internet através do Internet Gateway

 

### Passo 0: Estruturando o projeto terraform com S3 backend

Estaremos utilizando um bucket S3 para salvar o estado do nosso projeto terraform, dessa forma diversas pessoas podem trabalhar no mesmo projeto tendo o _state file_ centralizado. Para isso precisamos primeiro criar um bucket, que pode ser feito pela console ou pela cli:

`aws s3api create-bucket --bucket "<account-id>-terraform-state-us-west-2" --create-bucket-configuration LocationConstraint=us-west-2 --region us-west-2`

Com o bucket criado é necessário criar os arquivos de configuração do terraform para que ele utilize esse bucket para armazenar o _state file_:

- backend.tf

```bash
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.9.0"
    }
  }
  backend "s3" {
    encrypt              = true
    workspace_key_prefix = "shared/networking"
    key                  = "terraform.tfstate"
    bucket               = "<account-id>-terraform-state-us-west-2"
    region               = "us-west-2"
  }
}
```

- provider.tf

```bash
provider "aws" {
  region = var.region
}
```

- variables.tf

```bash
variable "region" {
  type        = string
  description = "The AWS region name in which to deploy resources."
  default     = "us-west-2"
}
```

Com todos os arquivos criados, basta iniciar o terraform para que ele faça o download do provider e você possa iniciar a criar os recursos, para iniciar utilize o comando:

`terraform init`
 

### Passo 1: Criando a VPC

Para criar uma VPC devemos definir um bloco de IPs para ela, nesse exemplo iremos utilizar a rede "172.25.0.0/16", todas as subnets que iremos criar futuramente pertencerão a essa rede. O recurso da VPC é bastante simples de criar no terraform:

- main.tf

```bash
resource "aws_vpc" "devops" {
  cidr_block = "172.25.0.0/16"

  tags = {
    Name = "devops"
  }
}
```
 

### Passo 2: Criação das subnets privadas

Nossa VPC possuirá uma subnet privada para cada Availability Zone da região escolhida. Essas subnets, como o nome dizem, não terão acesso a internet de forma direta, servindo apenas para comunicação interna dentro da VPC.
Para a criação das subnets, iremos ler todas as Availability Zones disponíveis para a região escolhida, iterar sobre elas e através da função do terraform [cidrsubnet ](https://developer.hashicorp.com/terraform/language/functions/cidrsubnet) criar de forma automática, com base na rede da VPC, uma subnet com prefixo /20 para cada AZ:

Portanto, primeiro precisamos criar o recurso _data_ que nos retorne as AZs disponíveis:
- data.tf

```bash
data "aws_availability_zones" "available_zones" {
  state = "available"
  filter {
    name   = "region-name"
    values = [var.region]
  }
}
```

Agora podemos criar as subnets:

- maint.tf

```bash
resource "aws_subnet" "private" {
  count             = length(data.aws_availability_zones.available_zones.names)
  vpc_id            = aws_vpc.devops.id
  cidr_block        = cidrsubnet(aws_vpc.devops.cidr_block, 6, count.index)
  availability_zone = data.aws_availability_zones.available_zones.names[count.index]
}
```

 
### Passo 3: Criação das subnets publicas

Como no passo anterior, também iremos criar as subnets de forma automática utilizando a mesma estrutura. A principal diferença é que daremos como base para a criação das subnets a "metade final" do bloco da VPC, a rede 172.25.128.0/17. Para calcular essa rede também iremos utilizar a função [cidrsubnet ](https://developer.hashicorp.com/terraform/language/functions/cidrsubnet). 

 
Importante notar que essas subnets terão a opção `map_public_ip_on_launch = true` habilitada, para que cada instância iniciada nessas subnets possua um IP público associado a ela.

```bash
resource "aws_subnet" "public" {
  count                   = length(data.aws_availability_zones.available_zones.names)
  vpc_id                  = aws_vpc.devops.id
  cidr_block              = cidrsubnet(cidrsubnet(aws_vpc.devops.cidr_block, 2, 2), 6, count.index)
  availability_zone       = data.aws_availability_zones.available_zones.names[count.index]
  map_public_ip_on_launch = true

  tags = {
    Public = "true"
  }
}
```
 

## Passo 4: Criando o Internet Gateway
Para que a subnet pública tenha acesso a internet, é necessário a criação de um Internet Gateway, que servirá, como o nome diz, de gateway para a tabela de roteamento que criaremos a seguir:

- main.tf

```bash
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.devops.id

  tags = {
    Name = "main"
  }
}
```
 

## Passo 5: Criando a tabela de roteamento e associando as subnets públicas

Com o Internet Gateway criado, basta criar uma tabela de roteamento que utilize esse gateway e então associar todas as subnets públicas a essa tabela. 

- main.tf

```bash
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.devops.id

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

  tags = {
    Name = "public"
  }
}

resource "aws_route_table_association" "public" {
  count          = length(aws_subnet.public)
  subnet_id      = aws_subnet.public[count.index].id
  route_table_id = aws_route_table.public.id
}
```
 
## Conclusão

Dessa forma, criamos uma VPC de forma automatizada utilizando infraestrutura como código através do Terraform. Com esse código, a VPC pode ser criada em qualquer região da AWS que as subnets serão provisionadas corretamente em todas as availability zones. 🚀
⠀
Notem, que o único parâmetro de rede que passamos foi o bloco de rede da VPC (172.25.0.0/16), todos os outros cálculos de subnet foram feitos de forma automática.
⠀
Todo o código criado aqui pode ser encontrado no meu github: [https://github.com/guilinden/basic-vpc](https://github.com/guilinden/basic-vpc) 
⠀
O próximo passo é transformar isso em módulo terraform para poder ser reutilizado em diversos projetos, permitindo a rápida criação da estrutura base de uma VPC.
⠀
Para a criação do módulo terraform nos vemos no próximo post 😁