Werkzeugwahl

Infrastructure as Code: Terraform, Bicep, Pulumi oder Crossplane richtig auswählen

Wer ausschließlich Azure betreibt, kommt mit Bicep schneller ans Ziel, weil neue Ressourcentypen dort am Tag der Veröffentlichung nutzbar sind und kein eigener State verwaltet werden muss. Sobald ein zweiter Anbieter, DNS, GitLab oder ein SaaS-Dienst dazukommen, dreht sich das zugunsten von Terraform und OpenTofu. Pulumi und das CDK lohnen sich, wenn ein Entwicklungsteam den Bestand pflegt. Crossplane erst dann, wenn Kubernetes bei euch ohnehin die Betriebsplattform ist.

5 Kapitel mit allen Befehlen
Zwei IT-Entscheider vergleichen Plattformoptionen an einem großen Bildschirm
Seit 1997 am Markt Präsenz & Live-Online 4,9 aus 503 Google-Bewertungen Auch Inhouse für dein Team
Worum es geht

Warum die Werkzeugfrage teurer ist, als sie zunächst aussieht

Die Entscheidung fällt in den meisten Häusern nebenbei. Jemand braucht kurzfristig eine Testumgebung, schreibt dreißig Zeilen Terraform, und zwei Jahre später hängt der komplette Bestand daran. Problematisch ist dabei nicht die Sprache, sondern die Kette, die mit ihr kommt: ein State-Format, ein Sperrmechanismus, ein Modulkonzept, eine Pipeline, eine Art Geheimnisse zu übergeben und ein Rollenmodell für die Anmeldung. Wer später wechselt, tauscht nicht Syntax, sondern genau diese Kette. Deshalb lohnt sich die bewusste Entscheidung, bevor die ersten hundert Ressourcen im Code stehen.

Der zweite Kostenpunkt ist der Bestand, der nicht im Code liegt. In fast jeder gewachsenen Umgebung gibt es von Hand angelegte Ressourcen, Änderungen aus dem Portal und Reste abgebrochener Projekte. Den Unterschied zwischen Beschreibung und Wirklichkeit nennt Terraform Drift, und solange dieser Drift nicht sichtbar ist, bleibt jeder Plan-Lauf ein Ratespiel. Bicep und CloudFormation gehen anders damit um, weil sie den Ist-Zustand direkt bei der Plattform erfragen statt ihn in einer eigenen Datei zu führen. Dieser Unterschied wiegt im Betrieb oft schwerer als jede Syntaxfrage.

Der dritte Punkt ist das Team. Ein deklaratives Werkzeug erzwingt eine feste Struktur und ist deshalb auch für Kolleginnen und Kollegen ohne Entwicklungshintergrund gut lesbar. Eine echte Programmiersprache wie bei Pulumi oder dem CDK bringt Schleifen, Tests und Bibliotheken mit, verlangt dafür aber Softwarehandwerk: Abhängigkeitsverwaltung, Versionsstände, Codereview und eine Teststrategie. Beides trägt. Was regelmäßig scheitert, ist ein reines Betriebsteam, das plötzlich TypeScript pflegen soll, und ebenso ein Entwicklungsteam, dem HCL als einzige Ausdrucksform vorgesetzt wird.

Miniatur-Szene: zwei Plattformen nebeneinander mit unterschiedlichen Cloud-Bausteinen, dazwischen eine Waage

Sechs Fragen, die die Werkzeugwahl entscheiden

  1. 01 Wie viele Plattformen musst du wirklich beschreiben?
  2. 02 Wer pflegt den Code dauerhaft: Betrieb oder Entwicklung?
  3. 03 Wo liegt der Ist-Zustand: eigener State oder Plattform?
  4. 04 Wie prüfst du Änderungen, bevor sie angewendet werden?
  5. 05 Wie kommt bestehende Infrastruktur nachträglich in den Code?
  6. 06 Welche Lizenz- und Anbieterbindung akzeptiert ihr?
Was du mitnimmst

Die Kandidaten und wofür sie taugen

Kein Werkzeug gewinnt alle Fälle. Sinnvoll ist die Zuordnung entlang von drei Achsen: wie viele Plattformen wirklich im Spiel sind, wer den Code dauerhaft pflegt und wo der Ist-Zustand geführt wird.

