Skip to main content

Azure Security Analyzer

Analyze Azure resource configurations against security best practices using Azure MCP bestpractices service. Produces per-resource security assessment with severity ratings and recommendations. Use during template generation before deployment confirmation.

Details​

PropertyValue
Skill Directory.github/skills/azure-security-analyzer/
PhasePre-Deploy
User Invocable✅ Yes
Usage/azure-security-analyzer

Documentation​

Azure Security Analyzer

Analyze Azure resource configurations against Microsoft security best practices and produce a per-resource security assessment report.

When to Use​

  • During template generation (invoked by the template generator before deployment confirmation)
  • To audit an existing ARM template for security gaps
  • When user asks "is this secure?" or "check security" for a deployment
  • Post-deployment security review

Verification Integrity Rules (CRITICAL)​

Every claim in the security report MUST be verifiable against the ARM template. Never fabricate, assume, or misrepresent security status.

Rule 1: Cite Exact Evidence​

Every "✅ Applied" status MUST cite the exact ARM template property path and its value that proves the control is in place. If you cannot point to a specific property in the template JSON, you cannot mark it as applied.

# ✅ CORRECT — cites exact property
| HTTPS-only | 🔴 Critical | ✅ Applied | `properties.httpsOnly: true` | Explicitly set in template |

# ❌ WRONG — no evidence from template
| Disk encryption | 🔴 Critical | ✅ Applied | `managedDisk.storageAccountType` | This property is the performance tier, NOT encryption |

Rule 2: Distinguish Explicit Config vs Platform Defaults​

Azure provides some security controls by default (e.g., SSE at rest on managed disks). These are NOT the same as explicitly configured controls.

StatusIconMeaningWhen to Use
✅ Applied✅Explicitly configured in the ARM templateProperty exists in template JSON with secure value
🔄 Platform Default🔄Azure provides this automatically, NOT in templateControl exists due to Azure platform behavior, not template config
⚠️ Not applied⚠️Control is missing and should be consideredProperty absent from template, no platform default covers it
❌ Misconfigured❌Property exists but set to an insecure valueProperty in template with wrong/insecure value
# ✅ CORRECT — distinguishes platform default from explicit config
| SSE at rest (managed disks) | 🟡 Medium | 🔄 Platform Default | Not in template | Azure encrypts all managed disks at rest with platform-managed keys automatically |
| Encryption at host (ADE) | 🟡 Medium | ⚠️ Not applied | `securityProfile.encryptionAtHost` absent | Not enabled — would encrypt temp disks and caches too |

# ❌ WRONG — claims explicit config for a platform default
| Managed disk encryption | 🔴 Critical | ✅ Applied | `managedDisk.storageAccountType` | WRONG: storageAccountType is performance tier, not encryption |

Rule 3: Never Use Misleading Framing​

Describe security status accurately and literally. Do not soften or reframe risks.

# ❌ WRONG — misleading framing
| No open SSH to internet | 🔴 Critical | ✅ Applied |
# This is misleading: the VM HAS a public IP with port 22 open.
# IP-restriction reduces risk but port 22 IS internet-reachable.

# ✅ CORRECT — accurate framing
| SSH not open to 0.0.0.0/0 | 🔴 Critical | ✅ Applied | `sourceAddressPrefix: 175.x.x.x/32` | Restricted to single IP |
| VM is internet-facing (public IP + port 22) | 🟠 High | ⚠️ Risk accepted | Public IP attached to NIC | Port 22 reachable from internet (IP-restricted). Safer: Azure Bastion |

Specific rules:

  • If a VM has a public IP → it IS internet-facing. Always flag this.
  • If any port is open, even IP-restricted → state the port IS open and note the restriction as mitigation, not as "closed."
  • If encryption is platform-default → say "platform default", not "applied."
  • If a property is absent from the template → say "not configured", not "applied" based on assumptions.

Rule 4: Verify Before Reporting​

