IaC na Enterprise Scale: Skutečné výzvy

Když Terraform přejde z týmu 3 lidí na organizaci s 50 týmy spravovat stovky cloudových prostředí, objevují se výzvy, které v úvodních článcích nikdy nezmiňují: jak zajistit, aby nikdo nemohl vytvořit instanci 50 000 $ měsíčně náhodou? Jak zabránit tomu, aby jeden tým přepsal stav jiného? Jak zajistit soulad s bezpečnostními zásadami společnosti bez blokování produktivita? Jak centrálně spravovat tajemství?

V tomto posledním článku série se zabýváme podnikovými vzory pro Terraform: HCP Terraform (dříve Terraform Cloud) jako platforma správy, Stráž jako jazyk zásad pro finanční záruky a dodržování předpisů, e HashiCorp Vault pro centralizovanou správu tajemství.

Co se naučíte

  • Strategie pracovního prostoru: plochý, monorepo, pro tým/prostředí/vrstvu
  • Sentinel: Jazyk politiky HashiCorp, falešné testování, úrovně prosazování
  • Finanční mantinely: blokování drahých instancí, automatická upozornění na rozpočet
  • Soukromý registr modulů: verzování, správa, RBAC pro moduly
  • Vault + Terraform: dynamická tajemství, tajná injekce bez hardcodingu
  • Škálování týmu: sady proměnných, spouštěče spuštění, fondy agentů

Strategie pracovního prostoru: Organizace infrastruktury ve velkém měřítku

Pracovní prostor Terraform Cloud/Enterprise odpovídá souboru izolovaného stavu. Strategie pojmenování a organizace pracovních prostorů je prvním rozhodnutím ovlivňuje celý životní cyklus podnikové infrastruktury. Existují tři vzory hlavní, z nichž každý má své klady a zápory.

Vzor 1: Podle prostředí (nejběžnější)

# Naming convention: {team}-{service}-{environment}
# Esempio per un team platform con servizi networking, compute, database:

platform-networking-dev
platform-networking-staging
platform-networking-prod

platform-compute-dev
platform-compute-staging
platform-compute-prod

platform-database-dev
platform-database-staging
platform-database-prod

# Pro: isolamento completo per ambiente
# Pro: policy diverse per prod vs non-prod (piu strict su prod)
# Con: se hai 20 team con 5 servizi ognuno = 300 workspace da gestire
# Con: aggiornare una variabile comune richiede toccare molti workspace

Vzor 2: Monorepo s dynamickými pracovními prostory

# Struttura monorepo con HCP Terraform
terraform-infra/
├── modules/                     # Moduli privati condivisi
├── stacks/                      # "Stack" = unita di deployment
│   ├── networking/
│   │   ├── main.tf
│   │   └── variables.tf
│   ├── eks-cluster/
│   └── rds-aurora/
└── workspaces/                  # Configurazione per ogni workspace
    ├── platform-networking-prod.tfvars
    ├── platform-networking-staging.tfvars
    └── team-a-eks-prod.tfvars

# HCP Terraform workspace configuration (via Terraform provider)
resource "tfe_workspace" "networking_prod" {
  name         = "platform-networking-prod"
  organization = "myorg"

  # Trigger: applica automaticamente su push al branch main
  # ma solo per i file nella directory stacks/networking
  trigger_prefixes  = ["stacks/networking/"]
  working_directory = "stacks/networking"

  # Auto-apply solo in non-prod
  auto_apply = false  # prod: sempre approvazione manuale

  # Terraform version
  terraform_version = "1.9.x"

  tag_names = ["env:prod", "team:platform", "tier:networking"]
}

Sady proměnných: Sdílená konfigurace mezi pracovními prostory

# Variable Sets = gruppo di variabili applicabili a piu workspace
# Evita di duplicare le stesse variabili in 50 workspace

# Esempio: Variable Set globale con configurazione AWS
resource "tfe_variable_set" "aws_prod" {
  name         = "AWS Production Credentials"
  description  = "Credenziali AWS per ambienti di produzione"
  organization = "myorg"
  global       = false  # Non globale: solo workspace con tag specifici
}

# Variabili nel set (environment variables per il runner)
resource "tfe_variable" "aws_role_arn" {
  key             = "AWS_ROLE_ARN"
  value           = "arn:aws:iam::123456789:role/TerraformProdRole"
  category        = "env"
  variable_set_id = tfe_variable_set.aws_prod.id
  sensitive       = false
}

# Applica il variable set a workspace con tag "env:prod"
resource "tfe_workspace_variable_set" "prod_networking" {
  variable_set_id = tfe_variable_set.aws_prod.id
  workspace_id    = tfe_workspace.networking_prod.id
}

Sentinel: Policy as Code for Enterprise Governance

