Geautomatiseerd Beheer Van Azure Policy Via Policy As Code

💼 Management Samenvatting

Geautomatiseerd beheer van Azure Policy via Policy as Code maakt het mogelijk om policy-definities, assignments en initiatieven te beheren als versiebeheerde code, waardoor governance, wijzigingscontrole en herhaalbaarheid worden geborgd. Voor Nederlandse overheidsorganisaties is dit essentieel om compliance-vereisten zoals BIO en NIS2 schaalbaar en transparant te implementeren, zonder afhankelijk te zijn van handmatige configuratie via de Azure Portal.

Aanbeveling
IMPLEMENTEER POLICY AS CODE VOOR GEAUTOMATISEERD AZURE POLICY-BEHEER
Risico zonder
High
Risk Score
8/10
Implementatie
160u (tech: 100u)
Van toepassing op:
Azure Tenant

Traditioneel wordt Azure Policy beheerd via de Azure Portal, waarbij policy-definities en assignments handmatig worden aangemaakt en aangepast. Deze aanpak schaalt slecht wanneer organisaties tientallen of honderden policies moeten beheren over meerdere management groups en subscriptions. Handmatig beheer leidt onvermijdelijk tot inconsistenties: dezelfde policy wordt in verschillende subscriptions anders geconfigureerd, uitzonderingen worden niet structureel vastgelegd en wijzigingen zijn niet traceerbaar. Bij audits of compliance-controles is het dan moeilijk om overtuigend aan te tonen dat het policy-beheer op orde is en dat wijzigingen volgens afgesproken processen zijn doorgevoerd. Voor Nederlandse overheidsorganisaties, die te maken hebben met strikte eisen rond transparantie, verantwoording en bewijslast, is dit risico onacceptabel.

PowerShell Modules Vereist
Primary API: Azure API
Connection: Connect-AzAccount
Required Modules: Az.Accounts, Az.Resources, Az.PolicyInsights, Az.Tools.Predictor

Implementatie

Dit artikel beschrijft hoe je Azure Policy volledig automatiseert via Policy as Code-principes, waarbij policy-definities, assignments en initiatieven worden opgeslagen in versiebeheer (zoals Azure DevOps of GitHub) en worden geïmplementeerd via CI/CD-pipelines. We gaan in op het structureren van policy-repositories, het gebruik van ARM-templates, Bicep of Terraform voor policy-definities, het automatiseren van assignments via scripts en pipelines, het implementeren van wijzigingscontrole en goedkeuringsworkflows, en het inrichten van geautomatiseerde tests en validaties. Daarnaast laten we zien hoe je met een PowerShell-script – gekoppeld aan dit artikel – policy-definities en assignments programmatisch kunt beheren en monitoren. Het resultaat is een volwassen governance-model waarin policy-beheer onderdeel is van de normale DevOps-werkwijze en waarin wijzigingen altijd traceerbaar, reproduceerbaar en gecontroleerd zijn.

Fundamenten van Policy as Code voor Azure Policy

