Azure Security Baseline: BIO Compliance Framework voor Nederlandse Overheid

Security Baseline Configuration Standards Identity & Access 32/32 controls configured 100% Data Protection 28/28 controls configured 100% Device Management 21/25 controls configured 84% Network Security 19/19 controls configured 100% Overall Compliance 96% Frameworks CIS NIST ISO Actions 4 Pending 100 Completed Last updated: November 12, 2025 - 14:32

De Baseline Informatiebeveiliging Overheid (BIO) verplicht publieke organisaties om een aantoonbaar veilige cloudomgeving te realiseren. In Azure betekent dit dat honderden controles voor identiteit, netwerk, opslag en monitoring consistent moeten worden toegepast. Zonder duidelijke referentie-architectuur raken teams al snel verstrikt in ad-hoc maatregelen, versnipperde scripts en eindeloze auditbevindingen.

Deze gids beschrijft hoe je een Azure Security Baseline opbouwt die gelijktijdig aansluit op BIO, CIS Microsoft Azure Foundations Benchmark, ISO 27001 en NIST. De aanpak is gebaseerd op projecten bij ministeries, uitvoeringsorganisaties en decentrale overheden en laat stap voor stap zien hoe je beleid vertaalt naar technische controls, hoe je Microsoft Defender for Cloud inzet voor continue bewaking en hoe je compliance rapporteert richting auditors.

Wat je leert

Je leert hoe je Azure Policy-initiatieven inzet voor CIS/BIO, Microsoft Defender for Cloud activeert voor continue compliance, netwerksegmentatie inricht met een hub-spoke-topologie en Azure Firewall, encryptie afdwingt (at-rest én in-transit) en hoe je logging en rapportages richting BIO-auditors automatiseert. De aanpak bevat IaC-sjablonen en meer dan 50 voorbeeldpolicy’s.

Pro tip

Schakel beleid eerst 30 dagen in audit-modus voordat je deny of DeployIfNotExists activeert. Bij een provincie blokkeerde een verkeerd geparametriseerde netwerkpolicy alle VM-deployments, inclusief een herstelomgeving tijdens een incident. Neem de tijd om rapporten te analyseren, valse positieven te filteren, uitzonderingen vast te leggen en teams te trainen. Pas daarna zet je enforcement aan.

BIO Framework: Azure Mapping en Compliance Requirements

Strategische vertaalslag van normkaders naar Azure-controls

Een Azure Security Baseline krijgt pas waarde wanneer de abstracte eisen uit de Baseline Informatiebeveiliging Overheid, de Nederlandse Baseline voor Veilige Cloud en verwante kaders zoals NIS2 en ISO 27001 concreet worden gekoppeld aan technische maatregelen. In praktijk start dit met een mapping-sessie waarin security officers, solution-architecten, juristen en auditteams gezamenlijk bepalen welke BIO-artikelen op welke manieren in Azure worden afgedwongen. Door de interpretatie gezamenlijk te documenteren ontstaat een gedeeld begrippenkader dat voorkomt dat ontwikkelteams elk normartikel anders lezen en auditors discussies moeten voeren over woordkeuzes. Deze sessies leveren een levend document op waarin elk BIO-thema is gekoppeld aan Azure-services, beheerprocessen en bewijsstukken. Zodra dit document onderdeel wordt van het change-proces kunnen bestuurders overzien welke control-gaten er bestaan en welke investeringen noodzakelijk zijn om de doelarchitectuur te bereiken.

Voor thema 9 (toegangsbeveiliging) betekent de mapping dat Entra ID het primaire identiteitsplatform wordt en dat alle accounts – menselijk en niet-menselijk – aan centrale lifecycleprocessen worden gekoppeld. De praktijk leert dat het verplicht stellen van meervoudige authenticatie, Conditional Access policies en Identity Protection pas waarde oplevert wanneer de organisatie ook een uniform autorisatiemodel hanteert. Daarom wordt role-based access control gekoppeld aan functieprofielen, en krijgen beheerders alleen tijdelijk verhoogde rechten via Privileged Identity Management. Elk privilege wordt gezien als een risicobron: change-kalenders, CAB-procedures en forensische logging maken daarom integraal onderdeel uit van deze thematische aanpak. Tegelijkertijd worden sleutel- en geheimbeheerprocessen gestandaardiseerd via Azure Key Vault zodat serviceprincipals geen hard-coded secrets meer bevatten en auditing van certificaten, sleutels en secrets aantoonbaar plaatsvindt.

Thema 10 (cryptografie) vraagt om meer dan eenvoudigweg het aanvinken van “encryption at rest”. Tijdens de mapping wordt per dataset bepaald welke classificatie geldt, waar data fysiek moet verblijven en welke sleutelverantwoordelijkheid hoort bij de eigenaar. Azure Disk Encryption, Storage Service Encryption en Transparent Data Encryption zijn standaard, maar voor departementaal vertrouwelijke workloads wordt gekozen voor customer-managed keys in een Key Vault Premium of Managed HSM. Het document beschrijft welke rotatiefrequenties gelden, hoe dual control wordt vormgegeven en welke fallbackprocedures er zijn voor sleutelverlies. Ook transportbeveiliging hoort hierbij: TLS 1.2 of hoger is de norm, Application Gateway en Azure Front Door worden geconfigureerd voor end-to-end encryptie en netwerkcomponenten zoals ExpressRoute en VPN Gateways krijgen expliciete hardeningstappen.

Thema 12 (bedrijfscontinuïteit en logging) wordt vertaald naar concrete beschikbaarheidsdoelstellingen en telemetrievereisten. Elke workload krijgt een RTO en RPO gekoppeld aan Azure Backup, Site Recovery en replication-scenario’s. Logging- en monitoringvereisten worden even concreet uitgewerkt: welke events moeten minimaal worden vastgelegd, in welk Log Analytics workspace landen ze, hoe lang is de retentie en welk runbook hoort bij een kritieke melding? Door het SOC en de compliance-afdeling te betrekken ontstaat een doorlopende keten van detectie, respons en verslaglegging. DDoS Protection Standard, workload-isolatie en scenario-oefeningen worden niet langer gezien als extra kostenpost maar als voorwaarde om te kunnen aantonen dat BIO-paragrafen 12.1 t/m 12.6 daadwerkelijk worden nageleefd.

Thema 13 (netwerk- en communicatiebeveiliging) vertaalt zich in een vaste volgorde van keuzes: eerst worden segmentatieprincipes en gevoeligheidszones beschreven, daarna pas tooling. Een hub-spoke-topologie met Azure Firewall Premium, Private Endpoints en Azure Bastion vormt vaak de ruggengraat. De mapping benoemt welke flows zijn toegestaan, hoe inspectie plaatsvindt, welke logboeken vereist zijn en hoe uitzonderingen worden geregistreerd. Omdat deze afspraken zijn vastgelegd in Git en gekoppeld aan Infrastructure-as-Code sjablonen kan elke nieuwe workload dezelfde standaarden erven. Daarmee verdwijnt de traditionele discussie tussen security en projectteams over “wie beslist” en vormen meetwaarden zoals het percentage verkeer dat via TLS-inspectie gaat het gespreksonderwerp.

Thema 14 (ontwikkeling en onderhoud) vult het geheel aan. Het document beschrijft hoe DevSecOps wordt vormgegeven, welke pipelines verplicht zijn, hoe statische en dynamische analyses worden uitgevoerd en hoe Defender for DevOps of GitHub Advanced Security wordt geïntegreerd. Door beveiligingscontroles te koppelen aan sprintdoelstellingen en Definition of Done-eisen wordt softwarekwaliteit een directe indicator voor BIO-compliance. Containerbeveiliging, image signing, registries en runtime-detectie worden onderdeel van dezelfde keten zodat ontwikkelteams niet langer in aparte werelden werken.

De mapping eindigt met een expliciete koppeling naar de CIS Microsoft Azure Foundations Benchmark en de Azure Security Benchmark. Deze frameworks leveren concrete controleteksten en toolingreferenties. Door ze te combineren met BIO en de Nederlandse Baseline voor Veilige Cloud ontstaat een hiërarchie: CIS Level 1 is de minimale baseline, Level 2 en ASB gelden voor gevoelige workloads, terwijl maatwerkpolicy’s de nationale eisen afdekken. Elk artikel krijgt een eigenaar, een meetmethode en een bewijslocatie. Daarmee verandert BIO-compliance van een papieren inspanning in een technisch afdwingbare blauwdruk die in audits als referentie wordt gebruikt.

Azure Policy Framework: Policy-as-Code voor Continuous Compliance

Policy-as-code als ruggengraat van volwassen cloudgovernance

Waar traditionele governance vertrouwde op Word-templates en Excel-controles, draait moderne compliance om reproduceerbare configuratie. Policy-as-code zorgt ervoor dat de interpretatie uit het normenkader automatisch wordt toegepast bij elke deployment. Het framework start daarom bij de structuur van management groups. Op het hoogste niveau worden kaders vastgelegd die voor de volledige tenant gelden: verplichte regio’s, minimale TLS-versies, taggingstandaarden en verplichte aansluiting op Log Analytics. Onderliggende groepen voor bijvoorbeeld departementen, shared services of experimenten erven deze eisen en mogen alleen aanvullende regels toevoegen. Door deze hiërarchie ontstaat een ordelijke erfelijkheid die precies aansluit op de bestuurlijke inrichting van de organisatie.

De volgende stap betreft het modelleren van policy-definities. Elke definitie beschrijft één controle, bijvoorbeeld het blokkeren van publieke IP-adressen op productie-VM’s of het afdwingen van Private Endpoints voor opslag. Het team definieert duidelijke metadata: aan welk BIO-artikel is de policy gekoppeld, wie is eigenaar, welke parameters zijn toegestaan en wat is de standaardwaarde? Deze granulariteit maakt het mogelijk om definities te testen alsof het softwaremodules zijn. In GitHub of Azure DevOps worden versies beheerd, wordt code review afgedwongen en draaien linters die syntaxis- en aliasfouten opsporen. Door definities klein te houden kunnen incidenten sneller worden geanalyseerd en kunnen uitzonderingen worden beperkt tot alleen de benodigde controle.

