Your SOC 2 Type II audit covers an observation window—typically three to twelve months, with most organizations targeting six to twelve months. Every misconfigured storage account, every unreviewed privileged role, every unencrypted database that existed during that window is fair game for the auditor. Not just the state of your environment on audit day—the entire period. If you’re collecting that evidence manually, you’re already losing.
This tutorial walks you through automating SOC 2 Type II controls on Azure using three tools that work together: Azure Policy for infrastructure guardrails and continuous configuration scanning, Microsoft Defender for Cloud for compliance visibility and evidence reporting, and Microsoft Entra ID (with Privileged Identity Management) for identity and access controls. You’ll assign the built-in SOC 2 Type 2 Regulatory Compliance initiative, configure Log Analytics for evidence retention, wire up Defender for Cloud’s compliance dashboard, implement just-in-time access via PIM, and lock in continuous compliance with Enterprise Policy as Code (EPAC) in a CI/CD pipeline.
What SOC 2 Type II Actually Requires from You
SOC 2, developed by the American Institute of Certified Public Accountants (AICPA), is an auditing standard for service organizations that evaluates how effectively controls protect customer data. The framework is organized around five Trust Services Criteria (TSC): Security, Availability, Processing Integrity, Confidentiality, and Privacy. Security is mandatory for all audits; the other four are optional depending on your scope.
The critical distinction that shapes everything in this tutorial: a Type I report is a point-in-time snapshot. An auditor visits, checks that controls exist, and leaves. A Type II report evaluates whether those controls operated effectively over the full observation period—a minimum of three months, and typically six to twelve months in practice. That’s not a nuance. It means a manually-generated screenshot of your encryption settings on audit day proves nothing about the nine months before the auditor showed up.
This is why automation matters. Not to make compliance easier—to make it continuous.
Key Insight: Azure Policy’s compliance dashboard showing 100% is not a SOC 2 attestation. Azure Policy evaluates specific policy definitions. Controls involving HR processes, vendor management, security awareness training, and executive oversight require separate evidence and won’t appear in any dashboard—ever.
Prerequisites
If you want to follow along hands-on, you’ll need:
-
An Azure subscription with Owner or User Access Administrator rights—you’ll be assigning initiatives at subscription or management group scope, which requires this level of access or the Resource Policy Contributor role
-
The Azure CLI installed and authenticated (
az login) -
Microsoft Defender for Cloud enabled at the subscription level—assigning non-default regulatory compliance standards like SOC 2 requires at least one paid Defender plan; the free foundational tier only includes the default Microsoft Cloud Security Benchmark
-
A Microsoft Entra ID P2 or Entra ID Governance license for any subscription where you plan to use Privileged Identity Management and Access Reviews—this is not optional for PIM
Step 1: Assign the SOC 2 Type 2 Regulatory Compliance Initiative
Azure Policy’s built-in SOC 2 Type 2 Regulatory Compliance initiative maps dozens of policy definitions to specific Trust Services Criteria controls. Assigning this initiative is the foundation of your automated compliance posture—it tells Azure what to evaluate and surfaces violations in both the Policy compliance view and Defender for Cloud’s dashboard.
Assign the initiative at management group scope if you have multiple subscriptions under one Azure tenant. That single assignment cascades down and gives you a unified compliance view across your entire hierarchy without per-subscription repetition.
# Get your management group ID
az account management-group list --query "[].{Name:name, DisplayName:displayName}" -o table
# Assign the SOC 2 Type 2 initiative at management group scope
az policy assignment create \
--name "soc2-type2-compliance" \
--display-name "SOC 2 Type 2 Regulatory Compliance" \
--scope "/providers/Microsoft.Management/managementGroups/<your-mg-id>" \
--policy-set-definition "4054785f-702b-4a98-9215-009cbd58b141" \
--mi-system-assigned \
--location eastus
The --policy-set-definition GUID (4054785f-702b-4a98-9215-009cbd58b141) is the built-in SOC 2 Type 2 initiative. The --mi-system-assigned flag creates a system-assigned managed identity for the assignment, which is required for any policy definitions that use the DeployIfNotExists or Modify effects—those effects need an identity to make changes on your behalf.
After assignment, Azure Policy runs an initial compliance scan that begins within about five minutes of the assignment being applied. The compliance dashboard will show incomplete data while the scan is running. Don’t attempt to draw conclusions from it until the scan finishes.
If you prefer to assign at subscription scope instead:
az policy assignment create \ --name "soc2-type2-compliance" \ --display-name "SOC 2 Type 2 Regulatory Compliance" \ --scope "/subscriptions/<your-subscription-id>" \ --policy-set-definition "4054785f-702b-4a98-9215-009cbd58b141" \ --mi-system-assigned \ --location eastus
Enabling the Initiative in Defender for Cloud
Assigning the initiative via CLI makes it visible in Azure Policy’s compliance view, but you also need to add it explicitly to Defender for Cloud’s Regulatory Compliance dashboard. Enable it via the Microsoft Security REST API:
az rest --method PUT \
--url "https://management.azure.com/subscriptions/<sub-id>/providers/Microsoft.Security/regulatoryComplianceStandards/SOC%202%20Type%202?api-version=2019-01-01-preview" \
--body '{"properties":{"state":"Passed"}}'
If you prefer the portal, the same toggle is at Defender for Cloud > Regulatory Compliance > Manage compliance standards.
Once enabled, Defender for Cloud maps its security recommendations—powered by Azure Policy evaluations—to the specific SOC 2 controls those recommendations satisfy. A red circle on a control means resources are non-compliant. A greyed-out icon means the control can’t be assessed automatically and requires manual attestation, which is the honest acknowledgment that some SOC 2 requirements fall outside what any tool can evaluate.
Once the standard is active, the Regulatory Compliance dashboard becomes the single pane your auditor will care about — overall compliance score, breakdown by Trust Services Criteria, and the per-control state across every assessed resource:
[Image: images/defender-cloud-soc2-dashboard.png]Defender for Cloud’s Regulatory Compliance dashboard for the active SOC 2 Type 2 standard. Per-control breakdowns and resource counts are what auditors actually request.
Step 2: Configure Log Analytics for 365-Day Evidence Retention
A SOC 2 Type II audit covers a minimum of three months, with most organizations running six to twelve months. Your Log Analytics workspace needs to retain data for at least that long—auditors will request evidence from the beginning of the observation period. The Log Analytics workspace is where Azure sends diagnostic logs, policy compliance data, Defender security alerts, and Entra ID sign-in/audit logs. Everything your auditor will eventually ask for.
Create a dedicated workspace for compliance logs and set retention to 365 days:
# Create a Log Analytics workspace az monitor log-analytics workspace create \ --resource-group <your-rg-name> \ --workspace-name soc2-compliance-logs \ --location eastus \ --retention-time 365
The --retention-time flag sets the data retention period in days. The default is 30 days—far too short for a Type II audit. 365 days keeps the full observation window plus buffer.
Log Analytics uses two log tiers: Analytics logs (fully queryable, higher cost) and Basic logs (lower cost, queryable with KQL but limited to single-table queries, no joins, and a 30-day time range). For SOC 2 evidence purposes, keep your compliance-critical tables—AuditLogs, SigninLogs, SecurityAlert, AzureActivity—in Analytics tier. Less critical diagnostic data can use Basic logs to control costs.
Sending Entra ID Audit Logs to the Workspace
Entra ID’s audit and sign-in logs are the primary evidence source for identity-related SOC 2 controls. Route them to your Log Analytics workspace via Diagnostic Settings:
# Enable Entra ID diagnostic settings (requires Microsoft.Insights permissions)
az monitor diagnostic-settings create \
--name "entra-to-soc2-logs" \
--resource "/providers/microsoft.aadiam/diagnosticSettings" \
--workspace "/subscriptions/<sub-id>/resourceGroups/<rg-name>/workspaces/soc2-compliance-logs" \
--logs '[{"category":"AuditLogs","enabled":true},{"category":"SignInLogs","enabled":true},{"category":"RiskyUsers","enabled":true}]'
Once logs are flowing, you can query them directly. Here’s a KQL query auditors commonly request—all privileged role activations over the past 90 days:
AuditLogs
| where TimeGenerated >= ago(90d)
| where OperationName == "Add eligible member to role in PIM completed (permanent)"
or OperationName == "Add eligible member to role in PIM completed (timebound)"
or OperationName contains "Activate eligible assignment"
| extend ActivatedBy = tostring(InitiatedBy.user.userPrincipalName)
| extend TargetRole = tostring(TargetResources[0].displayName)
| project TimeGenerated, ActivatedBy, TargetRole, ResultDescription
| sort by TimeGenerated desc
Save this query—and the ones in the evidence section later—to your Log Analytics workspace as saved searches. Running ad-hoc queries when an auditor asks is a bad look. Having pre-built, named queries ready is a good one.
Pro Tip: The 30-day default retention period in Log Analytics is a compliance trap. If you create your workspace with the default and realize three months into an audit period that you have no logs from month one, there’s no recovery. Set retention to 365 days on day one, not after the audit window opens.
The retention timeline below is what an auditor’s request actually maps to: continuous evidence capture across the three log streams an auditor will pull from, with quarterly review checkpoints baked into the observation period:
[Image: images/soc2-evidence-retention-timeline.png]The three log streams that satisfy most SOC 2 evidence requests. Without 365-day retention configured up front, the leftmost months disappear before the auditor asks for them.
Step 3: Configure Entra ID and Privileged Identity Management
Under SOC 2 Trust Services Criteria CC6 (Logical and Physical Access Controls), you’re required to restrict access to authorized users and limit privileges to those necessary for assigned functions. Two Entra ID capabilities make this automated and auditable: Conditional Access for MFA enforcement and Privileged Identity Management (PIM) for just-in-time access.
Enforcing MFA with Conditional Access
Auditors expect MFA for all privileged access without exception. Create a Conditional Access policy that targets your administrative roles:
# Using Microsoft Graph API via Azure CLI
# Create a Conditional Access policy requiring MFA for directory roles
az rest --method POST \
--url "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" \
--body '{
"displayName": "SOC2-RequireMFA-AdminRoles",
"state": "enabled",
"conditions": {
"users": {
"includeRoles": [
"62e90394-69f5-4237-9190-012177145e10",
"194ae4cb-b126-40b2-bd5b-6091b380977d"
]
},
"applications": {
"includeApplications": ["All"]
}
},
"grantControls": {
"operator": "OR",
"builtInControls": ["mfa"]
}
}'
The role GUIDs above are Global Administrator and Security Administrator respectively. Extend this to include any other privileged roles in your scope. If you’re using Microsoft Entra Security Defaults, MFA is already enforced—but Conditional Access gives you more granular control that auditors will recognize as a mature implementation.
Configuring PIM for Just-in-Time Access
Privileged Identity Management (PIM) converts permanent role assignments into on-demand, time-limited activations. Instead of having 12 people with standing Global Administrator access, PIM makes them eligible for the role. They must request it, provide a justification (optionally tied to a ticket number), receive approval, and the access expires automatically after the configured window—typically one to eight hours.
Configure PIM role settings for your highest-privilege roles via the Microsoft Graph roleManagementPolicies API. First, retrieve the policy ID for the Global Administrator role:
# Get the role management policy for Global Administrator az rest --method GET \ --url "https://graph.microsoft.com/v1.0/policies/roleManagementPolicies?\$filter=scopeId eq '/' and scopeType eq 'DirectoryRole'"
Then patch the individual rules to enforce your SOC 2 requirements. There are three rule IDs to update: Expiration_EndUser_Assignment (max activation duration), Enablement_EndUser_Assignment (justification and MFA requirements), and Approval_EndUser_Assignment (approvers). For example, to set the maximum activation duration to 4 hours:
az rest --method PATCH \
--url "https://graph.microsoft.com/v1.0/policies/roleManagementPolicies/<policy-id>/rules/Expiration_EndUser_Assignment" \
--body '{
"@odata.type": "#microsoft.graph.unifiedRoleManagementPolicyExpirationRule",
"id": "Expiration_EndUser_Assignment",
"isExpirationRequired": true,
"maximumDuration": "PT4H"
}'
The same toggles are available in the portal under Identity Governance > Privileged Identity Management > Entra roles > Settings if you prefer to configure interactively before scripting.
Every activation, approval, denial, and deactivation is captured in PIM’s audit log, which flows to your Log Analytics workspace via the AuditLogs table. This gives you the IAM evidence that auditors request without any manual collection effort. The following table maps PIM features to the SOC 2 controls they satisfy:
| PIM Feature | SOC 2 Control | Evidence Generated |
|---|---|---|
| Eligible assignments (no standing access) | CC6.3 Least Privilege | Role assignment history in AuditLogs |
| Time-bound activation (1-8 hours) | CC6.3 Least Privilege | Activation/deactivation timestamps |
| Approval workflows + justification | CC6.1 Authorization | Approval records with justification text |
| MFA on activation | CC6.1 Multi-factor Auth | Authentication events in SignInLogs |
| Quarterly Access Reviews | CC6.2 Access Review | Review completion records |
Automating Access Reviews
Configure recurring Access Reviews for privileged roles on a quarterly schedule via the Microsoft Graph accessReviews API:
az rest --method POST \
--url "https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/definitions" \
--body '{
"displayName": "SOC2-Quarterly-PIM-Review",
"descriptionForAdmins": "Quarterly review of privileged role assignments for SOC 2 CC6.2",
"scope": {
"@odata.type": "#microsoft.graph.principalResourceMembershipsScope",
"principalScopes": [{"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/users", "queryType": "MicrosoftGraph"}],
"resourceScopes": [{"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/roleManagement/directory/roleAssignments?$filter=roleDefinitionId eq '\''62e90394-69f5-4237-9190-012177145e10'\''",
"queryType": "MicrosoftGraph"}]
},
"reviewers": [{"query": "/groups/<your-reviewers-group-id>/members", "queryType": "MicrosoftGraph"}],
"settings": {
"mailNotificationsEnabled": true,
"reminderNotificationsEnabled": true,
"justificationRequiredOnApproval": true,
"autoApplyDecisionsEnabled": true,
"defaultDecision": "Deny",
"defaultDecisionEnabled": true,
"recurrence": {
"pattern": {"type": "absoluteMonthly", "interval": 3},
"range": {"type": "noEnd", "startDate": "2025-01-01"}
}
}
}'
The defaultDecision: Deny setting auto-removes users who don’t respond—which is exactly what auditors want to see for CC6.2. The access review completion records export as a CSV from the portal. That file is audit evidence.
Step 4: Enforce Infrastructure Controls with Azure Policy
With the SOC 2 initiative assigned and your identity controls in place, you need preventative guardrails at the infrastructure layer. Azure Policy’s Deny effect blocks non-compliant resource deployments before they happen—this is a control, not just a detective alert.
Preventative Policy Assignments
The following policy assignments cover several high-priority SOC 2 controls around data protection and access surface reduction. Assign each using the built-in policy definition IDs:
# Require HTTPS-only on Storage Accounts (Confidentiality / CC6.7) az policy assignment create \ --name "require-https-storage" \ --display-name "Secure transfer to storage accounts should be enabled" \ --scope "/subscriptions/<sub-id>" \ --policy "404c3081-a854-4457-ae30-26a93ef643f9" # Deny public network access to Key Vault (CC6.6 - restrict external access) az policy assignment create \ --name "deny-keyvault-public-access" \ --display-name "Azure Key Vault should disable public network access" \ --scope "/subscriptions/<sub-id>" \ --policy "405c5871-3e91-4644-8a63-58e19d68ff5b" \ --enforcement-mode Default # Require FTPS only on App Services (Confidentiality / CC6.7) az policy assignment create \ --name "require-ftps-appservice" \ --display-name "App Service apps should require FTPS only" \ --scope "/subscriptions/<sub-id>" \ --policy "4d24b6d4-5e53-4a4f-a7f4-618fa573ee4b"
Three assignments, three controls satisfied. The Deny effect is the part auditors actually care about—Audit is a sticky note; Deny is a lock on the door.
Automated Remediation for Existing Resources
Policies with DeployIfNotExists or Modify effects can automatically remediate non-compliant resources that already exist. For example, enabling Transparent Data Encryption on SQL databases:
# Create a remediation task for SQL TDE (runs against existing non-compliant databases) az policy remediation create \ --name "remediate-sql-tde" \ --policy-assignment "soc2-type2-compliance" \ --definition-reference-id "SqlDbTransparentDataEncryption" \ --resource-discovery-mode ReEvaluateCompliance
--resource-discovery-mode ReEvaluateCompliance tells Azure to re-scan resources for non-compliance before remediating, rather than using a potentially stale compliance state. The remediation task runs using the managed identity you created in Step 1. Check its status:
az policy remediation show \ --name "remediate-sql-tde" \ --policy-assignment "soc2-type2-compliance"
Warning: Automated remediation tasks modify live resources. Test remediation policies against non-production subscriptions first. A remediation that disables public access on a storage account used by an undocumented legacy application will cause an outage. Use audit mode (--enforcement-mode DoNotEnforce) initially, review the list of affected resources, then switch to enforced mode after validating scope.
Step 5: Generate Auditor-Ready Evidence with KQL
Evidence collection is where most teams burn hours before an audit. Auditors will ask for specific records—who had access to what, when, for how long, and whether it was authorized. These KQL queries pull exactly what they need from your Log Analytics workspace.
Run these from the Logs blade in your Log Analytics workspace or from the Azure Monitor portal.
Policy Compliance State History
AzureActivity
| where TimeGenerated >= ago(90d)
| where OperationNameValue startswith "Microsoft.PolicyInsights"
| where ActivityStatusValue in ("Failed", "Success")
| extend PolicyDefinitionName = tostring(Properties_d.policyDefinitionName)
| extend ComplianceState = tostring(Properties_d.complianceState)
| summarize NonCompliantCount = countif(ComplianceState == "NonCompliant"),
CompliantCount = countif(ComplianceState == "Compliant")
by bin(TimeGenerated, 1d), PolicyDefinitionName
| where NonCompliantCount > 0
| project TimeGenerated, PolicyDefinitionName, NonCompliantCount, CompliantCount
| sort by TimeGenerated desc
Privileged Role Activations
AuditLogs | where TimeGenerated >= ago(90d) | where Category == "RoleManagement" | where OperationName contains "Activate" or OperationName contains "eligible assignment" | extend Requestor = tostring(InitiatedBy.user.userPrincipalName) | extend TargetRole = tostring(TargetResources[0].displayName) | extend Justification = tostring(AdditionalDetails[0].value) | project TimeGenerated, Requestor, TargetRole, Justification, ResultDescription | sort by TimeGenerated desc
MFA Status for Sign-ins
SigninLogs
| where TimeGenerated >= ago(90d)
| where UserType == "Member"
| extend MfaUsed = tostring(AuthenticationDetails[0].authenticationMethod)
| extend ConditionalAccessResult = tostring(ConditionalAccessStatus)
| summarize
TotalSignins = count(),
MfaCompleted = countif(MfaUsed != ""),
CAPolicyApplied = countif(ConditionalAccessResult == "success")
by UserPrincipalName, bin(TimeGenerated, 7d)
| sort by TimeGenerated desc
These queries give you structured data you can export to CSV or pipe into Excel for the evidence package. Auditors want timestamped records—not dashboard screenshots.
Step 6: Continuous Compliance with Enterprise Policy as Code (EPAC)
Assigning the SOC 2 initiative once and reviewing the dashboard periodically is not continuous compliance—it’s periodic compliance with optimistic assumptions. Enterprise Policy as Code (EPAC) is a Microsoft-supported open-source framework that treats policy assignments as version-controlled code, deployed through a CI/CD pipeline. Every policy change goes through a pull request, gets reviewed, and is deployed to your Azure environment automatically after approval.
Install EPAC
Install-Module -Name EnterprisePolicyAsCode -Force
Initialize an EPAC repository structure:
New-HydrationDefinitionsFolder -DefinitionsRootFolder "./Definitions"
Define the SOC 2 Assignment in Code
Create an assignment file at Definitions/policyAssignments/soc2-type2.jsonc:
{
"$schema": "https://raw.githubusercontent.com/Azure/enterprise-azure-policy-as-code/main/Schemas/policy-assignment-schema.json",
"nodeName": "/SOC2-Compliance/",
"definitionEntry": {
"initiativeName": "4054785f-702b-4a98-9215-009cbd58b141",
"displayName": "SOC 2 Type 2 Regulatory Compliance"
},
"children": [
{
"nodeName": "management-group-assignment",
"assignment": {
"name": "soc2-type2-compliance",
"displayName": "SOC 2 Type 2 - Automated Assignment",
"description": "Assigns SOC 2 Type 2 initiative for continuous compliance monitoring"
},
"scope": {
"tenant": [
"/providers/Microsoft.Management/managementGroups/<your-mg-id>"
]
},
"managedIdentity": {
"systemAssignedIdentity": true
}
}
]
}
GitHub Actions Pipeline
Create .github/workflows/epac-deploy.yml to automatically validate and deploy policy changes on every pull request:
name: EPAC Policy Deployment
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Build Deployment Plans
shell: pwsh
run: |
Install-Module EnterprisePolicyAsCode -Force
Build-DeploymentPlans `
-DefinitionsRootFolder "./Definitions" `
-OutputFolder "./output" `
-PacEnvironmentSelector "tenant"
deploy:
needs: plan
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
environment: production
steps:
- uses: actions/checkout@v3
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Deploy Policies
shell: pwsh
run: |
Install-Module EnterprisePolicyAsCode -Force
Deploy-PolicyPlan `
-DefinitionsRootFolder "./Definitions" `
-PacEnvironmentSelector "tenant"
The pipeline plan stage runs on every pull request—it validates proposed policy changes and outputs what would be deployed without actually deploying. The deploy stage runs only on merges to main, and the environment: production gate can be configured in GitHub to require a manual approval step. That approval is Segregation of Duties, which satisfies the SOC 2 CC8.1 change management control without any extra process overhead.
When an engineer proposes a change that would remove an encryption policy, the pull request shows exactly what would happen, a reviewer approves or rejects, and the commit history preserves the decision forever. That’s your change management evidence, automatically generated.
Common Pitfalls and How to Avoid Them
Most SOC 2 automation failures follow predictable patterns. These are the ones that consistently catch teams off guard.
Confusing “Compliant” with “Certified”: Azure Policy marking your subscription as 100% compliant with the SOC 2 Type 2 initiative means your technical controls pass the automated evaluations. It says nothing about your HR onboarding process, your security awareness training completion rates, your vendor risk assessments, or your incident response procedures. Auditors evaluate those separately and will ask for documentation you can’t generate from any Azure dashboard.
Missing the non-automatable controls: SOC 2 Common Criteria 1 covers the control environment—organizational structure, accountability, and ethical values. CC3 covers risk assessment processes. These are documented, manual-evidence controls. Start collecting that evidence (organizational charts, risk register, board meeting minutes if applicable) in parallel with the Azure automation work, not after.
Forgetting remediation managed identity permissions: When a policy with DeployIfNotExists triggers a remediation task, it runs as the managed identity you assigned at Step 1. That identity needs appropriate RBAC permissions at the remediation scope. If your remediation task is failing silently, check the identity’s role assignments:
az role assignment list \ --assignee <managed-identity-object-id> \ --output table
Setting Log Analytics retention after logs exist: Changing retention to 365 days applies going forward. If you created the workspace 60 days into your audit period with 30-day retention, you’ve lost the first 60 days of evidence permanently. Set retention on workspace creation.
Policy exemptions without audit trails: Sometimes a resource legitimately can’t comply with a policy—a legacy system that doesn’t support TLS 1.2, for example. Azure Policy supports exemptions with Waiver or Mitigated categories. Document exemptions in code as versioned JSON files in your EPAC repository, including the justification and expiration date. An unexamined exemption list that grows indefinitely is its own audit finding.
Wrapping Up
Automated SOC 2 Type II compliance on Azure isn’t a product you buy—it’s a system you build. The SOC 2 Type 2 Regulatory Compliance initiative gives you the control mapping. Log Analytics gives you the evidence store. PIM gives you the just-in-time access model auditors expect. Defender for Cloud gives you the visibility layer and the compliance exports. EPAC ties it all into a repeatable, version-controlled process where every change is reviewed, deployed consistently, and documented by default.
What you’re left with isn’t a compliance dashboard to screenshot before the audit—it’s a compliance posture that generates its own evidence continuously. That’s what the observation window—whether three months or twelve—actually requires.
The non-technical controls—your HR processes, vendor questionnaires, and security training—still need human ownership. But the Azure side? That can run on its own.