Terraform State Management mit S3 und DynamoDB: Der produktionsreife Ansatz

3 Min. Lesezeit

Ursprünglich veröffentlicht auf LinkedIn.


Das Problem mit lokalem State

Wer Terraform zum ersten Mal nutzt, speichert den State lokal in terraform.tfstate. Das funktioniert für Einzelpersonen und Experimente — aber sobald ein zweites Teammitglied hinzukommt oder eine CI/CD-Pipeline Deployments übernimmt, entstehen Konflikte, Datenverluste und inkonsistente Infrastruktur.

Die Lösung: ein Remote-Backend. Auf AWS ist die Kombination aus S3 (State-Speicherung) und DynamoDB (State-Locking) der de-facto-Standard.

S3-Bucket für den State

Der S3-Bucket braucht einige wichtige Konfigurationen:

HCL
resource "aws_s3_bucket" "terraform_state" {  bucket = "my-project-tfstate"  # Verhindert versehentliches Löschen  lifecycle {    prevent_destroy = true  }}resource "aws_s3_bucket_versioning" "terraform_state" {  bucket = aws_s3_bucket.terraform_state.id  versioning_configuration {    status = "Enabled"  }}resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {  bucket = aws_s3_bucket.terraform_state.id  rule {    apply_server_side_encryption_by_default {      sse_algorithm = "aws:kms"    }  }}resource "aws_s3_bucket_public_access_block" "terraform_state" {  bucket                  = aws_s3_bucket.terraform_state.id  block_public_acls       = true  block_public_policy     = true  ignore_public_acls      = true  restrict_public_buckets = true}

Versioning ist entscheidend: Es ermöglicht das Zurückrollen auf einen früheren State, wenn ein apply schiefläuft.

DynamoDB-Tabelle für State Locking

State Locking verhindert, dass zwei terraform apply-Läufe gleichzeitig denselben State modifizieren:

HCL
resource "aws_dynamodb_table" "terraform_lock" {  name         = "my-project-tflock"  billing_mode = "PAY_PER_REQUEST"  hash_key     = "LockID"  attribute {    name = "LockID"    type = "S"  }}

PAY_PER_REQUEST ist hier die richtige Wahl — die Tabelle wird selten geschrieben, und On-Demand-Billing vermeidet unnötige Kosten.

Backend-Konfiguration

HCL
terraform {  backend "s3" {    bucket         = "my-project-tfstate"    key            = "prod/terraform.tfstate"    region         = "eu-central-1"    encrypt        = true    dynamodb_table = "my-project-tflock"  }}

Der key-Pfad ermöglicht mehrere State-Dateien im selben Bucket — nützlich für Workspaces oder mehrere Umgebungen.

Bootstrapping-Problem

Hier liegt die klassische Henne-Ei-Frage: Der S3-Bucket und die DynamoDB-Tabelle müssen existieren, bevor Terraform das Backend nutzen kann. Lösungsansätze:

  1. Manuell erstellen — einmalig per AWS CLI oder Konsole, dann in Terraform importieren
  2. Separates Bootstrap-Modul — ein kleines Terraform-Projekt mit lokalem State, das nur das Backend provisioniert
  3. Terraform Cloud — umgeht das Problem vollständig

Ich bevorzuge Option 2: Das Bootstrap-Modul ist klein, selten geändert, und der lokale State für dieses eine Modul ist akzeptabel.

IAM-Berechtigungen für CI/CD

Die CI/CD-Pipeline braucht minimale Berechtigungen:

JSON
{  "Version": "2012-10-17",  "Statement": [    {      "Effect": "Allow",      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],      "Resource": "arn:aws:s3:::my-project-tfstate/*"    },    {      "Effect": "Allow",      "Action": ["s3:ListBucket"],      "Resource": "arn:aws:s3:::my-project-tfstate"    },    {      "Effect": "Allow",      "Action": [        "dynamodb:GetItem",        "dynamodb:PutItem",        "dynamodb:DeleteItem"      ],      "Resource": "arn:aws:dynamodb:eu-central-1:*:table/my-project-tflock"    }  ]}

Least Privilege gilt auch hier: Die Pipeline braucht keine dynamodb:Scan- oder dynamodb:Query-Berechtigungen.

Fazit

S3 + DynamoDB als Terraform-Backend ist battle-tested, kostengünstig und einfach zu betreiben. Die Einrichtung dauert 30 Minuten — und spart Stunden an Debugging bei State-Konflikten.

Dieser Artikel wurde ursprünglich auf LinkedIn veröffentlicht und für die Website-Version erweitert.