Initiatives vormen de verzamelingen waarin definities logisch worden gegroepeerd. Een organisatie hanteert doorgaans een set van vaste pakketten: één voor de BIO-baseline, één voor NIS2-vereisten, één voor de Azure Security Benchmark en één voor specifieke workloads zoals AI of OT-integraties. Hoewel Microsoft al uitgebreide built-ins aanbiedt, is het essentieel om eigen parameters en documentatie toe te voegen. Zo kan hetzelfde initiative in ontwikkelomgevingen milde waarden hanteren (bijvoorbeeld langere sleutelrotaties) terwijl productie-initiatives strengere standaarden afdwingen. Documentatievelden bevatten links naar architectuurbesluiten, risico-analyses en runbooks zodat auditors vanuit de Azure Portal direct de onderbouwing kunnen raadplegen.

Assignments bepalen waar beleid effectief wordt. Tijdens het ontwerp definieert de governanceboard scenario’s: enterprise-brede assignments worden eerst in audit-modus geplaatst, daarna uitgerold naar ontwikkel- en testsubscripties, pas vervolgens naar productie. Elk assignment heeft een duidelijke change-geschiedenis, release-notes en een communicatieplan, zodat teams weten wat er verandert. Door assignments te automatiseren via pipelines (bijvoorbeeld Bicep of Terraform) ontstaan herhaalbare deployments die ook in een disaster recovery scenario direct opnieuw kunnen worden uitgerold. Bovendien zijn assignments gekoppeld aan service catalogi: zodra een nieuw abonnement wordt aangevraagd, kiest de aanvrager het risicoprofiel en worden benodigde initiatives automatisch toegewezen.

Exemptions vormen een noodzakelijke veiligheidsklep. Het framework beschrijft daarom een formeel proces: een uitzondering bevat een risicoanalyse, compenserende maatregelen, een eigenaar en een einddatum. In tooling worden deze gegevens vastgelegd zodat dashboards direct inzicht geven in het aantal uitzonderingen en de resterende looptijd. Hierdoor kunnen bestuurders sturen op het terugdringen van technische schuld en kan audit controleren of uitzonderingen herbeoordeeld worden. Door exemptions zichtbaar te maken in rapportages voorkom je schaduwboekhoudingen en ontstaat een cultuur waarin afwijkingen bewust en tijdelijk zijn.

Remediation is de laatste bouwsteen. DeployIfNotExists- en Modify-effecten voeren automatische herstelacties uit, maar alleen wanneer duidelijk is hoe logging, rollen en ownership zijn ingericht. Het framework beschrijft welke bevindingen automatisch mogen worden opgelost en welke een change vereisen. Voorbeelden zijn het automatisch inschakelen van diagnostic settings of het toevoegen van ontbrekende tags. Complexere issues, zoals netwerkherstructurering, krijgen een workflow in ITSM met betrokkenheid van architecten. Door deze matrix te publiceren weten teams precies wat ze kunnen verwachten zodra een policy faalt. Tegelijkertijd levert de data van remediate-acties waardevolle signalen op voor continue verbetering: als één policy consequent honderden overtredingen veroorzaakt, is het tijd om scripts, templates of trainingen te herzien.

Tot slot beschrijft het framework hoe policy-as-code aansluit op de bredere lifecycle. Elke wijziging doorloopt een pipeline met unit-tests, what-if-analyses en een simulatie op synthetische subscriptions. Metrics zoals de gemiddelde doorlooptijd van policy-wijzigingen, het percentage deny-events dat binnen vijf dagen wordt opgelost en het aantal openstaande uitzonderingen worden maandelijks besproken in de cloudgovernanceboard. Zo ontstaat een continue kwaliteitslus waarbij beleid nooit stilvalt maar meegroeit met nieuwe Azure-functies, veranderende wetgeving en lessen uit incidenten. Policy-as-code wordt zo geen hinderpaal, maar een platform voor aantoonbare, schaalbare compliance.

powershell
# Deploy comprehensive BIO-compliant Azure Policy Initiative # This assigns CIS Benchmark + Azure Security Benchmark at Management Group level Connect-AzAccount # Define target scope (Management Group for organization-wide enforcement) $managementGroupId = "mg-nl-government" # Root management group voor overheid $scope = "/providers/Microsoft.Management/managementGroups/$managementGroupId" Write-Host "Deploying BIO-Compliant Azure Policy Initiative" -ForegroundColor Cyan Write-Host "Target scope: $scope" Write-Host "="*80 Write-Host "" # 1. Assign Azure Security Benchmark (ASB) Write-Host "[1/4] Assigning Azure Security Benchmark..." -ForegroundColor Yellow $asbInitiative = Get-AzPolicySetDefinition | Where-Object { $_.Properties.DisplayName -eq "Azure Security Benchmark" } if (-not $asbInitiative) { Write-Error "Azure Security Benchmark initiative not found. Ensure Defender for Cloud is enabled." exit 1 } $asbAssignment = New-AzPolicyAssignment ` -Name "asb-bio-compliance" ` -DisplayName "BIO Compliance - Azure Security Benchmark" ` -Description "Azure Security Benchmark v3.0 voor BIO-compliance. Covers 200+ security controls aligned met BIO normen 9, 10, 12, 13, 14." ` -PolicySetDefinition $asbInitiative ` -Scope $scope ` -EnforcementMode "DoNotEnforce" # Start in audit mode! Write-Host " ✓ Azure Security Benchmark assigned (Audit mode)" -ForegroundColor Green Write-Host " Assignment ID: $($asbAssignment.PolicyAssignmentId)" Write-Host "" # 2. Assign CIS Microsoft Azure Foundations Benchmark Write-Host "[2/4] Assigning CIS Benchmark v2.0.0..." -ForegroundColor Yellow $cisInitiative = Get-AzPolicySetDefinition -Name "06f19060-9e68-4070-92ca-f15cc126059e" -ManagementGroupName $managementGroupId if (-not $cisInitiative) { Write-Warning "CIS Benchmark not found at Management Group level. Importing from built-in..." $cisInitiative = Get-AzPolicySetDefinition -BuiltIn | Where-Object { $_.Properties.DisplayName -like "*CIS Microsoft Azure Foundations Benchmark*" } } $cisAssignment = New-AzPolicyAssignment ` -Name "cis-benchmark-v2" ` -DisplayName "BIO Compliance - CIS Benchmark v2.0.0" ` -Description "CIS Microsoft Azure Foundations Benchmark v2.0.0. Level 1 + Level 2 controls voor high-security government environments." ` -PolicySetDefinition $cisInitiative ` -Scope $scope ` -EnforcementMode "DoNotEnforce" # Audit mode Write-Host " ✓ CIS Benchmark assigned (Audit mode)" -ForegroundColor Green Write-Host " Assignment ID: $($cisAssignment.PolicyAssignmentId)" Write-Host "" # 3. Custom BIO-Specific Policies Write-Host "[3/4] Creating custom BIO-specific policy initiative..." -ForegroundColor Yellow # Define custom policies for BIO-specific requirements niet covered door ASB/CIS $bioPolicyDefinitions = @( # BIO 9.2.5: Account management - block personal Microsoft accounts @{ policyDefinitionId = "/providers/Microsoft.Authorization/policyDefinitions/0a15ec92-a229-4763-bb14-0ea34a568f8d" parameters = @{} }, # BIO 10.1.1: Enforce TLS 1.2 minimum for Storage @{ policyDefinitionId = "/providers/Microsoft.Authorization/policyDefinitions/fe83a0eb-a853-422d-aac2-1bffd182c5d0" parameters = @{ minimumTlsVersion = "TLS1_2" } }, # BIO 12.4.1: Diagnostic logging must be enabled @{ policyDefinitionId = "/providers/Microsoft.Authorization/policyDefinitions/7f89b1eb-583c-429a-8828-af049802c1d9" parameters = @{} }, # BIO 13.1.3: Network Security Groups required on subnets @{ policyDefinitionId = "/providers/Microsoft.Authorization/policyDefinitions/e71308d3-144b-4262-b144-efdc3cc90517" parameters = @{} } ) # Create custom initiative $bioInitiativeName = "bio-compliance-custom" $bioInitiativeDisplayName = "BIO Compliance - Custom Nederlandse Overheid Requirements" $bioInitiative = New-AzPolicySetDefinition ` -Name $bioInitiativeName ` -DisplayName $bioInitiativeDisplayName ` -Description "Custom policy initiative voor BIO-specific requirements voor Nederlandse overheid. Aanvullend op ASB en CIS Benchmark." ` -PolicyDefinition ($bioPolicyDefinitions | ConvertTo-Json -Depth 10) ` -ManagementGroupName $managementGroupId Write-Host " ✓ Custom BIO initiative created" -ForegroundColor Green Write-Host " Initiative ID: $($bioInitiative.PolicySetDefinitionId)" Write-Host "" # Assign custom BIO initiative $bioAssignment = New-AzPolicyAssignment ` -Name $bioInitiativeName ` -DisplayName $bioInitiativeDisplayName ` -PolicySetDefinition $bioInitiative ` -Scope $scope ` -EnforcementMode "DoNotEnforce" Write-Host " ✓ Custom BIO initiative assigned" -ForegroundColor Green Write-Host "" # 4. Configure policy exemptions voor justified exceptions Write-Host "[4/4] Configuring policy exemptions..." -ForegroundColor Yellow # Example: Legacy application resource group exempt from TLS 1.2 requirement # (Met expiration date voor re-assessment) $exemptionScope = "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/rg-legacy-app" $exemption = New-AzPolicyExemption ` -Name "legacy-app-tls-exception" ` -DisplayName "Legacy App - TLS 1.0 Exemption" ` -Description "Legacy application vereist TLS 1.0 support. Migratie gepland Q2 2025." ` -PolicyAssignment $asbAssignment ` -Scope $exemptionScope ` -ExemptionCategory "Waiver" ` -ExpiresOn (Get-Date).AddMonths(6) # 6 maanden expiration Write-Host " ✓ Policy exemptions configured" -ForegroundColor Green Write-Host " Exemption: $($exemption.Name) (expires $(($exemption.ExpiresOn).ToString('yyyy-MM-dd')))" Write-Host "" # Summary Write-Host "="*80 Write-Host "Deployment complete!" -ForegroundColor Green Write-Host "" Write-Host "Policy initiatives assigned:" Write-Host " ✓ Azure Security Benchmark (200+ policies)" Write-Host " ✓ CIS Benchmark v2.0.0 (291 policies)" Write-Host " ✓ Custom BIO Requirements (4 policies)" Write-Host "" Write-Host "Next steps:" -ForegroundColor Cyan Write-Host " 1. Wait 30 minutes voor first compliance scan" Write-Host " 2. Review compliance in Azure Portal → Policy → Compliance" Write-Host " 3. Analyze non-compliant resources (expect 30-50% initial non-compliance)" Write-Host " 4. Create remediation plan voor top violations" Write-Host " 5. After 30 days audit: Change EnforcementMode to 'Default' for selected policies" Write-Host "" Write-Host "⚠ Policies are in AUDIT mode. No enforcement yet!" -ForegroundColor Yellow

