DMARC-implementatie Voor Nederlandse Overheidsdomeinen

💼 Management Samenvatting

DMARC (Domain-based Message Authentication, Reporting and Conformance) is de norm waarmee overheidsorganisaties afdwingen dat alleen geauthenticeerde e-mails namens hun domeinen worden afgeleverd. In een tijd waarin phishing en business e-mail compromise stijgen, vormt DMARC samen met SPF en DKIM de digitale identiteitskaart van de overheid.

Aanbeveling
IMPLEMENT
Risico zonder
High
Risk Score
8/10
Implementatie
100u (tech: 60u)
Van toepassing op:
Microsoft 365
Exchange Online
DNS-beheer
Microsoft Defender voor Office 365

Zonder DMARC bepalen ontvangende mailservers zelf hoe zij omgaan met berichten die de SPF- of DKIM-controles niet doorstaan. Dat leidt tot inconsistent gedrag, waardoor spoofingcampagnes vrij spel krijgen en burgers waarschuwingen ontvangen voor berichten die ogenschijnlijk van een gemeente, ministerie of uitvoeringsorganisatie komen. Voor de AVG, BIO en NIS2 is dat onacceptabel: organisaties moeten aantoonbaar passende maatregelen nemen tegen misbruik van communicatiekanalen. DMARC introduceert een beleidslaag waarmee u exact voorschrijft of gefaalde berichten worden geweigerd of in quarantaine belanden en creëert tegelijk zichtbaarheid via rapportages, zodat incidenten vroegtijdig worden opgespoord.

PowerShell Modules Vereist
Primary API: Microsoft 365 Defender portal, Exchange Online PowerShell, DNS-provider API
Connection: Connect-ExchangeOnline, Connect-MgGraph, REST-koppeling naar DNS-platform
Required Modules: ExchangeOnlineManagement, Microsoft.Graph, DnsClient

Implementatie

Dit artikel biedt een compleet kader om DMARC binnen Microsoft 365 te ontwerpen, uit te rollen en te borgen volgens de richtlijnen van de "Nederlandse Baseline voor Veilige Cloud". We behandelen governance en eigenaarschap, de technische implementatie over het volledige domeinportfolio, integratie met Exchange Online en Microsoft Defender, en de operationele monitoring en rapportage die auditors, CISO en FG verlangen. Het bijbehorende PowerShell-script helpt om configuraties te toetsen, rapportages vast te leggen en risicoacceptaties te onderbouwen.

Strategisch kader en governance voor DMARC

Een volwassen DMARC-programma begint met governance. Bestuur en directie moeten expliciet erkennen dat e-mailauthenticatie net zo cruciaal is als netwerksegmentatie of identity management, omdat burgers en ketenpartners vertrouwen ontlenen aan het afzenderdomein. Het strategische kader beschrijft welke risico’s DMARC adresseert (onder andere factuurfraude, reputatieschade en ondermijning van de democratische rechtsstaat), welke normen van toepassing zijn (AVG artikel 32, BIO 12 en 13, NIS2 artikel 21) en hoe DMARC past binnen de zero-trustprincipes van de organisatie. Door die positionering wordt DMARC geen geïsoleerd technologieproject maar een structureel onderdeel van de veiligheidsarchitectuur.

Daarna volgt eigenaarschap. Elk domein krijgt een functioneel eigenaar (vaak de proceseigenaar van het betreffende kanaal), een technisch eigenaar (DNS-beheer) en een security owner (CISO/SOC). In het domeinregister staat per domein waarvoor het wordt gebruikt, welke systemen e-mail versturen, welke leveranciers betrokken zijn, welke classificatie geldt en welke uitzonderingen eventueel zijn toegestaan. Nieuwe domeinen worden pas geactiveerd nadat SPF, DKIM en DMARC zijn ontworpen en oude domeinen worden pas uitgefaseerd als alle verzendrechten zijn ingetrokken. Ook verwerkersovereenkomsten worden aangepast: leveranciers moeten aantonen dat zij DMARC ondersteunen en incidenten binnen 24 uur melden.

