8
Módulos publicados
3
Entornos estandarizados
94%
Cobertura de tests
~2h
Provisioning nuevo entorno
AWS Modules
aws/vpc
v1.2.0
VPC multi-AZ con subnets públicas/privadas, Internet Gateway, NAT Gateways y route tables. Soporta hasta 6 AZs y Flow Logs habilitados.
aws/eks
v1.1.0
Clúster EKS gestionado con node groups auto-escalables, IRSA habilitado y add-ons preconfigurados (CoreDNS, kube-proxy, VPC CNI).
aws/rds
v1.3.0
RDS PostgreSQL/MySQL con Multi-AZ, réplica de lectura opcional, backups automáticos, encriptación KMS y parámetros de rendimiento optimizados.
aws/iam-role
v1.0.0
IAM Roles con políticas de mínimo privilegio, soporte de IRSA para pods de EKS y gestión de trust policies cross-account.
GCP Modules
gcp/bigquery
v1.0.0
Datasets BigQuery con control de acceso IAM, tablas particionadas por fecha, políticas de expiración y conexión Data Transfer Service.
gcp/gcs
v0.9.0 beta
Buckets GCS con lifecycle policies, CORS configurado para acceso web, versioning y encriptación con CMEK. Lifecycle para tiering automático.
📁 Estructura del repositorio — novasaas-platform/infra/
terraform-modules/
├── aws/
│ ├── vpc/
│ │ ├── main.tf # recursos VPC, subnets, IGW, NAT
│ │ ├── variables.tf # inputs con validación
│ │ ├── outputs.tf # vpc_id, subnet_ids, cidr
│ │ ├── versions.tf # provider ~> 5.0
│ │ ├── README.md
│ │ ├── examples/
│ │ │ └── complete/
│ │ │ └── main.tf
│ │ └── tests/
│ │ └── vpc_test.go
│ ├── eks/ ├── rds/ └── iam-role/
├── gcp/
│ ├── bigquery/ └── gcs/
└── environments/
├── dev/ # t3.small, single-AZ, 7d backups
├── staging/ # t3.medium, multi-AZ, 14d backups
└── production/ # t3.large, multi-AZ, 30d backups, Multi-Region
🟧 aws/vpc/ — módulo principal
main.tf
variables.tf
outputs.tf
versions.tf
# aws/vpc/main.tf — NovaSaaS Platform # Módulo VPC multi-AZ con subnets públicas/privadas locals { common_tags = merge( { Project = var.project Environment = var.environment ManagedBy = "terraform" CostCenter = var.cost_center }, var.tags ) nat_gateway_count = var.single_nat_gateway ? 1 : length(var.availability_zones) } resource "aws_vpc" "main" { cidr_block = var.cidr_block enable_dns_hostnames = true enable_dns_support = true tags = merge(local.common_tags, { Name = "${var.project}-${var.environment}-vpc" }) } resource "aws_subnet" "private" { count = length(var.private_subnet_cidrs) vpc_id = aws_vpc.main.id cidr_block = var.private_subnet_cidrs[count.index] availability_zone = var.availability_zones[count.index] tags = merge(local.common_tags, { Name = "${var.project}-${var.environment}-private-${count.index + 1}" Tier = "private" "kubernetes.io/role/internal-elb" = "1" }) } resource "aws_subnet" "public" { count = length(var.public_subnet_cidrs) vpc_id = aws_vpc.main.id cidr_block = var.public_subnet_cidrs[count.index] availability_zone = var.availability_zones[count.index] map_public_ip_on_launch = false tags = merge(local.common_tags, { Name = "${var.project}-${var.environment}-public-${count.index + 1}" Tier = "public" "kubernetes.io/role/elb" = "1" }) } resource "aws_internet_gateway" "main" { vpc_id = aws_vpc.main.id tags = merge(local.common_tags, { Name = "${var.project}-${var.environment}-igw" }) } resource "aws_nat_gateway" "main" { count = local.nat_gateway_count allocation_id = aws_eip.nat[count.index].id subnet_id = aws_subnet.public[count.index].id tags = merge(local.common_tags, { Name = "${var.project}-${var.environment}-nat-${count.index + 1}" }) depends_on = [aws_internet_gateway.main] } # VPC Flow Logs — habilitados por defecto para auditoría resource "aws_flow_log" "main" { count = var.enable_flow_logs ? 1 : 0 iam_role_arn = aws_iam_role.flow_log[0].arn log_destination = aws_cloudwatch_log_group.flow_log[0].arn traffic_type = "ALL" vpc_id = aws_vpc.main.id }
📋 aws/vpc/variables.tf — inputs con validación
variable "project" { description = "Nombre del proyecto (ej: novasaas)" type = string validation { condition = can(regex("^[a-z][a-z0-9-]{1,18}[a-z0-9]$", var.project)) error_message = "El nombre del proyecto debe ser lowercase, 3-20 chars, solo letras/numeros/guiones." } } variable "environment" { description = "Entorno de despliegue" type = string validation { condition = contains(["dev", "staging", "production"], var.environment) error_message = "El entorno debe ser: dev, staging o production." } } variable "cidr_block" { description = "CIDR block principal de la VPC" type = string validation { condition = can(cidrhost(var.cidr_block, 0)) error_message = "El CIDR block debe ser notacion IPv4 valida (ej: 10.0.0.0/16)." } } variable "availability_zones" { description = "Lista de AZs a utilizar (minimo 2 para HA)" type = list(string) validation { condition = length(var.availability_zones) >= 2 error_message = "Se requieren al menos 2 AZs para alta disponibilidad." } } variable "single_nat_gateway" { description = "Usar un solo NAT Gateway (ahorra costes en dev/staging)" type = bool default = false } variable "cost_center" { description = "Centro de coste para facturacion (ej: platform-team)" type = string default = "engineering" } variable "enable_flow_logs" { description = "Habilitar VPC Flow Logs para auditoria de trafico" type = bool default = true } variable "tags" { description = "Tags adicionales a mergear con los comunes" type = map(string) default = {} }
🔗 Composición de módulos — environments/production/main.tf
dev
staging
production ✓
# environments/production/main.tf — NovaSaaS Platform module "vpc" { source = "../../modules/aws/vpc" version = "1.2.0" project = "novasaas" environment = "production" cost_center = "platform-team" cidr_block = "10.0.0.0/16" availability_zones = ["eu-west-1a", "eu-west-1b", "eu-west-1c"] private_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] public_subnet_cidrs = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"] single_nat_gateway = false # 3 NAT GWs para HA en prod enable_flow_logs = true } module "eks" { source = "../../modules/aws/eks" version = "1.1.0" project = "novasaas" environment = "production" cluster_name = "novasaas-prod" k8s_version = "1.29" vpc_id = module.vpc.vpc_id subnet_ids = module.vpc.private_subnet_ids node_groups = { api = { instance_types = ["t3.large"] min_size = 3 max_size = 10 desired_size = 3 } workers = { instance_types = ["t3.xlarge"] min_size = 2 max_size = 8 desired_size = 2 } } } module "rds" { source = "../../modules/aws/rds" version = "1.3.0" project = "novasaas" environment = "production" identifier = "novasaas-prod-db" engine = "postgres" engine_version = "16.2" instance_class = "db.t3.large" multi_az = true deletion_protection = true backup_retention_period = 30 vpc_id = module.vpc.vpc_id subnet_ids = module.vpc.private_subnet_ids } module "bigquery_analytics" { source = "../../modules/gcp/bigquery" version = "1.0.0" project_id = "novasaas-gcp-prod" dataset_id = "sales_analytics" location = "EU" environment = "production" default_table_expiration_ms = null # Sin expiración en prod }
🧪 Terratest — Resultados de la suite de tests
✓ 22/22 PASS · 4m 31s
$ go test ./... -v -timeout 30m
--- Ejecutando suite NovaSaaS Terraform Module Tests ---
=== RUN TestVPCModule_CreateBasic
vpc_test.go:24: Aplicando terraform en examples/complete...
vpc_test.go:31: VPC creada: vpc-0a1b2c3d4e5f
vpc_test.go:38: Subnets privadas: [subnet-111, subnet-222, subnet-333]
--- PASS: TestVPCModule_CreateBasic (47.32s)
=== RUN TestVPCModule_DNSEnabled
--- PASS: TestVPCModule_DNSEnabled (0.18s)
=== RUN TestVPCModule_FlowLogsEnabled
vpc_test.go:89: Log group /aws/vpc/novasaas-test creado correctamente
--- PASS: TestVPCModule_FlowLogsEnabled (2.11s)
=== RUN TestVPCModule_TagsApplied
vpc_test.go:112: Tags verificados: Environment=test, Project=novasaas, ManagedBy=terraform, CostCenter=engineering
--- PASS: TestVPCModule_TagsApplied (0.09s)
=== RUN TestVPCModule_SingleNATGateway
--- PASS: TestVPCModule_SingleNATGateway (52.40s)
=== RUN TestEKSModule_ClusterCreation
eks_test.go:29: Cluster EKS novasaas-test creado en eu-west-1
eks_test.go:35: K8s version: 1.29 ✓
--- PASS: TestEKSModule_ClusterCreation (3m02.55s)
=== RUN TestRDSModule_PostgresCreation
rds_test.go:44: Instancia RDS postgres 16.2 disponible
rds_test.go:51: Encryption at rest: habilitada (KMS)
--- PASS: TestRDSModule_PostgresCreation (1m18.73s)
... 15 tests adicionales ...
PASS — 22 tests passed, 0 failed, 0 skipped
ok novasaas/terraform-modules/tests 4m31.04s
✅ Checklist de buenas prácticas IaC — NovaSaaS
✓
Versionado semántico — Todos los módulos siguen SemVer (1.x.y)
✓
Validación de inputs — Todos los
variable con bloques validation
✓
Tagging consistente — Environment, Project, ManagedBy, CostCenter en todos los recursos
✓
Provider pinning —
aws ~> 5.0, google ~> 5.0, terraform >= 1.7
✓
Recursos condicionales — Uso de
count y for_each para configuración flexible
✓
Outputs documentados — Todos los outputs con
description para composición entre módulos
✓
Tests Terratest — 22 tests cubren creación, tagging, configuración de seguridad y outputs
✓
Ejemplos funcionales — Directorio
examples/complete en cada módulo con valores realistas
⚠
Estado remoto — Pendiente configurar S3 backend + DynamoDB lock para el equipo (issue #47)
⚠
Atlantis / Terraform Cloud — Integración CI/CD en progreso para plan automático en PRs