Última revisão: maio de 2026
Construa os serviços da AWS do exame SAA-C03 com Terraform puro — um bloco de cada vez, cada um vinculado a um domínio do exame. O mesmo código funciona no OpenTofu.
Ao final deste laboratório, você terá provisionado, com Terraform puro, uma pilha web de alta disponibilidade multi-AZ conforme o livro — uma VPC personalizada com sub-redes públicas e privadas em duas AZs, um Application Load Balancer voltado para a internet, um Auto Scaling Group de instâncias EC2 na camada privada e um banco de dados RDS multi-AZ para o aplicativo se comunicar. Cinco pilares do exame em cinco passos.
Cada recurso é Terraform puro — o mesmo código funciona sem modificações no OpenTofu. Sem variáveis, sem módulos, sem estado remoto. Adicione os trechos de código em um único main.tf, execute terraform init uma vez e, em seguida, terraform apply passo a passo.
>= 1.5 ou OpenTofu >= 1.6.us-east-1 (região padrão para este laboratório — escolha a que quiser, mas a pesquisa de AMI no Passo 3 assume que a região possui Amazon Linux 2023).skip_final_snapshot = true para que a exclusão seja limpa — nunca use essa configuração em produção.A maior parte deste laboratório está no Nível Gratuito ou próximo a ele: a VPC, ALB, ASG, grupos de segurança, IAM e monitoramento CloudWatch são gratuitos. Os dois itens que geram cobrança em modo ocioso:
Se você é sensível a custos, defina db_instance.multi_az = false para o laboratório e leia a documentação Multi-AZ separadamente. O exame ainda recompensa o conhecimento do atributo, mesmo que você não execute o padrão completo de HA. Destrua quando terminar.
Fixamos o provedor AWS ~> 5.60 e escolhemos us-east-1 (qualquer região com pelo menos duas AZs funciona). O bloco data busca a lista de AZs disponíveis no momento do planejamento — codificar nomes de AZs como us-east-1a é um antipadrão do SAA-C03 porque o mapeamento de nome de AZ para zona física é específico da conta (sua us-east-1a pode ser uma AZ física diferente da minha).
Todos os recursos que criamos posteriormente são marcados com um único nome de projeto via default_tags — o Cost Explorer + as regras do AWS Config funcionam com tags, e o exame espera que você marque tudo.
terraform {
required_version = ">= 1.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.60"
}
}
}
provider "aws" {
region = "us-east-1"
default_tags {
tags = {
Project = "certlabpro-saa-c03"
ManagedBy = "terraform"
}
}
}
data "aws_availability_zones" "available" {
state = "available"
}Toda questão de alta disponibilidade do SAA-C03 assume que você distribuirá a carga de trabalho por pelo menos duas Zonas de Disponibilidade. Criamos uma VPC /16 e separamos quatro sub-redes /20 — duas públicas (para o ALB), duas privadas (para as instâncias EC2 e RDS). O gateway de internet se anexa à VPC; a tabela de rotas pública envia 0.0.0.0/0 através dele.
As sub-redes privadas deliberadamente NÃO possuem um gateway NAT neste laboratório — os NAT GWs cobram aproximadamente US$32/mês ociosos (por AZ) e o SAA-C03 testa explicitamente essa troca em questões de custo. Se seu aplicativo precisasse de internet de saída das sub-redes privadas em produção, você adicionaria um NAT (ou uma instância NAT, a alternativa mais barata do SAA-C03).
A VPC + sub-redes + IGW + tabela de rotas deste passo são a tela para tudo o que se segue — o ALB se conecta às sub-redes públicas, as instâncias do ASG vivem nas privadas, e o grupo de sub-redes RDS no Passo 5 abrange ambas as AZs privadas.
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
tags = { Name = "certlabpro-saa-c03-vpc" }
}
resource "aws_subnet" "public" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = { Name = "certlabpro-saa-c03-public-${count.index}" }
}
resource "aws_subnet" "private" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index + 10}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = { Name = "certlabpro-saa-c03-private-${count.index}" }
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
}
resource "aws_route_table_association" "public" {
count = 2
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}Um Application Load Balancer é o balanceador de carga que o SAA-C03 espera que você use sempre que a pergunta disser "HTTP / HTTPS" ou "roteamento baseado em caminho" ou "alvo um serviço específico". Network Load Balancers lidam com TCP/UDP e latência ultrabaixa; o Classic é legado. ALB é a escolha.
O ALB reside nas duas sub-redes públicas do Passo 2 — é isso que "multi-AZ" significa estruturalmente. Seu grupo de segurança aceita HTTP (porta 80) de qualquer lugar; o grupo de destino obterá seus membros do ASG que criamos no Passo 4. A verificação de saúde é o contrato entre o ALB e o destino — se / retornar diferente de 200, o ALB para de enviar tráfego para aquela instância.
Sem HTTPS neste laboratório — isso requer um certificado ACM e um nome DNS, que são dois serviços adicionais que não precisamos para tornar o padrão de HA visível. Adicione ACM em produção.
resource "aws_security_group" "alb" {
name = "certlabpro-saa-c03-alb"
description = "ALB ingress on port 80 from the internet"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
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"]
}
}
resource "aws_lb" "web" {
name = "certlabpro-saa-c03-alb"
load_balancer_type = "application"
internal = false
subnets = aws_subnet.public[*].id
security_groups = [aws_security_group.alb.id]
}
resource "aws_lb_target_group" "web" {
name = "certlabpro-saa-c03-tg"
port = 80
protocol = "HTTP"
target_type = "instance"
vpc_id = aws_vpc.main.id
health_check {
path = "/"
matcher = "200-299"
interval = 30
timeout = 5
healthy_threshold = 2
unhealthy_threshold = 3
}
}
resource "aws_lb_listener" "http" {
load_balancer_arn = aws_lb.web.arn
port = 80
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.web.arn
}
}Auto Scaling é o pilar de "elasticidade" do AWS Well-Architected e o segundo tópico mais testado no SAA-C03 depois de Multi-AZ. Combinado com o ALB do Passo 3, um ASG oferece tolerância a falhas (instâncias substituídas quando falham) e escalabilidade (a contagem de instâncias acompanha a demanda) — os dois resultados que o SAA-C03 continua a questionar.
O modelo de lançamento define como cada nova instância se parece. Usamos a AMI mais recente do Amazon Linux 2023, uma t3.micro, o SG equivalente ao do Passo 2 que aceita tráfego apenas do SG do ALB (privilégio mínimo na camada de rede), e um user-data mínimo que inicia o nginx para que a verificação de saúde passe.
O ASG conecta três coisas: onde as instâncias são executadas (vpc_zone_identifier = nossas sub-redes privadas, ambas as AZs), quantas devem existir (min_size = 2, max_size = 4 — duas para HA, margem para escalabilidade), e como as novas instâncias se juntam ao balanceador de carga (target_group_arns). Quando o ASG lança uma instância, ela é automaticamente registrada no grupo de destino do Passo 3.
resource "aws_security_group" "app" {
name = "certlabpro-saa-c03-app"
description = "App instances accept traffic only from the ALB SG"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
security_groups = [aws_security_group.alb.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
data "aws_ami" "al2023" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-kernel-6.1-x86_64"]
}
}
resource "aws_launch_template" "app" {
name_prefix = "certlabpro-saa-c03-app-"
image_id = data.aws_ami.al2023.id
instance_type = "t3.micro"
vpc_security_group_ids = [aws_security_group.app.id]
metadata_options {
http_tokens = "required"
}
user_data = base64encode(<<-EOT
#!/bin/bash
dnf install -y nginx
systemctl enable --now nginx
EOT
)
}
resource "aws_autoscaling_group" "app" {
name = "certlabpro-saa-c03-app-asg"
vpc_zone_identifier = aws_subnet.private[*].id
target_group_arns = [aws_lb_target_group.web.arn]
health_check_type = "ELB"
min_size = 2
max_size = 4
desired_capacity = 2
launch_template {
id = aws_launch_template.app.id
version = "$Latest"
}
}A joia da coroa de qualquer história multi-AZ do SAA-C03 é um banco de dados RDS Multi-AZ. A configuração multi_az = true é um dos atributos mais testados em todo o exame: ela instrui o RDS a provisionar uma réplica em espera síncrona em uma segunda AZ. Quando o primário falha, o RDS promove automaticamente o em espera — um failover típico leva ~60 segundos sem perda de dados. Dois bancos de dados de AZ única NÃO lhe dariam isso; a replicação manual NÃO lhe daria isso. Multi-AZ é a resposta para qualquer questão de "failover em menos de um minuto, zero perda de dados".
O grupo de sub-redes do DB precisa de sub-redes em pelo menos duas AZs — alimentamos com as sub-redes privadas do Passo 2. O grupo de segurança aceita a porta do banco de dados (5432 para PostgreSQL) apenas do SG do aplicativo, espelhando o padrão de segurança em camadas do Passo 4.
Com esta peça final no lugar, a pilha está completa: o tráfego entra no ALB em qualquer AZ pública, se distribui para as instâncias do ASG em qualquer AZ privada, e essas instâncias se comunicam com o primário do RDS (que possui um em espera ativo aguardando na outra AZ). Qualquer coisa, exceto uma falha total da região, possui um caminho de recuperação.
resource "aws_db_subnet_group" "main" {
name = "certlabpro-saa-c03"
subnet_ids = aws_subnet.private[*].id
}
resource "aws_security_group" "db" {
name = "certlabpro-saa-c03-db"
description = "DB accepts traffic only from the app SG"
vpc_id = aws_vpc.main.id
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.app.id]
}
}
resource "aws_db_instance" "main" {
identifier = "certlabpro-saa-c03"
engine = "postgres"
engine_version = "16"
instance_class = "db.t3.micro"
allocated_storage = 20
storage_encrypted = true
multi_az = true # the SAA-C03 headline
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = [aws_security_group.db.id]
username = "appuser"
password = "ChangeMe-Not-For-Prod-1234" # use Secrets Manager in production
skip_final_snapshot = true # lab-only setting; never use on prod
apply_immediately = true
}terraform destroy derruba tudo neste laboratório. Duas observações:
skip_final_snapshot = true, então destroy é concluído em alguns minutos sem deixar um snapshot. Nunca defina essa flag em um banco de dados de produção — a perda do snapshot final é a perda permanente de dados.destroy para o próprio ASG não é concluído até que todas as instâncias tenham desaparecido, o que pode levar de 2 a 3 minutos. Tenha paciência.Ctrl-C no meio do destroy — deixe-o terminar.O SAA-C03 abrange mais padrões arquitetônicos do que qualquer laboratório pode demonstrar — CloudFront para distribuição global de conteúdo, Route 53 para failover baseado em DNS, replicação entre regiões do S3, Aurora Global Database, Direct Connect, emparelhamento de VPC, Transit Gateway, ElastiCache, EFS, FSx, e muitos mais.
Deliberadamente, nos apegamos ao único padrão mais testado no exame: HA multi-AZ dentro de uma única região. Essa é a arquitetura que aparece em toda entrevista de Arquiteto de Soluções e em aproximadamente 30% das questões do SAA-C03. Os 70% restantes — padrões globais, cache, redes avançadas, nuvem híbrida — são abordados conceitualmente nas seções Navegar e Editorial desta página de certificação. Cada tópico de região cruzada ou rede avançada merece seu próprio laboratório; construir uma mega-pilha diluiria a disciplina de narrativa de construção da qual este formato depende.
Se você deseja praticar com os padrões de região cruzada (S3 CRR, Aurora Global, verificações de saúde do Route 53), eles se encaixam perfeitamente na mesma forma de Terraform puro e são bons candidatos para laboratórios de acompanhamento.