Setup guide
Everything you must provision before this skill can run โ the exact credentials, permissions, and where to click. Links go to the official consoles and docs, which stay current.
Provision an Azure AD (Entra ID) service principal that holds Owner or an equivalent role-bundle at the Tenant Root Management Group, register the Microsoft.Management / Microsoft.PolicyInsights / Microsoft.Security / Microsoft.CostManagement resource providers, install Azure CLI with the resource-graph and costmanagement extensions, and export the tenant, subscription and Entra group object IDs the skill's commands interpolate.
You need to already have
- An Entra ID Global Administrator willing to run the one-time elevateAccess call and then de-elevate โ without root-scope access the management-group hierarchy in step 2 cannot be created
- Owner (or Management Group Contributor + Resource Policy Contributor + User Access Administrator) at the Tenant Root Management Group for the identity that runs the skill
- At least one subscription designated as the platform/management subscription, in Enabled state, for the Log Analytics workspace and cost-export storage account
- Enterprise Agreement (EA) or Microsoft Customer Agreement (MCA) billing scope if Cost Management scheduled exports are in play โ exports are not offered on all pay-as-you-go/CSP scopes
- Azure CLI 2.60+ installed, plus 'az extension add -n resource-graph' and 'az extension add -n costmanagement'
- Entra ID P2 licensing only if standing write access is to be made PIM-eligible as the skill recommends
- Terraform 1.6+ with the hashicorp/azurerm provider ~> 4.20 if the reference implementation is used instead of raw az commands
How the pieces connect
Credentials this skill needs
Set these as environment variables. Never paste secrets into a chat or commit them.
| Variable | What it is | Where to get it |
|---|---|---|
AZURE_TENANT_ID | Entra ID tenant (directory) ID format: GUID | Microsoft Entra admin center > Identity > Overview > Tenant ID (copy button), or run 'az account show --query tenantId -o tsv' |
AZURE_CLIENT_ID | Service principal application (client) ID format: GUID | Microsoft Entra admin center > Applications > App registrations > <your app> > Overview > Application (client) ID |
AZURE_CLIENT_SECRETsecret | Service principal client secret value format: Opaque string, typically 40 chars starting with a short prefix; copy the Value column, never the Secret ID | Microsoft Entra admin center > Applications > App registrations > <your app> > Certificates & secrets > Client secrets > New client secret > copy the Value immediately (it is never shown again). A certificate under the Certificates tab is the preferred alternative for long-lived automation. |
AZURE_SUBSCRIPTION_ID | Default subscription for CLI context format: GUID | Azure portal > Subscriptions > <subscription> > Overview > Subscription ID, or 'az account list --all --query "[].{n:name,id:id}" -o table' |
TENANT_ID | Tenant root management group ID (same GUID as the tenant ID) format: GUID | The Tenant Root Group's name IS the tenant GUID. Azure portal > Management groups > the top row named 'Tenant Root Group', or 'az account management-group list --query "[?properties.details==null].name" -o tsv'. The skill interpolates this into --parent "$TENANT_ID" and into the hierarchy-settings REST URL. |
SUB_ID | Target subscription ID for Defender plans, budgets, diagnostic settings and cost exports format: GUID | Azure portal > Subscriptions > <subscription> > Overview > Subscription ID |
SUB_MGMT_ID | Platform/management subscription ID moved under mg-alz-platform format: GUID | Azure portal > Subscriptions > pick the subscription hosting the Log Analytics workspace > Overview > Subscription ID |
GRP_PLATFORM_OID | Entra security group object ID for platform operators format: GUID (directory object ID, not the group's display name) | Microsoft Entra admin center > Identity > Groups > All groups > <group> > Overview > Object Id. The skill passes it to 'az role assignment create --assignee-object-id ... --assignee-principal-type Group' precisely so no Microsoft Graph read permission is needed. |
BREAKGLASS_OID | Break-glass principal object ID excluded from deployment-stack deny settings format: GUID (directory object ID of the emergency-access account or group) | Microsoft Entra admin center > Identity > Users > <emergency access account> > Overview > Object ID (or the Groups blade for a break-glass group) |
SA_IDoptional | Storage account ARM resource ID that receives Cost Management exports format: ARM resource ID: /subscriptions/{guid}/resourceGroups/{rg}/providers/Microsoft.Storage/storageAccounts/{name} | Azure portal > Storage accounts > <account> > Settings > Endpoints (or JSON View > id), or 'az storage account show -g RG -n NAME --query id -o tsv' |
ARM_CLIENT_SECRETsecretoptional | Same client secret, under the name the Terraform azurerm provider reads format: Opaque string (identical value to AZURE_CLIENT_SECRET) | Only needed for the Terraform reference implementation. The azurerm provider reads ARM_CLIENT_ID, ARM_CLIENT_SECRET, ARM_TENANT_ID and ARM_SUBSCRIPTION_ID โ mirror the AZURE_* values into the ARM_* names before 'terraform plan'. |
Permissions to grant
Global AdministratorEntra ID directory roleadmin consent requiredRequired once to POST to /providers/Microsoft.Authorization/elevateAccess, which grants the caller User Access Administrator at the Tenant Root Group so the mg-alz hierarchy can be created at all.
โณ Activate the role through PIM for the shortest possible window, run elevateAccess, assign the durable roles below to the automation principal, then call DELETE on /providers/Microsoft.Authorization/elevateAccess to de-elevate.
OwnerIAM roleadmin consent requiredSimplest single role that covers creating management groups, policy assignments with managed identities, role assignments, workspaces, Defender pricings and budgets at the mg-alz scope.
โณ Replace with the four narrower roles below โ Management Group Contributor, Resource Policy Contributor, User Access Administrator and Security Admin โ assigned at mg-alz rather than at the Tenant Root Group.
Management Group ContributorIAM roleadmin consent requiredCreates, renames and reparents mg-alz / mg-alz-platform / mg-alz-lz / mg-alz-corp / mg-alz-sandbox and moves subscriptions between them.
โณ Management Group Reader is enough for the audit-only path where the hierarchy already exists and the skill is only reading compliance state.
Resource Policy ContributorIAM roleadmin consent requiredCreates the MCSB and tag policy assignments, remediation tasks and time-bounded policy exemptions at management-group scope.
โณ Policy Insights Data Writer (Preview) plus Reader suffices if the skill is only triggering scans and reading compliance rather than assigning policy.
User Access AdministratorIAM roleadmin consent requiredCreates the role assignments that back DeployIfNotExists/Modify managed identities and grants Contributor to the platform Entra group โ without it every remediation silently no-ops.
โณ Role Based Access Control Administrator (f58310d9-a9f6-439a-9e8d-f62e7b41a168) grants roleAssignments/write without the broad data-plane reach of User Access Administrator; prefer it and scope it to mg-alz.
Security AdminIAM roleadmin consent requiredSets Microsoft Defender for Cloud pricing tiers and subplans per subscription and writes the default security contact.
โณ Security Reader is sufficient for 'az security pricing list' and 'az security secure-scores list' during an audit-only run.
Log Analytics ContributorIAM roleCreates law-platform-eastus with retention and daily quota, and switches high-volume tables such as ContainerLogV2 to the Basic plan.
โณ Log Analytics Reader is enough to run the Usage KQL query that sizes ingestion before any change is made.
Monitoring ContributorIAM roleCreates the subscription-level diagnostic setting that ships Administrative, Security, Policy, ServiceHealth, ResourceHealth and Alert activity logs to the workspace.
โณ Monitoring Reader covers verification-only runs that just confirm the diagnostic setting exists.
Cost Management ContributorIAM roleCreates the monthly budget with actual and forecasted notification thresholds and the daily amortized cost export.
โณ Cost Management Reader is enough to read existing budgets and exports during an assessment.
Tag ContributorIAM roleadmin consent requiredGranted to the inherit-costcenter policy assignment's system-assigned managed identity via --role "Tag Contributor" --identity-scope so the Modify effect can actually write the costCenter tag.
โณ This is already the least-privileged role for tag remediation โ do not substitute Contributor, which the skill only uses for the broader MCSB initiative.
ReaderIAM roleBacks 'az graph query --management-groups mg-alz' โ Azure Resource Graph returns only resources the caller can already read, so a missing Reader assignment shows up as an empty result set rather than an error.
โณ Assign at mg-alz so it inherits to every child subscription instead of assigning per subscription.
https://management.azure.com/.defaultAPI scopeThe OAuth2 scope the service principal token is issued for; every az and Terraform call in this skill targets the Azure Resource Manager audience. No Microsoft Graph scope is required because the skill passes raw object IDs instead of resolving principals by name.
Step by step
- 1
Install Azure CLI and the two extensions the skill calls
Install Azure CLI 2.60 or later, then run: az extension add -n resource-graph --upgrade && az extension add -n costmanagement --upgrade. Confirm with 'az version' and 'az extension list -o table'. The skill's Resource Graph and cost-export steps fail with 'az: error: argument _subcommand: invalid choice' if these are missing.
Open in the console / docs โ - 2
Register the app and create the service principal
Microsoft Entra admin center > Applications > App registrations > New registration. Name it (for example alz-governance-automation), choose 'Accounts in this organizational directory only', leave the redirect URI blank, Register. From Overview copy Application (client) ID and Directory (tenant) ID. Then Certificates & secrets > Client secrets > New client secret, set an expiry of 6-12 months, and copy the Value column immediately.
Open in the console / docs โ - 3
Elevate a Global Administrator to the Tenant Root Group, once
As the Global Administrator, run: az rest --method post --url "https://management.azure.com/providers/Microsoft.Authorization/elevateAccess?api-version=2016-07-01". This grants that account User Access Administrator at /providers/Microsoft.Management/managementGroups/{tenantId}. Equivalent portal path: Microsoft Entra admin center > Identity > Overview > Properties > Access management for Azure resources > toggle to Yes. Revoke afterwards with the DELETE on the same URL.
Open in the console / docs โ - 4
Assign the durable roles to the service principal at root scope
Still elevated, run: az role assignment create --assignee-object-id $(az ad sp show --id "$AZURE_CLIENT_ID" --query id -o tsv) --assignee-principal-type ServicePrincipal --role Owner --scope "/providers/Microsoft.Management/managementGroups/$TENANT_ID". For least privilege repeat the command with --role "Management Group Contributor", "Resource Policy Contributor", "Role Based Access Control Administrator", "Security Admin", "Log Analytics Contributor", "Monitoring Contributor" and "Cost Management Contributor" instead of Owner. Role assignments at management-group scope can take several minutes to propagate.
Open in the console / docs โ - 5
Register the resource providers on every in-scope subscription
For each subscription run: az account set -s "$SUB_ID" && for ns in Microsoft.Management Microsoft.PolicyInsights Microsoft.Security Microsoft.OperationalInsights Microsoft.Insights Microsoft.CostManagement Microsoft.ResourceGraph; do az provider register -n "$ns"; done. Check progress with 'az provider list --query "[?registrationState!='\''Registered'\''].namespace" -o table'. Registration is asynchronous and can take a few minutes.
Open in the console / docs โ - 6
Sign the automation identity in and confirm root-scope visibility
Run: az login --service-principal -u "$AZURE_CLIENT_ID" -p "$AZURE_CLIENT_SECRET" --tenant "$AZURE_TENANT_ID", then az account set -s "$AZURE_SUBSCRIPTION_ID", then az account management-group list -o table. A single row means the identity still lacks root-scope access โ go back to the elevateAccess and role-assignment steps. This is the exact check the skill performs in its Inputs section.
Open in the console / docs โ - 7
Collect the object IDs and subscription IDs the commands interpolate
Export TENANT_ID (Azure portal > Management groups > Tenant Root Group, whose name is the tenant GUID), SUB_ID and SUB_MGMT_ID from 'az account list --all --query "[].{n:name,id:id,s:state}" -o table', GRP_PLATFORM_OID from Microsoft Entra admin center > Groups > <group> > Overview > Object Id, and BREAKGLASS_OID from the emergency-access account's Overview blade. Set SA_ID only if Cost Management exports are being created.
Open in the console / docs โ - 8
Confirm the billing scope supports budgets and scheduled exports
Azure portal > Cost Management + Billing > Cost Management > select the scope > Budgets / Exports. Scheduled exports and management-group budgets require an Enterprise Agreement or Microsoft Customer Agreement scope; on unsupported offers the Exports blade is absent and the PUT on Microsoft.CostManagement/exports is rejected. Verify before promising the cost-export step.
Open in the console / docs โ - 9
Mirror the credentials into ARM_* if using the Terraform reference implementation
export ARM_CLIENT_ID="$AZURE_CLIENT_ID"; export ARM_CLIENT_SECRET="$AZURE_CLIENT_SECRET"; export ARM_TENANT_ID="$AZURE_TENANT_ID"; export ARM_SUBSCRIPTION_ID="$SUB_MGMT_ID". The azurerm 4.x provider requires subscription_id to be set explicitly (in the provider block or via ARM_SUBSCRIPTION_ID) โ it no longer falls back to the CLI's default subscription.
Open in the console / docs โ - 10
Take the pre-change snapshots before the skill writes anything
Run the four snapshot commands from the skill's Procedure step 1 โ az account management-group list, az policy assignment list --disable-scope-strict-match, az role assignment list --all --include-inherited, az security pricing list โ redirecting each to JSON. These are the only rollback evidence for a governance change and must exist before the first write.
Open in the console / docs โ
Check it worked
az rest --method get --url "https://management.azure.com/providers/Microsoft.Management/managementGroups?api-version=2021-04-01" --query "value[].{id:name,display:properties.displayName}" -o tableIf you hit an error
AuthorizationFailed: The client '<appId>' with object id '<oid>' does not have authorization to perform action 'Microsoft.Management/managementGroups/write' over scope '/providers/Microsoft.Management/managementGroups/<tenantId>'Cause: The service principal has roles on subscriptions but nothing at the Tenant Root Group, so it can list its own subscriptions yet cannot create the mg-alz hierarchy.
Fix: Have a Global Administrator run the elevateAccess POST, then assign Owner (or Management Group Contributor) to the principal at /providers/Microsoft.Management/managementGroups/$TENANT_ID and wait a few minutes for propagation.
AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a client secret added to app '<appId>'.Cause: The Secret ID column was copied from Certificates & secrets instead of the Value column, or the secret expired.
Fix: Create a new client secret and copy the Value immediately; it is only displayed once. Re-export AZURE_CLIENT_SECRET and ARM_CLIENT_SECRET.
MissingSubscriptionRegistration: The subscription is not registered to use namespace 'Microsoft.PolicyInsights'.Cause: Resource provider registration was skipped for that subscription, so policy-state and remediation calls are rejected even though RBAC is correct.
Fix: Run 'az provider register -n Microsoft.PolicyInsights' (and the same for Microsoft.Security, Microsoft.OperationalInsights, Microsoft.CostManagement) on every subscription in scope and wait for registrationState to reach Registered.
PrincipalNotFound: Principal <objectId> does not exist in the directory <tenantId>.Cause: Entra replication lag โ the role assignment for a policy assignment's freshly created system-assigned managed identity is attempted before the service principal has propagated across the directory.
Fix: Retry the role assignment after 30-60 seconds. In Terraform this shows up on first apply of azurerm_role_assignment.mcsb_msi; re-running apply resolves it, or add a short time_sleep between the policy assignment and the role assignment.
LinkedAuthorizationFailed: The client has permission to perform action 'Microsoft.Authorization/roleAssignments/write' on scope '<mg scope>', however the current tenant '<tenantId>' is not authorized to access linked subscription '<subId>'.Cause: A DeployIfNotExists or Modify assignment's --identity-scope points at a scope the caller cannot itself grant roles over, or the subscription was moved between management groups mid-operation.
Fix: Set --identity-scope to the same management group the assignment targets, ensure the caller holds User Access Administrator or Role Based Access Control Administrator at that exact scope, and re-check RBAC after any subscription move.
Insufficient privileges to complete the operation.Cause: 'az role assignment create --assignee <upn-or-name>' forces a Microsoft Graph lookup, which a bare ARM service principal cannot perform without a directory read permission.
Fix: Use --assignee-object-id "$GRP_PLATFORM_OID" --assignee-principal-type Group as the skill does, which bypasses Graph entirely. Only grant Directory.Read.All / User.Read.All if name-based lookup is genuinely required.
RequestDisallowedByPolicy: Resource '<name>' was disallowed by policy. Policy identifiers: '[{"policyAssignment":{"name":"..."}}]'Cause: A deny-effect assignment created earlier in the run โ typically allowed locations e56962a6-4747-49cd-b67b-bf8b01975c4c or a require-tag policy โ now blocks the workspace, storage account or remediation deployment the skill itself is creating.
Fix: This is why the skill ships deny-capable assignments with --enforcement-mode DoNotEnforce first. Either flip the assignment back to DoNotEnforce, add the deploying region/tag to the parameters, or file a time-bounded 'az policy exemption create'.
ScopeLocked: The scope '/subscriptions/<subId>/resourceGroups/<rg>' cannot perform write operation because following scope(s) are locked: '...'. Please remove the lock and try again.Cause: A CannotDelete or ReadOnly management lock inherited from the subscription or management group blocks the workspace, diagnostic setting or deployment-stack write.
Fix: Azure portal > the scope > Settings > Locks > delete or temporarily downgrade the lock (requires Microsoft.Authorization/locks/delete), apply, then restore it.
az: error: unrecognized arguments: --alert-notifications On --alerts-admins OnCause: The 'az security contact' argument surface changed between CLI versions, exactly as the skill warns in Procedure step 4.
Fix: Run 'az security contact create --help' against the installed CLI version and use the argument names it reports, or pin the CLI version used in CI.
(BadRequest) Start date should be first day of the month and cannot be in the past.Cause: The budget timePeriod.startDate or the Terraform time_period start_date is not the first of a month, or the hard-coded 2026-08-01 date has since elapsed.
Fix: Set startDate to the first day of the current or a future month in UTC (for example 2026-08-01T00:00:00Z) and re-run the PUT on Microsoft.Consumption/budgets.
Official documentation: https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/ โ
API operations this skill uses (20)
Every call the skill makes, linked to its official reference page.
| Operation | Call | Permission | Ref |
|---|---|---|---|
| Create or update management group Builds the mg-alz / mg-alz-platform / mg-alz-lz / mg-alz-corp / mg-alz-sandbox hierarchy that every policy and RBAC assignment in the skill is anchored to. | PUT /providers/Microsoft.Management/managementGroups/{groupId}?api-version=2021-04-01 (CLI: az account management-group create -n mg-alz --display-name "ALZ Root" --parent "$TENANT_ID") | Microsoft.Management/managementGroups/write โ Management Group Contributor or Owner at the parent scope | docs โ |
| List management groups Root-access smoke test (a single returned row means no root-scope access) and the pre-change snapshot written to pre-mg.json. | GET /providers/Microsoft.Management/managementGroups?api-version=2021-04-01 (CLI: az account management-group list -o table) | Microsoft.Management/managementGroups/read โ Management Group Reader | docs โ |
| Add subscription to management group Maps the platform subscription under mg-alz-platform so it inherits the baseline; note this re-evaluates policy and drops role assignments inherited from the previous parent. | PUT /providers/Microsoft.Management/managementGroups/{groupId}/subscriptions/{subscriptionId}?api-version=2021-04-01 (CLI: az account management-group subscription add -n mg-alz-platform --subscription "$SUB_MGMT_ID") | Microsoft.Management/managementGroups/subscriptions/write plus Microsoft.Subscription/... write on the subscription | docs โ |
| Set hierarchy settings (default group, require authorization) Lands new subscriptions in Sandbox instead of the Tenant Root Group and blocks management-group creation by non-owners. | PUT /providers/Microsoft.Management/managementGroups/{tenantId}/settings/default?api-version=2021-04-01 with body {"properties":{"requireAuthorizationForGroupCreation":true,"defaultManagementGroup":"/providers/Microsoft.Management/managementGroups/mg-alz-sandbox"}} | Microsoft.Management/managementGroups/settings/write at the Tenant Root Group โ Owner at root | docs โ |
| Create policy assignment with managed identity Assigns Microsoft Cloud Security Benchmark (1f3afdf9-d0c9-4c3d-847f-89da613e70a8), require-tag 871b6d14-10aa-478d-b590-94f262ecfa99 and inherit-tag ea3f2387-9b95-492a-a190-fcdc54f7b070 at mg-alz, initially with --enforcement-mode DoNotEnforce. | PUT /providers/Microsoft.Management/managementGroups/{mg}/providers/Microsoft.Authorization/policyAssignments/{name}?api-version=2023-04-01 (CLI: az policy assignment create -n mcsb --scope "$MG" --mi-system-assigned --location eastus --role Contributor --identity-scope "$MG" --policy-set-definition ...) | Microsoft.Authorization/policyAssignments/write โ Resource Policy Contributor, plus roleAssignments/write for the identity grant | docs โ |
| Create remediation task at management group Applies Modify/DeployIfNotExists effects to resources that already exist; without it those effects only touch future writes. | PUT /providers/Microsoft.Management/managementGroups/{mg}/providers/Microsoft.PolicyInsights/remediations/{name}?api-version=2021-10-01 (CLI: az policy remediation create -n rem-inherit-costcenter --management-group mg-alz --resource-discovery-mode ReEvaluateCompliance --policy-assignment ...) | Microsoft.PolicyInsights/remediations/write โ Resource Policy Contributor | docs โ |
| Trigger policy evaluation scan Forces evaluation instead of waiting out the ~30 minute assignment lag or the 24 hour cycle; supported at subscription and resource-group scope only. | POST /subscriptions/{subId}/providers/Microsoft.PolicyInsights/policyStates/latest/triggerEvaluation?api-version=2019-10-01 (CLI: az policy state trigger-scan --subscription "$SUB_ID" --no-wait) | Microsoft.PolicyInsights/policyStates/triggerEvaluation/action โ Policy Insights Data Writer or Contributor | docs โ |
| Summarize policy compliance for management group The authoritative compliance read the skill reports before and after; compliance is never inferred from a successful apply. | POST /providers/Microsoft.Management/managementGroups/{mg}/providers/Microsoft.Authorization/policyStates/latest/summarize?api-version=2019-10-01 (CLI: az policy state summarize -m mg-alz --query "value[0].results") | Microsoft.PolicyInsights/policyStates/queryResults/read โ Reader or Security Reader | docs โ |
| List non-compliant policy states Produces the per-resource non-compliance table (resourceId, policyDefinitionName, effect) in the final report. | POST /providers/Microsoft.Management/managementGroups/{mg}/providers/Microsoft.Authorization/policyStates/latest/queryResults?api-version=2019-10-01&$filter=complianceState eq 'NonCompliant' (CLI: az policy state list -m mg-alz --filter "complianceState eq 'NonCompliant'") | Microsoft.PolicyInsights/policyStates/queryResults/read โ Reader | docs โ |
| Create time-bounded policy exemption Records legitimate exceptions with an expiry date instead of weakening the policy definition; each exemption is tracked in the Open items section. | PUT /{scope}/providers/Microsoft.Authorization/policyExemptions/{name}?api-version=2022-07-01-preview (CLI: az policy exemption create -n legacy-sql-waiver --policy-assignment "$ASSIGNMENT_ID" --exemption-category Waiver --expires-on 2026-12-31) | Microsoft.Authorization/policyExemptions/write โ Resource Policy Contributor | docs โ |
| Create role assignment for Entra group or policy managed identity Grants platform operators access to groups rather than users, and grants Contributor / Tag Contributor to DeployIfNotExists and Modify managed identities so remediation is not inert. | PUT /{scope}/providers/Microsoft.Authorization/roleAssignments/{guid}?api-version=2022-04-01 (CLI: az role assignment create --assignee-object-id "$GRP_PLATFORM_OID" --assignee-principal-type Group --role Contributor --scope "/providers/Microsoft.Management/managementGroups/mg-alz-platform") | Microsoft.Authorization/roleAssignments/write โ User Access Administrator, Role Based Access Control Administrator or Owner | docs โ |
| Create Log Analytics workspace with retention and daily cap Creates the central platform workspace; the explicit --quota is the guard against the uncapped-ingestion runaway bill the skill calls out as the top cost risk. | PUT /subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.OperationalInsights/workspaces/{name}?api-version=2023-09-01 (CLI: az monitor log-analytics workspace create -g rg-platform-mgmt-eastus -n law-platform-eastus --sku PerGB2018 --retention-time 90 --quota 50) | Microsoft.OperationalInsights/workspaces/write โ Log Analytics Contributor | docs โ |
| Create or update the default security contact Routes Defender for Cloud alert notifications to the security team; the skill warns that this command's argument names drift between CLI versions, so check 'az security contact create --help' first. | PUT /subscriptions/{subId}/providers/Microsoft.Security/securityContacts/default?api-version=2020-01-01-preview (CLI: az security contact create -n default --emails "[email protected]" --alert-notifications On --alerts-admins On) | Microsoft.Security/securityContacts/write โ Security Admin | docs โ |
| Set Defender for Cloud plan tier and subplan Enables CloudPosture, VirtualMachines (P1/P2), StorageAccounts (DefenderForStorageV2), Containers, Arm and KeyVaults per subscription; also used in reverse (--tier Free) for rollback. | PUT /subscriptions/{subId}/providers/Microsoft.Security/pricings/{pricingName}?api-version=2024-01-01 (CLI: az security pricing create -n VirtualMachines --tier Standard --subplan P1) | Microsoft.Security/pricings/write โ Security Admin | docs โ |
| List Defender for Cloud pricings (verification and snapshot) Writes pre-defender.json and proves per-subscription coverage, since Defender pricing is subscription-scoped and never inherited from a management group. | GET /subscriptions/{subId}/providers/Microsoft.Security/pricings?api-version=2024-01-01 (CLI: az security pricing list -o json) | Microsoft.Security/pricings/read โ Security Reader | docs โ |
| List secure scores Supplies the before/after Secure Score figures in the Verification output section. | GET /subscriptions/{subId}/providers/Microsoft.Security/secureScores?api-version=2020-01-01 (CLI: az security secure-scores list -o table) | Microsoft.Security/secureScores/read โ Security Reader | docs โ |
| Create subscription-level diagnostic setting to Log Analytics Routes Administrative, Security, Policy, ServiceHealth, ResourceHealth and Alert activity-log categories into the platform workspace as the audit trail. | PUT /subscriptions/{subId}/providers/Microsoft.Insights/diagnosticSettings/{name}?api-version=2021-05-01-preview (CLI: az monitor diagnostic-settings subscription create -n sub-activity-to-law --location eastus --workspace "$LAW" --logs '[...]') | Microsoft.Insights/diagnosticSettings/write โ Monitoring Contributor | docs โ |
| Create subscription budget with actual and forecasted notifications Called via az rest because 'az consumption budget create' cannot express the notifications block; creates the 80% Actual and 100% Forecasted alerts. Budgets notify only, they never halt spend. | PUT /subscriptions/{subId}/providers/Microsoft.Consumption/budgets/{budgetName}?api-version=2023-11-01 | Microsoft.Consumption/budgets/write โ Cost Management Contributor | docs โ |
| Query Azure Resource Graph across the hierarchy Aggregates compliance state tenant-wide and measures costCenter tag coverage, the gate for meaningful showback. | POST /providers/Microsoft.ResourceGraph/resources?api-version=2022-10-01 (CLI: az graph query --management-groups mg-alz -q "policyresources | where type =~ 'microsoft.policyinsights/policystates' | summarize count() by tostring(properties.complianceState)") | Microsoft.ResourceGraph/resources/action โ Reader at the queried scope (results are silently filtered to readable resources) | docs โ |
| Deploy the baseline as a management-group deployment stack Drift protection for the baseline, replacing the deprecated Azure Blueprints; break-glass principals are excluded from the deny settings. | PUT /providers/Microsoft.Management/managementGroups/{mg}/providers/Microsoft.Resources/deploymentStacks/{name}?api-version=2024-03-01 (CLI: az stack mg create --name stack-alz --management-group-id mg-alz --location eastus --template-file main.bicep --deny-settings-mode denyWriteAndDelete --deny-settings-excluded-principals "$BREAKGLASS_OID") | Microsoft.Resources/deploymentStacks/write plus Owner at the target management group | docs โ |