Governance is niet compleet zonder risicosturing en changeproces. Het kader schrijft voor dat elke wijziging aan SPF, DKIM of DMARC via het reguliere change management verloopt, inclusief vier-ogenreview en logging. Er worden escalatieroutes vastgelegd voor situaties waarin DMARC tijdelijk moet worden versoepeld, bijvoorbeeld tijdens een storing in het signing-platform. Alleen de CISO of diens gemachtigde mag een versoepeling goedkeuren, de wijziging wordt maximaal 72 uur toegestaan en alle betrokken stakeholders worden geïnformeerd. Daarmee blijft de organisatie aantoonbaar in control, ook tijdens incidenten.

Tot slot borgt het kader rapportage en bewustwording. Het bestuur ontvangt een kwartaalrapport met kernindicatoren zoals het percentage domeinen op p=reject, het aantal leveranciersissues, openstaande risicoacceptaties en trends uit DMARC-rapporten. Communicatie- en projectteams krijgen richtlijnen voor nieuwe campagnes: geen enkel project mag e-mails versturen voordat het DMARC-team het scenario heeft beoordeeld. Door governance te koppelen aan bestaande overlegstructuren (informatiebeveiligingsraad, stuurgroepen, auditcommissie) beklijft DMARC als bestuurlijk onderwerp in plaats van een eenmalige implementatie.

Gefaseerde technische implementatie over het volledige domeinportfolio

De technische implementatie start met randvoorwaarden: correcte SPF-records en geactiveerde DKIM voor alle verzendkanalen. Maak een inventaris van alle systemen die e-mail versturen, inclusief SaaS-toepassingen, marketingplatforms, zaaksystemen en noodvoorzieningen. Leg per systeem vast met welk afzenderdomein wordt gewerkt, welke IP-adressen of hostnames worden gebruikt en of DKIM wordt ondersteund. Deze inventaris vormt de input voor een gefaseerd DMARC-schema dat per domein beschrijft wanneer het beleid opschuift van p=none naar p=quarantine en uiteindelijk p=reject.

In de monitorfase (p=none) worden RUA-rapporten dagelijks verwerkt. Gebruik een analyseplatform of een Sentinel-workbook om bronnen te groeperen en onbekende verzenders te identificeren. Betrek leveranciers direct: stuur rapportfragmenten mee zodat zij kunnen aantonen dat hun systemen correct zijn ingesteld. Pas wanneer minstens 98 procent van de legitieme mailstroom aligned is, verschuift het domein naar p=quarantine. Deze stap wordt gecommuniceerd met service- en klantcontactcentra, omdat sommige externe ontvangers waarschuwingen kunnen zien. Na een stabiele periode van minimaal 30 dagen volgt p=reject, waarbij ook het sp-attribuut wordt ingesteld om subdomeinen te beschermen.

Microsoft 365 speelt hierin een centrale rol. In Exchange Online worden DKIM-sleutels van 2048-bit geactiveerd voor alle geautoriseerde domeinen en worden transportregels ingericht die DMARC-fail verbinden aan detectie en rapportage. Microsoft Defender voor Office 365 levert aanvullende telemetrie die helpt om foutieve configuraties te identificeren. Wanneer externe gateways of on-premises servers nog in de mailroute zitten, moet worden gecontroleerd dat zij DKIM-signatures niet overschrijven en SPF-mechanismen niet breken. Gebruik waar mogelijk connectors met mutual TLS, zodat de gehele keten traceerbaar blijft.