Terraform

Der Standard, wenn mehr als eine Plattform beschrieben werden soll. Über 4.000 Provider decken auch DNS, GitLab, Datenbanken und Monitoring ab, das Modulkonzept ist ausgereift und der Arbeitsmarkt kennt HCL. Der Preis ist der eigene State, den du sichern, sperren und schützen musst. Seit dem Wechsel auf die Business Source License gehört die Lizenzfrage in jede Entscheidung.

OpenTofu

Der quelloffene Abzweig unter der Linux Foundation, zu Terraform bis Version 1.5 weitgehend kompatibel und mit eigener Registry. Interessant für alle, die Lizenzrisiken ausschließen wollen oder deren Produkt selbst Infrastruktur bereitstellt. Der Umstieg ist meist ein Austausch des Kommandos, die Prüfung der Provider-Bezugsquellen kostet die eigentliche Zeit. Funktional laufen beide Projekte inzwischen auseinander.

Bicep

Die naheliegende Wahl in reinen Azure-Umgebungen. Bicep übersetzt in ARM-Vorlagen, kennt neue Ressourcentypen sofort, braucht keinen State und liefert mit dem What-If-Lauf eine belastbare Vorschau. Dafür endet die Reichweite an der Azure-Grenze, und Module lassen sich nicht so frei zusammenstellen wie in Terraform. Für Plattformteams, die nur Azure betreiben, ist der Einstieg deutlich kürzer.

CloudFormation und das AWS CDK

Das Gegenstück bei AWS. CloudFormation verwaltet Stacks samt Rollback und Change Sets serverseitig, das CDK erzeugt daraus Vorlagen aus TypeScript, Python oder Java. Attraktiv ist die enge Verzahnung mit Service Catalog und Organizations. Nachteil ist die Anbieterbindung und dass Fehler in erzeugtem Code schwerer zu lesen sind als in handgeschriebenem HCL.

Pulumi

Infrastruktur in einer echten Programmiersprache, mit Bibliotheken, Unit-Tests und der gewohnten Entwicklungsumgebung. Das lohnt sich, wenn ein Produktteam Infrastruktur mitliefert und dieselben Werkzeuge nutzen will wie für die Anwendung. In Betriebsteams ohne Entwicklungsroutine entsteht dagegen schnell Code, den außer der Autorin niemand pflegen kann. Der State liegt wahlweise beim Anbieter oder selbst gehostet.

Crossplane

Kein Kommandozeilenwerkzeug, sondern eine Control Plane im Cluster: Fremdressourcen werden zu Kubernetes-Objekten, ein Controller gleicht Soll und Ist dauerhaft ab. Damit verschwindet der klassische Plan-Lauf, Drift wird laufend korrigiert. Sinnvoll ist das, wenn Kubernetes bereits die Betriebsplattform ist und Teams sich Infrastruktur über eigene Ressourcentypen selbst anfordern sollen.

Tutorial

Von der Anforderung bis zum geprüften Plan

In reinen Azure-Umgebungen kommst du mit Bicep schneller ans Ziel, sobald ein zweiter Anbieter, DNS oder ein SaaS-Dienst dazukommt, gewinnen Terraform und OpenTofu. Den Rest entscheiden zwei Fragen: wer den Code dauerhaft pflegt und wo der Ist-Zustand geführt wird. Die Kapitel machen das nachprüfbar, von den messbaren Anforderungen über dieselbe Ressource in zwei Sprachen und den Umgang mit State und Drift bis zur geprüften Änderung und zu Crossplane als Sonderfall für Häuser, die Kubernetes bereits betreiben.

01

Schritt 1: Anforderungen sichtbar machen

Bevor du Produkte vergleichst, gehört auf den Tisch, was deine Umgebung überhaupt braucht. Diese Antworten holst du aus dem Bestand, nicht aus einem Blogbeitrag.