Before generating the security report, perform this verification checklist:

  1. For each "✅ Applied" entry: Search the ARM template JSON for the cited property. If not found → change status.
  2. For each security claim: Confirm the ARM property cited actually controls what you claim. (e.g., storageAccountType is NOT encryption)
  3. For network exposure: Check if any publicIPAddress resource is attached to a NIC. If yes → VM is internet-facing, period.
  4. For encryption claims: Distinguish between SSE (automatic), ADE (explicit extension), and encryption at host (explicit VM property).
  5. Cross-check property paths: Use the correct ARM template property paths, not invented or approximate ones.

Rule 5: When Uncertain, Mark as Unknown​

If you cannot determine a security status with certainty:

| {check} | {severity} | ❓ Unknown | {property} | Unable to verify — property path unclear or resource type not in checklist |

Never guess. Never fabricate. When in doubt, flag it.

Procedure​

1. Extract Resources from Template​

Parse the ARM template or requirements to identify all resources and their configurations:

Input: ARM template JSON or resource configuration list

Extract for each resource:
- Resource type (e.g., Microsoft.Storage/storageAccounts)
- Resource name
- All security-relevant properties
- Current configuration values

2. Query Azure MCP Best Practices (Per Resource)​

For EACH resource type, query the Azure MCP bestpractices service to get security recommendations:

Tool: mcp_azure_mcp_search
Intent: "bestpractices {resource-type}"

Examples:
- "bestpractices Microsoft.Storage/storageAccounts"
- "bestpractices Microsoft.Web/sites"
- "bestpractices Microsoft.Sql/servers"
- "bestpractices Microsoft.DocumentDB/databaseAccounts"
- "bestpractices Microsoft.KeyVault/vaults"
- "bestpractices Microsoft.ContainerApp/containerApps"

Parse the MCP response for:

  • Security recommendations with severity levels
  • Configuration best practices
  • Compliance alignment notes (CIS, SOC2, PCI-DSS)
  • Microsoft Defender for Cloud recommendations

3. Check Resource-Specific Security Properties​

Cross-reference MCP recommendations against the template configuration.

Storage Accounts (Microsoft.Storage/storageAccounts):

#CheckPropertySeveritySecure Value
1HTTPS-only transfersupportsHttpsTrafficOnly🔴 Criticaltrue
2TLS 1.2 minimumminimumTlsVersion🔴 CriticalTLS1_2
3Disable public blob accessallowBlobPublicAccess🟠 Highfalse
4Blob soft deletedeleteRetentionPolicy.enabled🟠 Hightrue
5Container soft deletecontainerDeleteRetentionPolicy.enabled🟡 Mediumtrue
6Disable shared key accessallowSharedKeyAccess� Highfalse
7Network rules / firewallnetworkAcls.defaultAction🟡 MediumDeny (prod)
8Private endpointPrivate endpoint resource🟡 MediumConfigured (prod)
9Infrastructure encryptionencryption.requireInfrastructureEncryption🔵 Lowtrue
10Immutability policyimmutableStorageWithVersioning🔵 LowEnabled (compliance)

Function Apps / App Services (Microsoft.Web/sites):

#CheckPropertySeveritySecure Value
1HTTPS-onlyhttpsOnly🔴 Criticaltrue
2TLS 1.2 minimumsiteConfig.minTlsVersion🔴 Critical1.2
3Managed identityidentity.type🔴 CriticalSystemAssigned
4Identity-based storage accessAzureWebJobsStorage__accountName (not AzureWebJobsStorage)🔴 CriticalIdentity-based
5RBAC for storageRole assignments for MI → Storage🔴 CriticalStorage Blob Data Owner + Storage Account Contributor
6FTP disabledsiteConfig.ftpsState🟠 HighDisabled
7Remote debugging offsiteConfig.remoteDebuggingEnabled🟠 Highfalse
8Latest runtime versionsiteConfig.linuxFxVersion or netFrameworkVersion🟠 HighLatest stable
9App Insights connectedAPPINSIGHTS_INSTRUMENTATIONKEY in appSettings🟡 MediumSet
8Health check enabledsiteConfig.healthCheckPath🟡 MediumSet
9CORS not wildcardsiteConfig.cors.allowedOrigins🟡 MediumNot *
10VNet integrationvirtualNetworkSubnetId🟡 MediumConfigured (prod)
11IP restrictionssiteConfig.ipSecurityRestrictions🔵 LowConfigured
12HTTP/2 enabledsiteConfig.http20Enabled🔵 Lowtrue

