Infrastructure as Code im Vergleich: Terraform, Ansible, Bicep
Terraform, Ansible und Bicep im Praxisvergleich: State-Handling, Entscheidungsbaum, Hybrid-Ansaetze und Migrationspfade fuer KMU-Infrastruktur.
Warum dieser Vergleich ueberhaupt noetig ist
In vielen Schweizer KMU sieht die Realitaet so aus: Ein paar VMs wurden vor Jahren manuell im Hyper-V-Cluster oder in Azure angelegt, die Konfiguration lebt in einem Wiki-Artikel (oder gar nur im Kopf des Admins), und niemand kann mit Sicherheit sagen, warum Server-03 eine andere Firewall-Regel hat als Server-04. Infrastructure as Code (IaC) loest genau dieses Problem: Infrastruktur wird als Text beschrieben, versioniert, geprueft und reproduzierbar ausgerollt.
Das Missverstaendnis, das in fast jedem Team auftaucht: Terraform, Ansible und Bicep werden oft als austauschbare Konkurrenten behandelt, dabei loesen sie unterschiedliche Probleme. Wer das nicht versteht, baut sich unnoetig komplizierte Pipelines oder verwendet das falsche Werkzeug fuer die falsche Aufgabe. Dieser Artikel klaert die Architekturunterschiede, zeigt einen Entscheidungsbaum fuer die Werkzeugwahl und geht auf die haerteste Frage im IaC-Alltag ein: das State-Handling.
Die drei Werkzeuge im Kern
Terraform: deklarative Provisionierung, cloud-agnostisch
Terraform (HashiCorp, seit 2024 unter Business Source License, mit dem Fork OpenTofu als freier Alternative) beschreibt den gewuenschten Endzustand deiner Infrastruktur in HCL (HashiCorp Configuration Language). Du definierst nicht die Schritte, sondern das Ziel - Terraform berechnet den Graphen der Abhaengigkeiten selbst und bringt die reale Welt in Uebereinstimmung mit deinem Code.
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.90"
}
}
backend "azurerm" {
resource_group_name = "rg-tfstate-prod"
storage_account_name = "sttfstateprodch01"
container_name = "tfstate"
key = "netzwerk.tfstate"
}
}
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "rg" {
name = "rg-filialen-zh"
location = "switzerlandnorth"
}
resource "azurerm_virtual_network" "vnet" {
name = "vnet-zh-prod"
address_space = ["10.20.0.0/16"]
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}
Terraform kann nicht nur Azure, sondern ueber Provider auch AWS, GCP, VMware vSphere, Proxmox VE, Cloudflare, sogar M365-Ressourcen ansprechen. Das ist der grosse Vorteil in hybriden KMU-Umgebungen, wo neben Azure oft noch On-Prem-Hyper-V oder ein Cloudflare-Account existiert.
Ansible: prozedurales Konfigurationsmanagement, agentless
Ansible (Red Hat) setzt eine Ebene tiefer an: Es geht nicht darum, eine VM zu erschaffen, sondern eine bestehende Maschine in einen bestimmten Zustand zu bringen - Pakete installieren, Dienste konfigurieren, Benutzer anlegen. Ansible braucht keinen Agenten auf dem Zielsystem, sondern verbindet sich per SSH (Linux) oder WinRM (Windows) und fuehrt Module aus.
# playbook-webserver.yml
- name: IIS und Basis-Haertung auf Windows-Servern
hosts: windows_webserver
gather_facts: true
tasks:
- name: IIS-Rolle installieren
ansible.windows.win_feature:
name: Web-Server
state: present
include_management_tools: true
- name: Firewall-Regel fuer HTTPS oeffnen
community.windows.win_firewall_rule:
name: "HTTPS-eingehend"
localport: 443
action: allow
direction: in
protocol: tcp
state: present
- name: TLS 1.0 und 1.1 deaktivieren
ansible.windows.win_regedit:
path: HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server
name: Enabled
data: 0
type: dword
Ansible fuehrt bei jedem Lauf die Tasks aus und prueft idempotent, ob der Zustand schon erreicht ist - es fuehrt aber kein persistentes State-File wie Terraform. Das ist ein entscheidender Architekturunterschied, dazu gleich mehr.
Bicep: Azure-natives DSL statt ARM-JSON
Bicep ist Microsofts Antwort auf die Frage “warum ist ARM-JSON so unleserlich?”. Es ist eine Domain Specific Language, die zu ARM-Templates transpiliert wird und direkt von Azure Resource Manager verstanden wird - ohne Umweg ueber einen Drittanbieter-State.
// main.bicep
param location string = resourceGroup().location
param vnetAddressSpace string = '10.30.0.0/16'
resource vnet 'Microsoft.Network/virtualNetworks@2023-11-01' = {
name: 'vnet-filiale-be'
location: location
properties: {
addressSpace: {
addressPrefixes: [
vnetAddressSpace
]
}
subnets: [
{
name: 'snet-clients'
properties: {
addressPrefix: '10.30.1.0/24'
}
}
]
}
}
output vnetId string = vnet.id
Deployment per Azure CLI:
az deployment group create \
--resource-group rg-filiale-be \
--template-file main.bicep \
--parameters vnetAddressSpace=10.30.0.0/16
Vergleichstabelle: die Architekturunterschiede
| Kriterium | Terraform | Ansible | Bicep |
|---|---|---|---|
| Paradigma | deklarativ | prozedural (Tasks in Reihenfolge) | deklarativ |
| Haupteinsatz | Provisionierung (Ressourcen erschaffen) | Konfiguration (Zustand auf bestehenden Systemen) | Provisionierung (nur Azure) |
| Multi-Cloud | ja, ueber Provider (Azure, AWS, GCP, VMware, …) | ja, ueber Module/Collections | nein, Azure-exklusiv |
| State-Datei | ja, zwingend (lokal oder Remote-Backend) | nein, kein persistenter State | indirekt via Deployment Stacks (Azure-verwaltet) |
| Agent noetig | nein | nein (SSH/WinRM) | nein |
| Sprache | HCL | YAML | Bicep-DSL (kompiliert zu ARM-JSON) |
| Lock-in-Risiko | mittel (HCL + Provider-Oekosystem, BSL-Lizenz seit v1.6) | gering (YAML, Module leicht austauschbar) | hoch (nur Azure) |
| Lizenzmodell | Business Source License (Fork: OpenTofu, MPL) | GPLv3, Community + Red Hat Enterprise | kostenlos, Teil von Azure |
| Typischer Skill-Level im KMU | mittel-hoch (State-Konzept muss sitzen) | niedrig-mittel (YAML ist zugaenglich) | mittel (wenn Azure-Fokus schon da ist) |
| Rollback bei Fehler | Plan/Apply mit State-Vergleich | kein eingebautes Rollback, nur erneuter Lauf | Deployment-Historie in ARM, teilweise rueckrollbar |
Entscheidungsbaum: Welches Werkzeug fuer welche Aufgabe
Praktischer Ablauf zur Werkzeugwahl:
- Betrifft die Aenderung die Existenz einer Ressource (VM erstellen/loeschen, Subnetz anlegen, Storage-Konto provisionieren)? Dann Provisionierungs-Tool: Terraform oder Bicep.
- Bewegst du dich ausschliesslich in Azure und willst kein Drittanbieter-Tool im Stack? Dann Bicep - geringere Einstiegshuerde, keine externe State-Verwaltung, direkte ARM-Integration, kostenlos ohne Lizenzfragen.
- Hast du (oder planst du) mehr als eine Plattform - Azure plus On-Prem-Hyper-V, Azure plus AWS, Azure plus Cloudflare-DNS, Azure plus VMware? Dann Terraform (oder den freien Fork OpenTofu), weil ein einziges Tool und eine einzige Pipeline fuer alle Plattformen reicht.
- Geht es um den Zustand INNERHALB einer laufenden Maschine (Software installieren, Konfigurationsdateien verteilen, Patches einspielen, Benutzer/Gruppen pflegen)? Dann Ansible - unabhaengig davon, ob die VM per Terraform oder Bicep erstellt wurde.
- Brauchst du Orchestrierung ueber viele bestehende Server hinweg (z. B. “installiere auf allen 40 Terminalservern das neue Sicherheitspatch in dieser Reihenfolge”)? Auch dann Ansible - das ist sein ureigenes Terrain.
Neue Ressource noetig? (VM, VNet, Storage, DNS-Zone)
├── Ja
│ ├── Nur Azure? ────────────► Bicep
│ └── Multi-Cloud/On-Prem? ──► Terraform (oder OpenTofu)
└── Nein, bestehende Maschine konfigurieren
└── Pakete, Dienste, Files, Registry, Patches ──► Ansible
Hybrid-Ansaetze: die drei Werkzeuge zusammen nutzen
In der Praxis ist die Kombination der Normalfall, kein Kompromiss. Ein gaengiges Muster im KMU-Umfeld:
- Terraform oder Bicep erstellt die Azure-VM, das VNet, die NSG und den Storage Account.
- Terraform Provisioner (
remote-execoder besser: ein separater Schritt in der Pipeline) uebergibt die IP-Adresse der frisch erstellten VM an ein Ansible-Inventory. - Ansible uebernimmt danach die komplette Serverkonfiguration - Rollen installieren, Haertung anwenden, Monitoring-Agent ausrollen.
resource "azurerm_linux_virtual_machine" "app" {
name = "vm-app01"
# ... weitere Attribute gekuerzt ...
provisioner "local-exec" {
command = "echo '${self.public_ip_address} ansible_user=azureuser' >> ../ansible/inventory.ini"
}
}
Alternative ohne Terraform-Provisioner (sauberer, weil Terraform nicht fuer Konfigurationslogik missbraucht wird): das dynamische Azure-Inventory-Plugin von Ansible nutzt die Azure-API direkt, um alle VMs mit einem bestimmten Tag automatisch einzulesen - ganz ohne manuelle Uebergabe.
# inventory.azure_rm.yml
plugin: azure.azcollection.azure_rm
include_vm_resource_groups:
- rg-filialen-zh
auth_source: auto
keyed_groups:
- prefix: tag
key: tags.rolle
State-Handling im Detail: der groesste Stolperstein
Das State-Konzept ist der Punkt, an dem die meisten KMU-Teams beim Terraform-Einstieg stolpern. Terraform fuehrt eine JSON-Datei (terraform.tfstate), die den zuletzt bekannten Zustand jeder verwalteten Ressource inklusive interner IDs enthaelt. Ohne diese Datei weiss Terraform nicht, was es verwaltet - es kann Ressourcen nicht importieren, aendern oder loeschen, wenn der State verloren geht oder nicht synchron ist.
Die drei kritischen Risiken:
- Lokaler State ohne Backend: Liegt
terraform.tfstatenur auf der Workstation eines Admins und wird versehentlich geloescht oder nicht ins Git-Repo committet (was ohnehin falsch waere, weil State Secrets im Klartext enthalten kann), verliert das Team die Kontrolle ueber die Infrastruktur. - State Drift: Jemand aendert eine Ressource manuell im Azure-Portal (schnelle Notloesung am Freitagabend), ohne den Terraform-Code anzupassen. Beim naechsten
terraform planzeigt Terraform eine Abweichung - im schlimmsten Fall will es die manuelle Aenderung rueckgaengig machen und ueberschreibt die Notloesung ungefragt. - Concurrent State Lock: Zwei Admins fuehren gleichzeitig
terraform applyaus. Ohne State-Locking (z. B. via Azure Blob Lease imazurerm-Backend) korrumpiert das den State.
# State-Drift erkennen, ohne etwas zu aendern
terraform plan -refresh-only
# Manuell erstellte Ressource nachtraeglich unter Terraform-Kontrolle bringen
terraform import azurerm_storage_account.logs /subscriptions/<sub-id>/resourceGroups/rg-log/providers/Microsoft.Storage/storageAccounts/stlogprod01
# Remote State mit Locking pruefen
terraform state list
terraform state show azurerm_virtual_network.vnet
Ansible hat dieses Problem strukturell nicht, weil es keinen persistierten State fuehrt - es prueft bei jedem Lauf live den Ist-Zustand ueber Facts (ansible_facts). Der Nachteil: Ansible kann dir nicht sagen “diese Ressource wuerde geloescht”, weil es kein Vorher-Nachher-Modell kennt wie Terraform mit plan. Bicep-Deployment-Stacks liegen dazwischen: Der State existiert, wird aber vollstaendig von Azure verwaltet - du kannst ihn nicht exportieren oder in einem Fremdsystem inspizieren, was einerseits Betriebsrisiken reduziert (kein State-File, das verloren gehen kann), andererseits den Vendor-Lock-in verstaerkt.
Lock-in-Risiken realistisch einordnen
- Bicep: voller Lock-in auf Azure. Ein Wechsel zu AWS oder GCP bedeutet Totalneuschrieb der Infrastruktur-Definitionen. Fuer ein KMU, das strategisch und dauerhaft auf Azure/M365 setzt, ist das oft ein akzeptables, sogar sinnvolles Risiko - man bekommt dafuer die beste Day-1-Unterstuetzung fuer neue Azure-Features.
- Terraform: technisch cloud-agnostisch, aber der Provider-Code selbst (z. B.
azurerm-Ressourcennamen und -Attribute) ist nicht 1:1 auf einen AWS-Provider uebertragbar - der Wechsel des Providers ist trotzdem Aufwand, nur eben nicht der Wechsel des Werkzeugs. Zusaetzlich: Seit der Lizenzumstellung auf die Business Source License (August 2023) ist Terraform selbst nicht mehr vollstaendig Open Source; wer das vermeiden will, evaluiert den Fork OpenTofu (Linux Foundation, MPL-2.0-Lizenz), der zu bestehendem Terraform-Code weitgehend kompatibel ist. - Ansible: das geringste Lock-in-Risiko der drei. YAML-Playbooks und Rollen sind gut lesbar, portabel, und Module lassen sich schrittweise ersetzen, ohne das ganze Automatisierungsmodell umzuwerfen.
Migration: von manueller Verwaltung zu IaC
Der haeufigste Fehler bei der Einfuehrung: alles auf einmal migrieren wollen. Bewaehrter, risikoarmer Ablauf fuer ein KMU mit gewachsener Infrastruktur:
- Inventar erstellen. Bevor du irgendetwas automatisierst, dokumentiere den Ist-Zustand (siehe auch IT-Dokumentation und Inventar). Ohne Inventar weisst du nicht, was du migrierst.
- Neuland zuerst automatisieren. Die naechste neue VM, das naechste neue VNet entsteht direkt per Terraform/Bicep - nicht mehr per Klick. So sammelt das Team Erfahrung, ohne Bestandssysteme zu gefaehrden.
- Bestehende Ressourcen schrittweise importieren.
terraform importbzw. bei Bicep der Export bestehender ARM-Ressourcen (az group export) holt Alt-Ressourcen nachtraeglich unter IaC-Kontrolle. Wichtig: nach jedem Import sofortterraform planlaufen lassen und pruefen, dass keine ungewollte Aenderung vorgeschlagen wird. - Konfiguration parallel mit Ansible dokumentieren. Fuehre ein
ansible-playbook --check(Dry-Run) gegen bestehende Server aus, um den Ist-Zustand mit einem Ziel-Playbook abzugleichen, bevor du es scharf anwendest. - Least-Privilege-Zugaenge fuer die Automatisierung einrichten. Der Service Principal (Azure) bzw. das Ansible-Vault-verschluesselte Credential darf nur, was es fuer seine Aufgabe braucht - keine Owner-Rolle “damit es sicher funktioniert”.
- Pipeline statt lokalem Apply. Sobald der erste Ordner sauber unter IaC laeuft, verschiebe
terraform apply/az deployment/ansible-playbookin eine CI/CD-Pipeline (Azure DevOps, GitHub Actions) mit Plan-Review vor jedem Apply.
# vault-verschluesseltes Secret in Ansible anlegen
# ansible-vault create group_vars/prod/vault.yml
db_admin_password: "Sup3rGeheim!2026"
ansible-vault encrypt group_vars/prod/vault.yml
ansible-playbook site.yml --ask-vault-pass
Typische Fallstricke im KMU-Alltag
- State-Backend vergessen. Terraform ohne Remote-Backend laeuft anfangs “irgendwie”, bis der Laptop des einzigen Admins den Geist aufgibt - dann ist die Infrastruktur faktisch nicht mehr verwaltbar, ausser durch komplettes Reimportieren.
- Secrets im Klartext. Sowohl Terraform-State als auch Ansible-Playbooks werden schnell zur Ablage fuer Passwoerter, wenn niemand auf Ansible Vault oder ein Secret-Backend (Azure Key Vault, HashiCorp Vault) besteht.
- Kein Plan-Review vor Apply.
terraform apply -auto-approvein der Pipeline spart Klicks, aber auch die letzte Kontrollinstanz vor einer ungewollten Loeschung. - Ansible-Idempotenz missachtet. Ad-hoc-
shell- odercommand-Module statt spezialisierter Ansible-Module (ansible.windows.win_feature,ansible.builtin.package) fuehren dazu, dass ein Playbook bei jedem Lauf Aenderungen meldet, obwohl nichts zu tun waere - das Playbook wird unbrauchbar als Statusanzeige. - Bicep-Deployment ohne Deny-Settings. Ohne
--deny-settings-modekann jeder mit Portal-Zugriff eine per Bicep verwaltete Ressource manuell aendern, was beim naechsten Deployment zu unerwarteten Ueberschreibungen fuehrt. - Ein Terraform-State fuer alles. Ein einziger riesiger State fuer Netzwerk, VMs, Datenbanken und DNS bedeutet: jeder Plan dauert laenger, jeder Lock blockiert das ganze Team, und ein Fehler in einem Modul kann den State fuer alles gefaehrden. Besser: State pro logischer Einheit trennen (Netzwerk-State, App-State, Daten-State).
- Ansible ueber WinRM ohne HTTPS. Windows-Hosts per WinRM nur mit HTTP statt HTTPS anzubinden, ist ein reales Sicherheitsrisiko im internen Netz - Zugangsdaten koennten im Klartext mitgelesen werden.
Sicherheitsaspekte kurz zusammengefasst
Automatisierungs-Credentials sind ein bevorzugtes Angriffsziel, weil sie oft weitreichende Rechte haben und selten rotiert werden. Fuer alle drei Werkzeuge gilt: Service Principals und SSH-Keys nach dem Least-Privilege-Prinzip vergeben, regelmaessig rotieren, und wo moeglich auf kurzlebige Zugangsdaten (OIDC-Federation zwischen CI/CD und Azure/AWS statt statischer Client Secrets) umstellen. Fuer den organisatorischen Rahmen dazu lohnt sich ein Blick in Passwort-Management und Zero-Trust-Architektur im KMU.
Weiterlernen
- Terraform-Dokumentation (offiziell)
- Bicep-Dokumentation - Microsoft Learn
- Azure Deployment Stacks - Microsoft Learn
- Ansible-Dokumentation (offiziell)
- OpenTofu - freier Terraform-Fork
- Ansible vs. Terraform - Red Hat
Vertiefend zum Thema: Terraform State Management und Drift, Ansible Playbooks, Inventory und Vault, Git fuer IT-Admins: Workflows und Branching, Azure-Grundlagen, Cloud-Migrationsstrategien und IaaS/PaaS/SaaS-Entscheidung.
Videos
Kommentare
Frage, Verbesserungsvorschlag oder eigene Erfahrung zu diesem Artikel? Schreib einen Kommentar. Neue Beiträge erscheinen nach kurzer Moderation.
- Lade Kommentare …