Ten slotte wordt het programma opgeschaald naar alle domeinen, inclusief historische of publiekscampagnes. Domeinen die nooit e-mail versturen krijgen expliciet een reject-beleid en verwijzen met een ruwe tekst naar het contactpunt voor incidentmeldingen. Subdomeinen die door leveranciers worden gebruikt krijgen aparte DMARC-records en een contractuele verplichting om DKIM te activeren. Dit alles wordt als code vastgelegd (bijvoorbeeld via Bicep of Terraform voor DNS) zodat wijzigingen herhaalbaar en auditeerbaar zijn. Het PowerShell-script dmarc-deployment.ps1 fungeert als controlemechanisme om te verifiëren dat DNS-records overeenkomen met het ontwerp.

Operationele monitoring, rapportage en scriptgestuurde controles

Zodra domeinen op p=reject staan, verschuift de focus naar continue monitoring. RUA-rapporten worden dagelijks ingelezen in een dataplatform en verrijkt met metadata (verantwoordelijk domeineigenaar, leverancier, classificatie). KPI's zoals het aantal onbekende verzenders per maand, het percentage aligned berichten per ketenproces en de doorlooptijd voor remediatie worden gedeeld met CISO en bestuur. Deze inzichten voeden ook crisiscommunicatie: wanneer een aanvaller pogingen doet om verkiezings- of belastingdomeinen te spoofing, is onmiddellijk zichtbaar waar het verkeer vandaan komt en welke maatregelen zijn genomen.

Monitoring is onlosmakelijk verbonden met incidentrespons. Het SOC integreert DMARC-data met Microsoft Sentinel en koppelt die aan meldingen uit Microsoft Defender, zodat een phishinggolf snel kan worden herleid tot specifieke infrastructuur. Wanneer een leverancier plotseling de DMARC-eisen niet meer haalt, genereert Sentinel een melding die automatisch een change-ticket opent. Het incidentproces beschrijft hoe communicatieafdelingen worden geïnformeerd en hoe externe partijen zoals NCSC of Logius worden betrokken. Door DMARC-rapporten te bewaren ontstaat bovendien bewijslast voor strafrechtelijke onderzoeken.

Compliance en audits vereisen dat processen aantoonbaar zijn gedocumenteerd. Het verwerkingsregister benoemt welke persoonsgegevens per e-mail worden verstuurd, DMARC-rapportage wordt benoemd als ondersteunende maatregel, en risicoacceptaties voor domeinen die nog niet op reject staan worden voorzien van deadlines en verantwoordelijken. Tijdens audits levert de organisatie DNS-exports, scriptuitvoer, change-logs en incidentrapporten aan. Deze bewijslast toont dat DMARC geen statische configuratie is maar een levend proces.

Het PowerShell-script dmarc-deployment.ps1 ondersteunt deze operationalisatie. In DebugMode gebruikt het script voorbeelddata zodat het lokaal getest kan worden. In productiemodus leest het DNS-records via Resolve-DnsName, controleert het of SPF aanwezig is, detecteert het DKIM-statussen via Exchange Online en vat het resultaten samen in een rapport dat kan worden gedeeld met auditors of bestuur. Door het script wekelijks te draaien houdt u een actueel overzicht van domeinen, openstaande issues en risicotrends.