SQL Servers (Microsoft.Sql/servers):

#CheckPropertySeveritySecure Value
1TDE enabledtransparentDataEncryption.status🔴 CriticalEnabled
2AAD-only authadministrators.azureADOnlyAuthentication🔴 Criticaltrue
3Minimal TLS 1.2minimalTlsVersion🔴 Critical1.2
4Auditing enabledauditingSettings.state🟠 HighEnabled
5Advanced threat protectionsecurityAlertPolicies.state🟠 HighEnabled
6Firewall rules restrictivefirewallRules🟠 HighNo 0.0.0.0/0 (prod)
7Vulnerability assessmentvulnerabilityAssessments🟡 MediumEnabled
8Private endpointPrivate endpoint resource🟡 MediumConfigured (prod)
9Long-term backup retentionbackupLongTermRetentionPolicies🟡 MediumConfigured
10Connection policyconnectionPolicies.connectionType🔵 LowRedirect

Cosmos DB (Microsoft.DocumentDB/databaseAccounts):

#CheckPropertySeveritySecure Value
1Firewall configuredipRules or virtualNetworkRules🔴 CriticalNot empty
2Disable key-based metadata writesdisableKeyBasedMetadataWriteAccess🟠 Hightrue
3RBAC-based accessdisableLocalAuth🟠 Hightrue (prefer RBAC)
4Continuous backupbackupPolicy.type🟡 MediumContinuous
5Customer-managed keyskeyVaultKeyUri🟡 MediumSet (prod)
6Diagnostic loggingDiagnostic setting resource🟡 MediumEnabled
7Private endpointPrivate endpoint resource🟡 MediumConfigured (prod)

Key Vault (Microsoft.KeyVault/vaults):

#CheckPropertySeveritySecure Value
1Soft delete enabledenableSoftDelete🔴 Criticaltrue (now default)
2Purge protectionenablePurgeProtection🔴 Criticaltrue
3RBAC authorizationenableRbacAuthorization🟠 Hightrue
4Network rulesnetworkAcls.defaultAction🟡 MediumDeny (prod)
5Private endpointPrivate endpoint resource🟡 MediumConfigured (prod)
6Diagnostic loggingDiagnostic setting resource🟡 MediumEnabled

Container Apps (Microsoft.App/containerApps):

#CheckPropertySeveritySecure Value
1Ingress HTTPS onlyingress.transport🔴 Criticalhttp with allowInsecure: false
2Managed identityidentity.type🟠 HighSystemAssigned
3Min replicas > 0 (prod)scale.minReplicas🟡 Medium> 0 for prod
4VNet integrationContainer Apps Environment🟡 MediumConfigured
5Secret managementsecrets with Key Vault refs🟡 MediumKey Vault references

Virtual Machines (Microsoft.Compute/virtualMachines):

#CheckPropertySeveritySecure Value
1Password authentication disabledosProfile.linuxConfiguration.disablePasswordAuthentication🔴 Criticaltrue
2SSH key configuredosProfile.linuxConfiguration.ssh.publicKeys🔴 CriticalAt least one key
3Internet exposure (public IP)Check if NIC references publicIPAddress🟠 HighNo public IP (use Bastion). If public IP present → flag as internet-facing
4NSG SSH not open to 0.0.0.0/0NSG securityRules[].sourceAddressPrefix for port 22🔴 CriticalNot * or Internet — must be specific IP/CIDR
5Encryption at hostsecurityProfile.encryptionAtHost🟡 Mediumtrue (encrypts temp disks + caches)
6Azure Disk Encryption (ADE)ADE VM extension resource🟡 MediumExtension present
7SSE at rest (managed disks)Platform default — NOT a template property🔵 Info🔄 Platform Default — Azure encrypts all managed disks automatically. Do NOT mark as "✅ Applied"
8Boot diagnosticsdiagnosticsProfile.bootDiagnostics.enabled🟡 Mediumtrue
9Managed identityidentity.type🟡 MediumSystemAssigned (if VM accesses Azure resources)
10Automatic OS updatesosProfile.linuxConfiguration.patchSettings.patchMode🔵 LowAutomaticByPlatform
11Trusted launchsecurityProfile.securityType🟡 MediumTrustedLaunch with vTPM and secure boot