Stráž a proprietární politický rámec HashiCorp, k dispozici v úrovních Plus a Enterprise HCP Terraform. Na rozdíl od OPA/Rego (open-source), Sentinel je navržen speciálně pro HashiCorp: má nativní přístup k plánu Terraform s bohatým datovým modelem a tříúrovňovým systémem prosazování.

Úrovně vymáhání

# Sentinel ha tre livelli di enforcement:

# 1. advisory: la policy fallisce ma il run procede (solo log/warning)
#    Uso: notifiche soft, metriche, awareness

# 2. soft-mandatory: la policy fallisce e blocca l'apply,
#    MA un utente con permessi puo fare override con giustificazione
#    Uso: policy importanti che potrebbero avere eccezioni legittime

# 3. hard-mandatory: la policy fallisce e NESSUNO puo fare override
#    Uso: compliance legale, sicurezza critica, guardrail finanziari

# Configurazione enforcement nel policy set (HCP Terraform):
resource "tfe_policy_set" "global_policies" {
  name         = "global-security-policies"
  organization = "myorg"
  global       = true   # Applica a tutti i workspace

  policy_ids = [
    tfe_sentinel_policy.no_public_s3.id,
    tfe_sentinel_policy.cost_limits.id,
    tfe_sentinel_policy.required_tags.id,
  ]
}

Strážce politiky: Finanční stráže

# cost-control.sentinel
# Blocca hard se il costo stimato supera soglie per ambiente

import "tfplan/v2" as tfplan
import "decimal"

# Leggi il tag "env" dal workspace per determinare le soglie
env = tfplan.variables["environment"].value

# Soglie di costo mensile (USD) per ambiente
cost_limits = {
  "dev":     decimal.new(500),
  "staging": decimal.new(2000),
  "prod":    decimal.new(50000),
}

# Tipi di istanza EC2 proibiti in non-prod
expensive_types = [
  "m5.4xlarge", "m5.8xlarge", "m5.16xlarge", "m5.24xlarge",
  "c5.9xlarge", "c5.18xlarge",
  "r5.8xlarge", "r5.16xlarge", "r5.24xlarge",
  "p3.2xlarge", "p3.8xlarge", "p4d.24xlarge",
]

# Regola 1: Blocca istanze costose in non-prod
deny_expensive_instances = rule {
  env is "prod" or
  all tfplan.resource_changes as _, rc {
    rc.type is not "aws_instance" or
    rc.change.after.instance_type not in expensive_types
  }
}

# Regola 2: Verifica costo stimato se disponibile (richiede Infracost)
check_estimated_cost = rule {
  # La policy puo accedere ai costi stimati tramite Terraform Cloud
  # se Infracost e integrato nel workflow
  true  # Placeholder: implementare con Infracost webhook
}

# Main: combina le regole
main = rule {
  deny_expensive_instances and
  check_estimated_cost
}

Zásady Sentinel: Povinné značky

# required-tags.sentinel
# Garantisce che tutte le risorse taggabili abbiano i tag obbligatori

import "tfplan/v2" as tfplan

# Tag obbligatori per ogni risorsa
required_tags = ["Environment", "Team", "CostCenter", "ManagedBy"]

# Tipi di risorsa che supportano i tag (lista parziale)
taggable_types = [
  "aws_instance", "aws_vpc", "aws_subnet", "aws_s3_bucket",
  "aws_rds_instance", "aws_eks_cluster", "aws_lb",
  "azurerm_virtual_machine", "azurerm_virtual_network",
  "google_compute_instance", "google_storage_bucket",
]

# Controlla ogni risorsa che viene creata o modificata
violations = []

for tfplan.resource_changes as address, rc {
  if rc.type in taggable_types and
     rc.change.actions contains "create" or rc.change.actions contains "update" {
    tags = rc.change.after.tags else {}
    for required_tags as tag {
      if tag not in tags or tags[tag] is "" {
        append(violations, sprintf(
          "Risorsa %s manca del tag obbligatorio: %s",
          [address, tag]
        ))
      }
    }
  }
}

# Stampa le violazioni per il feedback all'utente
print("Tag violations:", violations)

main = rule { length(violations) is 0 }

Testování zásad Sentinel

# Sentinel CLI per testing locale delle policy
# Installa Sentinel CLI
sentinel version
# Sentinel v0.26.x

# Struttura directory per testing:
policies/
├── cost-control.sentinel
├── required-tags.sentinel
└── test/
    ├── cost-control/
    │   ├── pass/
    │   │   └── mock-tfplan.json    # Plan con istanze economiche
    │   └── fail/
    │       └── mock-tfplan.json    # Plan con istanze costose
    └── required-tags/
        ├── pass/
        │   └── mock-tfplan.json    # Tutte le risorse hanno i tag
        └── fail/
            └── mock-tfplan.json    # Risorse senza tag

