Terraform Enterprise Patterns: Workspace, Sentinel a Team Scaling
Vzor pro přijetí Terraformu ve velkých organizacích: strategie pracovního prostoru pro prostředí/tým, Sentinel pro finanční mantinely a compliance, modul soukromý registr a správa tajných informací pomocí Vaultu.
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







