Última revisión: mayo de 2026
Crea los servicios de AWS del examen ANS-C01 con Terraform puro: bloque a bloque, cada uno vinculado a un dominio del examen. El mismo código funciona en OpenTofu.
Al final de este laboratorio, habrá aprovisionado, con Terraform simple, la troncal multi-VPC canónica de AWS — dos VPCs de doble pila (IPv4 + IPv6) en la misma región, conectadas a través de una Transit Gateway con asociaciones explícitas de tablas de enrutamiento, y Registros de Flujo de VPC respaldados por CloudWatch en la VPC principal para que pueda ver lo que está atravesando su red. Esta es la arquitectura que asume cada pregunta multi-VPC del ANS-C01.
Cada recurso es Terraform simple. Coloque los fragmentos en un solo archivo main.tf, ejecute terraform init, luego terraform apply paso a paso.
>= 1.5 o OpenTofu >= 1.6.us-east-1.La mayor parte de este laboratorio es económico o gratuito, pero la Transit Gateway no lo es:
La tarifa por hora de TGW es el costo principal de este laboratorio. Dos conexiones × $0.05/hora × 24 horas × 30 días ≈ $72/mes mientras esté en ejecución. Destrúyala tan pronto como haya terminado de explorar — TGW es la mayor trampa de costos en cualquier laboratorio ANS-C01.
Introducción estándar. Transit Gateway es regional — todas las conexiones deben estar en la región donde reside la TGW. Para conectividad entre regiones, añadiría emparejamiento de TGW (fuera del alcance para v1). Por defecto usamos us-east-1.
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-ans-c01"
ManagedBy = "terraform"
}
}
}
data "aws_availability_zones" "available" {
state = "available"
}El ANS-C01 prueba específicamente las VPCs de doble pila — AWS ahora asigna por defecto un IPv6 /56 a cada nueva VPC si establece assign_generated_ipv6_cidr_block = true. El dominio de Diseño de Red del examen prueba tanto la matemática de planificación de CIDR IPv4 ( /16s sin superposición si desea hacer emparejamiento o adjuntar a TGW) como la derivación de subredes IPv6 (cada subred obtiene un /64 extraído del /56 de la VPC).
Asignamos IPv4 10.0.0.0/16 y un IPv6 /56 generado automáticamente por AWS. La única subred aquí utiliza un bloque IPv4 /24 y un bloque IPv6 /64 extraído del /56 de la VPC — cidrsubnet es la función incorporada de Terraform para ese cálculo. El internet gateway es de doble pila por defecto en las regiones modernas de AWS.
resource "aws_vpc" "primary" {
cidr_block = "10.0.0.0/16"
assign_generated_ipv6_cidr_block = true
enable_dns_hostnames = true
tags = { Name = "certlabpro-ans-c01-primary" }
}
resource "aws_subnet" "primary_a" {
vpc_id = aws_vpc.primary.id
cidr_block = "10.0.1.0/24"
ipv6_cidr_block = cidrsubnet(aws_vpc.primary.ipv6_cidr_block, 8, 1)
availability_zone = data.aws_availability_zones.available.names[0]
assign_ipv6_address_on_creation = true
tags = { Name = "certlabpro-ans-c01-primary-a" }
}
resource "aws_internet_gateway" "primary" {
vpc_id = aws_vpc.primary.id
}Construimos una segunda VPC en 10.1.0.0/16 — deliberadamente sin superposición con el 10.0.0.0/16 de la VPC #1. El ANS-C01 insiste en esta regla de diseño porque en el momento en que desea conectar dos VPCs (emparejamiento, TGW, cualquier cosa), los CIDRs superpuestos lo prohíben a nivel de la API de AWS. No puede enrutar a un CIDR que también se reclama localmente.
La VPC #2 también obtiene su propio IPv6 /56 generado automáticamente por AWS (cada VPC obtiene un bloque globalmente único, por lo que no hay riesgo de superposición de IPv6 por defecto). La matemática de asignación de subredes tiene la misma forma que el Paso 2.
resource "aws_vpc" "secondary" {
cidr_block = "10.1.0.0/16"
assign_generated_ipv6_cidr_block = true
enable_dns_hostnames = true
tags = { Name = "certlabpro-ans-c01-secondary" }
}
resource "aws_subnet" "secondary_a" {
vpc_id = aws_vpc.secondary.id
cidr_block = "10.1.1.0/24"
ipv6_cidr_block = cidrsubnet(aws_vpc.secondary.ipv6_cidr_block, 8, 1)
availability_zone = data.aws_availability_zones.available.names[0]
assign_ipv6_address_on_creation = true
tags = { Name = "certlabpro-ans-c01-secondary-a" }
}La Transit Gateway es el hub. Escala a miles de conexiones de VPC, soporta el intercambio entre cuentas a través de AWS Resource Access Manager (RAM) y le proporciona una única tabla de enrutamiento para razonar en lugar de N² conexiones de emparejamiento. El ANS-C01 prueba esta elección de hub-and-spoke sobre el emparejamiento de VPC siempre que la pregunta menciona “más de tres VPCs” o “a medida que nuestra red crece”.
Creamos la TGW con la asociación y propagación predeterminada de la tabla de rutas deshabilitada — ese es el patrón más probado del ANS-C01 porque lo obliga a ser explícito sobre qué conexiones pueblan qué tablas de enrutamiento. La autoasociación es la configuración de conveniencia; la manual es la configuración amigable para auditorías.
El recurso de conexión es el puente por VPC. Con ambas VPCs conectadas, la TGW conoce sus CIDRs; todavía necesitamos añadir rutas desde la tabla de enrutamiento principal de cada VPC apuntando a la TGW (Paso 5).
resource "aws_ec2_transit_gateway" "hub" {
description = "certlabpro-ans-c01 hub"
default_route_table_association = "disable"
default_route_table_propagation = "disable"
multicast_support = "disable"
tags = { Name = "certlabpro-ans-c01-tgw" }
}
resource "aws_ec2_transit_gateway_route_table" "main" {
transit_gateway_id = aws_ec2_transit_gateway.hub.id
tags = { Name = "certlabpro-ans-c01-tgw-rt" }
}
resource "aws_ec2_transit_gateway_vpc_attachment" "primary" {
transit_gateway_id = aws_ec2_transit_gateway.hub.id
vpc_id = aws_vpc.primary.id
subnet_ids = [aws_subnet.primary_a.id]
transit_gateway_default_route_table_association = false
transit_gateway_default_route_table_propagation = false
}
resource "aws_ec2_transit_gateway_vpc_attachment" "secondary" {
transit_gateway_id = aws_ec2_transit_gateway.hub.id
vpc_id = aws_vpc.secondary.id
subnet_ids = [aws_subnet.secondary_a.id]
transit_gateway_default_route_table_association = false
transit_gateway_default_route_table_propagation = false
}
resource "aws_ec2_transit_gateway_route_table_association" "primary" {
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.primary.id
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.main.id
}
resource "aws_ec2_transit_gateway_route_table_association" "secondary" {
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.secondary.id
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.main.id
}
resource "aws_ec2_transit_gateway_route_table_propagation" "primary" {
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.primary.id
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.main.id
}
resource "aws_ec2_transit_gateway_route_table_propagation" "secondary" {
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.secondary.id
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.main.id
}La TGW del Paso 4 conoce ambas VPCs, pero la tabla de enrutamiento de cada VPC aún no sabe cómo llegar a la otra. Añadimos rutas explícitas en ambas direcciones: la tabla de rutas de la VPC #1 envía el tráfico 10.1.0.0/16 a la TGW, y viceversa. El examen prueba repetidamente este requisito de doble lado — “Conecté ambos a la TGW, ¿por qué no pueden hacer ping?” es casi siempre una ruta de retorno faltante.
Finalmente, los Registros de Flujo de VPC. El dominio de Monitorización de Red del ANS-C01 los prueba como la única forma de ver qué paquetes están realmente atravesando su red — aceptados, rechazados y solo metadatos (quíntuple + bytes + paquetes + resultado). Los activamos para la VPC principal, con los registros fluyendo a un grupo de registros de CloudWatch dedicado. El rol de IAM que adjuntamos es el que asumen los Registros de Flujo para escribir en el grupo de registros.
Con las rutas en su lugar y los Registros de Flujo en funcionamiento, la troncal está completa. Dos VPCs de doble pila, conectadas a través de una TGW con enrutamiento explícito (amigable para auditorías), con visibilidad a nivel de paquete en el lado principal. Cada patrón adicional del ANS-C01 (Direct Connect Gateway, emparejamiento de TGW, NAT, PrivateLink, puntos finales de VPC) se ancla a esta base.
resource "aws_route" "primary_to_secondary" {
route_table_id = aws_vpc.primary.main_route_table_id
destination_cidr_block = "10.1.0.0/16"
transit_gateway_id = aws_ec2_transit_gateway.hub.id
depends_on = [aws_ec2_transit_gateway_vpc_attachment.primary]
}
resource "aws_route" "secondary_to_primary" {
route_table_id = aws_vpc.secondary.main_route_table_id
destination_cidr_block = "10.0.0.0/16"
transit_gateway_id = aws_ec2_transit_gateway.hub.id
depends_on = [aws_ec2_transit_gateway_vpc_attachment.secondary]
}
# ── VPC Flow Logs ─────────────────────────────────────────────
resource "aws_cloudwatch_log_group" "vpc_flow" {
name = "/aws/vpc-flow/certlabpro-ans-c01-primary"
retention_in_days = 30
}
resource "aws_iam_role" "vpc_flow" {
name = "certlabpro-ans-c01-vpc-flow"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "vpc-flow-logs.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_role_policy" "vpc_flow" {
name = "write-flow-logs"
role = aws_iam_role.vpc_flow.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams",
]
Resource = aws_cloudwatch_log_group.vpc_flow.arn
}]
})
}
resource "aws_flow_log" "primary" {
vpc_id = aws_vpc.primary.id
traffic_type = "ALL"
log_destination_type = "cloud-watch-logs"
log_destination = aws_cloudwatch_log_group.vpc_flow.arn
iam_role_arn = aws_iam_role.vpc_flow.arn
max_aggregation_interval = 60
}terraform destroy destruye todo en este laboratorio, pero tenga cuidado con el orden — las conexiones de Transit Gateway tardan de 5 a 10 minutos en desconectarse, y la propia TGW no se puede eliminar hasta que ambas conexiones hayan desaparecido por completo. terraform destroy maneja correctamente el gráfico de dependencias, pero la operación no es rápida. No presione Ctrl-C a mitad de la destrucción o terminará con conexiones a medio desconectar que tendrá que limpiar a través de la consola.
La razón principal para destruir rápidamente es la tarifa por hora de TGW — dos conexiones a $0.05/hora cada una = $72/mes combinados. El costo del laboratorio se acumula rápidamente si olvida que está en ejecución.
El ANS-C01 cubre superficies de red que este laboratorio no puede incluir — Direct Connect (no hay entorno de prueba sin un puerto físico), AWS Site-to-Site VPN (necesita un punto final del lado del cliente), puntos finales de entrada/salida de Route 53 Resolver para DNS híbrido, servicios de punto final de PrivateLink + VPC, AWS Network Firewall, AWS Global Accelerator, comprobaciones de estado + conmutación por error de Route 53, Network Access Analyzer, Reachability Analyzer, emparejamiento de Transit Gateway (entre regiones), Cloud WAN, AWS App Mesh y escenarios específicos de BGP (filtrado de rutas, prepend, manipulación de AS-PATH).
Nos ceñimos a la forma de troncal multi-VPC porque es la arquitectura más probada en el examen — las conexiones de Direct Connect, los túneles VPN, el DNS híbrido y PrivateLink, todos se anclan a este tipo de hub de TGW. Entienda bien el hub-and-spoke; los tipos de «spoke» son extensiones de él.
Para las superficies no aprovisionadas, las secciones Buscar, Manual y Editorial de esta página de certificación tienen cobertura conceptual. Un laboratorio de seguimiento que añada Route 53 Resolver + una conexión VPN + PrivateLink completaría la historia de la red híbrida.