Audit week. Someone wants screenshots of policy compliance as of last Tuesday. The portal shows a different count today. Finance has a spreadsheet of resource IDs that no longer exist. You spend the week reconstructing history instead of answering the control.
Compliance in Azure is continuous export and queryable truth. A slide deck frozen in March is a story you tell yourself.
This is article three of Series 3. Policy taught effects and scope. Defender for Cloud gave you residual signal. This article is how you prove both later, when the auditor is a different firm and the engineer who built the landing zone has moved on.
Map controls to Azure artifacts once
Pick the baseline you actually run. Most Azure landing zones should start with the Microsoft Cloud Security Benchmark (MCSB) as the native mapping layer, then layer CIS Azure Foundations if customers or internal risk demand it. Customer frameworks (NIST, ISO, PCI) get a second column that points at the same Azure artifacts. Do not maintain three unrelated spreadsheets.
For each control ID you claim, record:
| Field | Example |
|---|---|
| Framework + control ID | MCSB NS-2, CIS 3.1, or customer AC-2 |
| Azure Policy definition or initiative ID | Built-in MCSB initiative assignment at mg-contoso-prod |
| Desired effect | Deny, DeployIfNotExists, Audit |
| Resource Graph query | Lists noncompliant resources today |
| Detective log source | AzureActivity, SigninLogs, KeyVault logs |
| Owner | Platform or workload |
| Evidence location | Repo path, export storage account, LA saved search |
Store the map in git next to the policy module. When auditors change firms, the map stays. When a control owner leaves, the next person inherits files, not folklore.
Prefer data over screenshots
Screenshots are narrative backup. They are not the system of record.
Build evidence from things you can re-run:
- Policy compliance state exported on a schedule (Log Analytics, Event Hub, or storage via automation)
- Azure Resource Graph queries checked into the repo and run in CI with a reader identity at the root management group
- Activity logs retained per your logging design
- Entra access reviews, PIM activation history, and Conditional Access reports for identity controls
- Defender continuous export for recommendation history and alert history
If the only proof of a control is a PNG in a SharePoint folder named Audit2025, you will rebuild that PNG under pressure. Pressure produces wrong scopes and missing timestamps.
Point-in-time without time travel fantasies
You cannot always reproduce last Tuesday’s portal UI. Portals change. Blades move. Filters get forgotten.
You can design for point-in-time answers:
- Nightly (or hourly) export of policy compliance snapshots to storage with a date prefix
- Log Analytics retention long enough for the investigation window Legal cares about
- Git history for exemptions, initiative assignments, and the control map itself
- CI logs that show ARG query results for a given commit SHA
Talk to Legal and Risk about retention before Security sets everything to 365 days hot. Hot retention is an invoice. Archive and exports are usually the cheaper way to keep “what was true.” Series 5 will care about the bill. Audit season still needs the bytes.
MCSB and CIS mapping that stays honest
MCSB controls are written for cloud platforms. Many map cleanly to Azure Policy and Defender recommendations. Some are shared responsibility: your control is “platform provides capability, workload configures the resource.” Put that split in the map so platform is not graded for an app team’s public storage account you already Denied at the MG.
CIS Azure Foundations Benchmark items often overlap MCSB. Where they duplicate, point both control IDs at one Policy assignment and one ARG query. Duplicated evidence packs are how teams drift and answer the same question two different ways in the same room.
When Microsoft updates built-in definitions, read the change. Initiatives evolve. Your map should note the assignment name and the version you intended, not “whatever the portal shows today.”
Exemptions are evidence too
An exemption without control ID, expiry, owner, and ticket link is a hole in the control, not a temporary relief valve.
Keep policy exemption resources in Terraform:
- Scope (resource, RG, subscription)
- Policy definition or set reference
- Exemption category (Waiver vs Mitigated) that matches how you talk in audits
- Display name that a stranger can understand
- Expires on a real date
- Metadata linking to the change ticket and the MCSB/CIS ID
Auditors will ask why Deny does not apply. “It broke the pipeline” needs a date when Deny returns and a mitigating control that is not vibes. If mitigation is “we watch it,” name the alert and the query.
ARG queries that earn a home in CI
Portal compliance blades are fine for exploration. CI is for the pack you trust.
Examples of queries worth keeping (shape them to your naming and tags):
PolicyResources
| where type =~ "microsoft.authorization/policyassignments"
| extend mg = tostring(properties.scope)
| where mg has "/providers/Microsoft.Management/managementGroups/"
| project name, mg, displayName = properties.displayName, enforcementMode = properties.enforcementMode
Resources
| where type =~ "microsoft.storage/storageaccounts"
| where isempty(tags["Environment"]) or tags["Environment"] =~ "prod"
| where properties.publicNetworkAccess =~ "Enabled"
| project name, resourceGroup, subscriptionId, tags
ResourceContainers
| where type =~ "microsoft.resources/subscriptions"
| project subscriptionId, name = name, state = properties.state
Run the pack on a schedule against a service principal that has Reader at the root management group and nothing more. Fail CI on new platform-scope noncompliance. File workload noncompliance to the Owner tag with the same escalation path you use for budgets.
Do not paste credentials into the pipeline. Use OIDC, same as Deployment Model.
Identity evidence sits next to Azure evidence
Many MCSB and CIS controls are Entra controls wearing Azure clothes: privileged access, access reviews, break-glass, MFA for admins.
Collect:
- PIM eligible vs active assignments for roles that can change the tenant or the root MG
- Access review completion exports for those roles
- Sign-in logs proving MFA challenges for privileged users
- Proof that break-glass accounts are excluded intentionally from some Conditional Access policies and monitored everywhere else
Identity already argued against standing privilege. Continuous evidence is how you show the argument survived last quarter.
Weekly platform ritual
Thirty to forty-five minutes. Same day as the Defender backlog review if that helps attendance.
- Run the top twenty ARG queries from the pack
- Diff results against last week’s saved output
- File work for new noncompliance on platform resources the same week
- Route workload noncompliance to
Ownerwith a due date - Open the exemption list: anything expiring in 30 days gets a decision (extend with ticket, or remove)
- Confirm exports still land (failed export jobs are silent audit failures)
If the ritual only produces screenshots for a steering committee, cancel the steering committee slide and keep the git diff.
What “good” looks like in an audit room
You open a laptop. You show:
- The control map row for the asked control
- The Policy assignment ID at the management group
- Live ARG output (or dated export) for noncompliant resources
- For detective controls, a Kusto query over the retained window
- For exceptions, the Terraform exemption with expiry and ticket
You do not open seven browser tabs and apologize for subscription filters. You do not say “we follow CAF” without assignment IDs. You do not blame the previous auditor’s template.
Article seven turns this into an audit-season runbook. This article is the system that runbook assumes exists.
Failure modes to kill early
- Map in Confluence only. Dies at reorg.
- Evidence SP with Owner. Becomes a control-plane asset you forgot to threat model.
- One giant CSV emailed weekly. Nobody diffs it.
- Retention “whatever default is.” Contradicts the policy you claim.
- Workload and platform mixed in one queue. Platform spends audit week fixing app storage accounts.
Fix those before you buy another GRC tool. Tools help when the artifacts exist. They cannot invent assignment IDs you never created.
Export destinations that survive reorgs
Pick one primary evidence store and treat it as a platform product:
- Storage account with private endpoint, immutability or legal hold where Legal requires it, and RBAC narrower than Contributor
- Log Analytics for queryable recent history, with archive or continuous export for the long tail
- Git for control maps, ARG queries, exemption Terraform, and CI logs tied to commit SHAs
Do not scatter evidence across a personal OneDrive, a SharePoint site named after last year’s auditor, and a workspace in a sandbox subscription. Sandbox cleanup already punched holes in logging. Evidence that lives there will vanish the same way.
OIDC for the export automation identity. Reader at the root management group (or the MG scope you claim). No Owner “so the script can fix things.” Evidence collectors collect. Remediation is a separate ticket and a separate identity.
Defender export as a second timeline
Policy compliance tells you configuration state. Defender continuous export tells you which recommendations were open when. Auditors ask both: “is it denied now” and “how long was it open.”
Land recommendation and alert data in Log Analytics with enough retention for your investigation window. Save a Kusto query that summarizes open High/Critical recommendations by assessment key and subscription for a given day. That query becomes the answer when someone asks for last Tuesday without demanding a portal time machine.
If export was never enabled, start it now. You cannot backfill a portal view. You can only start the clock.
Who can read evidence without becoming Owner
The ARG and export identity needs Reader at the root management group (or the MG scope you claim). It does not need Contributor. Humans who pull audit packs should use PIM-eligible Reader or Security Reader style roles, not standing Owner “because it was easier for the last audit.”
Table-level or workspace RBAC from the logging design still applies. Evidence collectors need Activity and Sign-in, not the ability to rewrite firewall rules. Identity undersizing shows up here as shared Owner accounts used to “just run the queries.”
Connect the ritual to tickets
Every new platform noncompliance in the weekly diff becomes a ticket with:
- Control ID from the map
- ARG query name
- Resource IDs
- Owner
- Due date that matches severity (Critical same week for platform)
Without tickets, the ritual is a status meeting. Status meetings do not remediate storage accounts.
Next: Secrets and Certificates at Scale. Managed identity first. Vaults that do not become a second identity provider.
Randy Bordeaux
Azure Trainer | Veteran | Engineer
Helping IT professionals grow through cloud, leadership, and shared knowledge.