Fünf Angaben reichen für eine belastbare Vorauswahl: die Zahl der Plattformen, die tatsächlich im Code landen sollen, die Zusammensetzung des Teams, die Menge an bestehender Infrastruktur ohne Code, die Anforderungen an Freigabe und Nachweis sowie die Frage, ob Anwendungsteams sich Infrastruktur künftig selbst anfordern sollen. Der letzte Punkt kippt die Entscheidung am häufigsten, weil Selbstbedienung eine Abstraktionsschicht braucht, die klassische Skripte nicht liefern. Wie diese Schicht aussieht, beschreibt Platform Engineering einführen genauer.

Wann das plattformeigene Werkzeug reicht und wann nicht

KriteriumSpricht für Bicep oder CloudFormationSpricht für Terraform oder OpenTofu
ReichweiteAlles liegt in einer einzigen CloudDNS, SaaS, Git-Plattform oder ein zweiter Anbieter gehören dazu
Ist-ZustandKein eigener State erwünscht, Plattform führt BuchZentraler State ist akzeptiert und wird ohnehin gesichert
Tempo neuer DiensteNeue Ressourcentypen sollen am Tag eins nutzbar seinEin Provider-Update von wenigen Tagen ist verkraftbar
TeamBetriebsteam, das Vorlagen liest statt Programme schreibtTeam arbeitet bereits mit Modulen, Registry und Pipelines
BestandWenig Altbestand, überwiegend NeubauViel gewachsene Infrastruktur, die schrittweise importiert wird
BindungAnbieterbindung ist ohnehin gesetztLizenz und Ausstiegspfad sollen offen bleiben
02

Schritt 2: Dieselbe Ressource in Terraform und in Bicep

Der Vergleich wird konkret, sobald dieselbe Ressource in beiden Sprachen steht. Beide Fassungen erzeugen dasselbe Speicherkonto mit erzwungenem TLS 1.2 und ohne öffentlichen Blob-Zugriff.

main.tf mit dem azurerm-Provider
terraform {
  required_version = ">= 1.9"
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 4.0"
    }
  }
}

provider "azurerm" {
  features {}
}

resource "azurerm_storage_account" "artefakte" {
  name                            = "stplattformprod01"
  resource_group_name             = azurerm_resource_group.plattform.name
  location                        = azurerm_resource_group.plattform.location
  account_tier                    = "Standard"
  account_replication_type        = "LRS"
  min_tls_version                 = "TLS1_2"
  allow_nested_items_to_be_public = false

  tags = {
    kostenstelle = "plattform"
    umgebung     = "prod"
  }
}

Die Versionsklammer ~> 4.0 gehört in jedes Projekt. Ohne sie zieht der nächste terraform init in einer frischen Pipeline eine neue Hauptversion des Providers, und ein Lauf, der gestern grün war, will heute Ressourcen ersetzen.

main.bicep mit derselben Aussage
// main.bicep
param location string = resourceGroup().location
param storageName string

resource artefakte 'Microsoft.Storage/storageAccounts@2023-05-01' = {
  name: storageName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    minimumTlsVersion: 'TLS1_2'
    allowBlobPublicAccess: false
  }
  tags: {
    kostenstelle: 'plattform'
    umgebung: 'prod'
  }
}

output blobEndpunkt string = artefakte.properties.primaryEndpoints.blob

Die API-Version steht in Bicep direkt am Ressourcentyp. Das ist unbequemer als eine Provider-Version im Kopf der Datei, macht aber jede Ressource einzeln festnagelbar, was bei Vorlagen mit langer Lebensdauer ein Vorteil ist.

Der sichtbare Unterschied ist gering, der unsichtbare groß. Terraform braucht ein Backend für den State, Bicep nicht, weil der Ist-Zustand im Azure Resource Manager liegt. Dafür kann derselbe Terraform-Bestand im selben Repository auch die DNS-Einträge beim externen Registrar, ein GitLab-Projekt und eine Datenbank bei einem SaaS-Anbieter beschreiben. Wenn die Entscheidung ohnehin auf Terraform fällt, klärt Terraform oder OpenTofu die anschließende Lizenzfrage.

03

Schritt 3: State, Sperren und Drift beherrschen

Alles, was in Terraform-Projekten wehtut, hängt am State. Ihn zentral, gesperrt und versioniert abzulegen ist keine Kür, sondern die Voraussetzung dafür, dass mehrere Leute am selben Bestand arbeiten können.