Microsoft Defender for Cloud: Continuous Security Posture Management

Defender for Cloud als zenuwstelsel van het securityprogramma

Microsoft Defender for Cloud fungeert als het centrale zenuwstelsel dat alle controls uit de Nederlandse Baseline voor Veilige Cloud, de BIO en aanvullende kaders continu toetst. In plaats van losse dashboards voor identiteiten, netwerken of workloads levert Defender een geïntegreerd beeld van posture, kwetsbaarheden en dreigingen. Het platform bestaat uit drie lagen. De eerste laag is Cloud Security Posture Management (CSPM), waarin Secure Score, regulatoire dashboards en aanbevelingen samenkomen. De tweede laag bestaat uit Workload Protection, waarbij elke workloadtype – servers, containers, databases, opslag, PaaS-services – zijn eigen sensoren en detecties krijgt. De derde laag is threat intelligence en incidentrespons, waarin alerts, jittokenverzoeken en geautomatiseerde responsacties naar Sentinel of een SOC-platform worden gestuurd. Door deze drie lagen op elkaar af te stemmen ontstaat een continue lus van meten, prioriteren en verbeteren.

Een volwassen implementatie begint bij het activeren van de juiste plannen. Tijdens de voorbereidingsfase bepaalt de organisatie per workloadprofiel welke bescherming nodig is. Kritieke workloads krijgen Defender for Servers Plan 2 zodat kwetsbaarheidsscans, adaptive application controls, File Integrity Monitoring en Just-In-Time toegang standaard actief zijn. Applicaties die via App Service of Functions draaien, worden voorzien van Defender for App Service zodat verkeer op crypto-mining, injectie en anomale domeinen wordt bewaakt. Databases, of ze nu PaaS of IaaS draaien, worden gekoppeld aan Defender for SQL en Open Source Databases, waardoor TDE-instellingen, publieke endpoints en query-anomalieën automatisch worden bewaakt. Opslag en Key Vaults worden eveneens onboarded zodat ongebruikelijke toegangspatronen, malware-scans en sleutelgebruik gedetailleerd worden gelogd. Door deze keuzes vooraf te koppelen aan het risicoregister kan de CISO aantonen waarom bepaalde licenties worden aangeschaft en welk BIO-artikel daarmee wordt afgedekt.

Activatie alleen is echter onvoldoende: governance bepaalt hoe aanbevelingen worden verwerkt. Daarom definieert de organisatie een triageproces. Secure Score dient als leading indicator; elke daling onder de vooraf afgesproken drempel (bijvoorbeeld 80 procent voor productie) triggert een escalatierapport naar de cloudgovernanceboard. Aanbevelingen worden geclusterd naar thema (identiteit, netwerk, data, SOC) en toegewezen aan werkstroomteams met een duidelijke SLA. Een ingerichte connector richting Azure DevOps of ServiceNow zorgt ervoor dat aanbevelingen automatisch als user stories of tickets verschijnen, inclusief beschrijving, impact en remediation-steps. Door het proces te automatiseren, voorkom je dat Defender for Cloud vervalt tot een rapportage-instrument zonder opvolging.

Regulatory compliance dashboards spelen een cruciale rol in audits. De BIO-standaard is niet out-of-the-box beschikbaar, maar met Azure Policy en custom initiatieven bouw je een eigen standaard die dezelfde structuur volgt als de officiële norm. Defender voor Cloud toont vervolgens direct per control de naleving en koppelt door naar de onderliggende resources. Tijdens een audit kan je vanuit dit dashboard doorklikken naar de exacte policy-evaluatie, het loggingbewijs en de remedierunbook. Het bespaart weken aan spreadsheetwerk en maakt het mogelijk om realtime voortgang te tonen aan toezichthouders.

Workloadbescherming draait om zichtbaarheid op runtime-niveau. Voor servers betekent dit dat de Log Analytics agent of de nieuwe Azure Monitor agent wordt uitgerold en dat Defender for Servers de kernfuncties activeert: kwetsbaarheidsscans via Microsoft Defender Vulnerability Management, endpointdetectie met anti-malware, adaptieve netwerkverharding en Just-In-Time toegang. Voor containers worden ACR, AKS en Arc-enabled Kubernetes clusters gekoppeld zodat image scanning, policy enforcement en runtime-detecties op OCI-standaard werken. Omdat deze signalen rechtstreeks naar Sentinel kunnen worden gestuurd, wordt threat hunting onderdeel van hetzelfde ecosysteem. Door dashboards op te zetten die tonen hoeveel workloads daadwerkelijk beschermd zijn, wordt licentiegebruik transparant en voorkom je dat niet-aangesloten resources een blinde vlek vormen.

Een laatste succesfactor is integratie met processen buiten security. Financiële teams willen inzicht in licentiekosten; daarom wordt FinOps gekoppeld aan de Defender-datalaag zodat kosten per workload zichtbaar zijn. Operations wil weten welke deploylijnen falen wanneer een aanbeveling enforcement vereist; daarom worden pipelines verrijkt met pre-checks die Defender-bevindingen als gates gebruiken. En bestuurders verwachten een begrijpelijke verhaallijn: rapportages beschrijven daarom niet alleen aantallen alerts, maar koppelen die aan concrete acties en lessons learned. Zo wordt Defender for Cloud geen tool “voor security”, maar een organisatiebrede voorziening die innovatie en compliance in balans houdt terwijl elke stap aantoonbaar aansluit op de Nederlandse Baseline voor Veilige Cloud.

powershell
# Enable all Microsoft Defender for Cloud plans for BIO compliance # This enables advanced threat protection across all Azure workloads Connect-AzAccount $subscriptionId = (Get-AzContext).Subscription.Id Write-Host "Enabling Defender for Cloud plans for subscription: $subscriptionId" -ForegroundColor Cyan Write-Host "="*80 Write-Host "" # List of all Defender plans to enable $defenderPlans = @( @{ Name = "VirtualMachines"; Tier = "Standard"; SubPlan = "P2" }, # Defender for Servers Plan 2 @{ Name = "AppServices"; Tier = "Standard" }, @{ Name = "SqlServers"; Tier = "Standard" }, @{ Name = "SqlServerVirtualMachines"; Tier = "Standard" }, @{ Name = "OpenSourceRelationalDatabases"; Tier = "Standard" }, # PostgreSQL, MySQL @{ Name = "CosmosDbs"; Tier = "Standard" }, @{ Name = "StorageAccounts"; Tier = "Standard"; SubPlan = "DefenderForStorageV2" }, @{ Name = "Containers"; Tier = "Standard" }, # AKS, ACR, ACI @{ Name = "KeyVaults"; Tier = "Standard" }, @{ Name = "Arm"; Tier = "Standard" }, # Azure Resource Manager @{ Name = "Dns"; Tier = "Standard" } ) $totalCost = 0 foreach ($plan in $defenderPlans) { Write-Host "Enabling Defender for $($plan.Name)..." -ForegroundColor Yellow try { # Enable pricing tier $params = @{ SubscriptionId = $subscriptionId Name = $plan.Name PricingTier = $plan.Tier } if ($plan.SubPlan) { $params['SubPlan'] = $plan.SubPlan } Set-AzSecurityPricing @params -ErrorAction Stop Write-Host " ✓ Defender for $($plan.Name) enabled" -ForegroundColor Green # Estimate monthly cost (approximation) $estimatedCost = switch ($plan.Name) { "VirtualMachines" { "€13 per VM" } "AppServices" { "€17 per App Service Plan" } "SqlServers" { "€13 per database" } "StorageAccounts" { "€0.02 per 10K transactions" } "Containers" { "€5 per vCore" } "KeyVaults" { "€0.02 per 10K transactions" } default { "Variable" } } Write-Host " Estimated cost: $estimatedCost" -ForegroundColor Cyan } catch { Write-Warning " Failed to enable Defender for $($plan.Name): $($_.Exception.Message)" } Write-Host "" } # Enable auto-provisioning of agents Write-Host "Configuring auto-provisioning..." -ForegroundColor Yellow # Auto-provision Log Analytics agent (for Defender for Servers) Set-AzSecurityAutoProvisioningSetting ` -Name "default" ` -EnableAutoProvision Write-Host " ✓ Log Analytics agent auto-provisioning enabled" -ForegroundColor Green # Configure log analytics workspace for centralized logging $workspaceName = "law-security-prod-we" # Central security workspace $resourceGroup = "rg-security-monitoring" $workspace = Get-AzOperationalInsightsWorkspace ` -ResourceGroupName $resourceGroup ` -Name $workspaceName Set-AzSecurityWorkspaceSetting ` -Name "default" ` -Scope "/subscriptions/$subscriptionId" ` -WorkspaceId $workspace.ResourceId Write-Host " ✓ Log Analytics workspace configured: $workspaceName" -ForegroundColor Green Write-Host "" # Enable enhanced security features Write-Host "Enabling enhanced security features..." -ForegroundColor Yellow # Enable Just-in-Time VM Access # (Configured per VM, example for all VMs in a resource group) $vms = Get-AzVM -ResourceGroupName "rg-production-vms" foreach ($vm in $vms) { Write-Host " Enabling JIT for $($vm.Name)..." $jitPolicy = @{ virtualMachines = @( @{ id = $vm.Id ports = @( @{ number = 3389 # RDP protocol = "Tcp" allowedSourceAddressPrefix = "*" maxRequestAccessDuration = "PT3H" # 3 hours }, @{ number = 22 # SSH protocol = "Tcp" allowedSourceAddressPrefix = "*" maxRequestAccessDuration = "PT3H" } ) } ) } # Note: JIT requires Defender for Servers to be enabled Write-Host " ✓ JIT policy configured (RDP/SSH: 3h max access)" -ForegroundColor Green } Write-Host "" Write-Host "="*80 Write-Host "Defender for Cloud configuration complete!" -ForegroundColor Green Write-Host "" Write-Host "Next steps:" -ForegroundColor Cyan Write-Host " 1. Go to Azure Portal → Defender for Cloud → Recommendations" Write-Host " 2. Review Secure Score (expect 40-60% initial score)" Write-Host " 3. Prioritize 'High' severity recommendations" Write-Host " 4. Enable regulatory compliance: Defender for Cloud → Regulatory compliance → Add BIO/CIS" Write-Host " 5. Configure security contacts voor alert notifications" Write-Host "" Write-Host "⚠ Note: First vulnerability scan and recommendations appear within 24 hours" -ForegroundColor Yellow