# Genera mock da un plan reale:
terraform plan -out=tfplan.bin
terraform show -json tfplan.bin > mock-tfplan.json
# Modifica il JSON per creare scenari pass/fail

# Esegui i test:
sentinel test cost-control.sentinel
# PASS - cost-control.sentinel (2 test)
#   PASS - test/cost-control/pass/mock-tfplan.json
#   PASS - test/cost-control/fail/mock-tfplan.json

sentinel apply cost-control.sentinel
# Execution trace...
# Policy result: true

Registr soukromých modulů

V podnikové organizaci jsou moduly Terraform primárním mechanismem standardizovat infrastrukturu: tým platformy vydává moduly „zlaté cesty“, které aplikační týmy spotřebují. HCP Terraform nabízí soukromý registr s verzováním sémantická, automaticky generovaná dokumentace a RBAC.

# Struttura di un modulo pubblicabile nel registry privato
terraform-module-aws-vpc/
├── main.tf
├── variables.tf
├── outputs.tf
├── versions.tf
├── README.md           # Documentazione auto-esposta nel registry
├── examples/
│   ├── simple/
│   │   └── main.tf     # Esempio minimo
│   └── full/
│       └── main.tf     # Esempio completo
└── tests/
    └── vpc_test.go     # Test Terratest

# Pubblicazione via Git tags (il registry legge i tag SemVer):
git tag v1.2.0
git push origin v1.2.0

# HCP Terraform registry: importa automaticamente il modulo
# dal repository GitHub/GitLab quando trova un tag vX.Y.Z

# Uso del modulo privato da altri workspace:
module "vpc" {
  source  = "app.terraform.io/myorg/aws-vpc/aws"
  version = "~> 1.2"

  environment  = var.environment
  cidr_block   = "10.0.0.0/16"
  subnet_count = 3
}

HashiCorp Vault: Tajná správa pro Terraform

The most common problem in Terraform enterprise pipelines is secret management: databázová hesla, API klíče, certifikáty. HashiCorp Vault řeší toto s dynamická tajemství: Místo statických přihlašovacích údajů generuje Vault dočasná pověření na vyžádání, jejichž platnost automaticky vyprší.

Dynamická tajemství trezoru pro AWS

# Configurazione Vault per generare credenziali AWS temporanee

# Provider Vault in Terraform
provider "vault" {
  address = "https://vault.myorg.internal:8200"
  # Autenticazione via AppRole (in CI/CD) o AWS IAM auth (in EC2/EKS)
}

# Leggi credenziali AWS dinamiche da Vault
data "vault_aws_access_credentials" "terraform_runner" {
  backend = "aws"
  role    = "terraform-role"
  type    = "iam_user"   # oppure "assumed_role" per STS
}

# Usa le credenziali nel provider AWS
provider "aws" {
  region     = var.aws_region
  access_key = data.vault_aws_access_credentials.terraform_runner.access_key
  secret_key = data.vault_aws_access_credentials.terraform_runner.secret_key
  token      = data.vault_aws_access_credentials.terraform_runner.security_token
}

# Vault genera credenziali con TTL di 1 ora
# Dopo il terraform apply, le credenziali scadono automaticamente
# Nessuna credenziale permanente nelle pipeline

Vault for Application Secrets

# Recuperare segreti da Vault per passarli alle risorse
# (es: password database RDS)

data "vault_kv_secret_v2" "db_password" {
  mount = "secret"
  name  = "prod/database/rds-main"
}

# Usa il segreto nella risorsa RDS
resource "aws_db_instance" "main" {
  identifier        = "${local.name_prefix}-rds"
  engine            = "postgres"
  engine_version    = "15.4"
  instance_class    = "db.r6g.xlarge"

  # Password da Vault: non hardcoded, non in tfvars
  password          = data.vault_kv_secret_v2.db_password.data["password"]

  username          = "app_user"
  db_name           = "appdb"

  # Output: il DB endpoint viene scritto su Vault dopo l'apply
  # tramite un provisioner o una pipeline separata
}

# Scrivi l'endpoint del DB su Vault dopo la creazione
resource "vault_kv_secret_v2" "db_connection" {
  mount = "secret"
  name  = "prod/database/connection-info"

  data_json = jsonencode({
    host     = aws_db_instance.main.address
    port     = aws_db_instance.main.port
    database = aws_db_instance.main.db_name
  })
}

Spusťte spouštěče a graf závislostí mezi pracovními prostory

# In organizzazioni grandi, i workspace hanno dipendenze:
# networking -> compute -> application
# Il cambio di networking deve triggerare il re-apply di compute