backend.tf mit Sperre
terraform {
  backend "s3" {
    bucket         = "tfstate-plattform-prod"
    key            = "netz/prod.tfstate"
    region         = "eu-central-1"
    encrypt        = true
    dynamodb_table = "tfstate-locks"
  }
}

# Azure-Variante:
# backend "azurerm" {
#   resource_group_name  = "rg-tfstate"
#   storage_account_name = "sttfstateprod01"
#   container_name       = "tfstate"
#   key                  = "netz/prod.tfstate"
#   use_azuread_auth     = true
# }

Aktuelle Terraform- und OpenTofu-Versionen können die Sperre auch ohne DynamoDB direkt im Bucket führen. Prüfe die Fassung, die deine Pipeline nutzt, und stelle bei beiden Backends Versionierung des Speichers an, sonst ist ein zerschossener State nicht wiederherstellbar.

Drift finden und Bestand übernehmen
terraform init -reconfigure

# Nur abgleichen, nichts ändern: zeigt Abweichungen zwischen State und Wirklichkeit
terraform plan -refresh-only

terraform state list
terraform state show azurerm_storage_account.artefakte

# Bestehende Ressource übernehmen, ohne sie anzufassen
terraform plan -generate-config-out=uebernommen.tf

Ab Terraform 1.5 beschreibst du Übernahmen als import-Block im Code statt als einmaligen Befehl. Der Plan erzeugt dann mit -generate-config-out einen Entwurf der Ressourcendefinition, den du nachbearbeitest. Das ist deutlich belastbarer als hundert Aufrufe von terraform import in einem Shell-Skript.

04

Schritt 4: Prüfen, bevor du anwendest

In der Cloud kostet ein Fehler sofort Geld, und manche Änderungen sind nicht rückholbar. Ein Plan-Lauf gehört deshalb durch drei Prüfungen: Was ändert sich, verletzt es Regeln, und was kostet es?

Terraform-Plan maschinell prüfen
terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json

# Sicherheitsregeln gegen den geplanten Zustand, nicht gegen den Quelltext
checkov -f tfplan.json --framework terraform_plan

# Eigene Richtlinien als Code, z. B. erlaubte Regionen und Pflicht-Tags
conftest test tfplan.json --policy policies/

# Kostenvorschau vor der Freigabe
infracost breakdown --path tfplan.json

terraform apply tfplan

Wichtig ist die Reihenfolge: Der Plan wird einmal erzeugt, geprüft und genau so angewendet. Wer terraform apply ohne gespeicherte Plandatei aufruft, wendet einen frisch berechneten Plan an, der von dem geprüften abweichen kann.

Dasselbe auf der Azure-Seite
az bicep build --file main.bicep

az deployment group what-if \
  --resource-group rg-plattform-prod \
  --template-file main.bicep \
  --parameters storageName=stplattformprod01

az deployment group create \
  --resource-group rg-plattform-prod \
  --template-file main.bicep \
  --parameters storageName=stplattformprod01 \
  --confirm-with-what-if

Der What-If-Lauf ist Bicep-Nutzenden ihr Plan. Mit --confirm-with-what-if zeigt die Bereitstellung die Änderungen und fragt vor der Ausführung nach, was in interaktiven Notfalleingriffen die letzte Bremse ist.

Was in die Pipeline gehört, egal welches Werkzeug gewinnt

  • Formatprüfung und Validierung bei jedem Merge RequestFormatfehler und Tippfehler in Ressourcennamen fallen sonst erst beim Anwenden auf, also im teuersten Moment.
  • Plan als Artefakt speichern und im Review verlinkenNur so lässt sich später belegen, welcher Zustand freigegeben wurde. Ohne Artefakt ist die Freigabe eine Behauptung.
  • Richtlinien als Code für Regionen, Tags und öffentliche EndpunkteMenschen übersehen im Review genau die Zeile, die einen Bucket öffentlich schaltet. Eine Regel übersieht sie nicht.
  • Kostenvorschau als Pflichtausgabe im Merge RequestEine falsch gewählte Maschinengröße oder ein zweites NAT-Gateway kostet monatlich, fällt ohne Vorschau aber erst auf der nächsten Rechnung auf.
  • Getrennte Anmeldung je Umgebung, ohne dauerhafte SchlüsselEin Pipeline-Konto mit Rechten auf allen Umgebungen macht jeden Fehler im Testzweig zu einem Produktionsvorfall.
  • Rückweg vorher beschreiben, nicht erst im VorfallBei zustandsbehafteten Ressourcen ist der Rückweg selten ein einfaches Zurücksetzen, sondern hängt an Sicherungen und Löschschutz.
