OMNI52
Terraform Cheatsheet OMNI52™ GmbH

Terraform
auf einem Blatt.

Dichte Referenz für Senior Platform Engineers und SREs zu HashiCorps Infrastructure-as-Code-Werkzeug. HCL-Kern, State und Locking, Module, Meta-Argumente, Import und Refactoring, Tests, CI/CD-Patterns und Anti-Patterns. Keine Einsteiger-Folien.

Vorschau (2 Seiten A4 quer + Brand-Rückseite)

Terraform Cheatsheet Seite 1: HCL-Kern, Provider, State, Module, Meta-Argumente
Terraform Cheatsheet Seite 2: Plan/Apply, Import und Refactoring, Workspaces, Tests, CI/CD, Anti-Patterns

PDF herunterladen

Direkter Download, keine Mail-Adresse nötig. CC BY-SA 4.0 — kopieren, drucken, weiterverteilen ist ausdrücklich erlaubt, solange die Quellenangabe sichtbar bleibt.

Terraform Cheatsheet (PDF, ~100 KB)

Was drin steht

HCL-Kern & Provider

resource/data/locals/variables/outputs, Typen + Validation, sensitive. Version-Pinning mit ~>, .terraform.lock.hcl, Provider-Alias für Multi-Region.

State & Drift

Remote Backends, natives S3-Locking (use_lockfile), state mv/rm, plan -refresh-only. Ephemeral Values und write-only Attribute gegen Klartext-Secrets.

Module & Meta-Argumente

Struktur, Registry-Versionierung, Git-ref-Pinning. for_each vs count, depends_on, lifecycle, dynamic blocks.

Plan/Apply & Import

plan -out als Artefakt, -detailed-exitcode, -replace, -target-Vorsicht. import-Block, -generate-config-out, moved/removed statt State-Chirurgie.

Workspaces & Tests

Workspaces und ihre Grenzen bei Prod-Trennung. terraform test mit .tftest.hcl, run/assert, Mocking seit 1.7.

CI/CD & Anti-Patterns

Plan-Artefakt + Approval-Gate, Pipeline-Hygiene, BUSL-Lizenzstand. Anti-Patterns aus der Praxis.

Cheatsheet im Volltext

Derselbe Inhalt wie im PDF — zum Mitlesen, Durchsuchen und direkten Kopieren der HCL-Snippets. Stand: Terraform v1.15 (Edition 2026.07).

HCL-Kern

Bausteine

resource: verwaltetes Objekt (Create/Update/Delete durch Terraform). data: Read-only-Lookup bestehender Objekte. variable: Eingabe pro Root-/Child-Modul. locals: benannte Zwischenwerte, DRY für Ausdrücke. output: Rückgabewerte, Schnittstelle zwischen Modulen und nach aussen.

Typen, Validation, sensitive

Typen explizit setzen: string, number, bool, list(...), map(...), object({...}) — fängt Fehler beim Plan statt beim Apply.

validation-Block prüft Eingaben mit condition + error_message.

sensitive = true maskiert Werte im CLI-Output, entfernt sie aber nicht aus State oder Plan-Datei.

variable "env" {
  type = string
  validation {
    condition     = contains(["dev","prod"], var.env)
    error_message = "env muss dev oder prod sein."
  }
}
locals {
  name_prefix = "app-${var.env}"
}
output "lb_dns" {
  value       = aws_lb.this.dns_name
  description = "Public LB-Endpoint"
}

Provider & Versionen

Version-Pinning

required_version pinnt die CLI, required_providers pinnt Provider (source + version). Pessimistic-Operator ~> erlaubt nur Patch-/Minor-Updates innerhalb der Grenze.

.terraform.lock.hcl einchecken — exakte Provider-Versionen + Hashes für alle Umgebungen. terraform init -upgrade ist eine bewusste Aktion, kein Default.

Provider-Alias

Mehrere Regionen/Accounts: gleicher Provider mit alias, Zuordnung per provider = am Resource- bzw. providers =-Map am Modul-Block.

terraform {
  required_version = ">= 1.10, < 2.0"
  required_providers {
    aws = { source = "hashicorp/aws",
            version = "~> 6.0" }
  }
}
provider "aws" { region = "eu-central-1" }
provider "aws" {
  alias  = "dr"
  region = "eu-west-1"
}
resource "aws_s3_bucket" "replica" {
  provider = aws.dr
  bucket   = "${local.name_prefix}-replica"
}

State

Remote Backend, Locking

State gehört in ein Remote Backend (S3, azurerm, gcs, …): gemeinsamer Stand + Locking gegen parallele Applies.

S3: natives Locking via use_lockfile = true (seit 1.10, GA in 1.11); die DynamoDB-Argumente sind seit 1.11 deprecated.

terraform {
  backend "s3" {
    bucket       = "tf-state-prod"
    key          = "network/terraform.tfstate"
    region       = "eu-central-1"
    use_lockfile = true   # natives S3-Locking
    encrypt      = true
  }
}

State ist sensibel

