Security Azure

Operationalizing Microsoft Defender for Cloud: CSPM, Secure Score, and Workload Protection

Most organizations “have Defender for Cloud” the way they have a smoke detector with the battery removed: it is enabled, the dashboard is green-ish, and nobody can tell you whether last month’s posture was better or worse than this month’s. This article is about closing that gap. We will treat Defender for Cloud as a program with owners, SLAs, enforcement, and a number that goes up.

1. Foundation vs Defender CSPM: know what you are actually paying for

Defender for Cloud ships two posture tiers. Foundational CSPM is free and always on once the subscription is registered with Microsoft.Security. It gives you Secure Score, the recommendation engine, asset inventory, and Azure Policy-based assessments. Defender CSPM is a paid plan that unlocks the parts that actually let you hunt risk: agentless machine scanning (vulnerabilities, secrets, software inventory without an agent), the cloud security graph, attack path analysis, and the cloud security explorer.

The distinction matters because the free tier tells you what is misconfigured while the paid tier tells you which misconfiguration is reachable from the internet and lands on a VM with a domain admin token. That second sentence is the whole reason to operationalize this.

Enable the foundation everywhere first. Register the provider and confirm auto-provisioning intent before turning on paid plans.

# Register the resource provider (idempotent)
az provider register --namespace Microsoft.Security

# Confirm Defender for Cloud sees the subscription
az security pricing list --query "value[].{plan:name, tier:pricingTier}" -o table

Then enable the Defender CSPM plan at the subscription scope. The plan name in the pricing API is CloudPosture.

az security pricing create \
  --name CloudPosture \
  --tier Standard

Callout: Defender CSPM and the workload plans are billed per subscription. Use Azure Policy at the management-group scope (Section 4) to enable them so new subscriptions inherit protection instead of joining the estate naked.

2. Workload protection plans: enable them deliberately, not reflexively

The workload plans are runtime threat detection (the “Defender for X” alerts), distinct from CSPM’s posture work. Turn on what maps to real assets. Here is what each plan earns its keep on:

Plan (az security pricing name) Protects Representative detections
VirtualMachines IaaS + Arc servers Fileless attacks, suspicious process trees, crypto-mining, reverse shells
StorageAccounts Blob/Files Malware upload (hash + on-upload scan), anomalous access, public exposure of containers
Containers AKS, Arc-enabled K8s, ACR Image vuln findings, runtime threats (crypto-miner pods), exposed Kubernetes dashboard
SqlServers / SqlServerVirtualMachines Azure SQL, SQL on VM SQL injection, brute force, anomalous data exfiltration
KeyVaults Key Vault Anomalous secret access, access from suspicious IPs/Tor, unusual app identity bursts
Api API Management OWASP-class abuse, anomalous traffic, exposure of sensitive endpoints

Enable the set you need in one pass:

for plan in VirtualMachines StorageAccounts Containers SqlServers KeyVaults; do
  az security pricing create --name "$plan" --tier Standard
done

For Defender for Servers specifically, choose the sub-plan. Plan 2 adds agentless scanning, file integrity monitoring, and just-in-time VM access; Plan 1 is core EDR integration only. Set it with the sub-plan property:

az security pricing create \
  --name VirtualMachines \
  --tier Standard \
  --subplan P2

Defender for Servers integrates Microsoft Defender for Endpoint automatically; you do not deploy MDE separately on Azure/Arc VMs once Plan 1 or 2 is on. Confirm the auto-provisioning of the required components after enabling.

3. Read Secure Score correctly: it is a percentage, not a leaderboard

Secure Score is the single most misused metric in Azure security. Two facts change how you use it:

  1. It is weighted, not a raw count. Each security control carries a maximum point value (the published “max score”). Your score for a control is (healthy resources / total resources) * max points. Remediating one recommendation inside a heavily weighted control (e.g., “Enable MFA”) moves the needle far more than clearing fifty findings in a 1-point control.
  2. Recommendations roll up into controls; controls roll up into the score. Chasing individual recommendation counts is how teams burn a sprint and move the score by 0.4%.