# HCP Terraform: Run Triggers
resource "tfe_run_trigger" "compute_from_networking" {
  workspace_id  = tfe_workspace.compute_prod.id        # workspace downstream
  sourceable_id = tfe_workspace.networking_prod.id     # workspace upstream
}

# Quando networking-prod completa un apply con successo,
# HCP Terraform triggera automaticamente un plan su compute-prod
# che legge gli output di networking via remote_state data source

# Lettura output da workspace upstream
data "tfe_outputs" "networking" {
  organization = "myorg"
  workspace    = "platform-networking-prod"
}

# Usa gli output nel compute workspace
resource "aws_eks_cluster" "main" {
  name = "${local.name_prefix}-eks"

  vpc_config {
    subnet_ids = data.tfe_outputs.networking.values.private_subnet_ids
  }
}

Agent Pools: Samoobslužný běžec v soukromých prostředích

# HCP Terraform Agent: per eseguire piani in reti private
# (es: infrastruttura on-premise, VPC senza accesso pubblico)

# Installa l'agent nel tuo ambiente
docker run -e TFE_AGENT_TOKEN="your-token" \
  -e TFE_AGENT_NAME="datacenter-agent-01" \
  hashicorp/tfc-agent:latest

# Oppure via Kubernetes DaemonSet nel cluster privato
kubectl apply -f - <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tfc-agent
  namespace: terraform-system
spec:
  replicas: 3
  selector:
    matchLabels:
      app: tfc-agent
  template:
    spec:
      containers:
        - name: tfc-agent
          image: hashicorp/tfc-agent:latest
          env:
            - name: TFE_AGENT_TOKEN
              valueFrom:
                secretKeyRef:
                  name: tfc-agent-token
                  key: token
            - name: TFE_AGENT_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
EOF

# Configura il workspace per usare l'agent pool privato
resource "tfe_workspace" "private_datacenter" {
  name              = "datacenter-networking-prod"
  organization      = "myorg"
  agent_pool_id     = tfe_agent_pool.datacenter.id
  execution_mode    = "agent"   # Usa l'agent invece del runner HCP
}

Tým RBAC v HCP Terraform

# Organizzare i permessi per team
resource "tfe_team" "platform_engineers" {
  name         = "platform-engineers"
  organization = "myorg"
  visibility   = "organization"
}

resource "tfe_team" "app_developers" {
  name         = "app-developers"
  organization = "myorg"
}

# Platform Engineers: accesso completo a tutti i workspace di networking
resource "tfe_team_access" "platform_networking" {
  access       = "admin"   # plan, apply, destroy, admin
  team_id      = tfe_team.platform_engineers.id
  workspace_id = tfe_workspace.networking_prod.id
}

# App Developers: solo plan (read) su prod, write su dev
resource "tfe_team_access" "dev_compute_prod" {
  access       = "read"   # Solo visualizzazione, nessun trigger
  team_id      = tfe_team.app_developers.id
  workspace_id = tfe_workspace.compute_prod.id
}

resource "tfe_team_access" "dev_compute_dev" {
  access       = "write"  # Plan e apply, ma non admin
  team_id      = tfe_team.app_developers.id
  workspace_id = tfe_workspace.compute_dev.id
}

Závěry: Vyspělost IaC Enterprise

Terraform enterprise není jen "Terraform s více pracovními prostory": je to systém správa infrastruktury s policy machine (Sentinel), správa tajných informací (Vault), úplný auditní záznam a granulární RBAC. Vzory popsané v tomto článku představují vyspělost Infrastructure as Code v organizacích, které řídí desítky týmů a stovky cloudových prostředí.

Tímto článkem uzavíráme řadu Terraform a IaC: od základního HCL až po Enterprise pattern, nyní máte všechny nástroje pro budování a správu infrastruktur profesionální cloudy v jakémkoli měřítku.

Kompletní série: Terraform a IaC

  • článek 01 — Terraform from Scratch: HCL, Provider a Plan-Apply-Destroy
  • článek 02 — Navrhování opakovaně použitelných modulů Terraform
  • článek 03 — Terraform State: Vzdálený backend s S3/GCS
  • článek 04 — Terraform v CI/CD: GitHub Actions a Atlantis
  • článek 05 — Testování IaC: Terratest a Terraform Test
  • článek 06 — Zabezpečení IaC: Checkov, Trivy a OPA
  • článek 07 — Terraform Multi-Cloud: AWS + Azure + GCP
  • článek 08 — GitOps pro Terraform: Flux TF Controller a Spacelift
  • článek 09 — Terraform vs Pulumi vs OpenTofu
  • Článek 10 (tento) — Terraform Enterprise Patterns: Workspace, Sentinel a Team Scaling