Policy as Code is een paradigma waarin governance-regels en compliance-vereisten worden vastgelegd als programmeerbare, versiebeheerde definities in plaats van handmatig geconfigureerde instellingen. Voor Azure Policy betekent dit dat policy-definities, assignments, initiatieven en uitzonderingen worden opgeslagen als code in een repository, versiebeheerd met Git, en geïmplementeerd via geautomatiseerde pipelines. Deze aanpak heeft fundamentele voordelen voor Nederlandse overheidsorganisaties: volledige traceerbaarheid van wijzigingen, herhaalbaarheid tussen omgevingen, gecontroleerde goedkeuringsprocessen en de mogelijkheid om policies te testen voordat ze worden toegepast in productie. Een eerste fundament is de repository-structuur. Policies worden logisch georganiseerd in folders, bijvoorbeeld per thema (security, compliance, cost-management), per normenkader (BIO, ISO27001, NIS2) of per omgeving (landing-zones, workloads). Binnen elke folder worden policy-definities opgeslagen als JSON-bestanden (voor ARM) of als Bicep-modules, waarbij duidelijke naming conventions worden gehanteerd zodat de relatie tussen definitie en doel direct duidelijk is. Naast de definitie-bestanden worden ook assignment-templates opgeslagen die beschrijven hoe policies worden toegewezen aan management groups of subscriptions, inclusief parameters, uitzonderingen en effecten. Deze structuur maakt het mogelijk om policies modulair te ontwikkelen, te hergebruiken en te combineren in initiatieven. Een tweede fundament is versiebeheer en change management. Door policies als code te beheren, ontstaat automatisch een volledige geschiedenis van wijzigingen: wie heeft welke policy wanneer aangepast, met welke motivatie en na welke goedkeuring. Dit sluit direct aan bij audit- en compliance-eisen waarbij wijzigingen in beveiligingsconfiguraties traceerbaar moeten zijn. Git-branches worden gebruikt om wijzigingen te isoleren totdat ze zijn goedgekeurd: een ontwikkelaar werkt aan een feature-branch, diensten een pull request in, deze wordt gereviewd door een architect of CISO, en na goedkeuring wordt de wijziging via een merge naar de main-branch overgenomen. Tags en releases maken het mogelijk om specifieke versies van policy-sets te markeren en te implementeren, bijvoorbeeld bij het uitrollen naar nieuwe omgevingen. Het derde fundament is automatisering via CI/CD-pipelines. Wanneer code naar de repository wordt gepusht, worden automatisch validaties uitgevoerd: syntax-controles, tests op policy-logica, en scans op beveiligingsproblemen. Na validatie worden policies geïmplementeerd in Azure, eerst in een testomgeving voor verificatie, en vervolgens – na handmatige of automatische goedkeuring – in productie. Deze pipeline zorgt ervoor dat wijzigingen niet per ongeluk kunnen worden doorgevoerd zonder de juiste controles en dat implementaties altijd reproduceerbaar zijn. Voor Nederlandse overheidsorganisaties is het belangrijk om in deze pipelines expliciete goedkeuringsstappen op te nemen, waarbij wijzigingen in kritieke policies (bijvoorbeeld die directe impact hebben op beschikbaarheid of beveiliging) alleen na expliciete handtekening van een verantwoordelijke kunnen worden doorgevoerd. Het vierde fundament is testbaarheid en validatie. Policies kunnen worden getest voordat ze worden toegepast, bijvoorbeeld door ze eerst alleen te evalueren (audit-mode) op een subset van resources, of door ze te valideren via policy-testtools. Door test-cases te definiëren – scenario's waarin een policy compliant of non-compliant moet zijn – kan worden geverifieerd dat policy-logica correct werkt. Dit voorkomt dat policies met onbedoelde bijwerkingen in productie belanden en helpt bij het documenteren van het verwachte gedrag van policies voor ontwikkelteams en beheerders.

Implementatiestrategieën voor geautomatiseerd Policy-beheer

