Azure Policy als Code organisieren: Mit Bicep, Terraform und Initiatives ein wartbares Regelwerk pflegen
Die meisten Azure-Policy-Probleme beginnen nicht bei der Policy Rule, sondern bei der Art, wie Teams Definitions, Initiatives, Assignments und Ausnahmen organisieren. Portal-Klicks sind schnell, aber sie hinterlassen selten einen belastbaren Änderungsprozess. Spätestens wenn mehrere Subscriptions, gemeinsame Baselines und begründete Ausnahmen zusammenkommen, wird aus einer scheinbar kleinen Verwaltungsaufgabe ein echtes Wartbarkeitsthema.
Genau deshalb gehören Policy as Code und Initiatives bei Azure Policy eng zusammen. Code sorgt für Nachvollziehbarkeit, Initiatives für ein lesbares Gesamtmodell. In diesem zweiten Teil der verkürzten Reihe geht es nicht um einen Tool-Wettbewerb zwischen Bicep und Terraform. Entscheidend ist, wie du aus einzelnen Policy-Ressourcen ein wartbares Regelwerk und einen stabilen Engineering-Prozess machst.
Warum Portal-Pflege bei Azure Policy schnell untragbar wird
Das Azure-Portal ist für einen ersten Blick sehr nützlich. Für den dauerhaften Betrieb eines Regelwerks ist es aber zu wenig. Manuelle Änderungen lassen sich schwer nachvollziehen, JSON-Unterschiede sind im Review unhandlich und Assignments driften schnell von Definitionen oder Exemptions weg. Der eigentliche Schaden zeigt sich oft erst später, wenn niemand mehr sauber erklären kann, warum eine Regel heute anders wirkt als vor drei Wochen.
Die Policy-as-Code-Empfehlungen von Microsoft sind deshalb erfreulich klar. Definitions, Initiatives, Assignments und Ausnahmen gehören in Source Control und sollten zentral über einen kontrollierten Workflow ausgerollt werden. Das ist keine Governance-Dekoration, sondern normale Plattform-Engineering-Praxis. Für Reviews, Rollbacks und reproduzierbare Deployments gibt es kaum eine robustere Alternative.
Vor allem die Kombination aus Scope und Änderungsverlauf macht Portal-Pflege so teuer. Eine kleine Anpassung an einer Definition kann bestehende Assignments sofort beeinflussen. Wenn diese Änderung nicht im Pull Request sichtbar war, fehlt dir der wichtigste Schutzmechanismus vor Überraschungen. Mit Code gewinnst du dagegen Diff, Review, Testscope und Promotion als normalen Bestandteil des Prozesses.
Policy as Code reduziert also nicht nur Wildwuchs. Es verschiebt Azure Policy in denselben Qualitätsrahmen wie Anwendungscode und andere Infrastrukturänderungen. Genau dort gehört ein produktiv wirksames Plattformregelwerk auch hin.
Welche Artefakte überhaupt in das Repository gehören
Viele Teams versionieren zunächst nur Policy Definitions. Das ist ein Anfang, aber noch kein vollständiges Regelwerk. Wirksam wird Azure Policy erst durch die gesamte Artefaktkette aus Definitions, Initiatives, Assignments, Parametern und bei Bedarf auch kontrolliert gepflegten Exemptions. Eine Definition ohne Assignment ist noch keine Plattformregel.
Die empfohlene Struktur aus der Workflow-Übersicht von Microsoft lässt sich sehr gut in normale Repositories übersetzen. Wichtig ist weniger die exakte Ordnerbezeichnung als die klare Trennung der Verantwortlichkeiten. Du solltest auf einen Blick erkennen können, welche Regeln es gibt, wie sie gebündelt werden, wo sie zugewiesen sind und welche Ausnahmen bewusst existieren.
Ein mögliches Repository-Skelett sieht zum Beispiel so aus.
policy/
definitions/
allowed-locations.bicep
storage-public-access-audit.bicep
initiatives/
platform-baseline.bicep
assignments/
nonprod/
platform-baseline.bicep
prod/
platform-baseline.bicep
parameters/
nonprod.json
prod.json
exemptions/
prod/
rg-legacy-waiver.bicep
Gerade Exemptions werden oft vergessen. Wenn du Ausnahmen bewusst nachvollziehbar und reviewbar halten willst, sollten auch sie als Code sichtbar sein. Sonst entsteht ein zweites Schattenmodell im Portal, das weder im Pull Request noch in der Dokumentation sauber auftaucht.
Wie du Initiatives fachlich sinnvoll schneidest
Spätestens mit mehreren Baselines reicht es nicht mehr, nur einzelne Definitions-Dateien sauber abzulegen. Dann entscheidet die Struktur deiner Initiatives darüber, ob das Regelwerk lesbar bleibt oder in viele lose Einzel-Assignments zerfällt. Eine Initiative ist deshalb nicht nur ein Container für mehrere Policies, sondern die eigentliche fachliche Klammer für Rollout, Parametrisierung und spätere Ausnahmen.
Der wichtigste Entwurfsfehler ist ein Schnitt nach Organigramm statt nach technischem Zielbild. Wenn eine Initiative nur deshalb existiert, weil ein bestimmtes Team im Portal seinen eigenen Bereich sehen möchte, entsteht noch kein gutes Regelwerk. Sinnvoller sind Bündel entlang gemeinsamer Baselines, etwa für Logging und Monitoring, Netzwerk-Exposition oder Storage- und Datenregeln. Solche Sets teilen oft Parameter, Rollout-Reihenfolge und Ausnahmelogik.
Ebenso wichtig ist der Mut zur Trennung. Eine einzige große Initiative für Regionen, Backups, Storage, Netzwerke und Spezialfälle wirkt anfangs bequem, wird aber schnell unlesbar. Wenn Regeln nicht gemeinsam ausgerollt werden, unterschiedliche Owner haben oder fachlich nichts miteinander verbindet, gehören sie meist nicht in dieselbe Initiative.
Für die eigentliche Wartbarkeit sind zwei Details entscheidend.
Nutze wenige, stabile Initiative-Parameter und gib policyDefinitionReferenceId sprechende Namen.
Spätestens bei Overrides, nonComplianceMessages und Exemptions innerhalb einer Initiative hängt die Präzision genau an diesen Referenzen.
Kryptische oder ständig wechselnde Namen machen spätere Rollouts und Ausnahmen unnötig teuer.
Built-in- und Custom-Policies kannst du dabei bewusst mischen. Built-ins sparen Pflegeaufwand, Custom-Policies schließen projektspezifische Lücken. Entscheidend ist nicht die Reinheit des Regelwerks, sondern dass eine Initiative ein verständliches technisches Zielbild abbildet und nicht bloß eine zufällige Sammlung verfügbarer Regeln.
Bicep: Wann es stark ist und worauf du achten musst
Bicep ist besonders naheliegend, wenn dein restliches Azure-Deployment ohnehin auf ARM und Bicep basiert.
Die nativen Ressourcentypen für policyDefinitions, policySetDefinitions und policyAssignments passen gut in denselben Delivery-Stack.
Du bleibst nah am Azure-Ressourcenmodell, kannst symbolische Referenzen nutzen und musst keine zusätzliche Werkzeuglogik zwischen Plattform und Zielsystem schieben.
Das ist vor allem bei Scope-Fragen angenehm.
Definitionen auf Management-Group-Ebene, Assignments auf Subscriptions oder Resource Groups und Referenzen zwischen Initiatives und Assignments lassen sich in Bicep meist direkt und lesbar modellieren.
Wichtig ist aber, dass du Scope-spezifische IDs sauber behandelst.
Built-in Definitions liegen tenantweit, eigene Definitionen oft auf Subscription- oder Management-Group-Scope.
Die richtigen Funktionen wie managementGroupResourceId, subscriptionResourceId oder tenantResourceId sind hier entscheidend.
Ein kleines Beispiel zeigt das Zusammenspiel aus Definition und Assignment.
targetScope = 'managementGroup'
param targetSubscriptionId string
resource allowedLocationsPolicy 'Microsoft.Authorization/policyDefinitions@2023-04-01' = {
name: 'allowed-locations-core'
properties: {
policyType: 'Custom'
mode: 'Indexed'
displayName: 'Nur freigegebene Regionen verwenden'
parameters: {
allowedLocations: {
type: 'Array'
}
}
policyRule: {
if: {
not: {
field: 'location'
in: '[parameters(''allowedLocations'')]'
}
}
then: {
effect: 'audit'
}
}
}
}
resource assignment 'Microsoft.Authorization/policyAssignments@2024-04-01' = {
name: 'allowed-locations-nonprod'
scope: subscription(targetSubscriptionId)
properties: {
displayName: 'Erlaubte Regionen für Non-Prod'
policyDefinitionId: allowedLocationsPolicy.id
parameters: {
allowedLocations: {
value: [
'westeurope'
'northeurope'
]
}
}
}
}
Der größte Stolperstein ist oft Lesbarkeit. Wenn du komplette JSON-Blöcke unstrukturiert inline einbettest, kippt auch Bicep schnell in schwer prüfbaren Text. Halte Definitionen klein, nutze Parameter bewusst und widerstehe dem Drang, jede Speziallogik in eine einzige Datei zu pressen.
Terraform: Wo es überzeugt und welche Eigenheiten wichtig sind
Terraform ist besonders sinnvoll, wenn deine Plattform ohnehin stark providerübergreifend oder bereits terraformlastig aufgebaut ist. Dann profitiert Azure Policy von demselben Plan- und Apply-Prozess, denselben Review-Mustern und denselben Teamkonventionen wie der Rest deiner Infrastruktur. Für Organisationen mit mehreren Cloud- oder Plattformwerkzeugen ist das ein sehr praktischer Vorteil.
Die relevanten Ressourcen sind gut überschaubar.
Custom Definitions laufen etwa über azurerm_policy_definition, Initiatives über azurerm_policy_set_definition und Assignments über scope-spezifische Ressourcen wie azurerm_subscription_policy_assignment oder azurerm_management_group_policy_assignment.
Das passt gut zu klar geschnittenen Modulen, erfordert aber etwas Disziplin bei JSON-Fragmenten und Provider-Eigenheiten.
Ein reduziertes Beispiel zeigt den Stil.
resource "azurerm_policy_definition" "allowed_locations" {
name = "allowed-locations-core"
policy_type = "Custom"
mode = "Indexed"
display_name = "Nur freigegebene Regionen verwenden"
parameters = jsonencode({
allowedLocations = {
type = "Array"
}
})
policy_rule = jsonencode({
if = {
not = {
field = "location"
in = "[parameters('allowedLocations')]"
}
}
then = {
effect = "audit"
}
})
}
resource "azurerm_subscription_policy_assignment" "allowed_locations_nonprod" {
name = "allowed-locations-nonprod"
display_name = "Erlaubte Regionen für Non-Prod"
subscription_id = "/subscriptions/00000000-0000-0000-0000-000000000000"
policy_definition_id = azurerm_policy_definition.allowed_locations.id
parameters = jsonencode({
allowedLocations = {
value = ["westeurope", "northeurope"]
}
})
}
Terraform überzeugt also vor allem dort, wo ein einheitlicher IaC-Workflow wichtiger ist als maximale Azure-Nähe. Dafür musst du Drift, Idempotenz und Unterschiede zwischen generischen und scope-spezifischen Ressourcen bewusst testen. Gerade bei Policy lohnt sich dieser Testaufwand, weil kleine Unterschiede große operative Wirkung entfalten können.
Versionsstrategie, Reviews und Promotion durch Umgebungen
Policy as Code lebt nicht nur von Dateien, sondern von einem belastbaren Prozess. Ein pragmischer Workflow beginnt im Feature Branch, läuft durch einen Pull Request, deployt zuerst in einen Testscope, validiert dort Compliance und Remediation und promoted erst danach in produktionsnahe Scopes. Dieses Muster ist bei Azure Policy besonders wichtig, weil Änderungen an Definitionen direkt auf bestehende Assignments wirken können.
Bei built-in Definitions kommt noch eine zweite Ebene hinzu. Du solltest Versionen bewusst pinnen oder zumindest kontrolliert aktualisieren. Wenn Microsoft eine Definition erweitert oder das Verhalten anpasst, kann sich dein Regelwerk sonst ändern, ohne dass dein Team den Effekt sauber geprüft hat. Die Safe-Deployment-Practices empfehlen genau deshalb kleine Rollout-Stufen und klare Prüfungen vor breiter Aktivierung.
Ebenso wichtig ist der Umgang mit Exemptions. Sie dürfen nicht als stilles Schattenobjekt neben dem eigentlichen Codeprozess entstehen. Wenn eine Ausnahme nötig ist, sollte sie mit Scope, Begründung, Ablaufdatum und Review im selben Änderungsmodell sichtbar sein wie jede andere Policy-Änderung. Sonst verlierst du gerade bei produktiven Sonderfällen die Nachvollziehbarkeit, die du mit Policy as Code eigentlich gewinnen wolltest.
Ein guter Review für Policy-Änderungen prüft deshalb nicht nur Syntax. Er fragt auch nach Scope, Rollout-Reihenfolge, Non-Compliance-Signal, Remediation-Auswirkung und den betroffenen Teams. So wird aus Policy as Code ein verlässlicher Delivery-Prozess statt bloß einer anderen Dateiablage.
Ein kleines, wartbares Regelwerk schlägt große Portal-Magie
Azure Policy als Code ist weniger ein Toolthema als ein Wartbarkeitsthema. Versioniere alle relevanten Artefakte, wähle Bicep oder Terraform passend zu deinem Plattform-Stack und mache Scopes, Parameter und Ausnahmen im Code explizit sichtbar. Dann lassen sich Regeln testen, erklären und ändern, ohne dass jedes Portal-Klickmuster zum Betriebsrisiko wird.
Die wichtigste Lehre ist deshalb überraschend schlicht.
Ein kleines, sauber versioniertes Regelwerk ist wertvoller als eine große Sammlung halb manuell gepflegter Policy-Objekte.
Im letzten Teil der Reihe geht es darum, wie du ein solches Regelwerk sicher ausrollst und wo Scopes, Vererbung, notScopes und Exemptions im Betrieb die meisten Probleme machen.
Wie pflegt ihr Azure Policy heute, noch direkt im Portal oder schon in einem echten IaC-Workflow? Schau gerne bei uns auf LinkedIn vorbei und diskutiere mit.
Autoren
Felix Burkhard
Felix ist Solution Architect mit Fokus auf skalierbare Azure-IoT-Lösungen, agile Entwicklungsprozesse und DevOps. Er verbindet tiefes technisches Verständnis mit pragmatischer Umsetzung und schafft so nachhaltigen Geschäftsnutzen.