Gebruik PowerShell-script dmarc-deployment.ps1 (functie Invoke-DmarcDeploymentAssessment) – Voert DMARC-, SPF- en DKIM-controles uit, genereert een samenvattend rapport en ondersteunt DebugMode voor veilige lokale tests..

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
<# .SYNOPSIS Controleert DMARC-, SPF- en DKIM-configuraties voor opgegeven domeinen. .DESCRIPTION Dit script hoort bij content/m365/email/dmarc-deployment.json binnen het project "Nederlandse Baseline voor Veilige Cloud". Het script analyseert DNS-records, optioneel Exchange Online DKIM-configuraties en DMARC-rapportgegevens en vat de resultaten samen voor CISO-rapportages en audits. In DebugMode wordt uitsluitend voorbeelddata gebruikt zodat het script veilig lokaal getest kan worden zonder verbinding te maken met productieomgevingen. .NOTES Filename: dmarc-deployment.ps1 Version: 1.0 Created: 2025-11-27 Related JSON: content/m365/email/dmarc-deployment.json Modules: DnsClient (standaard), ExchangeOnlineManagement (optioneel) .EXAMPLE .\dmarc-deployment.ps1 -InvokeDmarcDeploymentAssessment -Domains overheid.nl -DebugMode Voert een lokale test uit met voorbeelddata. .EXAMPLE .\dmarc-deployment.ps1 -InvokeDmarcDeploymentAssessment -Domains overheid.nl -ReportPath .\rapport.json Controleert het domein overheid.nl en schrijft de resultaten naar een JSON-bestand. #> #Requires -Version 5.1 param( [Parameter(Mandatory = $false, HelpMessage = "Start de DMARC-evaluatie.")] [switch]$InvokeDmarcDeploymentAssessment, [Parameter(Mandatory = $false, HelpMessage = "Een of meerdere domeinen om te evalueren.")] [string[]]$Domains, [Parameter(Mandatory = $false, HelpMessage = "Pad naar optioneel rapportbestand (JSON).")] [string]$ReportPath, [Parameter(Mandatory = $false, HelpMessage = "Gebruik lokale voorbeelddata i.p.v. productiegegevens.")] [switch]$DebugMode ) $ErrorActionPreference = 'Stop' $script:ExchangeConnected = $false function Connect-ExchangeOnlineSafe { if ($DebugMode) { Write-Host "DebugMode: Exchange Online-verbinding wordt overgeslagen." -ForegroundColor Yellow return $false } if (-not (Get-Module -ListAvailable -Name ExchangeOnlineManagement)) { Write-Host "Waarschuwing: ExchangeOnlineManagement-module niet gevonden. DKIM-status wordt via DNS gecontroleerd." -ForegroundColor Yellow return $false } try { $session = Get-PSSession | Where-Object { $_.ConfigurationName -eq "Microsoft.Exchange" -and $_.State -eq "Opened" } if (-not $session) { Write-Host "Voer Connect-ExchangeOnline uit voordat u DKIM-configuraties ophaalt." -ForegroundColor Yellow return $false } Write-Host "Exchange Online-verbinding gedetecteerd." -ForegroundColor Green return $true } catch { Write-Host "Kon Exchange Online-verbinding niet bevestigen: $_" -ForegroundColor Yellow return $false } } function Get-DmarcSampleData { return @( [PSCustomObject]@{ Domain = "voorbeeldgemeente.nl" DmarcRecord = "v=DMARC1; p=reject; rua=mailto:dmarc@voorbeeldgemeente.nl; aspf=s; adkim=s; pct=100" DmarcPolicy = "reject" AlignmentStrict = $true PctApplied = 100 SpfRecordFound = $true DkimEnabled = $true Issues = @() }, [PSCustomObject]@{ Domain = "dienst.example.nl" DmarcRecord = "v=DMARC1; p=quarantine; pct=50; rua=mailto:dmarc@dienst.example.nl" DmarcPolicy = "quarantine" AlignmentStrict = $false PctApplied = 50 SpfRecordFound = $true DkimEnabled = $false Issues = @("DMARC-policy staat niet op reject", "Alignment niet strikt", "DKIM ontbreekt", "pct kleiner dan 100 procent") } ) } function Get-DmarcInfo { param( [Parameter(Mandatory = $true)][string]$Domain ) $issues = New-Object System.Collections.Generic.List[string] $dmarcRecord = "" try { $dmarcRecord = (Resolve-DnsName -Name ("_dmarc.{0}" -f $Domain) -Type TXT -ErrorAction Stop).Strings -join "" } catch { $issues.Add("Geen DMARC-record gevonden") } $policyMatch = [regex]::Match($dmarcRecord, "p=([\w\-]+)", "IgnoreCase") $policy = if ($policyMatch.Success) { $policyMatch.Groups[1].Value.ToLowerInvariant() } else { "" } $pctMatch = [regex]::Match($dmarcRecord, "pct=(\d+)", "IgnoreCase") $pct = if ($pctMatch.Success) { [int]$pctMatch.Groups[1].Value } else { 100 } $alignmentStrict = [regex]::IsMatch($dmarcRecord, "aspf=s", "IgnoreCase") -and [regex]::IsMatch($dmarcRecord, "adkim=s", "IgnoreCase") if (-not $policy) { $issues.Add("DMARC-policy ontbreekt of is ongeldig") } elseif ($policy -ne "reject") { $issues.Add("DMARC-policy staat niet op reject") } if (-not $alignmentStrict) { $issues.Add("Alignment niet strikt voor SPF en DKIM") } if ($pct -lt 100) { $issues.Add("pct kleiner dan 100 procent") } $spfFound = $false try { $txtRecords = Resolve-DnsName -Name $Domain -Type TXT -ErrorAction Stop $spfFound = ($txtRecords.Strings | Where-Object { $_ -like "v=spf1*" }).Count -gt 0 if (-not $spfFound) { $issues.Add("Geen SPF-record gevonden") } } catch { $issues.Add("Kon SPF-record niet ophalen: $($_.Exception.Message)") } $dkimEnabled = $false if ($script:ExchangeConnected) { try { $dkimConfig = Get-DkimSigningConfig -Identity $Domain -ErrorAction Stop $dkimEnabled = $dkimConfig.Enabled if (-not $dkimEnabled) { $issues.Add("DKIM uitgeschakeld in Exchange Online") } } catch { $issues.Add("Kon DKIM-configuratie niet ophalen uit Exchange Online") } } else { try { $probe = Resolve-DnsName -Name ("selector1._domainkey.{0}" -f $Domain) -Type CNAME -ErrorAction Stop $dkimEnabled = $probe -ne $null if (-not $dkimEnabled) { $issues.Add("Geen DNS-record gevonden voor selector1._domainkey") } } catch { $issues.Add("Geen DKIM DNS-record gevonden voor selector1") } } return [PSCustomObject]@{ Domain = $Domain DmarcRecord = $dmarcRecord DmarcPolicy = if ($policy) { $policy } else { "onbekend" } AlignmentStrict = $alignmentStrict PctApplied = $pct SpfRecordFound = $spfFound DkimEnabled = $dkimEnabled Issues = $issues } } function Get-DmarcSummary { param( [Parameter(Mandatory = $true)][PSCustomObject[]]$Assessment ) $total = $Assessment.Count $rejectCount = ($Assessment | Where-Object { $_.DmarcPolicy -eq "reject" }).Count $aligned = ($Assessment | Where-Object { $_.AlignmentStrict -and $_.PctApplied -eq 100 }).Count $status = if ($total -gt 0 -and $rejectCount -eq $total -and $aligned -eq $total) { "Goed" } elseif ($total -gt 0 -and $rejectCount -ge [Math]::Ceiling($total * 0.75)) { "Bijna gereed" } else { "Aandacht vereist" } $riskSummary = switch ($status) { "Goed" { "Alle gecontroleerde domeinen staan op DMARC p=reject met strikte alignment." } "Bijna gereed" { "Een deel van de domeinen gebruikt nog quarantaine of versoepelde instellingen." } default { "Meerdere domeinen missen DMARC-reject of strikte alignment en zijn kwetsbaar voor spoofing." } } return [PSCustomObject]@{ TotalDomains = $total RejectCount = $rejectCount FullAlignment = $aligned OverallStatus = $status RiskSummary = $riskSummary } } function Invoke-DmarcDeploymentAssessment { try { Write-Host "`n========================================" -ForegroundColor Cyan Write-Host "DMARC Deployment Assessment" -ForegroundColor Cyan Write-Host "Nederlandse Baseline voor Veilige Cloud" -ForegroundColor Cyan Write-Host "========================================`n" -ForegroundColor Cyan if ($DebugMode) { $assessment = Get-DmarcSampleData } else { if (-not $Domains -or $Domains.Count -eq 0) { throw "Geen domeinen opgegeven. Gebruik -Domains of DebugMode." } $script:ExchangeConnected = Connect-ExchangeOnlineSafe $assessment = foreach ($domain in $Domains) { Write-Host "Controle uitvoeren voor $domain..." -ForegroundColor Gray Get-DmarcInfo -Domain $domain } } $summary = Get-DmarcSummary -Assessment $assessment Write-Host "Totaal aantal domeinen: $($summary.TotalDomains)" -ForegroundColor White Write-Host "Domeinen op p=reject: $($summary.RejectCount)" -ForegroundColor White Write-Host "Strikte alignment bereikt: $($summary.FullAlignment)" -ForegroundColor White $color = switch ($summary.OverallStatus) { "Goed" { "Green" } "Bijna gereed" { "Yellow" } default { "Red" } } Write-Host "Algemene status: $($summary.OverallStatus)" -ForegroundColor $color Write-Host "Risicosamenvatting: $($summary.RiskSummary)" -ForegroundColor Gray foreach ($domainResult in $assessment) { Write-Host "`n--- $($domainResult.Domain) ---" -ForegroundColor Cyan Write-Host "DMARC-record: $($domainResult.DmarcRecord)" -ForegroundColor White Write-Host "Policy: $($domainResult.DmarcPolicy)" -ForegroundColor White Write-Host "Strikte alignment: $($domainResult.AlignmentStrict)" -ForegroundColor White Write-Host "pct toegepast: $($domainResult.PctApplied)" -ForegroundColor White Write-Host "SPF aanwezig: $($domainResult.SpfRecordFound)" -ForegroundColor White Write-Host "DKIM actief: $($domainResult.DkimEnabled)" -ForegroundColor White if ($domainResult.Issues.Count -gt 0) { Write-Host "Issues:" -ForegroundColor Yellow $domainResult.Issues | ForEach-Object { Write-Host " - $_" -ForegroundColor Yellow } } else { Write-Host "Geen openstaande issues." -ForegroundColor Green } } if ($ReportPath) { $reportObject = [PSCustomObject]@{ GeneratedOn = (Get-Date).ToString("s") Summary = $summary Domains = $assessment DebugMode = [bool]$DebugMode } try { $reportObject | ConvertTo-Json -Depth 5 | Out-File -FilePath $ReportPath -Encoding UTF8 Write-Host "`nRapport opgeslagen op $ReportPath" -ForegroundColor Green } catch { Write-Host "Kon rapport niet opslaan: $_" -ForegroundColor Yellow } } } catch { Write-Host "Fout tijdens DMARC-assessment: $_" -ForegroundColor Red exit 1 } } if ($InvokeDmarcDeploymentAssessment) { Invoke-DmarcDeploymentAssessment } else { Write-Host "Geen actieparameter opgegeven. Gebruik -InvokeDmarcDeploymentAssessment om de controle uit te voeren." -ForegroundColor Yellow Write-Host "Voorbeeld: .\dmarc-deployment.ps1 -InvokeDmarcDeploymentAssessment -Domains overheid.nl -DebugMode" -ForegroundColor Yellow }

Risico zonder implementatie

Risico zonder implementatie
High: Zonder DMARC blijven overheidsdomeinen eenvoudig te spoofing, ontstaan fraudezaken en kan de organisatie niet aantonen dat zij voldoet aan AVG, BIO en NIS2. Dit resulteert in financiële schade, politieke druk en zware auditbevindingen.

Management Samenvatting

Breng alle domeinen in kaart, activeer SPF en DKIM voor elk verzendkanaal, dwing DMARC p=reject af en veranker monitoring en rapportage met het meegeleverde script zodat spoofing structureel wordt voorkomen.