Pull the current score and the per-control breakdown via the REST API (the CLI surface here is thin, so query directly):

SUB=$(az account show --query id -o tsv)

# Overall secure score
az rest --method get \
  --url "https://management.azure.com/subscriptions/$SUB/providers/Microsoft.Security/secureScores/ascScore?api-version=2020-01-01" \
  --query "properties.score"

# Per-control contribution, sorted by points you are leaving on the table
az rest --method get \
  --url "https://management.azure.com/subscriptions/$SUB/providers/Microsoft.Security/secureScores/ascScore/secureScoreControls?api-version=2020-01-01&\$expand=definition" \
  --query "sort_by(value[].{control:properties.displayName, current:properties.score.current, max:properties.score.max, gap:properties.score.max}[?max>\`0\`], &gap)" -o table

The correct prioritization is not “highest count” or even “highest max points” in isolation. It is points-at-risk weighted by exploitability. A control worth 6 points where the unhealthy resource sits on an internet-facing attack path beats a 10-point control buried behind three network hops with no public exposure. That is exactly what attack paths (Section 6) let you decide.

4. Drive remediation at scale with Azure Policy, not tickets

Manual remediation does not survive contact with a real estate. Defender for Cloud is built on Azure Policy: every assessment maps to a policy definition inside the Microsoft cloud security benchmark (MCSB) initiative. You get leverage three ways: assign initiatives broadly, use deny to stop drift at the source, and use remediation tasks to fix what already exists.

Assign the benchmark at the management group scope

Assign at the highest scope that makes sense so new subscriptions inherit it. The MCSB is the default initiative Defender uses to compute Secure Score.

# The built-in Microsoft cloud security benchmark initiative
MCSB="/providers/Microsoft.Authorization/policySetDefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8"

az policy assignment create \
  --name "mcsb-mg-root" \
  --display-name "Microsoft cloud security benchmark" \
  --policy-set-definition "$MCSB" \
  --scope "/providers/Microsoft.Management/managementGroups/contoso-root" \
  --location eastus \
  --mi-system-assigned

The managed identity is required because deployIfNotExists and modify policies need permissions to act. Grant it the appropriate role at the assignment scope (the policy definitions declare the roles they need; for the MCSB, Contributor at the assigned scope is the simplest correct grant).

Use deny effects to stop the bleeding

Posture improves fastest when you stop creating new violations. Pick the handful of policies that map to your worst recurring findings and assign them with the Deny effect via a parameter override. Example: deny storage accounts that allow public blob access.

# Built-in: Storage account public access should be disallowed
POLICY="/providers/Microsoft.Authorization/policyDefinitions/4fa4b6c0-31ca-4c0d-b10d-24b96f62a751"

az policy assignment create \
  --name "deny-storage-public" \
  --policy "$POLICY" \
  --scope "/providers/Microsoft.Management/managementGroups/contoso-root" \
  --params '{ "effect": { "value": "Deny" } }'

Callout: Roll out deny in audit mode first. Set the effect to Audit, watch the compliance results for a sprint to find the legitimate exceptions, encode those as policy exemptions, then flip to Deny. Flipping straight to Deny on a live estate is how you become the reason a deployment pipeline is red at 2 a.m.

Bulk-remediate existing resources

For deployIfNotExists/modify policies, create a remediation task to sweep resources that already violate the rule (new assignments only auto-remediate going forward).

az policy remediation create \
  --name "remediate-diag-settings" \
  --policy-assignment "mcsb-mg-root" \
  --definition-reference-id "deployDiagnosticSettings" \
  --resource-discovery-mode ReEvaluateCompliance

Many Defender recommendations also expose a one-click “Fix” in the portal that wires this up for you; for scale and auditability, prefer declaring it in IaC so the remediation is reviewable in a PR.