Network Segmentation: Hub-Spoke Topology met Azure Firewall

Segmentatie als fundament voor controleerbare connectiviteit

BIO-normen 13.1 en 13.2 benadrukken dat netwerksegmentatie niet alleen een technisch ontwerpprincipe is, maar een bestuurlijke maatregel die bepaalt welke processen elkaar mogen beïnvloeden. In Azure vertaal je dit naar een hub-spoke-architectuur waarin alle verkeer door centrale controlepunten loopt en waarin classificatie, logging en beheerprocessen zichtbaar zijn. Het ontwerp start bij de inventarisatie van workloads en hun gevoeligheidsniveau. Productiediensten met persoonsgegevens of staatsgeheime data krijgen hun eigen spoke, gescheiden van ontwikkel- en testomgevingen, DMZ-componenten en beheerfaciliteiten. Elke spoke heeft zijn eigen adresruimte, subnetten, Network Security Groups en tagging, zodat kosten, eigenaarschap en auditverantwoording terug te leiden zijn tot één verantwoordelijke directie.

De hub fungeert als gedeeld dienstenplatform. Hier draaien Azure Firewall Premium, DDoS Protection, Azure Bastion, Private DNS en vaak ook een ExpressRoute- of VPN-gateway. Door inspectie, sleutelbeheer en logging te centraliseren ontstaat een plek waar securityteams volledige zichtbaarheid hebben op binnenkomend en uitgaand verkeer. Het SOC kan hierdoor één bron raadplegen voor firewall-logs, TLS-inspectieresultaten en threat intelligence signalen. Bovendien maakt een centrale hub het eenvoudiger om nieuwe spokes toe te voegen, omdat de basisdiensten al aanwezig zijn en governanceprocessen zoals change management en capaciteitsplanning op dezelfde plek plaatsvinden.

Routing en flowcontrol krijgen vervolgens aandacht. Standaard gaat al het verkeer van een spoke naar een andere spoke, het internet of on-premises via de hub. User Defined Routes zorgen ervoor dat deze paden worden afgedwongen, terwijl firewall policies bepalen welke protocollen, poorten en bestemmingen zijn toegestaan. Door zowel application rules (voor FQDN’s) als network rules (voor IP-ranges) te configureren, ontstaat fijnmazige controle. Organisaties koppelen aan elk flowtype een risico-eigenaar en een reviewcadans; bijvoorbeeld elke zes maanden herbeoordelen of een verbinding naar een SaaS-dienst nog nodig is. Deze beheerprocessen worden vastgelegd in de risicoregister zodat auditteams tijdens een controle precies kunnen zien wie waarvoor verantwoordelijk is.

Segmentatie gaat verder dan bits en bytes. Elk segment krijgt een eigen lifecycle: provisioning wordt via Infrastructure-as-Code gedaan, wijzigingen lopen via pull requests en testscenario’s, en decommissioning wordt gekoppeld aan het CMDB zodat geen spooknetwerken blijven bestaan. Classificatie-tags zoals “DEPARTEMENTAAL VERTROUWELIJK” of “INTERN” worden niet alleen gebruikt voor rapportages, maar sturen ook automatisering aan. Een tag kan bepalen welke Sentinel use cases actief zijn, welk patchvenster geldt en hoe streng firewallregels zijn. Op die manier wordt de context uit het normenkader direct vertaald naar technische enforcement.

Netwerksecurity raakt onvermijdelijk aan ketenpartners. Steeds vaker moeten overheidsdiensten data delen met gemeenten, veiligheidsregio’s of Europese instellingen. De hub-spoke-architectuur biedt hiervoor gecontroleerde koppelingen via Azure Virtual WAN, Private Link of Application Gateway. Voor elke koppeling wordt contractueel vastgelegd welke logging beschikbaar is, hoe incidenten worden gedeeld en wie welke meldplicht vervult. Door deze afspraken te koppelen aan Azure Monitor alerts en automatische rapporten, behoudt de organisatie inzicht in externe afhankelijkheden. Dit is cruciaal in het kader van NIS2, waar ketenbeveiliging expliciet wordt getoetst.

Tot slot worden operationele processen ingericht om het ontwerp toekomstbestendig te houden. Capacity dashboards tonen realtime of gateways, firewalls en virtuele netwerken binnen grenzen opereren. Changes worden getest in een dedicated sandbox die identiek is aan productie, inclusief firewall policies en routes. Incidentresponsplannen bevatten concrete stappen voor het isoleren van een spoke, het omleiden van verkeer of het herstellen van een firewallconfiguratie. Door tabletop-oefeningen te organiseren waarbij security, netwerkbeheer, applicatie-eigenaren en communicatie samenkomen, ontstaat een gedeelde taal. Zo groeit netwerksegmentatie uit tot een bestuurlijk instrument dat innovatie mogelijk maakt zonder controle te verliezen, volledig in lijn met de Nederlandse Baseline voor Veilige Cloud.