⚠️ VM Internet Exposure Rule: If ANY Microsoft.Network/publicIPAddresses resource is attached to the VM's NIC, the VM IS internet-facing. Always flag this explicitly, even if NSG rules restrict source IPs. An IP-restricted port is still internet-reachable — the restriction is a mitigation, not a closure.

Network Security Groups (Microsoft.Network/networkSecurityGroups):

#CheckPropertySeveritySecure Value
1No rules with source * or Internet on management ports (22, 3389)securityRules[].sourceAddressPrefix🔴 CriticalSpecific IP/CIDR only
2Explicit deny-all inbound ruleCustom deny rule at high priority🟠 HighPresent
3No overly permissive rules (* destination port)securityRules[].destinationPortRange🟠 HighSpecific ports only
4NSG flow logsSeparate flow log resource🟡 MediumEnabled

3.5 Verify All Findings (MANDATORY)​

Before classifying posture, run the verification checklist from the Verification Integrity Rules section:

  1. Re-read the ARM template JSON.
  2. For every "✅ Applied" entry in your draft report, search for the exact property path and confirm the value.
  3. For every network-related check, confirm whether a publicIPAddress resource exists and which ports are open.
  4. For every encryption check, confirm whether the control is explicit (in template) or platform-default (Azure automatic).
  5. Remove or downgrade any entry that fails verification.
  6. Ensure no check uses misleading framing (see Rule 3).

If you find an error during verification: Fix it immediately. Do not present unverified findings to the user.

4. Classify Overall Security Posture & Gate Status​

Based on the per-resource analysis, calculate an overall score AND the Security Gate status:

Security Gate (BLOCKING):
- ALL 🔴 Critical checks MUST pass → if any fail, gate = 🔴 BLOCKED
- ALL 🟠 High checks MUST pass → if any fail, gate = 🔴 BLOCKED
- If all Critical + High pass → gate = 🟢 PASSED
- 🟡 Medium and 🔵 Low do NOT block deployment

"Pass" means status is ✅ Applied or 🔄 Platform Default.
"Fail" means status is ⚠️ Not applied, ❌ Misconfigured, or ❓ Unknown.

Overall Posture (informational — does NOT control gating):
- **EXCELLENT** — All critical+high passed, > 75% medium passed
- **GOOD** — All critical+high passed, > 50% medium passed
- **ACCEPTABLE** — All critical passed, some high missing
- **NEEDS ATTENTION** — Some high-severity checks failed
- **NEEDS IMMEDIATE ATTENTION** — Critical checks failed (DO NOT deploy without fixing)

The Security Gate is the authoritative deployment-blocking mechanism. The posture label is informational only. A posture of "ACCEPTABLE" still results in 🔴 BLOCKED if any High checks fail.

5. Generate Security Report​

Produce a structured security assessment:

# Security Best Practices Analysis

**Deployment ID:** {deployment-id}
**Analyzed:** {timestamp}
**Source:** Azure MCP bestpractices service
**Resources Analyzed:** {count}

## Overall Security Posture: {EXCELLENT|GOOD|ACCEPTABLE|NEEDS ATTENTION}

**Summary:**
- 🔴 Critical: {passed}/{total} passed
- 🟠 High: {passed}/{total} passed
- 🟡 Medium: {passed}/{total} passed
- 🔵 Low: {passed}/{total} passed

## Per-Resource Assessment

### {Resource Type}: {Resource Name}