5. Regulatory compliance: map to standards and export the evidence

The Regulatory compliance dashboard projects your assessments onto named standards. MCSB is on by default. Add the ones your auditors care about; common built-in standards include CIS Microsoft Azure Foundations, NIST SP 800-53, and PCI DSS. You add a standard by assigning its policy initiative (Defender surfaces it on the compliance dashboard automatically once assigned), or directly from the dashboard’s “Manage compliance policies”.

# Example: assign a CIS Azure Foundations initiative at a subscription scope.
# Resolve the exact definition ID for the version your auditor requires:
az policy set-definition list \
  --query "[?contains(displayName, 'CIS Microsoft Azure Foundations')].{name:displayName, id:name}" -o table

The operational win is exporting evidence on a schedule rather than screenshotting the dashboard during an audit. Two durable patterns:

For programmatic evidence, query assessment state from the workspace once continuous export is flowing. The data lands in the SecurityRecommendation and SecurityRegulatoryCompliance tables (Sentinel/Log Analytics), which you can pin to a workbook your auditors get read access to.

6. Investigate attack paths and hunt with the cloud security explorer

This is where Defender CSPM stops being a checklist. The cloud security graph ingests resource configuration, network reachability, identities, and agentless scan findings (vulnerabilities, exposed secrets) into a single graph. Attack paths are pre-computed, ranked chains through that graph: “Internet-exposed VM with a high-severity CVE has a managed identity with write access to a Key Vault holding a storage key.” Each path comes with a risk level and the exact remediation that breaks the chain.

Triage attack paths before raw recommendations. Breaking one path often clears the single recommendation that matters across a dozen low-value findings.

The cloud security explorer lets you query the graph ad hoc, KQL-style but graph-shaped, in the portal. High-value hunting queries to standardize on:

Pull the attack-path inventory programmatically to feed your risk register:

SUB=$(az account show --query id -o tsv)

az rest --method get \
  --url "https://management.azure.com/subscriptions/$SUB/providers/Microsoft.Security/attackPaths?api-version=2023-11-01-preview" \
  --query "value[].{name:properties.displayName, risk:properties.riskLevel}" -o table

Callout: Attack paths require the Defender CSPM plan (Section 1) and agentless scanning to be active. If your attack-paths list is empty on a busy subscription, check that agentless scanning provisioned, not that you have nothing to fix.

7. Continuous export and governance rules with owner SLAs

A finding nobody owns is a finding nobody fixes. Two mechanisms turn Defender into a closed loop.

Continuous export to Sentinel / Event Hub

Stream recommendations, alerts, secure score, and compliance data out continuously. Use Event Hub when you have a SIEM other than Sentinel or need fan-out; use the Log Analytics workspace target when Sentinel is your SIEM. Configure it as an automation resource so it is reviewable in IaC:

resource export 'Microsoft.Security/automations@2019-01-01-preview' = {
  name: 'export-to-sentinel'
  location: location
  properties: {
    isEnabled: true
    scopes: [
      { scopePath: subscription().id }
    ]
    actions: [
      {
        actionType: 'Workspace'
        workspaceResourceId: logAnalyticsWorkspaceId
      }
    ]
    sources: [
      { eventSource: 'Assessments' }
      { eventSource: 'Alerts' }
      { eventSource: 'SecureScores' }
      { eventSource: 'RegulatoryComplianceAssessment' }
    ]
  }
}

The native Microsoft Defender for Cloud data connector in Sentinel also pulls alerts; continuous export is what gets you the posture data (assessments, secure score, compliance) for trend analysis, not just the alerts.

Governance rules: assign owners and SLAs to recommendations

Governance rules (a Defender CSPM feature) auto-assign an owner and a due date to recommendations matching a filter, and can notify owners and their managers on overdue items. This is the difference between a backlog and a program. Build rules like:

Configure governance rules in the portal under Environment settings; they emit an Unassigned/Overdue status you can export and report on. Pair them with the continuous export above so the SLA breach shows up in Sentinel, not just in a UI nobody opens.

Enterprise scenario

A retail platform team I worked with flipped on Defender CSPM across a 140-subscription estate and immediately tried to “Fix” their way down the recommendation list. Secure score barely moved, and Finance flagged a five-figure spend jump. Two things had gone wrong. First, they had enabled CloudPosture per subscription by hand, so the dozen subscriptions onboarded that quarter were unprotected and silently dragging the org score. Second, agentless scanning had never provisioned because a pre-existing deny policy on the management group blocked the scanner’s snapshot disks in a restricted region, so the attack-paths blade was empty on their busiest workloads. They were optimizing a number computed over a graph that did not exist.

The fix was to stop clicking and move enablement to policy at the MG root, then exempt the scanner’s resource group from the offending deny so snapshots could be created.

# Enable Defender CSPM estate-wide via the built-in DINE policy at the MG root
az policy assignment create \
  --name "enable-cspm-mg" \
  --policy "/providers/Microsoft.Authorization/policyDefinitions/689f7782-ef2c-4270-a6d0-7664869076bd" \
  --scope "/providers/Microsoft.Management/managementGroups/contoso-root" \
  --location eastus --mi-system-assigned

# Carve the agentless scanner out of the blocking deny so snapshots provision
az policy exemption create \
  --name "allow-defender-scanner-snapshots" \
  --policy-assignment "deny-snapshots-restricted-region" \
  --exemption-category Mitigated \
  --scope "/subscriptions/$SCANNER_SUB/resourceGroups/DefenderForCloud-Scanner"

Within a week attack paths populated, three internet-exposed chains surfaced that no single recommendation had ranked, and the score climbed once new subscriptions inherited the plan instead of joining the estate naked.

Verify

Confirm the program is actually wired, not just toggled.

SUB=$(az account show --query id -o tsv)

# 1. CSPM + workload plans are Standard
az security pricing list \
  --query "value[?pricingTier=='Standard'].name" -o tsv

# 2. Secure score is being computed (returns a number 0-100)
az rest --method get \
  --url "https://management.azure.com/subscriptions/$SUB/providers/Microsoft.Security/secureScores/ascScore?api-version=2020-01-01" \
  --query "properties.score.percentage"

# 3. The MCSB assignment exists at the management group
az policy assignment list \
  --scope "/providers/Microsoft.Management/managementGroups/contoso-root" \
  --query "[?displayName=='Microsoft cloud security benchmark'].name" -o tsv

# 4. Continuous export automation is enabled
az rest --method get \
  --url "https://management.azure.com/subscriptions/$SUB/providers/Microsoft.Security/automations?api-version=2019-01-01-preview" \
  --query "value[].{name:name, enabled:properties.isEnabled}" -o table

In the portal, confirm: Attack paths shows ranked chains (proves the graph and agentless scanning are live), Regulatory compliance shows your assigned standards with passing/failing controls, and at least one governance rule shows assigned owners with due dates.

Operational checklist

Measuring success: drift detection and a monthly cadence

A posture program is a trend line, not a snapshot. Because continuous export retains secure score and assessment history, you can detect drift the moment it happens: a sudden drop in a control’s healthy-resource ratio means someone deployed around your guardrails (and tells you which deny policy you still need to promote out of audit mode). Build a Sentinel/Log Analytics query that alerts when secure score drops more than N points week-over-week, or when a previously-zero attack-path category becomes non-empty.

Run a monthly posture review with a fixed agenda: secure score delta vs last month, attack paths opened/closed, governance SLA breaches by owner, new Deny candidates from audit-mode findings, and compliance control regressions. The meeting’s output is a short list of policy changes and ownership reassignments, not admiration of the dashboard.

Pitfalls to avoid

Defender for CloudCSPMSecure ScoreAzure PolicyCompliancePosture

Comments

Keep Reading