Terraform ist einfach anzufangen und schwer gut zu machen. In kleinen Teams mit einem Monorepo ist es unkompliziert. Sobald 10+ Teams Infrastruktur provisionieren, entstehen Probleme, die man vorher nicht gesehen hat.
Hier sind die Muster, die ich in Enterprise-Projekten gelernt habe.
Das State-Problem
Terraform State ist der Kern aller Probleme in größeren Organisationen. Jeder, der schon mal einen terraform apply ausgeführt hat, während ein Kollege gerade die gleiche Infrastruktur anfasst, kennt das Ergebnis.
Die Lösung ist State-Isolation – aber wie granular?
Zu grob: Ein State-File für alles. Jeder plan läuft 10 Minuten, Locks blockieren das halbe Team.
Zu fein: Ein State-File pro Resource. Zu viel Overhead, Dependencies werden unübersichtlich.
Mein Ansatz: State-Files nach Verantwortungsbereich:
states/
├── networking/ # VPC, Subnets, DNS – selten geändert
├── platform/ # Kubernetes-Cluster, Datenbanken – moderately changed
└── workloads/
├── team-a/ # Jedes Team verwaltet seinen eigenen State
├── team-b/
└── team-c/
Module: Wann und wie
Das klassische Muster ist, alles in Module zu verpacken. Das klingt gut in der Theorie. In der Praxis entstehen Module, die niemand mehr anfasst, weil jede Änderung unklar ist.
Module sind sinnvoll für:
- Wiederverwendete Muster (z.B. ein Standard-EKS-Cluster mit vordefinierten Defaults)
- Compliance-Anforderungen, die zentral durchgesetzt werden müssen
- Abstraktion von Cloud-Provider-Unterschieden
Module sind falsch für:
- Einmalige Infrastruktur
- Alles, was sich oft ändert
- “Weil es ordentlicher aussieht”
Ein gutes Modul hat klare Inputs, sinnvolle Defaults, und verbirgt nichts Wichtiges:
module "eks_cluster" {
source = "git::https://github.com/company/terraform-modules.git//eks?ref=v2.3.0"
cluster_name = "production"
node_groups = {
general = {
instance_types = ["m5.xlarge"]
min_size = 3
max_size = 10
}
}
# Compliance-Defaults werden im Modul gesetzt:
# - encryption at rest: true
# - private endpoint: true
# - audit logging: true
}
Atlantis: Was es verändert
Der größte Qualitätssprung in Team-Workflows kommt nicht von besseren Modulen, sondern von Atlantis. Das Prinzip: Terraform-Plans und -Applies laufen nicht mehr lokal, sondern werden durch Pull Requests getriggert.
Was das verändert:
- Kein “works on my machine” – alle sehen den gleichen Plan
- Review vor Apply – ein zweites Paar Augen auf jede Infrastrukturänderung
- Audit Trail – jeder Apply ist einem PR und einer Person zugeordnet
- Keine lokalen Credentials – das Team braucht keine direkte AWS/GCP/Azure-Access mehr
# atlantis.yaml
version: 3
projects:
- name: platform
dir: infrastructure/platform
workspace: production
apply_requirements:
- approved
- mergeable
workflow: production
workflows:
production:
plan:
steps:
- init
- plan:
extra_args: ["-var-file=production.tfvars"]
apply:
steps:
- apply
OPA für Compliance-as-Code
In regulierten Umgebungen reichen Konventionen nicht. Niemand folgt freiwillig Tagging-Policies, wenn es unter Zeitdruck steht.
OPA (Open Policy Agent) mit Conftest macht Policies zu Tests:
# policies/tagging.rego
package terraform
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_instance"
not resource.change.after.tags.environment
msg := sprintf(
"Resource '%s' fehlt das Tag 'environment'",
[resource.address]
)
}
# In der CI-Pipeline
terraform plan -out=plan.tfplan
terraform show -json plan.tfplan > plan.json
conftest test plan.json --policy policies/
Policy-Verletzungen brechen den Build. Keine Ausnahmen, keine “ich mache es beim nächsten Mal”.
Fazit
Terraform in Enterprise skaliert nicht durch mehr Module oder bessere Verzeichnisstrukturen. Es skaliert durch:
- Klare State-Isolation nach Verantwortungsbereichen
- Atlantis für nachvollziehbare, reviewte Applies
- Policies als Code, nicht als Dokumentation
Der Rest ist Optimierung.