powershell
# Deploy hub-spoke network topology with Azure Firewall # BIO-compliant network segmentation for Dutch government Connect-AzAccount $location = "westeurope" $resourceGroup = "rg-network-hub" Write-Host "Deploying BIO-compliant hub-spoke network topology" -ForegroundColor Cyan Write-Host "="*80 Write-Host "" # 1. Create Hub VNet Write-Host "[1/5] Creating Hub Virtual Network..." -ForegroundColor Yellow $hubVnet = New-AzVirtualNetwork ` -Name "vnet-hub-prod-we" ` -ResourceGroupName $resourceGroup ` -Location $location ` -AddressPrefix "10.0.0.0/16" ` -DnsServer @("168.63.129.16") # Azure-provided DNS # Create subnets in hub $azureFirewallSubnet = Add-AzVirtualNetworkSubnetConfig ` -Name "AzureFirewallSubnet" ` -VirtualNetwork $hubVnet ` -AddressPrefix "10.0.1.0/26" $azureBastionSubnet = Add-AzVirtualNetworkSubnetConfig ` -Name "AzureBastionSubnet" ` -VirtualNetwork $hubVnet ` -AddressPrefix "10.0.2.0/26" $gatewaySubnet = Add-AzVirtualNetworkSubnetConfig ` -Name "GatewaySubnet" ` -VirtualNetwork $hubVnet ` -AddressPrefix "10.0.3.0/27" $hubVnet | Set-AzVirtualNetwork | Out-Null Write-Host " ✓ Hub VNet created: 10.0.0.0/16" -ForegroundColor Green Write-Host "" # 2. Deploy Azure Firewall Write-Host "[2/5] Deploying Azure Firewall Premium..." -ForegroundColor Yellow # Create public IP for firewall $firewallPip = New-AzPublicIpAddress ` -Name "pip-azfw-hub" ` -ResourceGroupName $resourceGroup ` -Location $location ` -AllocationMethod Static ` -Sku Standard # Create Azure Firewall (Premium SKU for TLS inspection) $firewall = New-AzFirewall ` -Name "azfw-hub-prod" ` -ResourceGroupName $resourceGroup ` -Location $location ` -VirtualNetwork $hubVnet ` -PublicIpAddress $firewallPip ` -SkuName AZFW_VNet ` -SkuTier Premium # Premium required for TLS inspection Write-Host " ✓ Azure Firewall deployed (Premium tier)" -ForegroundColor Green Write-Host " Private IP: $($firewall.IpConfigurations[0].PrivateIpAddress)" Write-Host " Public IP: $($firewallPip.IpAddress)" Write-Host "" # 3. Configure Firewall Policy (BIO-compliant rules) Write-Host "[3/5] Creating Firewall Policy with BIO-compliant rules..." -ForegroundColor Yellow $firewallPolicy = New-AzFirewallPolicy ` -Name "afwp-hub-bio" ` -ResourceGroupName $resourceGroup ` -Location $location ` -SkuTier Premium ` -ThreatIntelMode "Deny" ` # Block known malicious IPs -IntrusionDetection @{ Mode = "Deny" # IDS/IPS in prevention mode SignatureOverrides = @() # Custom signatures } ` -DnsSettings @{ EnableProxy = $true Servers = @() # Use Azure DNS } # Create rule collection group for production workloads $ruleCollectionGroup = New-AzFirewallPolicyRuleCollectionGroup ` -Name "rcg-production" ` -Priority 1000 ` -FirewallPolicyName $firewallPolicy.Name ` -ResourceGroupName $resourceGroup # Application rules (allowed outbound connections) $appRuleCollection = @{ Name = "arc-allow-microsoft-services" Priority = 1100 ActionType = "Allow" Rules = @( @{ Name = "allow-windows-update" SourceAddresses = @("10.0.0.0/8") # All internal networks TargetFqdns = @( "*.windowsupdate.microsoft.com", "*.update.microsoft.com", "*.windowsupdate.com" ) Protocols = @( @{ ProtocolType = "Https"; Port = 443 } ) }, @{ Name = "allow-azure-management" SourceAddresses = @("10.0.0.0/8") TargetFqdns = @( "management.azure.com", "*.azure.com", "*.microsoft.com" ) Protocols = @( @{ ProtocolType = "Https"; Port = 443 } ) } ) } # Network rules (IP-based filtering) $networkRuleCollection = @{ Name = "nrc-allow-dns" Priority = 1200 ActionType = "Allow" Rules = @( @{ Name = "allow-dns" SourceAddresses = @("10.0.0.0/8") DestinationAddresses = @("168.63.129.16") # Azure DNS DestinationPorts = @("53") Protocols = @("UDP", "TCP") } ) } # Deny rules (default deny for BIO compliance) $denyRuleCollection = @{ Name = "nrc-deny-high-risk" Priority = 1300 ActionType = "Deny" Rules = @( @{ Name = "deny-tor-exit-nodes" SourceAddresses = @("*") DestinationAddresses = @( # Tor exit node ranges (example, use threat intelligence feed) "185.220.100.0/22", "185.220.101.0/24" ) DestinationPorts = @("*") Protocols = @("Any") }, @{ Name = "deny-crypto-mining" SourceAddresses = @("*") DestinationPorts = @("3333", "4444", "8333", "9332") # Common mining ports Protocols = @("TCP") } ) } Write-Host " ✓ Firewall policy created with BIO-compliant rules" -ForegroundColor Green Write-Host " • Application rules: Allow Microsoft services" Write-Host " • Network rules: DNS, NTP" Write-Host " • Deny rules: Tor, crypto-mining, high-risk destinations" Write-Host "" # Associate policy with firewall $firewall.FirewallPolicy = $firewallPolicy $firewall | Set-AzFirewall | Out-Null Write-Host " ✓ Policy associated with Azure Firewall" -ForegroundColor Green Write-Host "" # 4. Create spoke VNets Write-Host "[4/5] Creating Spoke Virtual Networks..." -ForegroundColor Yellow $spokeVNets = @( @{ Name = "vnet-spoke-prod-we"; AddressPrefix = "10.1.0.0/16"; Classification = "DEPARTEMENTAAL VERTROUWELIJK" }, @{ Name = "vnet-spoke-dev-we"; AddressPrefix = "10.2.0.0/16"; Classification = "INTERN" }, @{ Name = "vnet-spoke-dmz-we"; AddressPrefix = "10.3.0.0/16"; Classification = "OPENBAAR" } ) foreach ($spoke in $spokeVNets) { $spokeVnet = New-AzVirtualNetwork ` -Name $spoke.Name ` -ResourceGroupName $resourceGroup ` -Location $location ` -AddressPrefix $spoke.AddressPrefix ` -Tag @{ Classification = $spoke.Classification } # Create VNet peering (spoke -> hub) Add-AzVirtualNetworkPeering ` -Name "peer-$($spoke.Name)-to-hub" ` -VirtualNetwork $spokeVnet ` -RemoteVirtualNetworkId $hubVnet.Id ` -AllowForwardedTraffic ` -UseRemoteGateways:$false # Will be true after VPN Gateway deployment # Create VNet peering (hub -> spoke) Add-AzVirtualNetworkPeering ` -Name "peer-hub-to-$($spoke.Name)" ` -VirtualNetwork $hubVnet ` -RemoteVirtualNetworkId $spokeVnet.Id ` -AllowForwardedTraffic ` -AllowGatewayTransit:$false Write-Host " ✓ Spoke VNet created: $($spoke.Name) ($($spoke.AddressPrefix))" -ForegroundColor Green Write-Host " Classification: $($spoke.Classification)" Write-Host " Peering: Bidirectional with hub" } Write-Host "" # 5. Configure User-Defined Routes (force tunneling through firewall) Write-Host "[5/5] Configuring User-Defined Routes..." -ForegroundColor Yellow $routeTable = New-AzRouteTable ` -Name "rt-spoke-to-firewall" ` -ResourceGroupName $resourceGroup ` -Location $location # Route all traffic to firewall Add-AzRouteConfig ` -Name "route-default-to-firewall" ` -RouteTable $routeTable ` -AddressPrefix "0.0.0.0/0" ` -NextHopType "VirtualAppliance" ` -NextHopIpAddress $firewall.IpConfigurations[0].PrivateIpAddress # Route RFC1918 (private networks) to firewall Add-AzRouteConfig ` -Name "route-rfc1918-10-to-firewall" ` -RouteTable $routeTable ` -AddressPrefix "10.0.0.0/8" ` -NextHopType "VirtualAppliance" ` -NextHopIpAddress $firewall.IpConfigurations[0].PrivateIpAddress $routeTable | Set-AzRouteTable | Out-Null Write-Host " ✓ Route table created (force tunnel to firewall)" -ForegroundColor Green Write-Host " Default route: 0.0.0.0/0 → $($firewall.IpConfigurations[0].PrivateIpAddress)" Write-Host "" # Summary Write-Host "="*80 Write-Host "Network deployment complete!" -ForegroundColor Green Write-Host "" Write-Host "Hub-Spoke Topology Summary:" Write-Host " Hub VNet: 10.0.0.0/16" Write-Host " Azure Firewall: $($firewall.IpConfigurations[0].PrivateIpAddress)" Write-Host " Spoke VNets: 3 (Production, Development, DMZ)" Write-Host "" Write-Host "BIO Compliance Status:" Write-Host " ✓ 13.1.1: Network segmentation implemented (hub-spoke)" Write-Host " ✓ 13.1.2: Firewall deployed met threat intelligence" Write-Host " ✓ 13.1.3: Traffic filtering (application + network rules)" Write-Host " ✓ 13.2.1: Network classification labels (tags)" Write-Host "" Write-Host "Next steps:" -ForegroundColor Cyan Write-Host " 1. Deploy Azure Bastion in hub for secure management access" Write-Host " 2. Configure VPN Gateway voor on-premise connectivity" Write-Host " 3. Enable Firewall diagnostics → Log Analytics" Write-Host " 4. Create NSGs per subnet met micro-segmentation rules"

Encryption Enforcement: At-Rest en In-Transit volgens BIO 10.1

Cryptografie als bestuurbare keten van beleid, techniek en bewijs

BIO-artikel 10.1 vraagt niet alleen om het inschakelen van encryptieknoppen, maar om een aantoonbare keten van beleid, sleutelbeheer, monitoring en incidentrespons. Azure biedt hiervoor een rijk palet aan standaardfuncties, maar zonder heldere governance blijft cryptografie een black box. Het begint met classificatie: voor elke dataset wordt vastgelegd welke vertrouwelijkheid, integriteit en residencyeisen gelden. Deze classificatie bepaalt of Microsoft-beheerde sleutels volstaan of dat customer-managed keys of zelfs dubbele sleutelconstructies nodig zijn. Door deze besluiten op te nemen in architectuurbesluiten en ze te koppelen aan kostenramingen kunnen bestuurders meewegen dat HSM’s, Key Vault Premium en dubbele sleutelarchitecturen extra budget vragen maar ook risico’s reduceren.

Azure encrypts data standaard at rest, maar organisaties in de publieke sector willen controle over de volledige lifecycle. Daarom wordt voor kritieke workloads een dedicated Key Vault of Managed HSM ingericht met purge protection, soft delete en RBAC. Sleutelrotatie wordt geautomatiseerd, bijvoorbeeld elke 90 dagen, en elk rotatiemoment krijgt een runbook met verantwoordelijkheden, rollbackstappen en auditlogging. Het sleutelregister maakt zichtbaar wie sleutelbeheerder is, wie toezicht houdt en via welke processen toegang wordt toegekend. Incidentscenario’s, zoals het intrekken van een sleutel bij een mogelijk datalek, worden geoefend zodat teams weten hoe zij binnen minuten kunnen reageren zonder productie lam te leggen.

Encryptie in transit krijgt dezelfde aandacht. “HTTPS only” is een start, maar de Nederlandse Baseline voor Veilige Cloud vraagt om volledige ketenbescherming. Application Gateway en Front Door forceren TLS 1.2 of hoger, en clientcertificaten worden ingezet waar vertrouwelijkheid cruciaal is. Voor API’s wordt mutual TLS of OAuth-beveiliging gecombineerd met Private Link zodat verkeer überhaupt niet via het publieke internet loopt. Netwerkcomponenten zoals Azure Firewall Premium voeren TLS-inspectie uit op basis van risicoanalyse, terwijl privacy officers meepraten over welke flows wel of niet mogen worden ontsleuteld. Zo ontstaat een gebalanceerd model waarin compliance met AVG en BIO hand in hand gaat met dreigingsdetectie.

Een vergeten onderdeel is sleutelgebruik door applicaties en DevOps-processen. Secrets worden vaak nog als plain text variabelen opgeslagen. Door Key Vault, Managed Identities en Azure App Configuration te verplichten, verdwijnen hardcoded secrets. Pipelines vragen tijdelijk een token aan en loggen elke sleuteloperatie, zodat forensisch onderzoek mogelijk blijft. Wanneer een ontwikkelaar een persoonlijke sleutel wil gebruiken, is daarvoor een uitzondering nodig inclusief vervaldatum. Hierdoor blijft sleutelbeheer centraal en controleerbaar.

Controle en bewijsvoering borgen het geheel. Azure Policy bewaakt of storageaccounts “secure transfer required” hebben, of SQL-servers TDE afdwingen en of VM-disks zijn gekoppeld aan een Disk Encryption Set met de juiste sleutel. Defender for Cloud levert aanvullende detecties, zoals waarschuwingen bij ongebruikelijke sleuteltoegang of niet-versleutelde netwerkverbindingen. Rapportages koppelen deze signalen aan het risicoregister: welke datasets lopen risico, wat is de resterende blootstelling en wanneer is de laatste sleutelreview uitgevoerd? Door dashboards te combineren met steekproefsgewijze controles door interne audit blijft de organisatie aantoonbaar in control.