Der State enthält Resource-Attribute im Klartext — auch Passwörter und Keys. Zugriff wie auf ein Secret beschränken, Verschlüsselung at rest aktivieren.

Werte aus dem State heraushalten: ephemeral Values/Resources (1.10+) und write-only Attribute (1.11+) werden nicht persistiert.

State-Kommandos, Drift

state list / state show: Inventar inspizieren. state mv / state rm: imperative Chirurgie — für geplantes Refactoring besser moved/removed-Blöcke.

Drift: plan -refresh-only zeigt Abweichungen der Realität vom State, apply -refresh-only übernimmt sie in den State (ohne Infrastruktur-Änderung).

terraform state list
terraform state show aws_s3_bucket.logs
terraform state mv aws_iam_role.a aws_iam_role.b
terraform state rm aws_iam_role.orphan
terraform plan -refresh-only   # Drift-Report

Module

Struktur

Standard-Layout: main.tf, variables.tf, outputs.tf (+ README). Kleine, fachlich geschnittene Module; Komposition flach im Root-Modul. Tiefe Modul-in-Modul-Ketten machen Plans träge und Schnittstellen unklar.

Quellen, Versionierung

Registry-Quelle <ns>/<name>/<provider> + version (nur Registry-Quellen unterstützen version).

Git-Quelle über ?ref= auf Tag/Commit pinnen — nie auf einen beweglichen Branch.

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 6.0"
  name    = local.name_prefix
  cidr    = "10.20.0.0/16"
}
module "baseline" {
  source = "git::https://git.example.com/tf/baseline.git?ref=v2.3.1"
}

Meta-Argumente

for_each, count, depends_on

for_each über Map/Set: stabile Keys als Adresse — Einträge löschen verschiebt keine Nachbarn.

count: nur für identische Kopien oder das An/Aus-Muster (count = var.enabled ? 1 : 0). Bei benannten Objekten drohen Index-Shifts.

depends_on: nur wenn die implizite Abhängigkeit über Referenzen nicht ausreicht (z.B. IAM-Policy vor Nutzung).

lifecycle

create_before_destroy: Ersatz zuerst hochziehen. prevent_destroy: Plan schlägt fehl, statt z.B. eine Datenbank zu löschen.

ignore_changes: einzelne Attribute extern verwalten lassen — chirurgisch einsetzen. replace_triggered_by: Ersatz an fremde Änderung koppeln.

resource "aws_iam_user" "team" {
  for_each = toset(["ci", "audit", "ops"])
  name     = "svc-${each.key}"
}
resource "aws_db_instance" "main" {
  # ...
  lifecycle {
    prevent_destroy = true
    ignore_changes  = [password]
  }
}

dynamic blocks

Wiederholte Nested Blocks

dynamic "<block>" + for_each + content erzeugt wiederholte verschachtelte Blöcke; Iterator heisst wie das Block-Label. Sparsam einsetzen: verschachtelte dynamics sind schwer lesbar — oft ist die ausgeschriebene Liste klarer.

resource "aws_security_group" "web" {
  name = "${local.name_prefix}-web"
  dynamic "ingress" {
    for_each = var.service_ports   # z.B. {http=80, https=443}
    content {
      from_port   = ingress.value
      to_port     = ingress.value
      protocol    = "tcp"
      cidr_blocks = ["10.0.0.0/8"]
    }
  }
}

Plan / Apply / Destroy

Kern-Workflow

fmt -check + validate als schnelles Gate, dann plan -out=tfplan und apply tfplan — es wird exakt der reviewte Plan angewandt.

plan -detailed-exitcode: 0 = keine Änderung, 2 = Änderungen — sauber für Pipelines. -replace=<addr> erzwingt gezielte Neuerstellung. destroy nur für ganze (Wegwerf-)Umgebungen.

-target ist ein Notfall-Werkzeug

-target schneidet den Abhängigkeitsgraphen ab — das Ergebnis entspricht nicht mehr der Konfiguration. Nur zur Incident-Reparatur, danach sofort ein voller Plan ohne -target, bis er leer ist.

terraform fmt -check -recursive
terraform validate
terraform plan -out=tfplan -detailed-exitcode
terraform apply tfplan
terraform apply -replace=aws_instance.worker[2]

Import & Refactoring

import-Block (1.5+)

Bestehende Infrastruktur deklarativ adoptieren: plannbar, reviewbar, im normalen Plan/Apply-Zyklus. -generate-config-out=<datei> erzeugt HCL für importierte Objekte ohne Config. for_each am import-Block seit 1.7.

moved / removed

moved (1.1+): Adresse geändert (Rename, Modul-Umzug) — Terraform migriert den State beim Plan, kein state mv.

removed (1.7+): Objekt aus Config + State entfernen, ohne es zu zerstören (destroy = false).

import {
  to = aws_s3_bucket.logs
  id = "legacy-logs-bucket"
}
moved {
  from = aws_instance.app
  to   = module.compute.aws_instance.app
}
removed {
  from = aws_s3_bucket.archiv
  lifecycle { destroy = false }
}

Workspaces & Tests