05

Schritt 5: Crossplane, wenn Kubernetes schon die Plattform ist

Crossplane spielt in einer anderen Kategorie. Statt eines Laufs in der Pipeline übernimmt ein Controller im Cluster den dauerhaften Abgleich zwischen Soll und Ist.

Bestand einer Crossplane-Installation ansehen
kubectl get providers.pkg.crossplane.io
kubectl get xrd                      # welche eigenen Ressourcentypen gibt es
kubectl get compositions

# Alle von Crossplane verwalteten Fremdressourcen
kubectl get managed

kubectl describe bucket artefakte-prod

Die Spalten SYNCED und READY sind die eigentliche Statusanzeige. SYNCED bedeutet, dass der Controller die Ressource beim Anbieter abgleichen konnte, READY, dass sie dort benutzbar ist. Steht SYNCED dauerhaft auf False, liegt es fast immer an den Rechten der hinterlegten ProviderConfig.

claim.yaml: Ein Team fordert eine Datenbank an, ohne Cloud-Rechte zu haben
apiVersion: plattform.example.de/v1alpha1
kind: PostgresInstanz
metadata:
  name: shop-prod
  namespace: team-shop
spec:
  groesse: mittel
  region: eu-central-1
  aufbewahrungTage: 14
  compositionRef:
    name: postgres-aws

Genau das ist der Unterschied zur Pipeline: Das Anwendungsteam schreibt kein HCL und bekommt keine Berechtigung beim Anbieter, sondern legt ein Objekt in seinem Namensraum an. Die Übersetzung in konkrete Ressourcen steckt in der Composition, die das Plattformteam pflegt.

Praktisch enden viele Häuser bei einer Kombination: Terraform oder OpenTofu bauen die Grundstruktur mit Konten, Netzen, Identität und Richtlinien, also die Landing Zone, und Crossplane oder ein Werkzeug wie Argo CD stellt Anwendungsteams darauf die einzelnen Bausteine bereit. Diese Trennung hat den Vorteil, dass selten geänderte Grundlagen und täglich geänderte Anwendungsressourcen nicht in derselben Pipeline und nicht im selben State liegen.

Gut zu wissen

Häufige Fragen zu Infrastructure as Code

Noch etwas offen? Wir sind ohne Warteschleife für dich da.