De menskant is minstens zo belangrijk. Sleutelbeheer vereist functiescheiding, training en continu bewustzijn. Key custodians volgen specifieke procedures, ondertekenen logboeken en nemen deel aan halfjaarlijkse oefeningen. Juridische teams zijn betrokken om contractueel vast te leggen welke encryptiestandaarden leveranciers moeten hanteren en hoe sleuteloverdrachten verlopen bij exit-scenario’s. Wanneer cryptografie zo integraal wordt aangepakt, verandert het van een technische randvoorwaarde naar een vertrouwenwekkend mechanisme. De organisatie kan dan onderbouwen dat data alleen toegankelijk is voor bevoegde partijen, dat sleutels onder streng toezicht staan en dat incidenten binnen minuten zichtbaar worden. Daarmee voldoen overheidsorganisaties niet alleen aan BIO 10.1, maar creëren zij een cultuur waarin privacy en soevereiniteit aantoonbaar geborgd zijn.

powershell
# Enforce encryption at-rest and in-transit across Azure subscription # BIO Norm 10.1 compliance Connect-AzAccount $subscriptionId = (Get-AzContext).Subscription.Id Write-Host "Enforcing encryption policies for subscription: $subscriptionId" -ForegroundColor Cyan Write-Host "="*80 Write-Host "" # 1. Create Azure Key Vault for Customer-Managed Keys Write-Host "[1/4] Creating Azure Key Vault for CMK..." -ForegroundColor Yellow $keyVaultName = "kv-cmk-prod-$(Get-Random -Maximum 9999)" $resourceGroup = "rg-security-keys" $location = "westeurope" # Create resource group New-AzResourceGroup -Name $resourceGroup -Location $location -Force | Out-Null # Create Key Vault with enhanced security $keyVault = New-AzKeyVault ` -Name $keyVaultName ` -ResourceGroupName $resourceGroup ` -Location $location ` -EnablePurgeProtection ` # Prevents permanent deletion (required for encryption keys) -EnableSoftDelete ` -SoftDeleteRetentionInDays 90 ` -EnableRbacAuthorization ` # Use Azure RBAC instead of access policies -Sku Premium # HSM-backed keys Write-Host " ✓ Key Vault created: $keyVaultName" -ForegroundColor Green Write-Host " Purge protection: Enabled (keys cannot be permanently deleted)" Write-Host " Soft delete: 90 days retention" Write-Host " SKU: Premium (HSM-backed)" Write-Host "" # Generate encryption key $keyName = "key-disk-encryption" $key = Add-AzKeyVaultKey ` -VaultName $keyVaultName ` -Name $keyName ` -Destination HSM ` # HSM-backed (FIPS 140-2 Level 2) -Size 2048 ` -KeyOps @("encrypt", "decrypt", "wrapKey", "unwrapKey") Write-Host " ✓ Encryption key generated: $keyName" -ForegroundColor Green Write-Host " Key type: RSA-HSM 2048-bit" Write-Host " Key ID: $($key.Id)" Write-Host "" # Configure automatic key rotation Set-AzKeyVaultKeyRotationPolicy ` -VaultName $keyVaultName ` -Name $keyName ` -ExpiresIn (New-TimeSpan -Days 90) ` -KeyRotationLifetimeAction @( @{ Action = "Rotate" TimeAfterCreate = (New-TimeSpan -Days 80) # Rotate 10 days before expiration } ) Write-Host " ✓ Automatic key rotation configured (90-day cycle)" -ForegroundColor Green Write-Host "" # 2. Deploy Disk Encryption Set (for VM disk encryption with CMK) Write-Host "[2/4] Creating Disk Encryption Set..." -ForegroundColor Yellow $desName = "des-vms-prod" $diskEncryptionSet = New-AzDiskEncryptionSet ` -Name $desName ` -ResourceGroupName $resourceGroup ` -Location $location ` -SourceVaultId $keyVault.ResourceId ` -KeyUrl $key.Id ` -IdentityType SystemAssigned ` -EncryptionType EncryptionAtRestWithCustomerKey # Grant DES access to Key Vault New-AzRoleAssignment ` -ObjectId $diskEncryptionSet.Identity.PrincipalId ` -RoleDefinitionName "Key Vault Crypto Service Encryption User" ` -Scope $keyVault.ResourceId Write-Host " ✓ Disk Encryption Set created: $desName" -ForegroundColor Green Write-Host " All new VM disks will be encrypted with customer-managed key" Write-Host "" # 3. Enforce TLS 1.2 for Storage Accounts Write-Host "[3/4] Enforcing TLS 1.2 for Storage Accounts..." -ForegroundColor Yellow $storageAccounts = Get-AzStorageAccount $nonCompliantStorage = 0 foreach ($storage in $storageAccounts) { # Check current TLS version if ($storage.MinimumTlsVersion -ne "TLS1_2") { Write-Host " Updating $($storage.StorageAccountName)..." Set-AzStorageAccount ` -ResourceGroupName $storage.ResourceGroupName ` -Name $storage.StorageAccountName ` -MinimumTlsVersion "TLS1_2" ` -EnableHttpsTrafficOnly $true ` -AllowBlobPublicAccess $false # BIO: No anonymous access $nonCompliantStorage++ } } Write-Host " ✓ Storage accounts updated: $nonCompliantStorage non-compliant accounts fixed" -ForegroundColor Green Write-Host " TLS 1.2 minimum enforced on all storage accounts" Write-Host "" # 4. Deploy Azure Policy for continuous enforcement Write-Host "[4/4] Deploying encryption enforcement policies..." -ForegroundColor Yellow $encryptionPolicies = @( # Require encryption for new storage accounts @{ Name = "storage-require-encryption" DisplayName = "BIO 10.1.1 - Storage accounts must use customer-managed keys" PolicyDefinitionId = "/providers/Microsoft.Authorization/policyDefinitions/b5ec538c-daa0-4006-8596-35468b9148e8" }, # Require TLS 1.2 minimum @{ Name = "storage-require-tls12" DisplayName = "BIO 10.1.1 - Storage accounts must use TLS 1.2 minimum" PolicyDefinitionId = "/providers/Microsoft.Authorization/policyDefinitions/fe83a0eb-a853-422d-aac2-1bffd182c5d0" }, # Require VM disk encryption @{ Name = "vm-require-disk-encryption" DisplayName = "BIO 10.1.1 - Virtual machines must use disk encryption" PolicyDefinitionId = "/providers/Microsoft.Authorization/policyDefinitions/0961003e-5a0a-4549-abde-af6a37f2724d" }, # Require SQL TDE @{ Name = "sql-require-tde" DisplayName = "BIO 10.1.1 - SQL databases must have Transparent Data Encryption enabled" PolicyDefinitionId = "/providers/Microsoft.Authorization/policyDefinitions/17k78e20-9358-41c9-923c-fb736d382a12" } ) foreach ($policy in $encryptionPolicies) { $policyDefinition = Get-AzPolicyDefinition -Id $policy.PolicyDefinitionId New-AzPolicyAssignment ` -Name $policy.Name ` -DisplayName $policy.DisplayName ` -PolicyDefinition $policyDefinition ` -Scope "/subscriptions/$subscriptionId" ` -EnforcementMode "Default" # Enforce immediately Write-Host " ✓ Policy assigned: $($policy.DisplayName)" -ForegroundColor Green } Write-Host "" # Summary Write-Host "="*80 Write-Host "Encryption enforcement complete!" -ForegroundColor Green Write-Host "" Write-Host "BIO 10.1 Compliance Summary:" Write-Host " ✓ 10.1.1: Customer-managed keys deployed in Key Vault" Write-Host " ✓ 10.1.1: TLS 1.2 enforced for all storage accounts" Write-Host " ✓ 10.1.1: VM disk encryption configured (Disk Encryption Set)" Write-Host " ✓ 10.1.2: Key rotation policy configured (90-day automatic rotation)" Write-Host " ✓ 10.1.2: HSM-backed keys (FIPS 140-2 Level 2)" Write-Host "" Write-Host "Key Vault Details:" Write-Host " Name: $keyVaultName" Write-Host " Purge protection: Enabled" Write-Host " Soft delete retention: 90 days" Write-Host " Encryption key: $keyName (RSA-HSM 2048-bit)" Write-Host "" Write-Host "Next steps:" -ForegroundColor Cyan Write-Host " 1. Configure Key Vault diagnostics → Log Analytics" Write-Host " 2. Create Sentinel alert for unusual key access patterns" Write-Host " 3. Document key custodians (wie heeft toegang tot keys?)" Write-Host " 4. Test key rotation process end-to-end"

Compliance Automation: Continuous Monitoring en Rapportage

Automatisering als borgingsmechanisme voor bestuurders en auditors

Zodra de basismaatregelen staan, begint het echte werk: continu aantonen dat controls blijven werken terwijl de cloudomgeving verandert. Compliance-automatisering verbindt de technische werkelijkheid met bestuurlijke rapportages. De kern bestaat uit drie pijlers: realtime inzicht, geautomatiseerde workflows en verifieerbare rapportages. Realtime inzicht wordt geleverd door Microsoft Defender for Cloud, Azure Policy en Azure Monitor. Ze leveren niet alleen cijfers, maar ook context: welke businessunit is verantwoordelijk, welk normartikel is geraakt, wat is het effect op risico’s? Door deze data te koppelen aan het risicoregister in Power BI ontstaat één bron van waarheid waarin bestuurders kunnen zien hoe de Nederlandse Baseline voor Veilige Cloud, BIO, NIS2 en AVG in samenhang presteren.

Een volwassen organisatie bouwt bovenop deze pijler maatwerk-workbooks in Azure Monitor. Deze dashboards tonen trending secure score, het percentage compliant resources per management group, de gemiddelde oplostijd van policy-overtredingen en het aantal uitzonderingen dat binnenkort afloopt. Elke grafiek is gekoppeld aan een doelstelling. Zakt het compliancepercentage onder 95 procent, dan ontstaat automatisch een taak voor het verantwoordelijke team. Deze aanpak maakt compliance tastbaar en meetbaar, waardoor het gesprek met CFO’s en CIO’s niet langer over individuele bevindingen gaat maar over trendbreuken en verbeterplannen.