Workspaces und ihre Grenzen

Ein Workspace = eigener State bei gleicher Config und gleichem Backend. Gut für kurzlebige Varianten (Feature-Test, Review-Umgebung).

Grenze: Prod/Non-Prod-Trennung — gleiche Credentials, gleicher State-Bucket, terraform.workspace-Verzweigungen im Code. Dafür getrennte Root-Module + Backends verwenden.

terraform workspace new review-142
terraform workspace select review-142
terraform workspace list
# im Code: name = "app-${terraform.workspace}"

terraform test (1.6+)

Tests in *.tftest.hcl: run-Blöcke führen command = plan (schnell, ohne echte Ressourcen) oder apply aus und prüfen assert-Bedingungen. Seit 1.7: mock_provider + Overrides — Provider-Antworten simulieren statt echte Infrastruktur anzulegen.

# tests/naming.tftest.hcl
run "prod_prefix" {
  command = plan
  variables { env = "prod" }
  assert {
    condition     = local.name_prefix == "app-prod"
    error_message = "Prefix-Schema verletzt"
  }
}

CI/CD-Patterns

Plan-Artefakt, Approval

Build-Job: plan -out=tfplan, Plan-Artefakt + lesbaren show-Output an den Review hängen. Nach Approval wendet der Apply-Job dasselbe Artefakt an — kein zweiter Plan zwischen Review und Apply, keine unbemerkte Differenz.

Pipeline-Hygiene

init -input=false (keine interaktiven Prompts), fmt -check + validate als frühes Gate, Lock-Datei committed.

State-Zugriff nur für die Pipeline-Identität; kurzlebige Cloud-Credentials statt statischer Keys.

terraform init -input=false
terraform plan -input=false -out=tfplan
terraform show -no-color tfplan > plan.txt  # Review
# --- nach Approval ---
terraform apply -input=false tfplan

Version & Lizenz

1.x-Release-Linie, BUSL

Aktuelle stabile Linie: 1.15 (Stand Juli 2026).

Seit 1.6 steht Terraform unter der Business Source License 1.1 (Change License: MPL 2.0 nach vier Jahren); die Einschränkung zielt auf konkurrierende Angebote. Versionen bis 1.5.x bleiben MPL 2.0. OpenTofu ist ein MPL-2.0-lizenzierter Community-Fork auf Basis von Terraform 1.5.

Anti-Patterns

Was du nicht tun solltest

-target als Routine: zerschnittener Graph, Code und Realität divergieren — nur im Notfall.

State von Hand editieren: JSON-Chirurgie korrumpiert Serial/Lineage — state-Kommandos oder moved/removed nutzen.

count für benannte Objekte: Löschen in der Mitte verschiebt Indizes — Nachbarn werden zerstört/neu erzeugt. for_each nehmen.

Provider/Module unpinned: nächstes init zieht ein Major-Update in den Apply — pinnen + Lock-Datei committen.

Secrets als Klartext-Variable: landen in State und Plan-Datei — ephemeral/write-only nutzen, State-Zugriff beschränken.

Workspaces als Prod-Trennung: ein Backend, eine Credential-Grenze für alles — getrennte Root-Module + Backends.

Apply ohne Plan-Artefakt in CI: zwischen Review und Apply entsteht ein anderer Plan — immer apply tfplan.

Monolith-Root-Modul: ein State für alles = maximaler Blast-Radius und träge Plans — nach Lebenszyklus/Team schneiden.

ignore_changes als Dauerpflaster: verdeckt Drift und echte Ownership-Fragen — klären, wer das Attribut verwaltet.

Aus der OMNI52 Cheatsheet-Fabrik

Verwandte Sheets in dichter Senior-Qualität:
vault-cheatsheet.de — Secrets-Management
flux-cheatsheet.de — GitOps mit Flux
argocd-cheatsheet.de — GitOps mit Argo CD
rancher-cheatsheet.de — Cluster-Management

Lizenz & Weiterverteilung

CC BY-SA 4.0. Du darfst dieses Cheatsheet kopieren, weiterverteilen, ausdrucken und in eigenen Materialien zitieren. Bedingung: Quellenangabe „Terraform Cheatsheet — OMNI52 GmbH, terraform-cheatsheet.de“ bleibt sichtbar, und abgeleitete Werke stehen unter der gleichen Lizenz (Share-Alike).

Nicht erlaubt: Logo, Marken oder den Eindruck zu vermitteln, dass der Inhalt von dir/euch stammt oder dass OMNI52 GmbH die Weiterverwendung sponsort.

Volltext der Lizenz: creativecommons.org/licenses/by-sa/4.0/deed.de.

Terraform and the Terraform logo are trademarks of HashiCorp, Inc. (HashiCorp is an IBM company). OMNI52™ is a trademark of OMNI52 GmbH (filed, not yet registered). This website is operated by OMNI52 GmbH and is not affiliated with, endorsed by, or sponsored by HashiCorp, Inc. or IBM. “Terraform” is used in a nominative / descriptive sense to indicate the technology this cheatsheet documents.