Biblioteca / Terraform / IaC
Terraform Starter Pack - AWS v2.0
14 modulos Terraform listos para produccion: VPC EC2 RDS S3 IAM CloudWatch y pipeline CI/CD.
Tabla de contenido
Capitulo 1
Introduccion a IaC con Terraform en AWS
Infrastructure as Code convierte la infraestructura en software versionable revisable y reproducible. Terraform es hoy el estandar de facto para gestionar infraestructura cloud de forma declarativa.
ClickOps vs Terraform
| Aspecto | Consola AWS ClickOps | Terraform IaC |
|---|---|---|
| Reproducibilidad | Imposible cada entorno es diferente | Identico en dev staging y produccion |
| Revision de cambios | No hay historial | Pull request con diff completo |
| Colaboracion | Un solo usuario a la vez | Multiples ingenieros con control de versiones |
| Aprovisionamiento | Horas o dias | Minutos con terraform apply |
| Deteccion de drift | Manual | Automatica con terraform plan |
| Rollback | Imposible o muy lento | terraform apply a version anterior |
Estructura de proyecto recomendada
infra/ ├── environments/ │ ├── dev/ │ │ ├── main.tf # llamadas a modulos para dev │ │ ├── variables.tf # valores especificos de dev │ │ └── backend.tf # backend S3 para dev │ ├── staging/ │ └── prod/ ├── modules/ │ ├── vpc/ │ ├── ec2/ │ ├── rds/ │ ├── s3/ │ ├── iam/ │ └── cloudwatch/ └── README.md
Usa el mismo modulo en todos los entornos cambiando solo las variables. Nunca copies y pegues bloques de HCL entre entornos.
Capitulo 2
Backend remoto y gestion de estado
El estado de Terraform es el mapa entre tu codigo y los recursos reales en AWS. Sin backend remoto compartido no puedes trabajar en equipo.
Bootstrap del backend S3 + DynamoDB
# S3 bucket para estado
aws s3api create-bucket --bucket tf-state-CUENTA-REGION --region us-east-1
aws s3api put-bucket-versioning \
--bucket tf-state-CUENTA-REGION \
--versioning-configuration Status=Enabled
aws s3api put-bucket-encryption \
--bucket tf-state-CUENTA-REGION \
--server-side-encryption-configuration \
'{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"}}]}'
# DynamoDB para locking
aws dynamodb create-table \
--table-name tf-state-lock \
--attribute-definitions AttributeName=LockID,AttributeType=S \
--key-schema AttributeName=LockID,KeyType=HASH \
--billing-mode PAY_PER_REQUESTConfiguracion del backend en cada entorno
terraform {
backend "s3" {
bucket = "tf-state-123456789-us-east-1"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "tf-state-lock"
}
required_providers {
aws = { source = "hashicorp/aws"; version = "~> 5.0" }
}
required_version = ">= 1.6.0"
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = var.environment
ManagedBy = "terraform"
}
}
}Capitulo 3
Modulo VPC - red base
La VPC es la red privada virtual de tu infraestructura. Un modulo bien disenado se reutiliza en todos los entornos sin modificacion.
Modulo VPC con tres capas
resource "aws_vpc" "this" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
}
resource "aws_subnet" "public" {
count = length(var.availability_zones)
vpc_id = aws_vpc.this.id
cidr_block = cidrsubnet(var.vpc_cidr, 4, count.index)
availability_zone = var.availability_zones[count.index]
map_public_ip_on_launch = false
}
resource "aws_subnet" "private" {
count = length(var.availability_zones)
vpc_id = aws_vpc.this.id
cidr_block = cidrsubnet(var.vpc_cidr, 4, count.index + 4)
availability_zone = var.availability_zones[count.index]
}
resource "aws_subnet" "data" {
count = length(var.availability_zones)
vpc_id = aws_vpc.this.id
cidr_block = cidrsubnet(var.vpc_cidr, 4, count.index + 8)
availability_zone = var.availability_zones[count.index]
}
resource "aws_internet_gateway" "this" { vpc_id = aws_vpc.this.id }
resource "aws_nat_gateway" "this" {
count = length(var.availability_zones)
allocation_id = aws_eip.nat[count.index].id
subnet_id = aws_subnet.public[count.index].id
depends_on = [aws_internet_gateway.this]
}
resource "aws_flow_log" "this" {
vpc_id = aws_vpc.this.id
traffic_type = "ALL"
log_destination = aws_s3_bucket.flow_logs.arn
log_destination_type = "s3"
}Capitulo 4
Modulos de computo EC2 y Auto Scaling
El modulo de computo combina Launch Template Auto Scaling Group y ALB para crear un servicio escalable y tolerante a fallos.
Launch Template con ASG y politica de escalado
resource "aws_launch_template" "app" {
name_prefix = "${var.app_name}-"
image_id = var.ami_id
instance_type = var.instance_type
vpc_security_group_ids = [aws_security_group.app.id]
iam_instance_profile { name = aws_iam_instance_profile.app.name }
metadata_options {
http_endpoint = "enabled"
http_tokens = "required"
http_put_response_hop_limit = 1
}
monitoring { enabled = true }
lifecycle { create_before_destroy = true }
}
resource "aws_autoscaling_group" "app" {
name = "${var.app_name}-asg"
vpc_zone_identifier = var.private_subnet_ids
target_group_arns = [aws_lb_target_group.app.arn]
health_check_type = "ELB"
min_size = var.asg_min
max_size = var.asg_max
desired_capacity = var.asg_desired
launch_template { id = aws_launch_template.app.id; version = "$Latest" }
instance_refresh {
strategy = "Rolling"
preferences { min_healthy_percentage = 75 }
}
}
resource "aws_autoscaling_policy" "cpu" {
name = "cpu-tracking"
autoscaling_group_name = aws_autoscaling_group.app.name
policy_type = "TargetTrackingScaling"
target_tracking_configuration {
predefined_metric_specification {
predefined_metric_type = "ASGAverageCPUUtilization"
}
target_value = 70.0
}
}Capitulo 5
Modulos de datos RDS y S3
Los datos son el activo mas critico. El modulo implementa Multi-AZ cifrado obligatorio y backups automatizados desde el primer deploy.
RDS Multi-AZ PostgreSQL con todas las protecciones
resource "aws_db_instance" "postgres" {
identifier = "${var.app_name}-${var.environment}"
engine = "postgres"
engine_version = "16.2"
instance_class = var.db_instance_class
allocated_storage = var.db_storage_gb
storage_type = "gp3"
db_name = var.db_name
username = var.db_username
multi_az = true
db_subnet_group_name = aws_db_subnet_group.this.name
vpc_security_group_ids = [aws_security_group.db.id]
backup_retention_period = 30
backup_window = "03:00-04:00"
storage_encrypted = true
kms_key_id = var.kms_key_arn
monitoring_interval = 60
monitoring_role_arn = aws_iam_role.rds_monitoring.arn
performance_insights_enabled = true
enabled_cloudwatch_logs_exports = ["postgresql", "upgrade"]
deletion_protection = true
skip_final_snapshot = false
final_snapshot_identifier = "${var.app_name}-final"
}Capitulo 6
IAM seguridad y cumplimiento como codigo
Implementar seguridad como codigo garantiza que los controles se aplican en cada deploy no solo cuando alguien lo recuerda.
AWS Config y CloudTrail automatizados
resource "aws_config_config_rule" "root_mfa" {
name = "root-account-mfa-enabled"
source {
owner = "AWS"
source_identifier = "ROOT_ACCOUNT_MFA_ENABLED"
}
}
resource "aws_config_config_rule" "s3_public" {
name = "s3-bucket-public-read-prohibited"
source {
owner = "AWS"
source_identifier = "S3_BUCKET_PUBLIC_READ_PROHIBITED"
}
}
resource "aws_cloudtrail" "this" {
name = "cloudtrail-all-regions"
s3_bucket_name = aws_s3_bucket.cloudtrail.id
include_global_service_events = true
is_multi_region_trail = true
enable_log_file_validation = true
kms_key_id = var.kms_key_arn
}Capitulo 7
Observabilidad CloudWatch y alertas
La observabilidad no es opcional en produccion. Sin metricas y alertas los problemas se descubren cuando los usuarios los reportan.
Modulo de alarmas criticas reutilizable
locals {
alarms = {
cpu_high = {
metric = "CPUUtilization"
namespace = "AWS/EC2"
threshold = 80
description = "CPU mayor 80% en produccion"
}
rds_connections = {
metric = "DatabaseConnections"
namespace = "AWS/RDS"
threshold = 80
description = "Conexiones RDS mayor 80% del maximo"
}
alb_5xx = {
metric = "HTTPCode_Target_5XX_Count"
namespace = "AWS/ApplicationELB"
threshold = 10
description = "Errores 5xx mayor 10 en 5 minutos"
}
alb_latency = {
metric = "TargetResponseTime"
namespace = "AWS/ApplicationELB"
threshold = 2
description = "Latencia P99 mayor 2 segundos"
}
}
}
resource "aws_cloudwatch_metric_alarm" "this" {
for_each = local.alarms
alarm_name = "${var.app_name}-${each.key}"
alarm_description = each.value.description
metric_name = each.value.metric
namespace = each.value.namespace
statistic = "Average"
period = 300
evaluation_periods = 2
threshold = each.value.threshold
comparison_operator = "GreaterThanThreshold"
treat_missing_data = "notBreaching"
alarm_actions = [aws_sns_topic.alerts.arn]
ok_actions = [aws_sns_topic.alerts.arn]
}Capitulo 8
CI/CD para Terraform
Automatizar el ciclo de validacion y aplicacion de Terraform elimina errores humanos y garantiza que los cambios pasen por revision.
Pipeline GitHub Actions completo
name: Terraform CI/CD
on:
pull_request:
branches: [main]
paths: ['infra/**']
push:
branches: [main]
paths: ['infra/**']
env:
TF_VERSION: '1.7.0'
AWS_REGION: 'us-east-1'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with: { terraform_version: '${{ env.TF_VERSION }}' }
- uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- run: terraform init
working-directory: infra/environments/prod
- run: terraform validate
- run: terraform fmt -check -recursive
plan:
needs: validate
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- run: terraform plan -out=tfplan
apply:
needs: plan
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
steps:
- run: terraform apply -auto-approve tfplanCon estos 14 modulos y el pipeline CI/CD tendras infraestructura reproducible revisada y auditada. El siguiente nivel es Terragrunt para gestionar multiples entornos de forma mas eficiente.