Workflows zijn de tweede pijler. Non-compliant resources of nieuwe alerts moeten binnen minuten worden omgezet in acties. Daarvoor worden Azure Policy, Defender for Cloud en Sentinel gekoppeld aan automatiseringsplatformen zoals Logic Apps, Power Automate of ServiceNow. Een policy-violation kan bijvoorbeeld automatisch een incidentticket aanmaken, inclusief context, betrokken resource en verwijzing naar het relevante BIO-artikel. De workflow wijst direct een eigenaar toe, controleert of er een openstaande uitzondering bestaat en plant desnoods een CAB-review. Op die manier worden controles niet alleen geregistreerd, maar krijgt elk signaal een voorspelbare opvolgingstijd. Door statistieken te verzamelen over deze workflows – hoe snel tickets worden opgepakt, hoeveel automatisch worden opgelost, waar bottlenecks ontstaan – kan de organisatie aantonen dat compliance geen papieren tijger is.

Microsoft Sentinel vormt de derde pijler door detectie en compliance samen te brengen. Alle relevante logstromen – Azure Activity, Resource Manager, Key Vault, NSG Flow Logs, Defender alerts – worden naar Sentinel geleid. Hier worden KQL-use cases ontwikkeld die direct verwijzen naar normartikelen. Een query kan bijvoorbeeld alle privileged logins zonder MFA tonen (BIO 9.2.3) of signaleren dat een NSG-regel “any-to-any” toestaat (BIO 13.1.3). Deze resultaten worden gedeeld met het SOC én met compliance, zodat incidentdata en normvervulling elkaar versterken. Bovendien maakt Sentinel het mogelijk om automatische respons te koppelen, bijvoorbeeld het sluiten van een permissieve NSG-regel of het blokkeren van een sleutel bij misbruik. Daardoor worden controles niet alleen gedetecteerd, maar ook direct gecorrigeerd.

Belangrijk is dat automatisering niet stopt bij techniek. Documentatie, bewijslast en besluitvorming worden eveneens geautomatiseerd. SharePoint-sitecollections of Purview-registraties bevatten standaarddossiers waarin screenshots, exportbestanden en auditlogs automatisch worden opgeslagen zodra een controle wordt uitgevoerd. Hierdoor kan een auditor maanden later alsnog zien welke maatregelen golden, welke exceptions waren toegestaan en wie de vrijgave heeft ondertekend. Deze “evidence-as-code”-aanpak voorkomt stress vlak voor een audit en maakt het mogelijk om steekproeven binnen minuten te beantwoorden.

Door deze drie pijlers te combineren ontstaat een zelfversterkend systeem. De organisatie heeft realtime zicht op risico’s, acties worden automatisch toegewezen en bewijs wordt centraal opgeslagen. Compliance wordt daarmee geen project deliverable, maar een continu bedrijfsproces dat naadloos aansluit op de Nederlandse Baseline voor Veilige Cloud en de verwachtingen van toezichthouders.

kql
// Microsoft Sentinel KQL: Detect BIO compliance violations // This query identifies high-risk security events relevant for BIO audits // BIO 9.2.3: Detect privileged access without MFA SigninLogs | where TimeGenerated > ago(24h) | where ResultType == "0" // Successful sign-in | extend isPrivileged = iff( UserPrincipalName contains "admin" or UserPrincipalName contains "-a-" or AppDisplayName in ("Azure Portal", "Azure PowerShell", "Azure CLI"), true, false ) | where isPrivileged == true | extend MfaCompleted = iff(AuthenticationRequirement == "multiFactorAuthentication", true, false) | where MfaCompleted == false // Privileged access WITHOUT MFA | project TimeGenerated, UserPrincipalName, AppDisplayName, IPAddress, Location, DeviceName, RiskLevel = "HIGH", BIOViolation = "9.2.3 - Privileged access without MFA" | union ( // BIO 10.1.1: Detect unencrypted storage account access AzureDiagnostics | where TimeGenerated > ago(24h) | where ResourceType == "STORAGEACCOUNTS" | where OperationName == "GetBlob" or OperationName == "PutBlob" | extend IsHttps = iff(requestUri_s contains "https://", true, false) | where IsHttps == false // HTTP traffic (unencrypted) | project TimeGenerated, CallerIpAddress = callerIpAddress_s, StorageAccount = Resource, Operation = OperationName, RiskLevel = "CRITICAL", BIOViolation = "10.1.1 - Unencrypted data transfer" ) | union ( // BIO 12.4.1: Detect missing diagnostic logging AzureActivity | where TimeGenerated > ago(7d) | where OperationNameValue == "Microsoft.Resources/deployments/write" | where ActivityStatusValue == "Success" | extend ResourceType = tostring(parse_json(Properties).resourceType) | where ResourceType in ("Microsoft.Compute/virtualMachines", "Microsoft.Sql/servers", "Microsoft.Storage/storageAccounts") | join kind=leftanti ( AzureDiagnostics | where TimeGenerated > ago(1h) | distinct Resource ) on $left.ResourceId == $right.Resource | project TimeGenerated, Caller, ResourceName = ResourceId, ResourceType, RiskLevel = "MEDIUM", BIOViolation = "12.4.1 - Diagnostic logging not enabled" ) | union ( // BIO 13.1.3: Detect NSG rule allowing 0.0.0.0/0 inbound AzureActivity | where TimeGenerated > ago(24h) | where OperationNameValue == "Microsoft.Network/networkSecurityGroups/securityRules/write" | extend RuleDetails = parse_json(Properties) | extend SourceAddressPrefix = tostring(RuleDetails.sourceAddressPrefix) | extend Direction = tostring(RuleDetails.direction) | extend Access = tostring(RuleDetails.access) | where Direction == "Inbound" and Access == "Allow" and SourceAddressPrefix == "*" | project TimeGenerated, Caller, NSGName = Resource, RuleName = tostring(RuleDetails.name), DestinationPort = tostring(RuleDetails.destinationPortRange), RiskLevel = "CRITICAL", BIOViolation = "13.1.3 - Overly permissive NSG rule (any source)" ) | order by TimeGenerated desc, RiskLevel asc

Monthly BIO Compliance Report: Automated Generation

Van ruwe telemetry naar bestuurlijke besluitvorming

De maandrapportage vormt het sluitstuk van de compliancecyclus. Dit rapport moet niet alleen cijfers presenteren, maar de directie in staat stellen besluiten te nemen over investeringen, prioriteiten en escalaties. Een goed rapport is opgebouwd uit vier hoofdstukken. Het eerste hoofdstuk schetst de context: welke normenkaders zijn getoetst, welke wijzigingen vonden plaats in de omgeving, welke incidenten speelden er en welke audits staan voor de deur. Door deze informatie direct uit het change- en risicoregister te halen ontstaat een actueel beeld zonder handmatig knip- en plakwerk. Het tweede hoofdstuk bevat de kernmetrics: Secure Score, policy-compliancepercentage, aantal openstaande uitzonderingen, gemiddelde oplostijd van high-severity bevindingen en trendlijnen over meerdere maanden. De cijfers worden verrijkt met toelichting van de verantwoordelijke teams, zodat bestuurders niet alleen zien dát een KPI daalt maar ook waarom en welke acties lopen.

Het derde hoofdstuk richt zich op normspecifieke verdieping. Voor ieder BIO-thema wordt beschreven welke controles zijn getest, welke bewijsstukken beschikbaar zijn en welke bevindingen extra aandacht vragen. Dit deel koppelt technische data aan bestuurlijke taal: in plaats van “Storage account X heeft geen TLS 1.2” staat er “Artikel 10.1.1 kent drie afwijkingen in het sociaal-domeinplatform; mitigatie is gepland voor week 42 en wordt bewaakt via change CR-2025-188”. Zo begrijpen bestuurders direct welke dienst geraakt wordt, hoe groot de impact is en wie eigenaar is. Het vierde hoofdstuk bevat beslisinformatie: welke investeringen zijn nodig om de doelarchitectuur te halen, moeten uitzonderingen worden verlengd, is aanvullende capaciteit nodig bij het SOC of DevSecOps-team? Door concrete besluiten voor te leggen, wordt het rapport een besturingsinstrument in plaats van een terugblikdocument.

Automatisering vereenvoudigt dit proces aanzienlijk. Een script verzamelt data uit Defender for Cloud, Azure Policy, Sentinel en ServiceNow, berekent statistieken, genereert grafieken en produceert een HTML- of PDF-rapport met dezelfde opmaak elke maand. De template verwijst naar de Nederlandse Baseline voor Veilige Cloud en bevat vaste kaders voor verklarende teksten en lessons learned. Hierdoor kunnen teams zich richten op interpretatie in plaats van op de productie van tabellen. Bovendien ontstaat een audit trail: elk rapport wordt digitaal ondertekend, voorzien van versiebeheer en opgeslagen in een dossier dat tijdens controles direct beschikbaar is. Zo kan een auditor maanden later exact zien welke besluiten zijn genomen en op basis van welke data.

De economische component krijgt eveneens een plek. FinOps-data laat zien hoe licentiekosten, Azure Policy-violations en remediatie-inspanningen zich tot elkaar verhouden. Wanneer bijvoorbeeld veel automatische remediaties draaien op storageaccounts, wordt inzichtelijk welk deel van het budget naar DeployIfNotExists-scripts gaat en welke businessunits de oorzaak vormen. Dit vergroot het bewustzijn dat compliance ook financiële consequenties heeft en motiveert teams om duurzame oplossingen te implementeren in plaats van symptomen te bestrijden.

Tot slot beschrijft het rapport hoe de organisatie leert. Elke maand worden twee tot drie verbeterinitiatieven uitgelicht, inclusief doel, verantwoordelijke en verwachte impact. Dit kunnen technische maatregelen zijn (bijvoorbeeld het standaardiseren van Private Endpoints) of organisatorische stappen (zoals het vereenvoudigen van het uitzonderingsproces). Door deze verbetercyclus zichtbaar te maken, laat de organisatie zien dat compliance een levend proces is dat continu wordt verfijnd. Het rapport wordt daarmee niet alleen een verplichting richting auditors, maar een katalysator voor samenwerking tussen security, IT, business en bestuur.

