Manage Subscription Defender Settings¶
The engineer's guide to Microsoft Defender for Cloud on a vended subscription. Use this runbook to:
- Turn a paid Defender plan on or off for a subscription.
- Change where a subscription's security alerts go.
- Triage a Defender alert or a new recommendation.
- Stop a recommendation from counting against one resource.
For which plans to choose and why, see Defender Plans. To switch an MCSB control off for every subscription, see Manage MCSB Control Overrides.
Plans cost money per resource
Foundational CSPM is free. Every other plan is billed per protected resource (per VM-hour, per storage account, per vault). Before turning one on, check how many of that resource the subscription has, and say the expected monthly cost in the MR. Raise the budget in the same MR if needed.
What every subscription gets¶
| Setting | Set by | Value |
|---|---|---|
| Foundational CSPM | Vending (foundational_cspm, default on) |
On: Secure Score, recommendations, asset inventory |
| Security contact | Vending (security_contact_email) |
neil@grinntec.net, High severity and above, plus subscription Owners |
| Paid plans | Vending (defender_plans, default {}) |
None managed. Every plan stays at Azure's default, Free. |
| MCSB control overrides | azure-mcsb-overrides, nightly |
The by-design not-applicable controls, switched off |
EPAC's psa-sec-defender-001 at mg-intermediate-root audits that
Foundational CSPM is on and a security contact is set. It runs as
DoNotEnforce, so it reports drift but doesn't fix it. Vending is what
actually sets them.
The projects¶
| Project | Lane | Holds |
|---|---|---|
subscription-vending-workload |
B | defender_plans and security_contact_email in each workload subscription's <name>.tf. CI applies on merge. |
subscription-vending-platform |
A | The same inputs for platform subscriptions. You apply with ./apply.ps1. |
azure-governance-epac |
B | The audit initiative, and policy exemptions in Definitions/policyExemptions/grinntec/exemptions.jsonc. |
Turn a plan on¶
📁
subscription-vending-*: 📃<name>.tf
Add defender_plans with the plan's resource type as the key:
defender_plans = {
Arm = "on" # Defender for Resource Manager
KeyVaults = "on"
StorageAccounts = "on" # sub-plan DefenderForStorageV2
}
| Key | Plan | Sub-plan when on |
|---|---|---|
Arm |
Resource Manager | — |
KeyVaults |
Key Vault | — |
StorageAccounts |
Storage | DefenderForStorageV2 |
VirtualMachines |
Servers | P1 |
AppServices |
App Service | — |
SqlServers, SqlServerVirtualMachines, OpenSourceRelationalDatabases, CosmosDbs |
Databases | — |
Containers, ContainerRegistry, KubernetesService |
Containers | — |
Api, AI, Dns, CloudPosture |
APIs, AI, DNS, Defender CSPM (paid) | — |
Open an MR. The plan should show one azapi_update_resource.defender_plan
add per key, setting pricingTier = "Standard", and nothing else. Merge
(and for a platform subscription,
apply).
Servers is Plan 1 only
VirtualMachines = "on" always selects P1. Plan 2 (file integrity
monitoring, the vulnerability assessment add-ons) needs a change to
local.defender_subplans in the solution and a new release.
Expect the Secure Score to drop
A new plan brings recommendations that didn't count before. Mention it in the MR so the weekly governance report's drop isn't mistaken for a regression.
Turn a plan off¶
Set it to "off" first. Don't just delete the line.
Plans are Azure singletons: Terraform updates them but can't delete them.
Removing the key only stops Terraform managing the plan, and it stays on,
and billed, at whatever it was last set to. Apply with "off", and only
then remove the line if you want to.
"off" also holds the plan off: if someone turns it on in the portal, the
next apply turns it off again.
Change the security contact¶
Use a monitored team mailbox. The plan should show one in-place update
to azapi_resource.security_contact. The setting takes one address. Owners
of the subscription are also notified, but vended subscriptions have no
standing Owners, so in practice this address is the only one that gets the
alerts.
Triage an alert or recommendation¶
Security alert (from a paid plan, by email to the security contact):
- Open it from the email, or Defender for Cloud → Security alerts, filtered to the subscription.
- Read Affected resource, Activity start time and the Take action tab, which lists Defender's own mitigation steps.
- If it looks real, follow the incident response process. Don't delete or rebuild the resource before evidence is kept.
- If it's a known, expected activity (a pen test, a scheduled job), dismiss it with a reason, or create a suppression rule scoped to the resource and alert type, with an expiry date.
New recommendation (Secure Score dropped, or the weekly report flagged it):
- Defender for Cloud → Recommendations, filtered to the subscription.
- Open the recommendation and read Affected resources.
- Decide which applies:
| Situation | Do this |
|---|---|
| It can be fixed | Fix it in the workload's Terraform, not in the portal. |
| It can't be fixed yet for one resource | Exempt that resource, up to 90 days. |
| It can never apply under our operating model, anywhere | Manage MCSB Control Overrides. |
Exempt one resource¶
📁
azure-governance-epac: 📃Definitions/policyExemptions/grinntec/exemptions.jsonc
Add one entry, scoped as narrowly as possible, with an expiry no more than 90 days out:
{
"name": "exm-sec-mcsb-st-payments-001",
"displayName": "MCSB waiver - st-payments-export public network access",
"description": "Export account needs a public endpoint until the partner's private link is live (GRIN-1234).",
"exemptionCategory": "Waiver",
"expiresOn": "2027-01-15",
"scope": "/subscriptions/<sub-id>/resourceGroups/rg-payments-prod/providers/Microsoft.Storage/storageAccounts/stpaymentsexport",
"policyAssignmentId": "psa-sec-mcsb-001",
"policyDefinitionReferenceIds": [ "<policyDefinitionReferenceId>" ],
"metadata": {
"requestedBy": "someone@grinntec.net",
"approvedBy": "neil@grinntec.net",
"ticket": "GRIN-1234"
}
}
A CODEOWNER other than you approves the MR. The full rules are in the EPAC
repo's Definitions/policyExemptions/README.md.
An EPAC exemption covers the compliance dashboard only
psa-sec-mcsb-001 feeds the regulatory compliance dashboard. Defender's
own Secure Score comes from SecurityCenterBuiltIn on the subscription,
which EPAC doesn't manage. To take one resource out of the Secure Score
as well, use Exempt on the recommendation in Defender for Cloud, with
the same expiry and reason as the EPAC entry.
Check it worked¶
# Plans on the subscription
az security pricing list --subscription <sub-id> \
--query "value[?pricingTier=='Standard'].{plan:name, subPlan:subPlan}" -o table
# Security contact
az rest --method get \
--url "https://management.azure.com/subscriptions/<sub-id>/providers/Microsoft.Security/securityContacts?api-version=2020-01-01-preview" \
--query "value[].properties.emails"
In the portal: Defender for Cloud → Environment settings →
When it fails¶
| Symptom | Cause | Fix |
|---|---|---|
404 Subscription Not Registered on Microsoft.Security/pricings |
Microsoft.Security registration hadn't finished on a new subscription |
Re-run the pipeline. Registration is idempotent. |
| Plan removed from the file but the subscription still shows it on, and billed | The key was deleted instead of set to "off" |
Add it back as "off", apply, then remove it. |
| A plan someone turned on in the portal keeps turning off | The subscription file holds it "off" |
Intended. Turn it on in code. |
psa-sec-defender-001 shows the subscription non-compliant |
The plan or contact was changed outside Terraform, or foundational_cspm = "off" |
Re-run the pipeline on main to restore it. Find who changed it in the Activity Log. |
| Secure Score still counts an EPAC-exempted resource | EPAC exemptions don't reach SecurityCenterBuiltIn |
Exempt it in Defender for Cloud as well (see above). |