Der Terraform State ist die wichtigste Datei im ganzen Projekt und gleichzeitig die, über die am wenigsten geredet wird. Er hält fest, welche realen Ressourcen zu welchem Code gehören. Wer ihn verliert, kann nicht mehr sauber planen. Wer ihn ungeschützt liegen lässt, gibt Klartext-Geheimnisse preis. In diesem Beitrag geht es um drei Dinge, die in der Praxis am häufigsten schiefgehen: das Backend, das Locking und die Secrets im State selbst.
Warum der lokale State ein Problem ist
Standardmäßig schreibt Terraform den State in eine Datei terraform.tfstate im Projektverzeichnis. Solange man allein auf dem eigenen Rechner arbeitet, fällt das nicht auf. Sobald aber ein zweiter Mensch oder eine Pipeline dazukommt, beginnt das Chaos. Jeder hat eine eigene Kopie, niemand weiß welche aktuell ist, und ein Commit der State-Datei ins Git-Repository ist der schnellste Weg, Zugangsdaten ins Versionskontrollsystem zu schreiben. Der State gehört nicht ins Repo. Er gehört in ein Remote Backend.
Remote Backend mit Versionierung
Ein Remote Backend legt den State an einem zentralen, versionierten Ort ab. Auf AWS ist die übliche Kombination ein S3-Bucket für den State und eine DynamoDB-Tabelle für das Locking. Wichtig ist, dass der Bucket Versionierung und Verschlüsselung aktiviert hat, damit man bei einem kaputten State auf eine frühere Version zurück kann.
terraform { backend "s3" { bucket = "meinprojekt-tfstate" key = "prod/terraform.tfstate" region = "eu-central-1" dynamodb_table = "terraform-locks" encrypt = true }}
Das encrypt = true sorgt für Verschlüsselung at rest, die Versionierung am Bucket für die Wiederherstellbarkeit. Beides ist kein Komfort, sondern Pflicht, sobald echte Infrastruktur dranhängt.
Locking gegen parallele Läufe
Wenn zwei terraform apply gleichzeitig laufen, entsteht ein Race auf denselben State. Das Ergebnis ist ein inkonsistenter State, der im schlimmsten Fall Ressourcen doppelt anlegt oder Referenzen verliert. State Locking verhindert das, indem der erste Lauf eine Sperre setzt und der zweite wartet. Bei S3 übernimmt das die DynamoDB-Tabelle. Die Tabelle braucht nur einen Partition Key namens LockID:
resource "aws_dynamodb_table" "locks" { name = "terraform-locks" billing_mode = "PAY_PER_REQUEST" hash_key = "LockID" attribute { name = "LockID" type = "S" }}
Falls ein Lauf hart abbricht und die Sperre hängen bleibt, hilft terraform force-unlock LOCK_ID. Das aber bitte nur, wenn man sicher ist, dass wirklich kein anderer Lauf aktiv ist.
Das eigentliche Problem: Secrets im State
Hier liegt der Punkt, den viele unterschätzen. Terraform schreibt jeden Wert, den es kennt, im Klartext in den State. Ein Datenbankpasswort, ein generierter Token, ein privater Schlüssel aus einer random_password-Resource, alles steht lesbar im State. Markiert man eine Variable als sensitive, verschwindet sie nur aus der Konsolenausgabe, nicht aus dem State.
variable "db_password" { type = string sensitive = true}
Die Konsequenz ist einfach: Wer Zugriff auf den State hat, hat Zugriff auf die Geheimnisse. Deshalb gilt der State selbst als sensibel und muss entsprechend geschützt werden. Verschlüsselung am Backend, restriktive IAM-Policies auf den Bucket, kein State im Repo. Wer es sauberer will, hält Secrets ganz aus dem State heraus, indem sie zur Laufzeit aus einem Secret Manager gezogen werden statt sie von Terraform erzeugen und speichern zu lassen.
Drei Regeln, die ich konsequent durchziehe
Erstens: kein State im Git, niemals. Eine Zeile in der .gitignore für *.tfstate* ist Minimum, das Backend die eigentliche Lösung. Zweitens: Backend mit Verschlüsselung und Versionierung von Tag eins an, nicht nachträglich. Drittens: den State als Geheimnisträger behandeln und die Zugriffsrechte darauf so eng wie die auf die Produktionsdatenbank ziehen.
Der State ist kein Nebenprodukt, er ist Teil der Angriffsfläche. Wer Infrastruktur als Code ernst nimmt, behandelt auch die Spuren, die dieser Code hinterlässt, mit der gleichen Sorgfalt. Mehr zu dem Gedanken, Sicherheit direkt in den Build- und Delivery-Prozess zu ziehen statt sie nachzulagern, schreibe ich regelmäßig auf digital-business.blog.
Hinterlasse einen Kommentar