"Fasse niemals die AWS-Konsole in der Produktion an" klingt nach einer extremen Regel. Ist es aber nicht. Es ist die wichtigste betriebliche Disziplin in einem Cloud-nativen Team, und die Kosten ihrer Verletzung akkumulieren sich leise, bis sie einen schweren Vorfall verursachen.

Dieser Beitrag erklart, warum, und wie man IaC-First-Entwicklung in einem echten Team durchsetzt.

Das State-Drift-Problem

Terraform (und OpenTofu) pflegt eine State-Datei, die darstellt, welche Infrastruktur existiert. Wenn du apply ausfuhrst, vergleicht Terraform die State-Datei mit deiner Konfiguration und fuhrt die minimale Anzahl von Anderungen durch, um die Realitat mit der Konfiguration in Einklang zu bringen.

Wenn du in der AWS-Konsole herumklickst und Ressourcen erstellst oder anderst, veranderst du die Realitat, ohne die State-Datei zu andern.

Jetzt: Der nachste Plan zeigt Drift: Terraform will Ressourcen zerstoren oder neu erstellen, die "nicht existieren sollten" (weil sie nicht in der Konfiguration stehen).

Oder schlimmer: Terraforms State sagt, die Ressource existiert mit Konfiguration A, aber die Konsole hat sie zu Konfiguration B geandert. plan zeigt "keine Anderungen", obwohl die Ressource falsch konfiguriert ist.

Oder: Jemand fugt eine Ressource in der Konsole hinzu, sie funktioniert, wird von anderen Ressourcen abhangig, und dann lauft ein apply und loscht sie, weil sie nicht im State ist.

Die Konsole ist nicht die Source of Truth. Deine IaC ist es. Die Konsole ist eine Luge.

Der Import-Workflow: Die richtige Reaktion auf "Es existiert bereits"

Wenn eine Ressource in AWS existiert, aber nicht in deiner Terraform-Konfiguration (erstellt von jemandem in der Konsole, manuell per CLI erstellt oder von einem anderen Tool migriert), ist die richtige Massnahme, sie zu importieren:

Eine existierende Ressource in den Terraform State importieren

./deploy.sh --infra --import aws_s3_bucket.service existing-bucket-name
./deploy.sh --infra --import aws_dynamodb_table.service_files serviceFiles
./deploy.sh --infra --import aws_lambda_function.service_api myapp-service-api

Nach dem Importieren fuhre plan aus:
./deploy.sh --infra

Der Plan zeigt den Unterschied zwischen dem, was in AWS existiert, und dem, was deine Konfiguration vorgibt. Korrigiere die Konfiguration, bis der Plan keine unerwarteten Anderungen zeigt. Dann fuhre apply aus, um die State-Datei zu synchronisieren.

Losche niemals eine Ressource aus der Konsole und erstelle sie per Terraform neu. Das zerstort Daten und bricht Abhangigkeiten. Importieren -> abgleichen -> anwenden.

Die eine legitime Konsolennutzung

Die Konsole ist angemessen fur:

  • Nur-Lese-Erkundung. CloudWatch Logs, CloudWatch Metriken, Lambda-Aufrufhistorie, DynamoDB-Elementinspektion.
  • Notfalloperationen mit sofortigem Import. Wenn die Produktion ausfallt und die Behebung eine Konsolenanderung erfordert, fuhre die Anderung durch; aber dokumentiere sie und importiere sie innerhalb derselben Arbeitssitzung in Terraform.

Das war's. Alles, was Ressourcen erstellt, andert oder loscht, gehort in die IaC.

Das Deploy-Skript als einziger Einstiegspunkt

Rohe terraform apply- oder tofu apply-Befehle, die direkt auf dem Host ausgefuhrt werden, sind gefahrlich, weil sie den Standard-Deploy-Workflow deines Teams umgehen (Validierung, Linting, Plan-Review). Erstelle ein Deploy-Skript, das alle Terraform-Operationen einheitlich umschliesst:

#!/bin/bash
# deploy.sh - the only way to interact with infrastructure

case “$1” in –infra) case “$2” in –apply) run_apply ;; –plan) run_plan ;; –validate) run_validate ;; –tflint) run_tflint ;; –import) run_import “$3” “$4” ;; *) run_plan ;; # default: plan only (safe) esac ;; esac

Schlusseleigenschaften eines guten Deploy-Skripts:

  • Standardmassig plan. Die Ausfuhrung von ./deploy.sh --infra ohne zweites Argument sollte den Plan anzeigen, niemals apply. Apply erfordert eine explizite Absicht (--apply).
  • Immer vor apply validieren. Fuhre terraform validate und tflint vor jedem apply aus. Lehne das Deployment ab, wenn eines davon fehlschlagt.
  • Immer den Plan vor dem Anwenden anzeigen. Selbst bei --apply, zeige die Plan-Ausgabe und verlange Bestatigung im interaktiven Modus.
  • Konsistente var-file. Verwende immer dieselbe var-file (vars/production.tfvars). Niemals ohne sie anwenden.

Plan Review als Gate

Bevor ein Infrastruktur-PR gemerged wird, sollte die Plan-Ausgabe im PR sichtbar sein:
## Terraform Plan

