# Terraform para GCP — Proveedores, Módulos y State Remoto

Referencia de patrones Terraform para infraestructura en Google Cloud Platform.

---

## 1. Configuración del provider y state remoto en GCS

```hcl
# versions.tf
terraform {
  required_version = ">= 1.5.0"

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 5.0"
    }
    google-beta = {
      source  = "hashicorp/google-beta"
      version = "~> 5.0"
    }
  }

  backend "gcs" {
    bucket = "mi-proyecto-terraform-state"
    prefix = "env/produccion"
  }
}

# provider.tf
provider "google" {
  project = var.project_id
  region  = var.region
}

provider "google-beta" {
  project = var.project_id
  region  = var.region
}
```

```hcl
# variables.tf
variable "project_id" {
  description = "ID del proyecto GCP"
  type        = string
}

variable "region" {
  description = "Región principal de despliegue"
  type        = string
  default     = "us-central1"
}

variable "env" {
  description = "Entorno: dev, staging, produccion"
  type        = string
  validation {
    condition     = contains(["dev", "staging", "produccion"], var.env)
    error_message = "El entorno debe ser dev, staging o produccion."
  }
}
```

---

## 2. Módulo para Cloud Run

```hcl
# modules/cloud-run/main.tf
resource "google_cloud_run_v2_service" "servicio" {
  name     = var.nombre
  location = var.region
  project  = var.project_id

  ingress = "INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER"

  template {
    service_account = google_service_account.sa.email

    scaling {
      min_instance_count = var.min_instancias
      max_instance_count = var.max_instancias
    }

    containers {
      image = var.imagen

      resources {
        limits = {
          cpu    = var.cpu
          memory = var.memoria
        }
      }

      dynamic "env" {
        for_each = var.variables_entorno
        content {
          name  = env.key
          value = env.value
        }
      }

      dynamic "env" {
        for_each = var.secretos
        content {
          name = env.key
          value_source {
            secret_key_ref {
              secret  = env.value.nombre
              version = env.value.version
            }
          }
        }
      }
    }

    annotations = {
      "run.googleapis.com/cloudsql-instances" = var.cloud_sql_instance
    }
  }

  labels = local.etiquetas_comunes
}

resource "google_service_account" "sa" {
  account_id   = "${var.nombre}-sa"
  display_name = "SA para ${var.nombre}"
  project      = var.project_id
}

locals {
  etiquetas_comunes = {
    env      = var.env
    servicio = var.nombre
    equipo   = var.equipo
    gestion  = "terraform"
  }
}
```

```hcl
# modules/cloud-run/variables.tf
variable "nombre" { type = string }
variable "region" { type = string }
variable "project_id" { type = string }
variable "imagen" { type = string }
variable "min_instancias" { type = number; default = 1 }
variable "max_instancias" { type = number; default = 10 }
variable "cpu" { type = string; default = "1" }
variable "memoria" { type = string; default = "512Mi" }
variable "env" { type = string }
variable "equipo" { type = string }
variable "cloud_sql_instance" { type = string; default = "" }
variable "variables_entorno" { type = map(string); default = {} }
variable "secretos" {
  type = map(object({ nombre = string; version = string }))
  default = {}
}
```

---

## 3. Cloud SQL con configuración de alta disponibilidad

```hcl
resource "google_sql_database_instance" "principal" {
  name             = "${var.env}-db-principal"
  database_version = "POSTGRES_15"
  region           = var.region
  project          = var.project_id

  deletion_protection = var.env == "produccion" ? true : false

  settings {
    tier              = var.tier_db
    availability_type = var.env == "produccion" ? "REGIONAL" : "ZONAL"
    disk_autoresize   = true
    disk_size         = 20

    backup_configuration {
      enabled                        = true
      start_time                     = "03:00"
      point_in_time_recovery_enabled = true
      transaction_log_retention_days = 7
    }

    ip_configuration {
      ipv4_enabled    = false                  # Sin IP pública
      private_network = google_compute_network.vpc.id
      require_ssl     = true
    }

    insights_config {
      query_insights_enabled  = true
      query_string_length     = 1024
      record_application_tags = true
    }

    user_labels = {
      env    = var.env
      equipo = var.equipo
    }
  }
}
```

---

## 4. VPC y subredes privadas

```hcl
resource "google_compute_network" "vpc" {
  name                    = "${var.env}-vpc"
  auto_create_subnetworks = false
  project                 = var.project_id
}

resource "google_compute_subnetwork" "privada" {
  name          = "${var.env}-subred-privada"
  ip_cidr_range = "10.0.0.0/20"
  region        = var.region
  network       = google_compute_network.vpc.id
  project       = var.project_id

  secondary_ip_range {
    range_name    = "pods"
    ip_cidr_range = "10.1.0.0/16"
  }

  secondary_ip_range {
    range_name    = "servicios"
    ip_cidr_range = "10.2.0.0/20"
  }

  private_ip_google_access = true  # Acceso a APIs GCP sin IP pública
}

# Cloud NAT para que los nodos privados puedan salir a internet
resource "google_compute_router" "router" {
  name    = "${var.env}-router"
  region  = var.region
  network = google_compute_network.vpc.id
}

resource "google_compute_router_nat" "nat" {
  name                               = "${var.env}-nat"
  router                             = google_compute_router.router.name
  region                             = var.region
  nat_ip_allocate_option             = "AUTO_ONLY"
  source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"
}
```

---

## 5. Gestión del state y workspaces

```bash
# Crear bucket para state remoto (una sola vez por proyecto)
gsutil mb -p $PROJECT_ID -l us-central1 gs://mi-proyecto-terraform-state
gsutil versioning set on gs://mi-proyecto-terraform-state

# Usar workspaces para múltiples entornos
terraform workspace new staging
terraform workspace new produccion
terraform workspace select produccion

# Inicializar con backend remoto
terraform init -backend-config="bucket=mi-proyecto-terraform-state"

# Plan y apply con variables por entorno
terraform plan -var-file="entornos/produccion.tfvars"
terraform apply -var-file="entornos/produccion.tfvars" -auto-approve
```

---

## 6. Estructura de directorios recomendada

```
infra/
├── modules/
│   ├── cloud-run/         # Módulo reutilizable de Cloud Run
│   ├── cloud-sql/         # Módulo reutilizable de Cloud SQL
│   └── gke-cluster/       # Módulo reutilizable de GKE
├── entornos/
│   ├── dev.tfvars
│   ├── staging.tfvars
│   └── produccion.tfvars
├── main.tf                # Composición de módulos
├── variables.tf           # Variables del root module
├── outputs.tf             # Outputs exportados
└── versions.tf            # Versiones de providers y Terraform
```

---

## 7. Reglas obligatorias para Terraform GCP

- `deletion_protection = true` en Cloud SQL de producción
- State en GCS con versionado habilitado — nunca state local en producción
- Un módulo por tipo de recurso (cloud-run, cloud-sql, gke) — no monolitos
- `labels` en TODOS los recursos: `env`, `equipo`, `gestion=terraform`
- Variables con `validation` para entornos y valores críticos
- NUNCA hacer `terraform apply` sin `terraform plan` previo revisado
