Terraform in CI/CD
Automatisierter Plan/Apply in Pipelines.
Lernziele
Nach dieser Lektion kannst du Terraform sinnvoll in CI/CD-Pipelines einbinden: Plan in Pull Requests, Apply in kontrollierten Deploy-Jobs. Du kennst das Pattern mit gespeichertem Plan-Artefakt, OIDC-basierter Authentifizierung ohne Long-Lived-Keys und typische Pipeline-Stages. Außerdem weißt du, wie du Apply-Freigaben und Drift-Checks organisierst.
Das Problem: Terraform auf dem Laptop in Produktion
Der klassische Weg — terraform apply lokal mit Admin-Credentials — hat vier Schwachstellen: Kein auditierbarer Review-Pfad (wer hat approved?), Credentials auf Entwickler-Maschinen, kein reproduzierbarer Plan (lokale Provider-Version, lokale tfvars) und kein Gate zwischen „ich habe reviewed” und „es läuft”.
In Platform-Teams ist Terraform in CI/CD der Mindeststandard: Plan läuft automatisch bei jedem PR, Apply nur aus der Pipeline mit least-privilege-Credentials und — in Produktion — manueller oder policy-basierter Freigabe.
Die Pipeline-Architektur: zwei Jobs, ein Plan
Das bewährte Muster trennt Plan und Apply strikt:
PR geöffnet → terraform init → terraform plan → Plan-Artefakt + PR-Kommentar
↓
PR merged → terraform init → terraform apply (gespeicherter Plan) → nur auf main/protected branch
Kernregel: Der Apply-Job nutzt denselben Plan, der im PR reviewed wurde — nicht einen frisch berechneten.
# Auszug GitHub Actions — vereinfacht
jobs:
plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init
- run: terraform plan -out=plan.tfplan -var-file=env/prod.tfvars
- run: terraform show -no-color plan.tfplan > plan.txt
- uses: actions/upload-artifact@v4
with:
name: tfplan
path: plan.tfplan
apply:
needs: plan
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production # GitHub Environment Protection Rules
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- uses: actions/download-artifact@v4
with:
name: tfplan
- run: terraform init
- run: terraform apply -auto-approve plan.tfplan
environment: production aktiviert Required Reviewers — ein Mensch muss explizit freigeben, bevor Apply startet.
Authentifizierung: OIDC statt Access Keys
Long-Lived AWS Access Keys in GitHub Secrets sind ein Sicherheitsrisiko — Rotation vergessen, Keys geleakt, übermäßige Rechte. OIDC Federation erlaubt der Pipeline, kurzlebige Tokens von AWS/Azure/GCP anzufordern:
permissions:
id-token: write
contents: read
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-terraform
aws-region: eu-central-1
Die IAM-Rolle vertraut nur Requests von deinem GitHub-Repo und optional nur vom main-Branch. Kein Secret außer der Role-ARN — und selbst der ist nicht sensibel.
In Terraform selbst ändert sich nichts: Der AWS-Provider nutzt die Credential Chain, die OIDC befüllt hat.
Was in jede Pipeline gehört — und was nicht
Pflicht:
terraform fmt -check— Stil-Diff vermeidenterraform validate— Syntax vor Planterraform planbei jedem PR- Plan-Artefakt speichern und im Apply wiederverwenden
TF_IN_AUTOMATION=true— unterdrückt interaktive Prompts
Empfohlen:
tflint/checkov— Linting und Security (Lektionen 11–12)- Scheduled
terraform planauf main — Drift-Detection ohne Code-Änderung -var-fileaus verschlüsselten Secrets oder S3, nicht hardcoded
Nicht in Standard-Pipelines:
terraform apply -auto-approveauf Prod ohne Environment-Gateterraform destroyohne expliziten, separaten Workflow mit Extra-Approval-targetals Dauerlösung
Drift-Detection: Plan ohne Code-Änderung
Ein Cron-Job, der täglich terraform plan auf main ausführt und bei „Changes detected” alertet, findet ClickOps und externe Änderungen:
on:
schedule:
- cron: '0 6 * * 1-5'
jobs:
drift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init
- run: terraform plan -detailed-exitcode -var-file=env/prod.tfvars
continue-on-error: true
id: plan
- if: steps.plan.outcome == 'failure' && steps.plan.outputs.exitcode == 2
run: echo "Drift detected!" && exit 1
Exit Code 2 bei -detailed-exitcode bedeutet: es gibt Änderungen. Exit 0: No changes. Exit 1: Fehler.
Praxis: Minimale Pipeline lokal simulieren
Du kannst den Plan-Apply-Flow ohne CI nachstellen:
mkdir cicd-lab && cd cicd-lab
cat > main.tf <<'EOF'
resource "random_pet" "server" { length = 2 }
output "name" { value = random_pet.server.id }
EOF
export TF_IN_AUTOMATION=true
terraform init
terraform plan -out=plan.tfplan
terraform show -no-color plan.tfplan > plan.txt # das wäre der PR-Kommentar
cat plan.txt
terraform apply -auto-approve plan.tfplan
terraform destroy -auto-approve
TF_IN_AUTOMATION=true ist das, was CI setzt — probiere den Flow einmal ohne und einmal mit, um den Unterschied in der Ausgabe zu sehen.
Typische Stolperfallen
Apply ohne Plan-Artefakt: Jeder Apply-Job, der selbst plan berechnet, kann vom reviewed Plan abweichen — durch Provider-Updates, geänderte tfvars oder API-Drift zwischen den Jobs.
Backend-Credentials in CI zu mächtig: Die Pipeline braucht State-Write und Cloud-Apply — aber nicht iam:* auf *. Scoped Roles pro Stack.
Plan in PR kommentieren, aber niemand liest: Automatisierte PR-Kommentare mit terraform show helfen nur, wenn Reviewer den Diff verstehen. Schulung und kleine Stacks sind wichtiger als fancy Bots.
Init in jedem Job vergessen: Plan- und Apply-Job brauchen beide init — der Apply-Job lädt nicht automatisch den State des Plan-Jobs, nur das Plan-Artefakt.
Secrets in Plan-Output: Auch mit sensitive können manche Provider Werte leaken. PR-Kommentare filtern oder nur Summary posten.
Interview-Vorbereitung
„Wie integrierst du Terraform in CI/CD?” — Plan bei PR, Apply nur auf main mit gespeichertem Plan; OIDC statt Long-Lived Keys; Environment-Gates für Prod; fmt/validate/lint vor Plan.
Follow-ups:
- „Warum Plan und Apply trennen?” — Reviewbarkeit, Reproduzierbarkeit, Apply = exakt der reviewed Diff.
- „Wie authentifizierst du die Pipeline?” — OIDC Federation → kurzlebige Cloud-Credentials; IAM Role mit minimalen Rechten.
- „Was ist Drift-Detection?” — Scheduled plan auf unverändertem Code; Exit Code 2 = Abweichung.
- „Wann
-auto-approve?” — Nur in CI nach Plan-Artefakt und Environment-Approval — nie interaktiv auf Prod-Laptops.
Zusammenfassung
Terraform in CI/CD bedeutet: Plan bei jedem Change, Apply nur kontrolliert mit dem gespeicherten Plan-Artefakt. OIDC ersetzt Long-Lived Access Keys; Environment Protection Rules gate Prod-Deploys. fmt, validate und optional Lint laufen vor Plan; Drift-Checks per Scheduled Plan finden ClickOps. Wer das Pattern beherrscht, hat den Übergang von Solo-Hacking zu Team-Betrieb gemeistert.
In der nächsten Lektion schärfen wir die Qualität mit Testing und Validation.