De implementatie van geautomatiseerd Policy-beheer begint met de keuze voor de juiste technologie en tooling. Azure biedt meerdere opties: ARM-templates (JSON), Bicep (declaratieve DSL), Terraform (infrastructure as code) of directe PowerShell-cmdlets. Voor Policy as Code zijn ARM-templates en Bicep het meest gangbaar omdat ze native Azure-concepten ondersteunen en goed integreren met Azure Resource Manager. Bicep heeft het voordeel dat de syntax leesbaarder is dan JSON en dat complexe structuren eenvoudiger te beheren zijn, terwijl ARM-templates breder worden ondersteund en meer voorbeelden beschikbaar zijn. De keuze hangt af van de bestaande tooling en expertise binnen de organisatie. Een eerste strategische keuze is de inrichting van een centrale policy-definitie-library. In plaats van policies ad-hoc te ontwikkelen per project of omgeving, wordt een gedeelde library opgezet waarin standaard policy-definities worden beheerd die door alle teams kunnen worden hergebruikt. Deze library wordt bijvoorbeeld georganiseerd in modules: een security-module met policies voor encryptie, logging en toegangscontrole, een compliance-module met policies voor BIO- en NIS2-vereisten, en een cost-management-module met policies voor resource-limieten en tagging. Teams kunnen deze modules importeren in hun eigen repositories en aanvullen met specifieke policies voor hun workloads. Deze aanpak voorkomt duplicatie, zorgt voor consistentie en maakt het mogelijk om verbeteringen in de centrale library automatisch beschikbaar te stellen aan alle gebruikers. Een tweede strategie is het gebruik van policy-initiatieven (policy sets) om gerelateerde policies logisch te bundelen. Initiatieven maken het mogelijk om tientallen policies tegelijk toe te wijzen aan een management group of subscription, waarbij parameters per initiatief kunnen worden geconfigureerd. In een Policy as Code-omgeving worden initiatieven gedefinieerd als templates die beschrijven welke policies zijn opgenomen, welke parameters beschikbaar zijn en welke standaardwaarden worden gebruikt. Bijvoorbeeld: een 'BIO Basisbeveiliging'-initiatief kan twintig policies bundelen rond encryptie, logging, netwerksegmentatie en toegangscontrole, met parameters voor toegestane regio's, retentieperioden en logging-doelen. Door initiatieven te gebruiken in plaats van individuele policies wordt de complexiteit van assignments drastisch verminderd. Een derde strategie is het implementeren van een gelaagde assignment-structuur. Policies worden niet willekeurig toegewezen, maar volgens een hiërarchisch model: generieke basispolicies op het hoogste management group-niveau (bijvoorbeeld voor alle productie-subscriptions), meer specifieke policies op tussenliggende niveaus (bijvoorbeeld per domein of per omgeving), en workloadspecifieke policies op subscription- of resourcegroup-niveau. In Policy as Code wordt deze structuur vastgelegd in assignment-templates die expliciet aangeven op welk niveau een policy moet worden toegewezen en welke parameters gelden. Dit maakt het mogelijk om de gehele policy-hiërarchie programmatisch te genereren en te valideren, en om bij wijzigingen te controleren dat de hiërarchie consistent blijft. Een vierde strategie is het automatiseren van remediatie en herstel. Policies kunnen niet alleen non-compliant resources detecteren, maar ook automatisch herstellen via deployIfNotExists-effecten of remediation-tasks. In een geautomatiseerde omgeving worden deze remediation-acties ook als code beheerd: de remediation-definitie wordt opgeslagen in de repository, getest in een gecontroleerde omgeving, en geïmplementeerd via pipelines. Daarnaast kunnen geautomatiseerde scripts worden ingezet om bulk-remediatie uit te voeren op bestaande non-compliant resources, bijvoorbeeld bij de introductie van een nieuwe policy. Deze scripts worden ook versiebeheerd en getest, zodat remediatie-acties reproduceerbaar en gecontroleerd zijn.

CI/CD-integratie voor Policy-implementatie en -wijzigingen

CI/CD-integratie is het kloppend hart van Policy as Code: het verbindt code-ontwikkeling met Azure-implementatie en zorgt ervoor dat wijzigingen gecontroleerd, getest en reproduceerbaar worden doorgevoerd. Voor Azure Policy betekent dit dat pipelines worden ingericht die automatisch policies valideren, testen en implementeren wanneer code naar de repository wordt gepusht. Deze pipelines worden typisch geïmplementeerd in Azure DevOps of GitHub Actions, waarbij Azure-verbindingen worden gebruikt om toegang te krijgen tot de Azure-tenant en policies te deployen. Een eerste component van CI/CD-integratie is pre-commit validatie. Voordat code überhaupt naar de repository wordt gepusht, worden lokale checks uitgevoerd om syntaxfouten, best practices-schendingen en potentiële problemen te detecteren. Tools zoals ARM Template Toolkit (arm-ttk), PSRule voor Azure of Bicep Linter kunnen worden geïntegreerd in Git hooks of in de ontwikkelomgeving, zodat ontwikkelaars direct feedback krijgen over de kwaliteit van hun policy-definities. Dit voorkomt dat foutieve code in de repository belandt en vermindert de feedback-loop aanzienlijk. De CI-fase (Continuous Integration) begint wanneer code naar een branch wordt gepusht. De pipeline voert automatisch een reeks validaties uit: syntax-controles op ARM-templates of Bicep-bestanden, JSON-schema-validaties, en scans op beveiligingsproblemen of best practices-schendingen. Vervolgens worden unit-tests uitgevoerd op de policy-logica, indien mogelijk met behulp van policy-testtools die kunnen simuleren of een policy correct evalueert op voorbeeld-resources. Als alle validaties slagen, wordt de code gebouwd tot deploybare artifacts (bijvoorbeeld gecompileerde ARM-templates) en opgeslagen als pipeline-artifacts. Als validaties falen, wordt de pipeline gestopt en krijgt de ontwikkelaar gedetailleerde feedback over wat er mis is gegaan. De CD-fase (Continuous Deployment) zorgt ervoor dat goedgekeurde code automatisch wordt geïmplementeerd in Azure. Voor policy-definities betekent dit dat ze worden gepusht naar een policy-definition-scope (management group of subscription), waarbij versie-informatie en metadata worden toegevoegd. Voor assignments betekent dit dat ze worden toegewezen aan de juiste scopes met de geconfigureerde parameters. De implementatie verloopt typisch in fasen: eerst naar een testomgeving voor verificatie, vervolgens naar een acceptatieomgeving voor uitgebreidere tests, en ten slotte naar productie na expliciete goedkeuring. Tussen elke fase kunnen handmatige goedkeuringsstappen worden ingebouwd, vooral voor wijzigingen in kritieke policies die directe impact kunnen hebben op de beschikbaarheid of beveiliging van workloads. Een belangrijk aspect van CI/CD-integratie is rollback-capaciteit. Wanneer een policy-implementatie onverwachte problemen veroorzaakt, moet het mogelijk zijn om snel terug te vallen op een eerdere versie. Dit wordt gefaciliteerd door versiebeheer: elke policy-definitie heeft een versie, en assignments kunnen verwijzen naar specifieke versies. In de pipeline wordt bij elke implementatie een backup gemaakt van de huidige state, zodat bij problemen snel kan worden teruggedraaid. Daarnaast kunnen pipelines worden geconfigureerd om automatisch te rollback wanneer bepaalde drempelwaarden worden overschreden, bijvoorbeeld wanneer het aantal non-compliant resources plotseling sterk toeneemt na een policy-wijziging.