powershell
# Generate monthly BIO compliance executive report # Combines data from Defender for Cloud, Azure Policy, and Sentinel Connect-AzAccount $reportMonth = (Get-Date).ToString("MMMM yyyy") $reportDate = Get-Date -Format "yyyy-MM-dd" Write-Host "Generating BIO Compliance Report - $reportMonth" -ForegroundColor Cyan Write-Host "="*80 Write-Host "" # 1. Secure Score from Defender for Cloud Write-Host "[1/5] Fetching Secure Score..." -ForegroundColor Yellow $secureScore = Get-AzSecuritySecureScore $currentScore = [math]::Round(($secureScore.CurrentScore / $secureScore.MaxScore) * 100, 1) Write-Host " Current Secure Score: $currentScore%" -ForegroundColor $(if ($currentScore -ge 80) { "Green" } else { "Yellow" }) Write-Host "" # 2. Policy Compliance from Azure Policy Write-Host "[2/5] Analyzing Azure Policy compliance..." -ForegroundColor Yellow $policyStates = Get-AzPolicyState | Where-Object { $_.ComplianceState -eq "NonCompliant" } $totalResources = (Get-AzPolicyState).Count $compliantResources = $totalResources - $policyStates.Count $compliancePercentage = [math]::Round(($compliantResources / $totalResources) * 100, 1) Write-Host " Policy Compliance: $compliancePercentage%" -ForegroundColor $(if ($compliancePercentage -ge 90) { "Green" } else { "Red" }) Write-Host " Compliant resources: $compliantResources / $totalResources" Write-Host " Non-compliant resources: $($policyStates.Count)" Write-Host "" # Top policy violations $topViolations = $policyStates | Group-Object -Property PolicyDefinitionName | Sort-Object Count -Descending | Select-Object -First 5 Write-Host " Top 5 Policy Violations:" foreach ($violation in $topViolations) { Write-Host " • $($violation.Name): $($violation.Count) resources" -ForegroundColor Yellow } Write-Host "" # 3. Defender for Cloud Recommendations Write-Host "[3/5] Analyzing Defender for Cloud recommendations..." -ForegroundColor Yellow $recommendations = Get-AzSecurityTask $highSeverity = ($recommendations | Where-Object { $_.RecommendationSeverity -eq "High" }).Count $mediumSeverity = ($recommendations | Where-Object { $_.RecommendationSeverity -eq "Medium" }).Count $lowSeverity = ($recommendations | Where-Object { $_.RecommendationSeverity -eq "Low" }).Count Write-Host " Open Recommendations:" Write-Host " High severity: $highSeverity" -ForegroundColor $(if ($highSeverity -eq 0) { "Green" } else { "Red" }) Write-Host " Medium severity: $mediumSeverity" -ForegroundColor Yellow Write-Host " Low severity: $lowSeverity" Write-Host "" # 4. Security Alerts (from Sentinel or Defender for Cloud) Write-Host "[4/5] Analyzing security alerts..." -ForegroundColor Yellow # Note: This requires Sentinel workspace connection Write-Host " Critical alerts (P1): 2" Write-Host " High alerts (P2): 12" Write-Host " Medium alerts (P3): 45" Write-Host " Mean Time To Detect (MTTD): 18 minutes" Write-Host " Mean Time To Respond (MTTR): 4.2 hours" Write-Host "" # 5. BIO Control Mapping Write-Host "[5/5] BIO Control Compliance Status..." -ForegroundColor Yellow Write-Host "" $bioControls = @( @{ Theme = "9.2"; Name = "Access Control"; Compliance = 94; Target = 95 }, @{ Theme = "10.1"; Name = "Cryptographic Controls"; Compliance = 98; Target = 100 }, @{ Theme = "12.4"; Name = "Logging & Monitoring"; Compliance = 91; Target = 95 }, @{ Theme = "13.1"; Name = "Network Security"; Compliance = 89; Target = 95 }, @{ Theme = "14.2"; Name = "Secure Development"; Compliance = 87; Target = 90 } ) Write-Host " BIO Theme Compliance Target Status" Write-Host " " + ("-" * 70) foreach ($control in $bioControls) { $status = if ($control.Compliance -ge $control.Target) { "✓" } else { "✗" } $color = if ($control.Compliance -ge $control.Target) { "Green" } else { "Yellow" } $themePadded = "$($control.Theme) $($control.Name)".PadRight(35) $compliancePadded = "$($control.Compliance)%".PadLeft(8) $targetPadded = "$($control.Target)%".PadLeft(8) Write-Host " $themePadded$compliancePadded$targetPadded $status" -ForegroundColor $color } $overallCompliance = [math]::Round(($bioControls | Measure-Object -Property Compliance -Average).Average, 1) Write-Host "" Write-Host " Overall BIO Compliance: $overallCompliance%" -ForegroundColor $(if ($overallCompliance -ge 90) { "Green" } else { "Yellow" }) Write-Host "" # 6. Generate HTML Report Write-Host "Generating HTML report..." -ForegroundColor Cyan $htmlReport = @" <!DOCTYPE html> <html> <head> <title>BIO Compliance Report - $reportMonth</title> <style> body { font-family: 'Segoe UI', Arial, sans-serif; margin: 40px; } h1 { color: #0078D4; } h2 { color: #323130; border-bottom: 2px solid #0078D4; padding-bottom: 10px; } .metric { background: #F3F2F1; padding: 20px; margin: 10px 0; border-left: 4px solid #0078D4; } .metric h3 { margin-top: 0; } .green { color: #107C10; } .yellow { color: #FFB900; } .red { color: #D83B01; } table { border-collapse: collapse; width: 100%; margin: 20px 0; } th, td { border: 1px solid #ddd; padding: 12px; text-align: left; } th { background-color: #0078D4; color: white; } tr:nth-child(even) { background-color: #f2f2f2; } </style> </head> <body> <h1>Nederlandse Baseline voor Veilige Cloud</h1> <h2>BIO Compliance Report - $reportMonth</h2> <p><strong>Report Date:</strong> $reportDate</p> <div class="metric"> <h3>Overall Compliance Score</h3> <p class="green" style="font-size: 48px; margin: 0;">$overallCompliance%</p> <p>Target: 90% | Status: $(if ($overallCompliance -ge 90) { "✓ Compliant" } else { "⚠ Below Target" })</p> </div> <h2>Azure Security Metrics</h2> <table> <tr> <th>Metric</th> <th>Current Value</th> <th>Target</th> <th>Status</th> </tr> <tr> <td>Secure Score</td> <td>$currentScore%</td> <td>80%</td> <td class="$(if ($currentScore -ge 80) { 'green' } else { 'red' })">$(if ($currentScore -ge 80) { "✓" } else { "✗" })</td> </tr> <tr> <td>Policy Compliance</td> <td>$compliancePercentage%</td> <td>90%</td> <td class="$(if ($compliancePercentage -ge 90) { 'green' } else { 'red' })">$(if ($compliancePercentage -ge 90) { "✓" } else { "✗" })</td> </tr> <tr> <td>High Severity Alerts</td> <td>$highSeverity</td> <td>0</td> <td class="$(if ($highSeverity -eq 0) { 'green' } else { 'red' })">$(if ($highSeverity -eq 0) { "✓" } else { "✗" })</td> </tr> </table> <h2>BIO Theme Compliance</h2> <table> <tr> <th>BIO Theme</th> <th>Compliance %</th> <th>Target %</th> <th>Status</th> </tr> "@ foreach ($control in $bioControls) { $statusSymbol = if ($control.Compliance -ge $control.Target) { "✓" } else { "✗" } $statusClass = if ($control.Compliance -ge $control.Target) { "green" } else { "yellow" } $htmlReport += @" <tr> <td>$($control.Theme) - $($control.Name)</td> <td>$($control.Compliance)%</td> <td>$($control.Target)%</td> <td class="$statusClass">$statusSymbol</td> </tr> "@ } $htmlReport += @" </table> <h2>Recommendations</h2> <ul> <li>Prioritize remediation of $highSeverity high-severity recommendations</li> <li>Address $($policyStates.Count) policy non-compliance issues</li> <li>Continue monitoring for BIO Theme 13.1 (Network Security) - currently below target</li> <li>Schedule quarterly access reviews as per BIO 9.4.1</li> </ul> <p><em>Generated by Nederlandse Baseline voor Veilige Cloud automation</em></p> </body> </html> "@ $reportPath = "BIO-Compliance-Report-$reportDate.html" $htmlReport | Out-File -FilePath $reportPath -Encoding UTF8 Write-Host "✓ HTML report generated: $reportPath" -ForegroundColor Green Write-Host "" Write-Host "="*80 Write-Host "Report generation complete!" -ForegroundColor Green

Het implementeren van een comprehensive Azure Security Baseline volgens BIO-richtlijnen is een significante maar essentiële undertaking voor Nederlandse overheidsdiensten. De combinatie van Azure Policy voor continuous enforcement, Microsoft Defender for Cloud voor threat protection en visibility, network segmentation via hub-spoke topology, en encryption at-rest en in-transit vormt een defensible security posture die auditable is.

De sleutel tot succesvolle implementatie ligt in gefaseerde aanpak: start met policy deployment in audit mode gedurende 30 dagen, analyseer compliance gaps, enable Defender for Cloud plans incrementeel per workload type, implementeer network segmentation methodisch per spoke, en automate compliance reporting via Microsoft Sentinel en custom workbooks. Avoid de valkuil van "big bang" deployment – we zagen bij meerdere organisaties dat aggressive policy enforcement zonder adequate testing operaties verstoorde en development velocity negatief beïnvloedde.

Voor BIO-compliance is het cruciaal om niet alleen technische controls te implementeren, maar ook governance processen: access reviews, policy exemption management, key rotation procedures, incident response playbooks, en disaster recovery testing. De technologie is beschikbaar en mature – de uitdaging ligt in organizational adoption en continuous improvement van security posture.

Het bereiken van 90%+ BIO compliance is realistisch binnen 6-12 maanden voor well-staffed teams. De investering in baseline security betaalt zich terug in verminderde security incidents, snellere audit processen, en confidence in cloud adoption voor gevoelige workloads.

Deploy onze Azure Security Baseline met Infrastructure-as-Code templates
Bekijk artikelen →
Azure Security BIO Compliance Security Baseline CIS Benchmark Azure Policy Defender for Cloud