| # | Recommendation | Severity | Status | Property | Evidence | Notes |
|---|---------------|----------|--------|----------|----------|-------|
| 1 | {check name} | {severity} | ✅ Applied | {exact property path} | {actual value from template} | {note} |
| 2 | {check name} | {severity} | 🔄 Platform Default | {property} | Not in template | {Azure provides this automatically} |
| 3 | {check name} | {severity} | ⚠️ Not applied | {property} | Absent | {recommendation} |

**Score: {applied}/{total}** ({percentage}%)

{Repeat for each resource}

## Recommendations

### Must Fix (before deployment)
{List any failed critical checks — these should block deployment}

### Should Fix (strongly recommended)
{List any failed high checks — warn user but don't block}

### Consider (best practice)
{List failed medium/low checks — informational}

## Environment-Specific Notes

**For production deployments:**
- Private endpoints should be configured for all data resources
- Network rules should default to Deny
- VNet integration recommended for compute resources
- Consider customer-managed keys for encryption

**For dev/staging:**
- Network rules can use Allow for easier development
- Private endpoints are optional
- Shared key access acceptable for development

6. Return Results with Gate Status​

Return the security report to the calling agent (template generator) with two key outputs:

  1. Security Report — Full per-resource assessment (saved to security-analysis.md)
  2. Security Gate Status — 🟢 PASSED or 🔴 BLOCKED with list of blocking findings

The gate status MUST be prominently displayed at the top of the report:

## Security Gate: 🟢 PASSED
All Critical and High security checks pass. Deployment may proceed.

or:

## Security Gate: 🔴 BLOCKED
Deployment cannot proceed. The following checks must be resolved:

| # | Check | Severity | Resource | Status | Required Fix |
|---|-------|----------|----------|--------|--------------|
| 1 | {check} | 🔴 Critical | {resource} | ⚠️ Not applied | {fix} |

Also save the report to .azure/deployments/$DEPLOYMENT_ID/security-analysis.md.

Save the gate result to .azure/deployments/$DEPLOYMENT_ID/security-gate.json:

{
"gate": "PASSED",
"blockingFindings": [],
"criticalTotal": 4,
"criticalPassed": 4,
"highTotal": 6,
"highPassed": 6,
"timestamp": "2026-02-19T10:00:00Z"
}

Severity Classification​

SeverityIconMeaningAction
Critical🔴Security vulnerability if missingMust fix before deployment
High🟠Strongly recommended by MicrosoftShould fix, warn user
Medium🟡Best practice, may have trade-offsRecommend, user decides
Low🔵Nice to have, optionalInformational only

Environment Sensitivity​

Some checks are environment-dependent:

CheckDevStagingProd
Private endpoints🔵 Optional🟡 Recommended🟠 Required
Network firewall (Deny)🔵 Optional🟡 Recommended🟠 Required
VNet integration🔵 Optional🟡 Recommended🟠 Required
Customer-managed keys🔵 Optional🔵 Optional🟡 Recommended
IP restrictions🔵 Optional🟡 Recommended🟠 Required
Shared key access🟡 Acceptable🟡 Restricted🔴 Disabled

When analyzing, adjust severity ratings based on the target environment from the requirements.

Usage​

Invoked by template generator:

/azure-security-analyzer

Input: ARM template resources and target environment
Output: Per-resource security assessment with severity ratings

Manual invocation:

User: /azure-security-analyzer

Agent: Provide the ARM template or resource configurations to analyze.

User: [pastes template or points to deployment]

Agent: Analyzing 3 resources against Azure best practices...

[Produces security report]

Post-deployment audit:

User: /azure-security-analyzer --deployment-id deploy-20260218-193500

Agent: Loading template from .azure/deployments/deploy-20260218-193500/template.json...

[Analyzes and produces report]

Error Handling​

If MCP bestpractices service is unavailable:

  1. Fall back to the built-in security checklists defined in this skill
  2. Note in the report: "Analysis based on built-in checklists (MCP bestpractices unavailable)"
  3. Still produce a complete report — the checklists above are comprehensive

If a resource type is not in the checklists:

  1. Query MCP bestpractices for the specific resource type
  2. If no results, note: "No security checklist available for {resource-type}"
  3. Apply generic checks: tags, diagnostic logging, encryption