Terraform will perform the following actions:
module.service_api.aws_lambda_function.service_api will be updated in-place
~ resource "aws_lambda_function" "service_api" {
~ timeout = 30 -> 60
}

Plan: 0 to add, 1 to change, 0 to destroy.

module.service_api.aws_lambda_function.service_api will be updated in-place

~ resource "aws_lambda_function" "service_api" {
~ timeout = 30 -> 60
}

Plan: 0 to add, 1 to change, 0 to destroy.

Das erreicht zwei Dinge:

  1. Der Reviewer kann genau sehen, was sich in der Produktion andern wird, bevor er genehmigt.
  2. Die Plan-Ausgabe ist eine historische Aufzeichnung dessen, was zum Merge-Zeitpunkt beabsichtigt war.

Ein Plan, der unerwartete Zerstorungen zeigt (N to destroy), sollte den PR blockieren, bis der Autor erklart, warum.

Die No-Exclude-Regel

Ein haufiger Fehler, wenn ein apply fehlschlagt: die fehlschlagende Ressource ausschliessen und trotzdem anwenden.

# FALSCH tofu apply -exclude='aws_bedrockagent_knowledge_base.kb'

Das erzeugt ein partielles Apply: Einige Ressourcen wurden aktualisiert, einige nicht. Die State-Datei spiegelt jetzt eine teilweise angewandte Konfiguration wider. Die ausgeschlossene Ressource ist nicht synchron mit allem, was von ihr abhangt.

Die richtige Reaktion auf eine fehlschlagende Ressource:

  1. Lass das apply zu Ende laufen. Unterbrich es nicht.
  2. Verstehe, warum die Ressource fehlgeschlagen ist.
  3. Korrigiere die Konfiguration oder importiere die existierende Ressource.
  4. Fuhre apply erneut aus, bis null Fehler auftreten.

Wenn der Fehler "resource already exists" ist: importiere sie.
Wenn der Fehler ein Config Mismatch ist: korrigiere die Konfiguration, um sie mit der existierenden Ressource abzugleichen.
Wenn der Fehler ein Dependency Ordering-Problem ist: korrigiere depends_on.

Niemals: ausschliessen, auskommentieren oder anderweitig Ressourcen uberspringen. Die IaC-Konfiguration muss immer die Realitat widerspiegeln.

Das Force-Unlock

Terraform verwendet eine Lock-Tabelle (DynamoDB), um gleichzeitige Applies zu verhindern. Wenn ein Lock feststeckt (Lambda-Time-out mitten im Apply, Prozess wurde beendet), siehst du:

Error: Error locking state: Error acquiring the state lock

Die verlockende Losung: terraform force-unlock. Das ist gefahrlich, wenn ein anderes apply tatsachlich lauft -- das Force-Unlock eines laufenden Applies fuhrt zu Korruption.

Die richtige Reaktion:

  1. Uberprufe, ob tatsachlich ein Apply lauft (prufe CloudWatch fur die Deploy-Lambda, frage die Teamkollegen).
  2. Wenn kein Apply lauft und du sicher bist, dass der Lock veraltet ist, dann force-unlock.
  3. Dokumentiere, dass du einen Lock forciert hast -- es ist ein Signal, zu untersuchen, warum das vorherige Apply nicht ordnungsgemass aufgeraumt hat.

Niemals force-unlock als erste Reaktion. Verifiziere immer zuerst, dass kein Live-Apply lauft.

Drift-Erkennung

Selbst mit strikter IaC-Disziplin akkumuliert sich Drift. AWS kann Ressourcen automatisch andern (z.B. Cognito, das eine Lambda-Trigger-Verknupfung aktualisiert), oder ein Teammitglied macht eine Notfall-Konsolenanderung und vergisst, sie zu importieren.

Plane eine regelmassige Plan-Ausfuhrung (wochentlich oder nach Phasen signifikanter Aktivitat) ohne Apply ein:

# In CI/CD: weekly scheduled plan ./deploy.sh --infra --plan 2>&1 | tee plan-output.txt # Alert if plan shows unexpected changes

Wenn der Plan Anderungen zeigt, die nicht existieren sollten, untersuche sie, bevor das nachste Apply sie zerstort.

Schlusselerkenntnisse

  • Die AWS-Konsole ist zum Lesen da, nicht zum Schreiben. Jede Infrastrukturanderung gehort in die IaC.
  • Wenn eine Ressource in AWS existiert, aber nicht in Terraform: importiere sie, gleiche die Konfiguration ab, dann wende an.
  • Verwende niemals -exclude, um eine fehlschlagende Ressource zu umgehen. Behebe die eigentliche Ursache.
  • Ummantle alle Terraform-Operationen in einem Deploy-Skript. Standardmassig plan; erfordere explizite Absicht fur apply.
  • Fuge die Plan-Ausgabe in jeden Infrastruktur-PR ein. Unerwartete Zerstorungen sollten den PR blockieren.
  • Niemals force-unlock, ohne zu verifizieren, dass kein Live-Apply lauft.
  • Fuhre geplante Plan-Checks durch, um Drift fruhzeitig zu erkennen.