Assess ARM template resources for Azure Policy compliance. Analyse the template, query existing subscription assignments via `az policy assignment list`, identify unassigned built-in and custom policies (CIS, NIST, FedRAMP), and emit a two-part report: template-fixable gaps (Part 1) and subscription-level policy assignments (Part 2). USE FOR: recommending Azure Policy assignments for an ARM template, auditing a subscription against CIS/NIST/general best practices, deciding which initiatives to assign at sub or management-group scope, distinguishing template-fixable vs platform-level governance gaps. DO NOT USE FOR: per-resource security configuration assessment (use azure-security-analyzer), RBAC role recommendations (use azure-role-selector), CAF naming abbreviations (use azure-naming-research), or pricing estimates (use azure-cost-estimator). INVOKES: az policy assignment list, az policy set-definition list, microsoft_docs_search, microsoft_docs_fetch.
Assess ARM template resources for Azure Policy compliance. Analyse the template, query existing subscription assignments via `az policy assignment list`, identify unassigned built-in and custom policies (CIS, NIST, FedRAMP), and emit a two-part report: template-fixable gaps (Part 1) and subscription-level policy assignments (Part 2). USE FOR: recommending Azure Policy assignments for an ARM template, auditing a subscription against CIS/NIST/general best practices, deciding which initiatives to assign at sub or management-group scope, distinguishing template-fixable vs platform-level governance gaps. DO NOT USE FOR: per-resource security configuration assessment (use azure-security-analyzer), RBAC role recommendations (use azure-role-selector), CAF naming abbreviations (use azure-naming-research), or pricing estimates (use azure-cost-estimator). INVOKES: az policy assignment list, az policy set-definition list, microsoft_docs_search, microsoft_docs_fetch.
metadata
{"argument-hint":"ARM template JSON or resource types to assess, and optionally a compliance framework (CIS, NIST, general)","user-invocable":true}
Azure Policy Advisor
Recommend Azure Policy assignments for ARM template resources by combining three sources of truth: existing Azure subscription policy state (assignments + definitions), Microsoft Learn built-in recommendations, and ARM template configuration analysis. The skill analyses each resource, queries the live subscription, classifies gaps, and produces per-resource recommendations with severity ratings, built-in/custom definition IDs, and ready-to-use implementation options.
USE FOR
"What Azure Policies should we enforce on this template?"
"Which built-in initiative covers governance for this deployment?"
"Split policy work between template fixes vs subscription-level assignments"
"Recommend baseline policy assignments for a new subscription"
DO NOT USE FOR
Per-resource security configuration assessment (HTTPS-only, public access, shared-key access, TLS version, etc.) → use azure-security-analyzer
RBAC role recommendations / least-privilege role selection → use azure-role-selector
CAF naming abbreviations or name-string length/character constraints → use azure-naming-research
Pricing or monthly cost estimation → use azure-cost-estimator
VM SKU / API version / quota availability checks → use azure-resource-availability
Comparing deployed state vs stored template state (configuration drift) → use azure-drift-detector
Generating a new ARM template from requirements → invoke the Azure Template Generator agent
Scope: This skill assesses (a) ARM template resources you supply and (b) the existing policy state in the target Azure subscription (active assignments + unassigned custom definitions). It does not enumerate the live configuration of deployed resources — for that, use azure-drift-detector.
MCP Tools
Tool
Purpose
microsoft_docs_search
Search Microsoft Learn for built-in policy definitions per resource type
microsoft_docs_fetch
Retrieve full Microsoft Learn pages (built-in policies index, framework initiatives)
Prerequisites
Requirement
How
Azure CLI logged in
az login (skill degrades gracefully — see Troubleshooting if az is unavailable)
MCP server microsoft.docs.mcp available
Configure in your MCP client; used by Step 4 to look up built-in policy IDs
ARM template OR resource type list
Provided by the user or generated by Azure Template Generator
Procedure
1. Load Compliance Context and Identify Resources
Read compliance preferences from the ## Compliance & Azure Policy section in copilot-instructions.md (available automatically in conversation context). Extract:
Compliance frameworks (e.g., CIS Azure Foundations v3.0, NIST SP 800-53 Rev 5, general best practices)
If no compliance section exists in copilot-instructions.md, ask the user:
Which compliance approach should I assess against?
1. General Azure best practices (recommended)
2. CIS Azure Foundations v3.0
3. NIST SP 800-53 Rev 5
4. Custom — tell me what to check
Then parse the ARM template (if provided) to extract all resource types:
Extract for each resource:
- Resource type (e.g., Microsoft.Storage/storageAccounts)
- Resource name
- Current security-relevant properties (cross-reference with security-analyzer output if available)
1b. Resolve Subscription and Management Group Context
If {subscription-id} is not provided, discover it:
az account show --query id -o tsv — current default subscription
az account list --query "[].{id:id, name:name}" -o table — all subscriptions the user has access to
If {mg-name} is needed (for management-group-scoped queries) and not provided, list available management groups:
az account management-group list --query "[].{name:name, displayName:displayName}" -o table
If multiple subscriptions or management groups exist, ask the user which one to assess — do not guess.
2. Discover Existing Policy State (Assignments + Custom Definitions)
Before recommending new policies, discover what is already enforced in the target subscription and what custom definitions exist but are unassigned. This prevents redundant recommendations, surfaces enforcement gaps, and lets you prefer unassigned custom definitions over equivalent built-ins.
The script wraps az policy assignment list, az policy definition list, and az policy set-definition list at both subscription and (optional) management-group scope, then normalises the output into a single JSON document:
Use .assigned_policies keyed by policy_definition_id for the "already-assigned" lookup in Step 5. Use .unassigned_custom_policies filtered by target_resource_type matching ARM template resources to surface unassigned custom definitions that the platform team should consider assigning.
If az is not available or az login has not been run, the script exits non-zero and prints an error to stderr. Skip Step 5's assigned-vs-unassigned classification and note in the report:
⚠️ Could not query Azure subscription — existing assignments and custom
definitions unknown. Recommendations are based on Microsoft Learn and
template analysis only. Run `az login` and re-run for subscription-aware
assessment.
3. Verify Definition IDs Before Recommending
Always verify policy and initiative definition IDs from Microsoft Learn (microsoft_docs_search / microsoft_docs_fetch) or by calling az policy set-definition list --query "[?contains(displayName, 'CIS')]" -o table and az policy definition list before recommending them for assignment. Definition IDs and display names change over time and across Microsoft cloud regions (Public, Government, China). Do not rely on memorized IDs from training data — emit only IDs you have verified live in this run.
4. Research Applicable Built-in Policies via Microsoft Learn
For EACH resource type, query Microsoft Learn for current built-in policy definitions:
When search results reference a high-value page, use microsoft_docs_fetch to retrieve the full content:
Tool: microsoft_docs_fetch
URL: https://learn.microsoft.com/azure/governance/policy/samples/built-in-policies
Use this to get the complete list of built-in policies organized by category (Storage, App Service, SQL, Key Vault, Network, Monitoring, etc.)
Key Microsoft Learn reference pages: Read references/ms-learn-policy-pages.md when you need a specific Microsoft Learn URL (canonical built-in policies list, framework-specific pages for CIS/NIST/FedRAMP/PCI-DSS, ARM assignment syntax) — it lists the high-value entry points with guidance on which to fetch when.
5. Classify and Prioritize Recommendations
For each recommended policy, assign a severity tier, classify its current status against the ARM template and Steps 2–3 inventory, and resolve precedence when multiple sources cover the same control. Read references/classification-rules.yaml for the full rule set — it defines the four severity tiers (Critical/High/Medium/Low with Audit/Deny effects), the five status classifications (✅ Already assigned, 🔵 Compliant via template, 🟣 Unassigned custom available, ⚠️ Gap, 🔄 Complementary), and the three-rule precedence ladder (assigned_wins → custom_over_builtin → builtin_fallback).
Per resource type, prioritize policy categories ranked by severity. Read references/per-resource-policy-priorities.md when classifying recommendations for any of these resource types: Storage Accounts, App Service / Function Apps, SQL Servers / Databases, Key Vault, Compute / VMs, AKS / Kubernetes, Networking, or general cross-cutting controls. For resource types not in that list, fall back to the microsoft_docs_search query template in Step 4.
6. Generate Policy Recommendations Report
Present findings split into two clear action tracks: template improvements (changes to the ARM template) and subscription-level actions (policy/initiative assignments). This separation clarifies who needs to act and where.
Report outline — Read references/policy-assessment-template.md before producing the final markdown report. The template includes the canonical heading order, table column definitions for each section, and example rows. Skim the headings here, then fetch the full template:
## Azure Policy Compliance Assessment**Scope** · **Deployment** · **Compliance Framework** · **Enforcement Mode** · **Subscription Policy State**### Summary — table of {Recommended, Already Assigned, Template Compliant, Template Fixable, Subscription-Level Gap} per category## Part 1: Template Improvements (developer acts; edit the ARM template)### Gaps Fixable in the Template — table of {Resource Type, Gap, Compliance Control, Fix}### Already Compliant in Template — table of {Resource Type, Property, Template Value, Compliance Control}## Part 2: Subscription-Level Actions (platform team acts; assign at sub/mg scope)### Existing Policy Assignments — table of {Policy/Initiative, Scope, Enforcement, Type, Relevant?}### Unassigned Custom Policies — table of {Policy, Category, Target Resource, Effect, Scope}### Recommended Built-in Assignments — table of {Policy, Effect, Severity, Definition ID, Category, Source}### Recommended Compliance Initiative — table of {Initiative, Policies, Built-in ID, Status}
7. Provide Implementation Options
Split implementation guidance into both tracks:
Track 1: Template Changes (for gaps in Part 1)
For each gap listed in Part 1, provide the exact ARM template JSON to add. Include:
The full resource definition (type, apiVersion, name, properties)
Required dependsOn references
Any new variables needed (e.g., Log Analytics workspace name)
Present as ready-to-copy code blocks that the developer can insert into the nested template's resources array. Group related resources together (e.g., Log Analytics workspace + all diagnostic settings that depend on it).
Track 2: Subscription-Level Assignments (for gaps in Part 2)
Option A: Azure CLI (quickest for individual policies)
Active enforcement — new non-compliant resources are denied or audited
DoNotEnforce
Audit-only — evaluates compliance without blocking. Recommended for initial rollout
Policy Gate
The policy gate is advisory — it surfaces findings without blocking deployment.
### Policy Gate: ADVISORY**Part 1 — Template Compliance:**
🔵 {T} of {R} checks pass via template configuration
🔧 {F} gaps can be fixed by updating the template (see Part 1)
**Part 2 — Subscription Enforcement:**
✅ {A} policies already assigned in subscription
🟣 {C} custom policies available but unassigned — assign for immediate coverage
⚠️ {S} subscription-level gaps — recommend assigning built-in policies or initiative
Enforcement coverage: {percentage}% of recommended policies actively assigned
**Action items:**_Template (developer):_1. 🔧 {list of template changes from Part 1, e.g. "Add blob soft delete", "Add diagnostic settings"}
_Subscription (platform team):_1. 🟣 Assign existing custom policies: {list — these already exist, just need assignment}
2. ⚠️ Assign built-in policies: {list of built-in policies to assign}
3. {initiative to assign if framework selected}
Output Artifacts
When invoked during a deployment workflow, save results to the deployment directory:
File
Format
Content
policy-assessment.md
Markdown
Full assessment report (Section 4 output)
policy-recommendations.json
JSON
Structured policy data for automation
JSON structure for policy-recommendations.json — Read references/policy-recommendations-schema.json when emitting the JSON sidecar. The reference includes complete field definitions, status/actionTrack enum values, and a fully-worked example. Skeleton:
{"assessedAt":"...","deploymentId":"...","framework":"...","enforcementMode":"Audit|Deny","subscriptionState":"queried|unavailable","summary":{"totalRecommended":16,"alreadyAssigned":2,"templateCompliant":8,"templateFixable":3,"customAvailable":1,"subscriptionGaps":3},"existingAssignments":[/* from Step 2 .assigned_policies */],"unassignedCustomDefinitions":[/* from Step 2 .unassigned_custom_policies */],"templateImprovements":[/* Part 1 gaps */],"policies":[/* full recommendation list with status + actionTrack */],"initiative":{/* compliance-framework initiative if selected */}}
Status values for the status field:
Value
Meaning
Action Track
already-assigned
Policy actively assigned in subscription (✅)
none
template-compliant
ARM template satisfies the policy, not assigned (🔵)
subscription (assign to prevent drift)
template-fixable
Gap that can be closed by modifying the template (🔧)
template
custom-available
Custom definition exists but not assigned (🟣)
subscription
gap
Not covered — recommend built-in policy assignment (⚠️)
subscription
complementary
Would add enforcement on top of existing config (🔄)
subscription
Action track values for the actionTrack field:
Value
Meaning
template
Fix by modifying the ARM template (Part 1 — developer)
subscription
Fix by assigning a policy at subscription scope (Part 2 — platform team)
none
No action needed (already assigned or compliant)
Integration with Git-Ape
Template Generator: After /azure-security-analyzer, optionally invoke /azure-policy-advisor to recommend subscription-level policies that complement the template
Onboarding: After RBAC setup, the onboarding flow captures compliance preferences and adds them to copilot-instructions.md — this skill reads them automatically
Drift Detector: Cross-reference drift findings with policy recommendations — drift items covered by assigned policies will auto-remediate
Examples
Example 1 — Post-template recommendation (general best practices)
"I just generated an ARM template with a Storage Account, Function App, and Key Vault for production. What Azure Policies should we enforce? Separate template fixes from subscription-level assignments."
Skill activates → Step 1 reads "General best practices" + Audit from copilot-instructions → Step 2 runs discover_policy_state.sh → finds SecurityCenterBuiltIn (MCSB) initiative covers 13 of 17 recommendations → Step 6 emits Part 1 (4 template fixes: blob soft delete + 3 diagnostic settings) and Part 2 (3 monitoring built-ins to assign).
Example 2 — Compliance framework audit
"Audit our subscription resources against CIS Azure Foundations v3.0 — what's covered and what's missing?"
Skill activates → Step 1 captures framework: CIS Azure Foundations v3.0 → Step 2 discovers existing assignments → Step 4 fetches the CIS Azure Foundations Benchmark v3.0.0 built-in initiative ID from Microsoft Learn → Step 3 verifies the ID via az policy set-definition list --query "[?contains(displayName, 'CIS')]" → Step 6 emits per-control coverage + recommended initiative assignment.
Troubleshooting
Symptom
Cause
Resolution
discover_policy_state.sh exits non-zero, errors about az login
Azure CLI not authenticated
Run az login and retry. If unauthenticated by design (e.g., template-only review), the skill still produces Part 1 + recommended built-ins from Microsoft Learn, with subscriptionState: "unavailable" in the JSON sidecar
Recommended definition ID returns "not found" from az policy definition show
Display-name drift or wrong cloud (Public vs Government vs China)
Re-verify via Step 3: az policy set-definition list --query "[?contains(displayName, '<keyword>')]" -o table. Definition IDs are stable; display names evolve (e.g., "purge protection" → "deletion protection")
Skill reports ⚠️ for a policy already enforced via initiative
assigned_policies lookup keyed on individual policy IDs; initiative members aren't expanded
Cross-check assigned_initiatives in the policy-state JSON — if MCSB (1f3afdf9-d0c9-4c3d-847f-89da613e70a8) is assigned, 200+ individual policies are covered indirectly. Filed as a known limitation; expansion via az policy set-definition show --query "policyDefinitions[].policyDefinitionId" is on the roadmap
microsoft_docs_search returns stale or empty results
MCP server not configured, or Microsoft Learn page moved
Fall back to microsoft_docs_fetch with the canonical URL from references/ms-learn-policy-pages.md (built-in policies index)