Gebruik PowerShell-script policy-automation.ps1 (functie Invoke-Monitoring) – Monitort de status van policy-definities en assignments, inclusief versie-informatie en compliance-statistieken..

Governance, onderhoud en levenscyclusbeheer van Policies

Geautomatiseerd Policy-beheer is geen eenmalige implementatie, maar een continu proces dat governance, onderhoud en levenscyclusbeheer vereist. Zonder duidelijke governance dreigt policy-library te verworden tot een verzameling verouderde, inconsistente definities die niet meer worden onderhouden of gebruikt. Voor Nederlandse overheidsorganisaties is het daarom essentieel om vanaf het begin een volwassen governance-model in te richten waarin rollen, verantwoordelijkheden en processen expliciet zijn vastgelegd. Een eerste pijler van governance is eigenaarschap en verantwoordelijkheid. Elke policy of policy-module heeft een duidelijke eigenaar: een team, een persoon of een functie die verantwoordelijk is voor het ontwikkelen, onderhouden en actualiseren van de policy. Deze eigenaar is het eerste aanspreekpunt bij vragen, wijzigingsverzoeken of problemen, en is verantwoordelijk voor het periodiek beoordelen of de policy nog steeds relevant en effectief is. In de code-repository wordt eigenaarschap vastgelegd via CODEOWNERS-bestanden of via metadata in de policy-definitie zelf, zodat bij pull requests automatisch de juiste personen worden benaderd voor review. Een tweede pijler is wijzigingscontrole en goedkeuringsprocessen. Niet elke wijziging in een policy kan zomaar worden doorgevoerd: sommige wijzigingen hebben grote impact en vereisen expliciete goedkeuring van meerdere belanghebbenden. In het governance-model worden daarom verschillende approval-levels gedefinieerd: kleine wijzigingen (bijvoorbeeld tekstuele aanpassingen of parameter-wijzigingen) kunnen door de policy-eigenaar worden goedgekeurd, terwijl grote wijzigingen (bijvoorbeeld nieuwe deny-policies of wijzigingen in bestaande deny-policies) goedkeuring vereisen van een governance-board waarin CISO, architecten en proceseigenaren deelnemen. Deze goedkeuringsprocessen worden geautomatiseerd in de CI/CD-pipeline via branch-protection rules, required reviewers en approval-gates. Een derde pijler is documentatie en kennisoverdracht. Policies moeten niet alleen technisch correct zijn, maar ook goed gedocumenteerd zodat ontwikkelteams, beheerders en auditors begrijpen wat de policy doet, waarom deze bestaat en wat de impact is. In Policy as Code wordt documentatie opgeslagen naast de code, bijvoorbeeld als README-bestanden, inline-comments in de definitie, of als aparte documentatie-site. Deze documentatie wordt automatisch bijgewerkt wanneer policies worden gewijzigd, en wordt meegenomen in de review-processen. Voor complexe policies kunnen ook voorbeelden worden opgenomen van compliant en non-compliant resources, zodat ontwikkelteams direct begrijpen wat wordt verwacht. Een vierde pijler is periodiek onderhoud en levenscyclusbeheer. Policies verouderen: nieuwe Azure-services worden geïntroduceerd, best practices veranderen, en compliance-vereisten worden aangescherpt. Zonder actief onderhoud raken policies achterhaald en verliezen ze hun effectiviteit. Daarom wordt een periodiek onderhoudsproces ingericht, bijvoorbeeld elk kwartaal, waarbij alle policies worden beoordeeld op actualiteit, effectiviteit en relevantie. Policies die niet meer worden gebruikt, worden gearchiveerd of verwijderd. Policies die verouderd zijn, worden bijgewerkt naar nieuwe best practices. En nieuwe policies worden ontwikkeld voor nieuwe services of vereisten. Dit onderhoudsproces wordt gefaciliteerd door metrics en dashboards die inzicht geven in policy-usage, compliance-rates en trends. Tot slot is er de pijler van meten en verbeteren. Geautomatiseerd Policy-beheer moet niet alleen policies implementeren, maar ook meten of ze effectief zijn. Metrics zoals policy-compliance-percentages, aantallen non-compliant resources, en tijd-tot-remediatie helpen bij het identificeren van problemen en het prioriteren van verbeteracties. Deze metrics worden opgehaald via Azure Policy Insights API's en gevisualiseerd in dashboards die regelmatig worden besproken in governance-overleggen. Op basis van deze metingen kunnen policies worden aangepast, nieuwe policies worden ontwikkeld, of processen worden verbeterd. De bij dit artikel horende PowerShell-script kan worden gebruikt om periodiek deze metrics op te halen en te rapporteren, zodat governance en verbetering data-gedreven plaatsvinden.

