Installation

Install with CLI Recommended
gh skills-hub install azure-compliance

Don't have the extension? Run gh extension install samueltauil/skills-hub first.

Download and extract to your repository:

.github/skills/azure-compliance/

Extract the ZIP to .github/skills/ in your repo. The folder name must match azure-compliance for Copilot to auto-discover it.

Skill Files (16)

SKILL.md 4.6 KB
---
name: azure-compliance
description: "Run Azure compliance and security audits with azqr plus Key Vault expiration checks. Covers best-practice assessment, resource review, policy/compliance validation, and security posture checks. WHEN: compliance scan, security audit, BEFORE running azqr (compliance cli tool), Azure best practices, Key Vault expiration check, expired certificates, expiring secrets, orphaned resources, compliance assessment."
license: MIT
metadata:
  author: Microsoft
  version: "1.0.3"
---

# Azure Compliance & Security Auditing

## Quick Reference

| Property | Details |
|---|---|
| Best for | Compliance scans, security audits, Key Vault expiration checks |
| Primary capabilities | Comprehensive Resources Assessment, Key Vault Expiration Monitoring |
| MCP tools | azqr, subscription and resource group listing, Key Vault item inspection |

## When to Use This Skill

- Run azqr or Azure Quick Review for compliance assessment
- Validate Azure resource configuration against best practices
- Identify orphaned or misconfigured resources
- Audit Key Vault keys, secrets, and certificates for expiration

## Skill Activation Triggers

Activate this skill when user wants to:
- Check Azure compliance or best practices
- Assess Azure resources for configuration issues
- Run azqr or Azure Quick Review
- Identify orphaned or misconfigured resources
- Review Azure security posture
- "Show me expired certificates/keys/secrets in my Key Vault"
- "Check what's expiring in the next 30 days"
- "Audit my Key Vault for compliance"
- "Find secrets without expiration dates"
- "Check certificate expiration dates"

## Prerequisites

- Authentication: user is logged in to Azure via `az login`
- Permissions to read resource configuration and Key Vault metadata

## Assessments

| Assessment | Reference |
|------------|-----------|
| Comprehensive Compliance (azqr) | [references/azure-quick-review.md](references/azure-quick-review.md) |
| Key Vault Expiration | [references/azure-keyvault-expiration-audit.md](references/azure-keyvault-expiration-audit.md) |
| Resource Graph Queries | [references/azure-resource-graph.md](references/azure-resource-graph.md) |

## MCP Tools

| Tool | Purpose |
|------|---------|
| `mcp_azure_mcp_extension_azqr` | Run azqr compliance scans |
| `mcp_azure_mcp_subscription_list` | List available subscriptions |
| `mcp_azure_mcp_group_list` | List resource groups |
| `keyvault_key_list` | List all keys in vault |
| `keyvault_key_get` | Get key details including expiration |
| `keyvault_secret_list` | List all secrets in vault |
| `keyvault_secret_get` | Get secret details including expiration |
| `keyvault_certificate_list` | List all certificates in vault |
| `keyvault_certificate_get` | Get certificate details including expiration |

## Assessment Workflow

1. Select scope (subscription or resource group) for Comprehensive Resources Assessment.
2. Run azqr and capture output artifacts.
3. Analyze Scan Results and summarize findings and recommendations.
4. Review Key Vault Expiration Monitoring output for keys, secrets, and certificates.
5. Classify issues and propose remediation or fix steps for each finding.

### Priority Classification

| Priority | Guidance |
|---|---|
| Critical | Immediate remediation required for high-impact exposure |
| High | Resolve within days to reduce risk |
| Medium | Plan a resolution in the next sprint |
| Low | Track and fix during regular maintenance |

## Error Handling

| Error | Message | Remediation |
|---|---|---|
| Authentication required | "Please login" | Run `az login` and retry |
| Access denied | "Forbidden" | Confirm permissions and fix role assignments |
| Missing resource | "Not found" | Verify subscription and resource group selection |

## Best Practices

- Run compliance scans on a regular schedule (weekly or monthly)
- Track findings over time and verify remediation effectiveness
- Separate compliance reporting from remediation execution
- Keep Key Vault expiration policies documented and enforced

## SDK Quick References

For programmatic Key Vault access, see the condensed SDK guides:

- **Key Vault (Python)**: [Secrets/Keys/Certs](references/sdk/azure-keyvault-py.md)
- **Secrets**: [TypeScript](references/sdk/azure-keyvault-secrets-ts.md) | [Rust](references/sdk/azure-keyvault-secrets-rust.md) | [Java](references/sdk/azure-security-keyvault-secrets-java.md)
- **Keys**: [.NET](references/sdk/azure-security-keyvault-keys-dotnet.md) | [Java](references/sdk/azure-security-keyvault-keys-java.md) | [TypeScript](references/sdk/azure-keyvault-keys-ts.md) | [Rust](references/sdk/azure-keyvault-keys-rust.md)
- **Certificates**: [Rust](references/sdk/azure-keyvault-certificates-rust.md)

references/
auth-best-practices.md 6.0 KB
# Azure Authentication Best Practices