Frag uns direkt
Lohnt sich Terraform, wenn wir nur Azure einsetzen?
Wenn wirklich nur Azure im Spiel ist und das Team keine Terraform-Erfahrung mitbringt, ist Bicep der kürzere Weg. Du sparst dir State, Sperren und die Sicherung einer zusätzlichen Datei, und neue Azure-Dienste sind sofort beschreibbar. Terraform lohnt sich, sobald Dinge außerhalb von Azure dazukommen, etwa DNS bei einem externen Registrar, Konten in einer Git-Plattform oder Monitoring bei einem SaaS-Anbieter. In der Praxis passiert das häufiger als geplant, deshalb ist die ehrliche Frage nicht, was heute gilt, sondern was in zwei Jahren im Repository stehen soll.
Ist Pulumi besser als Terraform, weil man eine richtige Programmiersprache nutzt?
Besser ist es nur für Teams, die tatsächlich Software entwickeln. Schleifen, Bedingungen und Tests sind in TypeScript oder Python angenehmer als in HCL, und wiederkehrende Muster lassen sich als Bibliothek verpacken. Der Preis ist, dass Infrastrukturcode damit allen Regeln der Softwareentwicklung unterliegt: Abhängigkeiten veralten, Sprachversionen wechseln, und schlecht strukturierter Code wird schnell unlesbar. In einem Betriebsteam ohne Entwicklungsroutine erzeugt die Freiheit meist mehr Aufwand als sie spart. Deklarativ zu bleiben ist dort die robustere Entscheidung.
Wie bekommen wir bestehende Infrastruktur nachträglich in den Code?
Schrittweise und niemals alles auf einmal. Nimm ein abgeschlossenes Stück, etwa ein Netz oder eine Ressourcengruppe, beschreibe es im Code und übernimm es mit einem import-Block. Der Plan-Lauf muss danach keine Änderung mehr melden, das ist die Erfolgskontrolle. Erst wenn das sitzt, kommt das nächste Stück. Der häufigste Fehler ist der Versuch, eine gewachsene Umgebung in einem Rutsch zu importieren: Der State wird unübersichtlich, ein einziger Fehler betrifft alles, und niemand traut sich mehr, apply auszuführen.
Brauchen wir Policy as Code, wenn es Reviews im Merge Request gibt?
Ja, weil beide unterschiedliche Fehler finden. Ein Review erkennt fachliche Fehler, also ob die Architektur so gemeint war. Regeln erkennen mechanische Fehler zuverlässig, auch am Freitagnachmittag: eine falsche Region, ein fehlendes Kostenstellen-Tag, ein Speicher ohne Verschlüsselung, ein Sicherheitsgruppen-Eintrag mit Quelle 0.0.0.0/0. Menschen übersehen genau diese Zeilen, weil sie unauffällig aussehen. Mit Conftest gegen den Plan im JSON-Format oder mit Azure Policy auf der Plattformseite ist der Aufwand überschaubar und der Nutzen sofort messbar.
Was ist der teuerste Fehler beim Einstieg in Infrastructure as Code?
Ein einziger großer Bestand für alles. Wenn Netz, Datenbanken, Cluster und Anwendungen in einem State liegen, dauert jeder Plan-Lauf minutenlang, jede Änderung sperrt den gesamten Bestand und ein Fehler kann Ressourcen anfassen, die niemand ändern wollte. Schneide stattdessen nach Änderungsrhythmus: selten geänderte Grundlagen in einen Bestand, oft geänderte Anwendungsressourcen in einen anderen, und verbinde beide über explizit veröffentlichte Ausgabewerte statt über Querzugriffe auf fremde States.

Zuletzt geprüft am 26. Juli 2026.

Das sagen Teilnehmer

Echte Stimmen aus unseren IT-Kursen

Sehr kompetent, kurzweilig, hat mich nochmals sehr weitergebracht in meinem täglichen doing.
Rückmeldung aus dem Kurs „AZ-400 Training: Designing and Implementing Microsoft DevOps solutions (AZ-400T00-A)“
Der Kursinhalt entsprach voll meinen Erwartungen, die richtige Mischung aus Theorie und Praxis.
Rückmeldung aus dem Kurs „Kubernetes Grundkurs“
Persönlich für dich da

Deine Ansprechpartner

Du bist dir nicht sicher, welcher Kurs oder welches Level zu dir passt? Wir beraten dich persönlich und kostenlos.

Yves Hoppe

Yves Hoppe

Weiterbildung & Beratung

Hilft dir, aus dem Cloud-Programm den passenden Kurs oder Lernpfad zu finden.

Norbert Jansen

Norbert Jansen

Beratung & Inhouse

Plant mit dir Inhouse-Trainings, die exakt auf eure Systemlandschaft und Distributionen zugeschnitten sind.

Nächster Schritt

Werkzeug gewählt, jetzt das Team dahinter aufbauen

Wenn die Richtung steht, bringen wir dein Team auf den Stand. Für den Terraform-Weg gibt es Einführungskurse mit Azure und mit AWS, für die lizenzfreie Variante den OpenTofu Grundkurs und für den Kubernetes-Weg die Crossplane Schulung. Bist du bei der Auswahl noch unentschieden, sprich uns an: Wir schauen uns eure Ausgangslage an und sagen ehrlich, welcher Weg zu eurem Team passt. Alle Kurse gibt es als Live-Online-Termin und als Inhouse-Schulung.