M5 — DLP Policies (M365) — Test Runbook¶
Asset: M5 — M365 Data Loss Prevention as policy-as-code (
policy/dlp/): committed YAML policy definitions + offline gate + idempotent Security & Compliance PowerShell deploy. Owner: CO · Milestone: M4.Division of labor (read first): M5 covers the M365 content-inspection layer (Exchange/SharePoint/OneDrive/Teams). The cloud-storage half of "DLP" is already enforced by existing Azure assets — public-network deny (
N5), encryption (M1), TLS (M3), residency (M6). M5 does not duplicate them.
Part A — Offline gate (~2 min, $0)¶
Acceptance:
- [ ] validate.sh reports the 3 seeded policies valid (pii-financial,
pii-personal, healthcare-phi).
- [ ] The validator unit tests pass, and the broken fixtures under
tests/fixtures/broken/ (bad mode, unknown location, no rules,
min_count 0) + duplicate-names/ each fail the gate (exit 1) — the gate is
fail-closed.
- [ ] Schema enforced per policy: name, mode (Enable | TestWithNotifications
| TestWithoutNotifications | Disable), locations (Exchange/SharePoint/
OneDrive/Teams), non-empty rules, each sensitive_types[].min_count ≥ 1,
unique policy names.
Part B — Policy-set review (~4 min, $0)¶
- Audit-first rollout — all three ship in
TestWithNotifications(the SnowOps enforce=false→true stance);block_externalonly triggers on the high-volume rule. PHI (healthcare-phi.yaml) shipsenabled: false— opt in for HIPAA clients only. - Each policy has a low-volume rule (notify on ≥1) and a high-volume rule (block external + High incident on ≥10) — graduated response, not a blunt block.
- Sensitive info types are real Purview types (e.g. "Credit Card Number", "International Banking Account Number (IBAN)", SSN/passport, health identifiers).
Part C — Live deploy (requires M365 Compliance admin + licensing)¶
Requires appropriate M365 compliance licensing (E5 / Compliance add-on) for full DLP, the
ExchangeOnlineManagement+powershell-yamlmodules, and the Compliance Administrator role.
# Dry run first — prints the plan without connecting/changing anything
./deploy-dlp.ps1 -DryRun
# Real deploy (connects via Connect-IPPSSession)
./deploy-dlp.ps1
-
-DryRunprints each policy + rule it would create/update; no connection made. - Real run is idempotent —
New-DlpCompliancePolicywhen absent,Set-DlpCompliancePolicywhen present; re-running makes no further changes. - In the Purview compliance portal, the 3 policies appear (PHI disabled) in
TestWithNotifications. - Send a test email containing a fake card-number-shaped string to an external address → the policy-tip/notification fires and an incident report is generated; external send is blocked once the high-volume threshold is crossed.
- Soak, then enforce: leave in
TestWithNotificationsfor the agreed soak period (tune false positives), then flipmode: Enablein the YAML, re-validate, and re-deploy.
Notes¶
- Terraform/azurerm cannot manage M365 DLP — hence the policy-as-code + PowerShell-deploy shape (same pattern as J5 dashboards-as-code and F8).
- The YAML is the single source of truth; the portal is never hand-edited (drift would be overwritten on the next deploy).