Gebruik PowerShell-script policy-automation.ps1 (functie Invoke-Remediation) – Ondersteunt geautomatiseerde policy-implementatie en -wijzigingen, inclusief validatie en rollback-capaciteit..

Compliance & Frameworks

Automation

Gebruik het onderstaande PowerShell script om deze security control te monitoren en te implementeren. Het script bevat functies voor zowel monitoring (-Monitoring) als remediation (-Remediation).

PowerShell
<# ================================================================================ AZURE POWERSHELL SCRIPT - Nederlandse Baseline voor Veilige Cloud ================================================================================ .SYNOPSIS Geautomatiseerd beheer en monitoring van Azure Policy-definities en assignments .DESCRIPTION Dit script ondersteunt Policy as Code door: - Policy-definities en assignments te inventariseren en monitoren - Versie-informatie en compliance-statistieken op te halen - Policy-structuur en -hierarchie te valideren - Ondersteuning te bieden voor geautomatiseerde policy-implementatie Dit script sluit aan op het artikel 'Geautomatiseerd beheer van Azure Policy via Policy as Code' en is bedoeld als praktische tool voor policy-beheer. .NOTES Filename: policy-automation.ps1 Author: Nederlandse Baseline voor Veilige Cloud Version: 1.0 Related JSON: content/azure/compliance/policy-automation.json #> #Requires -Version 5.1 #Requires -Modules Az.Accounts, Az.Resources, Az.PolicyInsights [CmdletBinding()] param( [Parameter()] [switch]$Monitoring, [Parameter()] [string]$ManagementGroupName, [Parameter()] [string]$SubscriptionId ) $ErrorActionPreference = 'Stop' $PolicyName = "Azure Policy Automation - Beheer en Monitoring" function Connect-RequiredServices { if (-not (Get-AzContext -ErrorAction SilentlyContinue)) { Connect-AzAccount -ErrorAction Stop | Out-Null } } function Get-PolicyInventory { <# .SYNOPSIS Haalt een overzicht op van policy-definities en assignments .OUTPUTS PSCustomObject met TotalDefinitions, TotalAssignments, TotalInitiatives #> [CmdletBinding()] param( [string]$ScopeId ) $definitions = @() $assignments = @() $initiatives = @() try { if ($ScopeId) { $definitions = Get-AzPolicyDefinition -ManagementGroupName $ScopeId -ErrorAction SilentlyContinue if (-not $definitions) { $definitions = Get-AzPolicyDefinition -SubscriptionId $ScopeId -ErrorAction SilentlyContinue } $assignments = Get-AzPolicyAssignment -Scope $ScopeId -ErrorAction SilentlyContinue $initiatives = Get-AzPolicySetDefinition -ManagementGroupName $ScopeId -ErrorAction SilentlyContinue if (-not $initiatives) { $initiatives = Get-AzPolicySetDefinition -SubscriptionId $ScopeId -ErrorAction SilentlyContinue } } else { $definitions = Get-AzPolicyDefinition -ErrorAction SilentlyContinue $assignments = Get-AzPolicyAssignment -ErrorAction SilentlyContinue $initiatives = Get-AzPolicySetDefinition -ErrorAction SilentlyContinue } } catch { Write-Verbose "Kon policy-inventarisatie niet volledig ophalen: $_" } [PSCustomObject]@{ TotalDefinitions = ($definitions | Measure-Object).Count TotalAssignments = ($assignments | Measure-Object).Count TotalInitiatives = ($initiatives | Measure-Object).Count CustomDefinitions = ($definitions | Where-Object { $_.ResourceId -notlike '*/providers/Microsoft.Authorization/policyDefinitions/*' } | Measure-Object).Count BuiltInDefinitions = ($definitions | Where-Object { $_.ResourceId -like '*/providers/Microsoft.Authorization/policyDefinitions/*' } | Measure-Object).Count } } function Get-PolicyComplianceSummary { <# .SYNOPSIS Haalt compliance-statistieken op voor policy-assignments .OUTPUTS PSCustomObject met compliance-statistieken #> [CmdletBinding()] param( [string]$SubscriptionId ) $totalNonCompliant = 0 $totalCompliant = 0 $totalResources = 0 $subscriptions = @() if ($SubscriptionId) { $subscriptions = Get-AzSubscription -SubscriptionId $SubscriptionId -ErrorAction SilentlyContinue } else { $subscriptions = Get-AzSubscription -ErrorAction Stop | Where-Object { $_.State -eq 'Enabled' } } foreach ($sub in $subscriptions) { Set-AzContext -SubscriptionId $sub.Id -ErrorAction SilentlyContinue | Out-Null try { $summary = Get-AzPolicyStateSummary -ErrorAction SilentlyContinue if ($summary -and $summary.Results) { foreach ($result in $summary.Results) { if ($result.NonCompliantResources) { $totalNonCompliant += [int]$result.NonCompliantResources } if ($result.CompliantResources) { $totalCompliant += [int]$result.CompliantResources } if ($result.ResourceDetails) { foreach ($detail in $result.ResourceDetails) { $totalResources++ } } } } } catch { Write-Verbose "Kon compliance-summary voor subscription '$($sub.Name)' niet ophalen: $_" } } $compliancePercentage = $null if (($totalCompliant + $totalNonCompliant) -gt 0) { $compliancePercentage = [math]::Round(($totalCompliant / ($totalCompliant + $totalNonCompliant)) * 100, 1) } [PSCustomObject]@{ TotalCompliant = $totalCompliant TotalNonCompliant = $totalNonCompliant TotalResources = $totalResources CompliancePercentage = $compliancePercentage } } function Test-PolicyStructure { <# .SYNOPSIS Valideert de policy-structuur en -hierarchie .OUTPUTS PSCustomObject met validatieresultaten #> [CmdletBinding()] param() $issues = @() try { $assignments = Get-AzPolicyAssignment -ErrorAction SilentlyContinue foreach ($assignment in $assignments) { if (-not $assignment.Properties.DisplayName) { $issues += "Assignment '$($assignment.Name)' heeft geen displayname" } if ($assignment.Properties.PolicyDefinitionId -and -not (Get-AzPolicyDefinition -Id $assignment.Properties.PolicyDefinitionId -ErrorAction SilentlyContinue)) { $issues += "Assignment '$($assignment.Name)' verwijst naar niet-bestaande policy: $($assignment.Properties.PolicyDefinitionId)" } } } catch { Write-Verbose "Kon policy-structuur niet volledig valideren: $_" } [PSCustomObject]@{ IsValid = ($issues.Count -eq 0) Issues = $issues IssueCount = $issues.Count } } try { Connect-RequiredServices $scopeId = $null if ($ManagementGroupName) { $scopeId = $ManagementGroupName } elseif ($SubscriptionId) { $scopeId = $SubscriptionId } $inventory = Get-PolicyInventory -ScopeId $scopeId $compliance = Get-PolicyComplianceSummary -SubscriptionId $SubscriptionId $structure = Test-PolicyStructure if ($Monitoring) { Write-Host "" -ForegroundColor White Write-Host "========================================" -ForegroundColor Cyan Write-Host $PolicyName -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "" Write-Host "--- Policy Inventarisatie ---" -ForegroundColor Yellow Write-Host ("Totaal definitions : {0}" -f $inventory.TotalDefinitions) -ForegroundColor White Write-Host (" - Ingebouwd : {0}" -f $inventory.BuiltInDefinitions) -ForegroundColor Gray Write-Host (" - Aangepast : {0}" -f $inventory.CustomDefinitions) -ForegroundColor Gray Write-Host ("Totaal assignments : {0}" -f $inventory.TotalAssignments) -ForegroundColor White Write-Host ("Totaal initiatives : {0}" -f $inventory.TotalInitiatives) -ForegroundColor White Write-Host "" Write-Host "--- Compliance Status ---" -ForegroundColor Yellow if ($null -ne $compliance.CompliancePercentage) { Write-Host ("Compliance percentage : {0}%" -f $compliance.CompliancePercentage) -ForegroundColor White Write-Host ("Compliant resources : {0}" -f $compliance.TotalCompliant) -ForegroundColor Green Write-Host ("Non-compliant resources: {0}" -f $compliance.TotalNonCompliant) -ForegroundColor $(if ($compliance.TotalNonCompliant -gt 0) { "Yellow" } else { "White" }) } else { Write-Host "Compliance percentage : n.v.t. (geen gegevens beschikbaar)" -ForegroundColor Yellow } Write-Host "" Write-Host "--- Structurele Validatie ---" -ForegroundColor Yellow if ($structure.IsValid) { Write-Host "Policy-structuur : OK" -ForegroundColor Green } else { Write-Host "Policy-structuur : WAARSCHUWING - $($structure.IssueCount) probleem(en) gevonden" -ForegroundColor Yellow foreach ($issue in $structure.Issues) { Write-Host (" - {0}" -f $issue) -ForegroundColor Gray } } if ($null -ne $compliance.CompliancePercentage -and $compliance.CompliancePercentage -lt 80) { Write-Host "" Write-Host "[WAARSCHUWING] Compliance-percentage ligt onder 80%. Onderzoek non-compliant resources en prioriteer remediatie." -ForegroundColor Yellow } } else { Write-Host "" Write-Host ("Azure Policy Automation: {0} definitions, {1} assignments, {2} initiatives, compliance {3}" -f ` $inventory.TotalDefinitions, ` $inventory.TotalAssignments, ` $inventory.TotalInitiatives, ` ($(if ($null -ne $compliance.CompliancePercentage) { "$($compliance.CompliancePercentage)%" } else { "n.v.t." }))) } } catch { Write-Error $_ exit 1 } # ================================================================================ # Standaard Invoke-* Functions (conform Azure script-schema) # ================================================================================ function Invoke-Implementation { <# .SYNOPSIS Implementeert configuratie (delegeert naar remediatie) #> [CmdletBinding()] param() Invoke-Remediation } function Invoke-Monitoring { <# .SYNOPSIS Voert monitoring uit op policy-definities en assignments #> [CmdletBinding()] param() $Monitoring = $true try { Connect-RequiredServices $scopeId = $null if ($ManagementGroupName) { $scopeId = $ManagementGroupName } elseif ($SubscriptionId) { $scopeId = $SubscriptionId } $inventory = Get-PolicyInventory -ScopeId $scopeId $compliance = Get-PolicyComplianceSummary -SubscriptionId $SubscriptionId $structure = Test-PolicyStructure Write-Host "" -ForegroundColor White Write-Host "========================================" -ForegroundColor Cyan Write-Host $PolicyName -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "" Write-Host "--- Policy Inventarisatie ---" -ForegroundColor Yellow Write-Host ("Totaal definitions : {0}" -f $inventory.TotalDefinitions) -ForegroundColor White Write-Host (" - Ingebouwd : {0}" -f $inventory.BuiltInDefinitions) -ForegroundColor Gray Write-Host (" - Aangepast : {0}" -f $inventory.CustomDefinitions) -ForegroundColor Gray Write-Host ("Totaal assignments : {0}" -f $inventory.TotalAssignments) -ForegroundColor White Write-Host ("Totaal initiatives : {0}" -f $inventory.TotalInitiatives) -ForegroundColor White Write-Host "" Write-Host "--- Compliance Status ---" -ForegroundColor Yellow if ($null -ne $compliance.CompliancePercentage) { Write-Host ("Compliance percentage : {0}%" -f $compliance.CompliancePercentage) -ForegroundColor White Write-Host ("Compliant resources : {0}" -f $compliance.TotalCompliant) -ForegroundColor Green Write-Host ("Non-compliant resources: {0}" -f $compliance.TotalNonCompliant) -ForegroundColor $(if ($compliance.TotalNonCompliant -gt 0) { "Yellow" } else { "White" }) } else { Write-Host "Compliance percentage : n.v.t. (geen gegevens beschikbaar)" -ForegroundColor Yellow } Write-Host "" Write-Host "--- Structurele Validatie ---" -ForegroundColor Yellow if ($structure.IsValid) { Write-Host "Policy-structuur : OK" -ForegroundColor Green } else { Write-Host "Policy-structuur : WAARSCHUWING - $($structure.IssueCount) probleem(en) gevonden" -ForegroundColor Yellow foreach ($issue in $structure.Issues) { Write-Host (" - {0}" -f $issue) -ForegroundColor Gray } } if ($null -ne $compliance.CompliancePercentage -and $compliance.CompliancePercentage -lt 80) { Write-Host "" Write-Host "[WAARSCHUWING] Compliance-percentage ligt onder 80%. Onderzoek non-compliant resources en prioriteer remediatie." -ForegroundColor Yellow } } catch { Write-Error $_ exit 1 } } function Invoke-Remediation { <# .SYNOPSIS Ondersteunt geautomatiseerde policy-implementatie en -beheer .DESCRIPTION Dit script voert geen automatische policy-implementatie uit, maar geeft richtlijnen en validatie voor Policy as Code workflows. Gebruik dit script in combinatie met CI/CD-pipelines voor geautomatiseerde deployment. #> [CmdletBinding()] param() Write-Host "[INFO] Dit script ondersteunt Policy as Code workflows maar voert geen automatische implementatie uit." -ForegroundColor Yellow Write-Host "[INFO] Gebruik dit script in combinatie met CI/CD-pipelines voor geautomatiseerde policy-deployment." -ForegroundColor Yellow Write-Host "[INFO] Raadpleeg het artikel 'Geautomatiseerd beheer van Azure Policy via Policy as Code' voor implementatierichtlijnen." -ForegroundColor Yellow Write-Host "" Invoke-Monitoring Write-Host "" Write-Host "[INFO] Voor geautomatiseerde policy-implementatie:" -ForegroundColor Cyan Write-Host " - Gebruik ARM-templates of Bicep voor policy-definities" -ForegroundColor Gray Write-Host " - Implementeer via CI/CD-pipelines (Azure DevOps, GitHub Actions)" -ForegroundColor Gray Write-Host " - Valideer policies voordat ze worden toegepast" -ForegroundColor Gray Write-Host " - Gebruik versiebeheer en rollback-capaciteit" -ForegroundColor Gray }

Risico zonder implementatie

Risico zonder implementatie
High: Zonder geautomatiseerd Policy-beheer via Policy as Code ontstaat een groot risico op inconsistente, ongetraceerde en moeilijk te onderhouden governance-configuraties. Handmatig beheer schaalt niet bij groei van de Azure-omgeving, wijzigingen zijn niet reproduceerbaar of traceerbaar, en bij audits kan niet worden aangetoond dat policies volgens afgesproken processen zijn beheerd. Dit leidt tot compliance-risico's, governance-gaten en verlies van vertrouwen van toezichthouders en bestuur.

Management Samenvatting

Policy as Code maakt Azure Policy-beheer schaalbaar, traceerbaar en reproduceerbaar door policies te beheren als versiebeheerde code en te implementeren via CI/CD-pipelines. Dit artikel beschrijft de fundamenten van Policy as Code, implementatiestrategieën, CI/CD-integratie en governance voor levenscyclusbeheer. Door policies modulair te ontwikkelen, te testen voordat ze worden toegepast, en expliciete wijzigingscontrole en goedkeuringsprocessen in te richten, ontstaat een volwassen governance-model dat aantoonbaar bijdraagt aan compliance en risicoreductie.