> Source: [Microsoft — Passwordless connections for Azure services](https://learn.microsoft.com/azure/developer/intro/passwordless-overview) and [Azure Identity client libraries](https://learn.microsoft.com/dotnet/azure/sdk/authentication/).

## Golden Rule

Use **managed identities** and **Azure RBAC** in production. Reserve `DefaultAzureCredential` for **local development only**.

## Authentication by Environment

| Environment | Recommended Credential | Why |
|---|---|---|
| **Production (Azure-hosted)** | `ManagedIdentityCredential` (system- or user-assigned) | No secrets to manage; auto-rotated by Azure |
| **Production (on-premises)** | `ClientCertificateCredential` or `WorkloadIdentityCredential` | Deterministic; no fallback chain overhead |
| **CI/CD pipelines** | `AzurePipelinesCredential` / `WorkloadIdentityCredential` | Scoped to pipeline identity |
| **Local development** | `DefaultAzureCredential` | Chains CLI, PowerShell, and VS Code credentials for convenience |

## Why Not `DefaultAzureCredential` in Production?

1. **Unpredictable fallback chain** — walks through multiple credential types, adding latency and making failures harder to diagnose.
2. **Broad surface area** — checks environment variables, CLI tokens, and other sources that should not exist in production.
3. **Non-deterministic** — which credential actually authenticates depends on the environment, making behavior inconsistent across deployments.
4. **Performance** — each failed credential attempt adds network round-trips before falling back to the next.

## Production Patterns

### .NET

```csharp
using Azure.Identity;

var credential = Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT") == "Development"
    ? new DefaultAzureCredential()                          // local dev — uses CLI/VS credentials
    : new ManagedIdentityCredential();                      // production — deterministic, no fallback chain
// For user-assigned identity: new ManagedIdentityCredential("<client-id>")
```

### TypeScript / JavaScript

```typescript
import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";

const credential = process.env.NODE_ENV === "development"
  ? new DefaultAzureCredential()                          // local dev — uses CLI/VS credentials
  : new ManagedIdentityCredential();                      // production — deterministic, no fallback chain
// For user-assigned identity: new ManagedIdentityCredential("<client-id>")
```

### Python

```python
import os
from azure.identity import DefaultAzureCredential, ManagedIdentityCredential

credential = (
    DefaultAzureCredential()                              # local dev — uses CLI/VS credentials
    if os.getenv("AZURE_FUNCTIONS_ENVIRONMENT") == "Development"
    else ManagedIdentityCredential()                      # production — deterministic, no fallback chain
)
# For user-assigned identity: ManagedIdentityCredential(client_id="<client-id>")
```

### Java

```java
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.azure.identity.ManagedIdentityCredentialBuilder;

var credential = "Development".equals(System.getenv("AZURE_FUNCTIONS_ENVIRONMENT"))
    ? new DefaultAzureCredentialBuilder().build()          // local dev — uses CLI/VS credentials
    : new ManagedIdentityCredentialBuilder().build();      // production — deterministic, no fallback chain
// For user-assigned identity: new ManagedIdentityCredentialBuilder().clientId("<client-id>").build()
```

## Local Development Setup

`DefaultAzureCredential` is ideal for local dev because it automatically picks up credentials from developer tools:

1. **Azure CLI** — `az login`
2. **Azure Developer CLI** — `azd auth login`
3. **Azure PowerShell** — `Connect-AzAccount`
4. **Visual Studio / VS Code** — sign in via Azure extension

```typescript
import { DefaultAzureCredential } from "@azure/identity";

// Local development only — uses CLI/PowerShell/VS Code credentials
const credential = new DefaultAzureCredential();
```

## Environment-Aware Pattern

Detect the runtime environment and select the appropriate credential. The key principle: use `DefaultAzureCredential` only when running locally, and a specific credential in production.

> **Tip:** Azure Functions sets `AZURE_FUNCTIONS_ENVIRONMENT` to `"Development"` when running locally. For App Service or containers, use any environment variable you control (e.g. `NODE_ENV`, `ASPNETCORE_ENVIRONMENT`).

```typescript
import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";

function getCredential() {
  if (process.env.NODE_ENV === "development") {
    return new DefaultAzureCredential();          // picks up az login / VS Code creds
  }
  return process.env.AZURE_CLIENT_ID
    ? new ManagedIdentityCredential(process.env.AZURE_CLIENT_ID)  // user-assigned
    : new ManagedIdentityCredential();                            // system-assigned
}
```

## Security Checklist

- [ ] Use managed identity for all Azure-hosted apps
- [ ] Never hardcode credentials, connection strings, or keys
- [ ] Apply least-privilege RBAC roles at the narrowest scope
- [ ] Use `ManagedIdentityCredential` (not `DefaultAzureCredential`) in production
- [ ] Store any required secrets in Azure Key Vault
- [ ] Rotate secrets and certificates on a schedule
- [ ] Enable Microsoft Defender for Cloud on production resources

## Further Reading

- [Passwordless connections overview](https://learn.microsoft.com/azure/developer/intro/passwordless-overview)
- [Managed identities overview](https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview)
- [Azure RBAC overview](https://learn.microsoft.com/azure/role-based-access-control/overview)
- [.NET authentication guide](https://learn.microsoft.com/dotnet/azure/sdk/authentication/)
- [Python identity library](https://learn.microsoft.com/python/api/overview/azure/identity-readme)
- [JavaScript identity library](https://learn.microsoft.com/javascript/api/overview/azure/identity-readme)
- [Java identity library](https://learn.microsoft.com/java/api/overview/azure/identity-readme)
azqr-recommendations.md 5.7 KB
# azqr Recommendation Categories

This document describes how to interpret azqr recommendations and prioritize remediation.

## Recommendation Sources

azqr aggregates recommendations from multiple sources:

| Source | Description | Priority |
|--------|-------------|----------|
| **APRL** | Azure Proactive Resiliency Library - reliability-focused best practices | High |
| **Orphaned Resources** | Resources that are unused or disconnected | Medium |
| **Azure Advisor** | Microsoft's built-in recommendation engine | Medium |
| **Defender for Cloud** | Security-focused recommendations | Critical |
| **Azure Policy** | Governance compliance status | Varies |

## Impact Categories

### Reliability

Recommendations that affect service availability and resiliency:

| Issue | Risk | Example Resources |
|-------|------|-------------------|
| No zone redundancy | Single zone failure causes outage | VMs, Storage, SQL, AKS |
| Single instance | No failover capability | App Service, Redis, VMs |
| No backup configured | Data loss risk | VMs, SQL, Cosmos DB |
| No disaster recovery | Regional failure exposure | Storage, SQL, Key Vault |

### Security

Recommendations that affect security posture:

| Issue | Risk | Example Resources |
|-------|------|-------------------|
| Public endpoint exposed | Attack surface exposure | Storage, SQL, Key Vault |
| Missing encryption | Data exposure risk | Storage, Disks, SQL |
| No private endpoint | Traffic on public internet | PaaS services |
| Weak TLS version | Protocol vulnerabilities | App Service, API Management |
| No managed identity | Credential management risk | App Service, Functions, AKS |

### Operational Excellence

Recommendations for better operations:

| Issue | Risk | Example Resources |
|-------|------|-------------------|
| No diagnostic settings | Blind to failures | All resources |
| Missing alerts | Delayed incident response | All resources |
| No tags | Governance/cost tracking gaps | All resources |
| Outdated SKU/version | Missing features/security fixes | All resources |

### Cost Optimization

Recommendations to reduce spending:

| Issue | Risk | Example Resources |
|-------|------|-------------------|
| Orphaned disk | Paying for unused storage | Managed Disks |
| Orphaned public IP | Paying for unused IP | Public IP |
| Oversized SKU | Excess capacity cost | VMs, SQL, App Service |
| No reserved capacity | Missing discounts | VMs, SQL, Cosmos DB |

## Severity Levels

Prioritize remediation using this severity matrix:

| Severity | Criteria | Response Time |
|----------|----------|---------------|
| **Critical** | Security vulnerability with active exploit risk | Immediate |
| **High** | Reliability risk affecting availability | Within 1 week |
| **Medium** | Best practice violation with moderate risk | Within 1 month |
| **Low** | Optimization opportunity | As capacity allows |

## Excel Report Columns

### Recommendations Sheet

| Column | Description |
|--------|-------------|
| Recommendation ID | Unique identifier for the recommendation |
| Category | Reliability, Security, Cost, etc. |
| Recommendation | Description of the issue |
| Learn More | Link to documentation |
| Impacted Resources | Count of affected resources |

### ImpactedResources Sheet

| Column | Description |
|--------|-------------|
| Subscription | Subscription ID (may be masked) |
| Resource Group | Resource group name |
| Type | Azure resource type |
| Name | Resource name |
| Recommendation ID | Links to Recommendations sheet |
| Recommendation | Issue description |
| Learn More | Documentation link |
| Param1-5 | Additional context (varies by recommendation) |

### Inventory Sheet

| Column | Description |
|--------|-------------|
| Subscription | Subscription ID |
| Resource Group | Resource group name |
| Location | Azure region |
| Type | Resource type |
| Name | Resource name |
| SKU | SKU tier/name |
| SLA | Calculated SLA percentage |
| Availability Zones | Zone configuration |
| Private Endpoint | Private endpoint status |
| Diagnostic Settings | Diagnostic configuration status |

## Common Recommendation IDs

High-impact recommendations to prioritize:

### Storage Accounts

| ID | Issue |
|----|-------|
| `st-001` | Enable soft delete for blobs |
| `st-002` | Enable soft delete for containers |
| `st-003` | Enable versioning |
| `st-004` | Use private endpoints |
| `st-005` | Disable public blob access |

### Virtual Machines

| ID | Issue |
|----|-------|
| `vm-001` | Enable Azure Backup |
| `vm-002` | Use managed disks |
| `vm-003` | Deploy in availability zones |
| `vm-004` | Enable boot diagnostics |
| `vm-005` | Use managed identity |

### Azure Kubernetes Service

| ID | Issue |
|----|-------|
| `aks-001` | Enable Azure Policy |
| `aks-002` | Use managed identity |
| `aks-003` | Enable Defender for Containers |
| `aks-004` | Use availability zones |
| `aks-005` | Enable cluster autoscaler |

### Key Vault

| ID | Issue |
|----|-------|
| `kv-001` | Enable soft delete |
| `kv-002` | Enable purge protection |
| `kv-003` | Use private endpoints |
| `kv-004` | Enable diagnostic logging |
| `kv-005` | Use RBAC for data plane |

### SQL Database

| ID | Issue |
|----|-------|
| `sql-001` | Enable Transparent Data Encryption |
| `sql-002` | Enable auditing |
| `sql-003` | Use private endpoints |
| `sql-004` | Enable zone redundancy |
| `sql-005` | Enable Advanced Threat Protection |

## Additional Resources

- [Azure Proactive Resiliency Library](https://aka.ms/aprl)
- [Azure Orphaned Resources](https://github.com/dolevshor/azure-orphan-resources)
- [Azure Advisor Documentation](https://learn.microsoft.com/azure/advisor/)
- [Defender for Cloud Recommendations](https://learn.microsoft.com/azure/defender-for-cloud/recommendations-reference)
azqr-remediation-patterns.md 7.8 KB
# Remediation Patterns for Common azqr Findings

This document provides remediation templates for frequently identified compliance issues.

## Storage Account Issues

### Enable Private Endpoints

**Issue:** Storage account accessible via public endpoint

**Azure CLI:**
```bash
# Create private endpoint
az network private-endpoint create \
  --name pe-storage \
  --resource-group <rg-name> \
  --vnet-name <vnet-name> \
  --subnet <subnet-name> \
  --private-connection-resource-id $(az storage account show -n <storage-name> -g <rg-name> --query id -o tsv) \
  --group-id blob \
  --connection-name pe-storage-connection

# Disable public access
az storage account update \
  --name <storage-name> \
  --resource-group <rg-name> \
  --public-network-access Disabled
```

**Bicep:**
```bicep
resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-05-01' = {
  name: 'pe-${storageAccount.name}'
  location: location
  properties: {
    subnet: {
      id: subnet.id
    }
    privateLinkServiceConnections: [
      {
        name: 'pe-${storageAccount.name}-connection'
        properties: {
          privateLinkServiceId: storageAccount.id
          groupIds: ['blob']
        }
      }
    ]
  }
}
```

### Enable Soft Delete

**Issue:** No soft delete protection for blobs

**Azure CLI:**
```bash
az storage account blob-service-properties update \
  --account-name <storage-name> \
  --resource-group <rg-name> \
  --enable-delete-retention true \
  --delete-retention-days 7 \
  --enable-container-delete-retention true \
  --container-delete-retention-days 7
```

**Bicep:**
```bicep
resource blobServices 'Microsoft.Storage/storageAccounts/blobServices@2023-01-01' = {
  parent: storageAccount
  name: 'default'
  properties: {
    deleteRetentionPolicy: {
      enabled: true
      days: 7
    }
    containerDeleteRetentionPolicy: {
      enabled: true
      days: 7
    }
  }
}
```

---

## Key Vault Issues

### Enable Purge Protection

**Issue:** Key Vault can be permanently deleted

**Azure CLI:**
```bash
az keyvault update \
  --name <vault-name> \
  --resource-group <rg-name> \
  --enable-purge-protection true
```

**Bicep:**
```bicep
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
  name: keyVaultName
  location: location
  properties: {
    enableSoftDelete: true
    softDeleteRetentionInDays: 90
    enablePurgeProtection: true
    // ... other properties
  }
}
```

### Use RBAC for Data Plane

**Issue:** Using access policies instead of RBAC

**Azure CLI:**
```bash
az keyvault update \
  --name <vault-name> \
  --resource-group <rg-name> \
  --enable-rbac-authorization true
```

---

## Virtual Machine Issues

### Enable Diagnostic Settings

**Issue:** No diagnostics configured for VM

**Azure CLI:**
```bash
# Create Log Analytics workspace (if needed)
az monitor log-analytics workspace create \
  --resource-group <rg-name> \
  --workspace-name <workspace-name>

# Enable diagnostics
az monitor diagnostic-settings create \
  --name diag-vm \
  --resource $(az vm show -g <rg-name> -n <vm-name> --query id -o tsv) \
  --workspace $(az monitor log-analytics workspace show -g <rg-name> -n <workspace-name> --query id -o tsv) \
  --metrics '[{"category": "AllMetrics", "enabled": true}]'
```

**Bicep:**
```bicep
resource diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = {
  name: 'diag-${vm.name}'
  scope: vm
  properties: {
    workspaceId: logAnalyticsWorkspace.id
    metrics: [
      {
        category: 'AllMetrics'
        enabled: true
      }
    ]
  }
}
```

### Enable Azure Backup

**Issue:** VM not protected by Azure Backup

**Azure CLI:**
```bash
# Create Recovery Services vault (if needed)
az backup vault create \
  --resource-group <rg-name> \
  --name <vault-name> \
  --location <location>

# Enable backup with default policy
az backup protection enable-for-vm \
  --resource-group <rg-name> \
  --vault-name <vault-name> \
  --vm $(az vm show -g <rg-name> -n <vm-name> --query id -o tsv) \
  --policy-name DefaultPolicy
```

---

## AKS Issues

### Enable Defender for Containers

**Issue:** No security monitoring for AKS

**Azure CLI:**
```bash
az aks update \
  --resource-group <rg-name> \
  --name <cluster-name> \
  --enable-defender
```

**Bicep:**
```bicep
resource aksCluster 'Microsoft.ContainerService/managedClusters@2024-01-01' = {
  name: clusterName
  location: location
  properties: {
    securityProfile: {
      defender: {
        securityMonitoring: {
          enabled: true
        }
        logAnalyticsWorkspaceResourceId: logAnalyticsWorkspace.id
      }
    }
    // ... other properties
  }
}
```

### Use Managed Identity

**Issue:** AKS using service principal instead of managed identity

**Azure CLI:**
```bash
az aks update \
  --resource-group <rg-name> \
  --name <cluster-name> \
  --enable-managed-identity
```

---

## SQL Database Issues

### Enable Auditing

**Issue:** SQL Server auditing not enabled

**Azure CLI:**
```bash
# Enable to Log Analytics
az sql server audit-policy update \
  --resource-group <rg-name> \
  --name <server-name> \
  --state Enabled \
  --lats Enabled \
  --lawri $(az monitor log-analytics workspace show -g <rg-name> -n <workspace-name> --query id -o tsv)
```

**Bicep:**
```bicep
resource sqlAudit 'Microsoft.Sql/servers/auditingSettings@2023-05-01-preview' = {
  parent: sqlServer
  name: 'default'
  properties: {
    state: 'Enabled'
    isAzureMonitorTargetEnabled: true
    retentionDays: 90
  }
}
```

### Enable Private Endpoint

**Issue:** SQL Server accessible via public endpoint

**Azure CLI:**
```bash
# Create private endpoint
az network private-endpoint create \
  --name pe-sql \
  --resource-group <rg-name> \
  --vnet-name <vnet-name> \
  --subnet <subnet-name> \
  --private-connection-resource-id $(az sql server show -g <rg-name> -n <server-name> --query id -o tsv) \
  --group-id sqlServer \
  --connection-name pe-sql-connection

# Disable public access
az sql server update \
  --resource-group <rg-name> \
  --name <server-name> \
  --enable-public-network false
```

---

## App Service Issues

### Use Managed Identity

**Issue:** App Service not using managed identity

**Azure CLI:**
```bash
az webapp identity assign \
  --resource-group <rg-name> \
  --name <app-name>
```

**Bicep:**
```bicep
resource webApp 'Microsoft.Web/sites@2023-01-01' = {
  name: appName
  location: location
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    // ... other properties
  }
}
```

### Enforce HTTPS Only

**Issue:** HTTP traffic allowed

**Azure CLI:**
```bash
az webapp update \
  --resource-group <rg-name> \
  --name <app-name> \
  --https-only true
```

### Set Minimum TLS Version

**Issue:** TLS version below 1.2

**Azure CLI:**
```bash
az webapp config set \
  --resource-group <rg-name> \
  --name <app-name> \
  --min-tls-version 1.2
```

---

## Bulk Remediation Script

For multiple resources of the same type, use a loop:

```powershell
# Example: Enable soft delete on all storage accounts
$storageAccounts = az storage account list --query "[].{name:name, rg:resourceGroup}" -o json | ConvertFrom-Json

foreach ($sa in $storageAccounts) {
    Write-Host "Enabling soft delete on $($sa.name)..."
    az storage account blob-service-properties update `
        --account-name $sa.name `
        --resource-group $sa.rg `
        --enable-delete-retention true `
        --delete-retention-days 7
}
```

---

## Remediation Validation

After applying fixes, re-run the azqr scan using the Azure MCP tool to verify the issues have been resolved:

```
mcp_azure_mcp_extension_azqr
  subscription: <subscription-id>
```

## Additional Resources

- [Azure CLI Reference](https://learn.microsoft.com/cli/azure/)
- [Bicep Documentation](https://learn.microsoft.com/azure/azure-resource-manager/bicep/)
- [Azure Policy Built-in Definitions](https://learn.microsoft.com/azure/governance/policy/samples/built-in-policies)
azure-keyvault-expiration-audit.md 5.0 KB
# Key Vault Expiration Audit & Compliance

Automated auditing of Azure Key Vault resources to identify expired or expiring keys, secrets, and certificates before they cause service disruptions.

## Overview

This skill monitors Azure Key Vault resources (keys, secrets, certificates) for expiration issues. It helps prevent service disruptions by identifying:
- **Expired resources** causing active problems
- **Expiring soon** (within customizable days threshold)
- **Missing expiration dates** (security risk)
- **Disabled resources** needing cleanup

## Core Workflow

1. **List Resources**: Enumerate keys, secrets, and certificates in target vault(s)
2. **Get Details**: Retrieve expiration metadata for each resource
3. **Analyze Status**: Compare expiration dates against current date and threshold
4. **Generate Report**: Organize findings by priority with actionable recommendations

## Audit Patterns

### Pattern 1: Single Vault Quick Scan
Check one Key Vault for all expiration issues with configurable day threshold (default: 30 days).

**Tools**: `keyvault_key_list`, `keyvault_key_get`, `keyvault_secret_list`, `keyvault_secret_get`, `keyvault_certificate_list`, `keyvault_certificate_get`

### Pattern 2: Multi-Vault Compliance Report
Scan multiple vaults across subscription for comprehensive security review.

**Use for**: Quarterly audits, organization-wide compliance checks

### Pattern 3: Resource Type Focus
Audit only keys, secrets, OR certificates when specific resource type is mentioned.

**Use for**: Certificate renewal planning, secret rotation tracking

### Pattern 4: Emergency Expired Finder
Quick scan for already-expired resources (negative days) to troubleshoot active incidents.

**Use for**: Production issues, authentication failures

## Key Data Fields

When retrieving resource details, analyze these fields:
- **expiresOn**: Expiration timestamp (null = no expiration set - security risk!)
- **enabled**: Resource is active (false = disabled/inactive)
- **notBefore**: When resource becomes valid
- **createdOn/updatedOn**: For tracking resource age and last rotation
- **subject/issuer**: Certificate-specific metadata

## Report Format

Organize findings into:
- **Summary Statistics**: Total count, expired count, expiring count, no-expiration count per resource type
- **Critical Issues**: Expired resources requiring immediate action
- **Warnings**: Expiring within threshold (e.g., 30 days)
- **Risks**: Resources without expiration dates
- **Recommendations**: Set expiration policies, rotate credentials, remove disabled items

## Remediation Priority

**🔴 Critical** - Expired (< 0 days): Rotate immediately  
**🟠 High** - Expiring 0-7 days: Schedule rotation within 24 hours  
**🟡 Medium** - Expiring 8-30 days: Plan rotation within 1 week  
**🟡 Medium** - No expiration set: Apply expiration policy  
**🟢 Low** - Active (> 30 days): Monitor on regular schedule

## Best Practices

- Run weekly audits to catch issues early
- All resources should have expiration dates (Azure Policy recommendation)
- Configure Azure Event Grid for 30-day advance notifications
- Rotation schedule: Secrets every 60-90 days, Keys annually, Certificates per CA requirements (max 1 year)
- Prioritize production Key Vaults over dev/test
- Automate rotation with Azure Functions or Logic Apps

## MCP Tools Used

| Tool | Purpose |
|------|---------|
| `keyvault_key_list` | List all keys in a vault |
| `keyvault_key_get` | Get key details including expiration |
| `keyvault_secret_list` | List all secrets in a vault |
| `keyvault_secret_get` | Get secret details including expiration |
| `keyvault_certificate_list` | List all certificates in a vault |
| `keyvault_certificate_get` | Get certificate details including expiration |

**Required**: `vault` (Key Vault name)  
**Optional**: `subscription`, `tenant`

## Fallback Strategy: Azure CLI Commands

If Azure MCP Key Vault tools fail, timeout, or are unavailable, use Azure CLI commands as fallback.

### CLI Command Reference

| Operation | Azure CLI Command |
|-----------|-------------------|
| List secrets | `az keyvault secret list --vault-name <vault-name>` |
| Get secret details | `az keyvault secret show --vault-name <vault-name> --name <secret-name>` |
| List keys | `az keyvault key list --vault-name <vault-name>` |
| Get key details | `az keyvault key show --vault-name <vault-name> --name <key-name>` |
| List certificates | `az keyvault certificate list --vault-name <vault-name>` |
| Get certificate details | `az keyvault certificate show --vault-name <vault-name> --name <cert-name>` |

### When to Fallback

Switch to Azure CLI when:
- MCP tool returns timeout error
- MCP tool returns "service unavailable" or connection errors
- MCP tool takes longer than 30 seconds to respond
- Empty response when vault is known to have resources

## Common Issues

- **Access Denied**: Verify RBAC permissions (Key Vault Reader + data plane access)
- **Vault Not Found**: Check vault name and subscription context
- **Null expiresOn**: Resource has no expiration (security risk - requires policy)
- **Time zones**: All timestamps are UTC
azure-quick-review.md 5.0 KB
# Azure Quick Review Compliance Assessment

This skill enables comprehensive Azure compliance assessments using Azure Quick Review (azqr), analyzing findings against Azure best practices, and providing actionable remediation guidance.

## Prerequisites

- **Azure authentication** - Logged in via Azure CLI (`az login`) or using Service Principal/Managed Identity
- **Reader permissions** - Minimum Reader role on target subscription or management group

## Assessment Workflow

### Step 1: Determine Scan Scope

Ask the user or detect from context:

| Scope | Use Case | Required Info |
|-------|----------|---------------|
| Subscription | Full subscription assessment | Subscription ID |
| Resource Group | Targeted assessment | Subscription ID + Resource Group name |
| Management Group | Enterprise-wide assessment | Management Group ID |
| Specific Service | Deep-dive on one resource type | Subscription ID + Service abbreviation |

### Step 2: Run Compliance Scan

Use the Azure MCP tool to run the scan:

```
mcp_azure_mcp_extension_azqr
  subscription: <subscription-id>
  resource-group: <optional-rg-name>
```

### Step 3: Analyze Scan Results

The scan produces an Excel file with these sheets:

| Sheet | Contents | Priority |
|-------|----------|----------|
| **Recommendations** | All recommendations with impacted resource count | High |
| **ImpactedResources** | Resources with specific issues to address | High |
| **Inventory** | All scanned resources with SKU, Tier, SLA details | Medium |
| **Advisor** | Azure Advisor recommendations | Medium |
| **DefenderRecommendations** | Microsoft Defender for Cloud findings | High |
| **Azure Policy** | Non-compliant resources per Azure Policy | Medium |
| **Costs** | 3-month cost history by subscription | Low |
| **Defender** | Defender plan status and tiers | Medium |
| **OutOfScope** | Resources not scanned | Low |

**Focus analysis on:**
1. High-severity recommendations from ImpactedResources
2. Defender recommendations (security-critical)
3. Advisor recommendations (reliability/performance)
4. Policy non-compliance (governance)

### Step 4: Categorize Findings

Group findings by category for prioritized remediation:

| Category | Examples | Severity |
|----------|----------|----------|
| **Security** | Public endpoints, missing encryption, no private endpoints | Critical |
| **Reliability** | No zone redundancy, single instance, no backup | High |
| **Performance** | Undersized SKUs, missing caching, no CDN | Medium |
| **Cost** | Orphaned resources, oversized SKUs, unused reservations | Medium |
| **Operations** | Missing diagnostics, no alerts, no tags | Low |

### Step 5: Generate Remediation Guidance

For each high-priority finding:
1. Explain the risk in plain language
2. Provide remediation options (Portal, CLI, Bicep)
3. Estimate effort and impact

See [azqr-remediation-patterns.md](azqr-remediation-patterns.md) for common fix templates.

### Step 6: Present Summary

Provide a structured summary:

```markdown
## Compliance Assessment Summary

**Scope:** [Subscription/RG/MG name]
**Scanned:** [Date/Time]
**Resources Analyzed:** [Count]

### Key Findings

| Severity | Count | Top Issues |
|----------|-------|------------|
| Critical | X | [List top 3] |
| High | X | [List top 3] |
| Medium | X | [List top 3] |

### Recommended Actions

1. **[Issue]** - [Brief remediation]
2. **[Issue]** - [Brief remediation]
3. **[Issue]** - [Brief remediation]

### Next Steps
- [ ] Address critical security findings
- [ ] Review and remediate high-severity items
- [ ] Schedule follow-up scan to verify fixes
```

## Supported Azure Services

azqr supports 70+ Azure resource types including:

- Azure Kubernetes Service (AKS)
- API Management
- App Configuration
- App Service
- Container Apps
- Cosmos DB
- Container Registry
- Key Vault
- Load Balancer
- Azure Database for MySQL
- Azure Database for PostgreSQL
- Azure Cache for Redis
- Service Bus
- Azure SQL Database
- Storage Accounts
- Virtual Machines
- Virtual Networks

## Tools Used

| Tool | Purpose |
|------|---------|
| `mcp_azure_mcp_extension_azqr` | Run azqr scans via Azure MCP |
| `mcp_azure_mcp_subscription_list` | List available subscriptions |
| `mcp_azure_mcp_group_list` | List resource groups in subscription |

## Troubleshooting

| Issue | Symptom | Solution |
|-------|---------|----------|
| Permission denied | 403 errors during scan | Verify Reader role on scope |
| Not authenticated | `AADSTS` errors | Run `az login` first |
| Slow scan | Scan takes very long | Use resource group scope |

## Example Prompts

- "Check my Azure subscription for compliance issues"
- "Run azqr on my production resource group"
- "What Azure resources don't follow best practices?"
- "Assess my storage accounts for security issues"

## Reference Documentation

- [Recommendation Categories](azqr-recommendations.md)
- [Remediation Patterns](azqr-remediation-patterns.md)
- [Azure Quick Review Documentation](https://azure.github.io/azqr/docs/)
- [Azure Proactive Resiliency Library](https://aka.ms/aprl)
azure-resource-graph.md 2.7 KB
# Azure Resource Graph Queries for Compliance Auditing

Azure Resource Graph (ARG) enables fast, cross-subscription resource querying using KQL via `az graph query`. Use it for compliance scanning, tag audits, and configuration validation.

## How to Query

Use the `extension_cli_generate` MCP tool to generate `az graph query` commands:

```yaml
mcp_azure_mcp_extension_cli_generate
  intent: "query Azure Resource Graph to <describe what you want to audit>"
  cli-type: "az"
```

Or construct directly:

```bash
az graph query -q "<KQL>" --query "data[].{name:name, type:type}" -o table
```

> ⚠️ **Prerequisite:** `az extension add --name resource-graph`

## Key Tables

| Table | Contains |
|-------|----------|
| `Resources` | All ARM resources (name, type, location, properties, tags) |
| `ResourceContainers` | Subscriptions, resource groups, management groups |
| `AuthorizationResources` | Role assignments and role definitions |
| `AdvisorResources` | Azure Advisor recommendations |

## Compliance Query Patterns

**Find resources missing a required tag:**

```kql
Resources
| where isnull(tags['Environment']) or isnull(tags['CostCenter'])
| project name, type, resourceGroup, tags
```

**Tag coverage analysis:**

```kql
Resources
| extend hasEnvTag = isnotnull(tags['Environment'])
| summarize total=count(), tagged=countif(hasEnvTag) by type
| extend coverage=round(100.0 * tagged / total, 1)
| order by coverage asc
```

**Find storage accounts without HTTPS enforcement:**

```kql
Resources
| where type =~ 'microsoft.storage/storageaccounts'
| where properties.supportsHttpsTrafficOnly == false
| project name, resourceGroup, location
```

**Find resources with public network access enabled:**

```kql
Resources
| where properties.publicNetworkAccess =~ 'Enabled'
| project name, type, resourceGroup, location
```

**Query role assignments across subscriptions:**

```kql
AuthorizationResources
| where type == 'microsoft.authorization/roleassignments'
| extend principalType = tostring(properties.principalType)
| summarize count() by principalType
```

**Find resource groups without locks:**

```kql
ResourceContainers
| where type == 'microsoft.resources/subscriptions/resourcegroups'
| project rgName=name, rgId=id
| join kind=leftanti (
    Resources
    | where type == 'microsoft.authorization/locks'
    | project rgId=tostring(properties.resourceId)
) on rgId
```

## Tips

- Use `=~` for case-insensitive type matching (resource types are lowercase)
- Navigate properties with `properties.fieldName`
- Use `--first N` to limit result count
- Use `--subscriptions` to scope to specific subscriptions
- Combine with `AdvisorResources` for security recommendations
references/sdk/
azure-keyvault-certificates-rust.md 1.0 KB
# Key Vault Certificates — Rust SDK Quick Reference

> Condensed from **azure-keyvault-certificates-rust**. Full patterns
> (certificate policies, import, lifecycle management)
> in the **azure-keyvault-certificates-rust** plugin skill if installed.

## Install
cargo add azure_security_keyvault_certificates azure_identity

## Quick Start
```rust
use azure_identity::DeveloperToolsCredential;
use azure_security_keyvault_certificates::CertificateClient;
let credential = DeveloperToolsCredential::new(None)?;
let client = CertificateClient::new("https://<vault>.vault.azure.net/", credential.clone(), None)?;
```

## Best Practices
- Use Entra ID auth — `DeveloperToolsCredential` for dev
- Use managed certificates — auto-renewal with supported issuers
- Set proper validity period — balance security and maintenance
- Use certificate policies — define renewal and key properties
- Monitor expiration — set up alerts for expiring certificates
- Enable soft delete — required for production vaults
azure-keyvault-keys-rust.md 1.2 KB
# Key Vault Keys — Rust SDK Quick Reference

> Condensed from **azure-keyvault-keys-rust**. Full patterns (EC keys,
> backup/restore, crypto operations, RBAC permissions)
> in the **azure-keyvault-keys-rust** plugin skill if installed.

## Install
cargo add azure_security_keyvault_keys azure_identity

## Quick Start
```rust
use azure_identity::DeveloperToolsCredential;
use azure_security_keyvault_keys::KeyClient;
let credential = DeveloperToolsCredential::new(None)?;
let client = KeyClient::new("https://<vault>.vault.azure.net/", credential.clone(), None)?;
```

## Best Practices
- Use Entra ID auth — `DeveloperToolsCredential` for dev, `ManagedIdentityCredential` for production
- Use HSM keys for sensitive workloads — hardware-protected keys
- Use EC for signing — more efficient than RSA
- Use RSA for encryption — when encrypting data
- Backup keys for disaster recovery
- Enable soft delete — required for production vaults
- Use key rotation — create new versions periodically

## Non-Obvious Patterns
```rust
use azure_security_keyvault_keys::models::{CreateKeyParameters, KeyType};
let params = CreateKeyParameters { kty: KeyType::Rsa, key_size: Some(2048), ..Default::default() };
client.create_key("name", params.try_into()?, None).await?.into_model()?;
```
azure-keyvault-keys-ts.md 1.0 KB
# Key Vault Keys — TypeScript SDK Quick Reference

> Condensed from **azure-keyvault-keys-ts**. Full patterns (crypto operations,
> key rotation policies, backup/restore, CryptographyClient)
> in the **azure-keyvault-keys-ts** plugin skill if installed.

## Install
npm install @azure/keyvault-keys @azure/identity

## Quick Start
```typescript
import { KeyClient } from "@azure/keyvault-keys";
import { DefaultAzureCredential } from "@azure/identity";
const keyClient = new KeyClient(`https://${vaultName}.vault.azure.net`, new DefaultAzureCredential());
```

## Best Practices
- Use DefaultAzureCredential for **local development only**. In production, use ManagedIdentityCredential — see [auth-best-practices.md](../auth-best-practices.md)
- Enable soft-delete — required for production vaults
- Set expiration dates on keys
- Use key rotation policies — automate key rotation
- Limit key operations — only grant needed operations (encrypt, sign, etc.)
- Browser not supported — this SDK is Node.js only
azure-keyvault-py.md 1.1 KB
# Key Vault — Python SDK Quick Reference

> Condensed from **azure-keyvault-py**. Full patterns (async clients,
> cryptographic operations, certificate management, error handling)
> in the **azure-keyvault-py** plugin skill if installed.

## Install
pip install azure-keyvault-secrets azure-keyvault-keys azure-keyvault-certificates azure-identity

## Quick Start
```python
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
client = SecretClient(vault_url="https://<vault>.vault.azure.net/", credential=DefaultAzureCredential())
```

## Best Practices
- Use DefaultAzureCredential for **local development only**. In production, use ManagedIdentityCredential — see [auth-best-practices.md](../auth-best-practices.md)
- Use managed identity in Azure-hosted applications
- Enable soft-delete for recovery (enabled by default)
- Use RBAC over access policies for fine-grained control
- Rotate secrets regularly using versioning
- Use Key Vault references in App Service/Functions config
- Cache secrets appropriately to reduce API calls
- Use async clients for high-throughput scenarios
azure-keyvault-secrets-rust.md 1.3 KB
# Key Vault Secrets — Rust SDK Quick Reference

> Condensed from **azure-keyvault-secrets-rust**. Full patterns (versioning,
> update properties, tags, soft delete recovery)
> in the **azure-keyvault-secrets-rust** plugin skill if installed.

## Install
cargo add azure_security_keyvault_secrets azure_identity

## Quick Start
```rust
use azure_identity::DeveloperToolsCredential;
use azure_security_keyvault_secrets::SecretClient;
let credential = DeveloperToolsCredential::new(None)?;
let client = SecretClient::new("https://<vault>.vault.azure.net/", credential.clone(), None)?;
```

## Best Practices
- Use Entra ID auth — `DeveloperToolsCredential` for dev, `ManagedIdentityCredential` for production
- Use `into_model()?` to deserialize responses
- Use `ResourceExt` trait for extracting names from IDs
- Handle soft delete — deleted secrets can be recovered within retention period
- Set content type — helps identify secret format
- Use tags for organizing and filtering secrets
- Version secrets — new values create new versions automatically

## Non-Obvious Patterns
```rust
use azure_security_keyvault_secrets::models::SetSecretParameters;
let params = SetSecretParameters { value: Some("secret-value".into()), ..Default::default() };
client.set_secret("name", params.try_into()?, None).await?.into_model()?;
```
azure-keyvault-secrets-ts.md 1.0 KB
# Key Vault Secrets — TypeScript SDK Quick Reference

> Condensed from **azure-keyvault-secrets-ts**. Full patterns (key rotation,
> cryptographic operations, backup/restore, wrap/unwrap)
> in the **azure-keyvault-secrets-ts** plugin skill if installed.

## Install
npm install @azure/keyvault-secrets @azure/identity

## Quick Start
```typescript
import { DefaultAzureCredential } from "@azure/identity";
import { SecretClient } from "@azure/keyvault-secrets";
const client = new SecretClient("https://<vault>.vault.azure.net", new DefaultAzureCredential());
```

## Best Practices
- Use DefaultAzureCredential for **local development only**. In production, use ManagedIdentityCredential — see [auth-best-practices.md](../auth-best-practices.md)
- Enable soft-delete — required for production vaults
- Set expiration dates on both keys and secrets
- Use key rotation policies — automate key rotation
- Limit key operations — only grant needed operations (encrypt, sign, etc.)
- Browser not supported — these SDKs are Node.js only
azure-security-keyvault-keys-dotnet.md 1.1 KB
# Key Vault Keys — .NET SDK Quick Reference

> Condensed from **azure-security-keyvault-keys-dotnet**. Full patterns
> (crypto operations, key rotation, backup/restore, HSM, KeyResolver)
> in the **azure-security-keyvault-keys-dotnet** plugin skill if installed.

## Install
dotnet add package Azure.Security.KeyVault.Keys
dotnet add package Azure.Identity

## Quick Start
```csharp
using Azure.Security.KeyVault.Keys;
using Azure.Identity;
var client = new KeyClient(new Uri("https://<vault>.vault.azure.net"), new DefaultAzureCredential());
```

## Best Practices
- Use DefaultAzureCredential for **local development only**. In production, use ManagedIdentityCredential — see [auth-best-practices.md](../auth-best-practices.md)
- Enable soft-delete — protect against accidental deletion
- Use HSM-backed keys — set `HardwareProtected = true` for sensitive keys
- Implement key rotation — use automatic rotation policies
- Limit key operations — only enable required KeyOperations
- Set expiration dates — always set ExpiresOn for keys
- Use specific versions — pin to versions in production
- Cache CryptographyClient — reuse for multiple operations
azure-security-keyvault-keys-java.md 1.3 KB
# Key Vault Keys — Java SDK Quick Reference

> Condensed from **azure-security-keyvault-keys-java**. Full patterns
> (crypto operations, HSM keys, key rotation, backup/restore, import)
> in the **azure-security-keyvault-keys-java** plugin skill if installed.

## Install
```xml
<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-security-keyvault-keys</artifactId>
    <version>4.9.0</version>
</dependency>
<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-identity</artifactId>
</dependency>
```

## Quick Start

> **Auth:** `DefaultAzureCredential` is for local development. See [auth-best-practices.md](../auth-best-practices.md) for production patterns.

```java
import com.azure.security.keyvault.keys.KeyClientBuilder;
import com.azure.identity.DefaultAzureCredentialBuilder;
var keyClient = new KeyClientBuilder()
    .vaultUrl("https://<vault>.vault.azure.net")
    .credential(new DefaultAzureCredentialBuilder().build())
    .buildClient();
```

## Best Practices
- Use HSM keys for production — set `setHardwareProtected(true)` for sensitive keys
- Enable soft delete — protects against accidental deletion
- Key rotation — set up automatic rotation policies
- Least privilege — use separate keys for different operations
- Local crypto when possible — use CryptographyClient with local key material to reduce round-trips
azure-security-keyvault-secrets-java.md 1.5 KB
# Key Vault Secrets — Java SDK Quick Reference

> Condensed from **azure-security-keyvault-secrets-java**. Full patterns
> (async client, secret rotation, backup/restore, config loader)
> in the **azure-security-keyvault-secrets-java** plugin skill if installed.

## Install
```xml
<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-security-keyvault-secrets</artifactId>
    <version>4.9.0</version>
</dependency>
<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-identity</artifactId>
</dependency>
```

## Quick Start

> **Auth:** `DefaultAzureCredential` is for local development. See [auth-best-practices.md](../auth-best-practices.md) for production patterns.

```java
import com.azure.security.keyvault.secrets.SecretClientBuilder;
import com.azure.identity.DefaultAzureCredentialBuilder;
var secretClient = new SecretClientBuilder()
    .vaultUrl("https://<vault>.vault.azure.net")
    .credential(new DefaultAzureCredentialBuilder().build())
    .buildClient();
```

## Best Practices
- Enable soft delete — protects against accidental deletion
- Use tags — tag secrets with environment, service, owner
- Set expiration — use `setExpiresOn()` for credentials that should rotate
- Content type — set contentType to indicate format (e.g., application/json)
- Version management — don't delete old versions immediately during rotation
- Access logging — enable diagnostic logging on Key Vault
- Least privilege — use separate vaults for different environments

License (MIT)

View full license text
MIT License

Copyright 2025 (c) Microsoft Corporation.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.