IaC — Biblioteca de Módulos Terraform

NovaSaaS Terraform Library

Módulos Terraform reutilizables y listos para producción · AWS + GCP · v1.2.0

📦 8 módulos verificados
⚙️ Terraform ≥ 1.7
✅ Tests Terratest
🕒 Actualizado Jun 2026
▲ AWS ◆ GCP
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.
networking multi-az nat-gateway flow-logs
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).
kubernetes irsa auto-scaling addons
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.
postgres multi-az kms backups
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.
iam least-privilege irsa 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.
bigquery analytics partitioned iam
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.
storage lifecycle cmek versioning
📁 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 pinningaws ~> 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