Claude
Skills
Sign in
Back

azure-resource-discovery

Included with Lifetime
$97 forever

Azure resource dependency tracing patterns for mapping infrastructure topology, networking, security, and identity. Use when tracing Azure resource dependencies, generating topology diagrams, or documenting how a specific resource connects to its environment.

Cloud & DevOps

What this skill does


# Azure Resource Discovery

Patterns for tracing Azure resource dependencies, mapping networking and security topology, and generating architecture diagrams.

**SAFETY: All discovery operations are strictly READ-ONLY. NEVER execute `az` commands that create, modify, or delete resources. Only use `show`, `list`, `get`, and `query` operations. This skill is for observation and documentation only.**

## When to Use

- Tracing all dependencies of a specific Azure resource (networking, security, identity, monitoring)
- Documenting how a container app, VM, AKS cluster, or other resource connects to its environment
- Generating topology diagrams showing resource relationships
- Auditing networking and security configuration (VNets, NSGs, private endpoints)

## Prerequisites

- **Azure CLI** (`az`) installed and authenticated (`az login`)
- **Reader** role (minimum) on the target subscription or resource group
- **Azure Resource Graph** extension: required for `az graph query`. Usually auto-installed on first use; if not, the user must run `az extension add --name resource-graph`
- **Graphviz** (optional): `dot` command for rendering complex topologies. Install via `brew install graphviz` (macOS) or `apt install graphviz` (Linux). Falls back to Mermaid if not available.

## Query Guidelines

**IMPORTANT: Use the exact query templates below. Do NOT improvise Resource Graph KQL syntax.** Azure Resource Graph uses a subset of Kusto Query Language with restrictions that differ from full KQL. Improvised queries frequently produce `InvalidQuery` errors.

When you need filtering beyond what the templates cover, prefer `az resource list` with JMESPath `--query` over crafting new Resource Graph queries:

```bash
# GOOD: Use az resource list with JMESPath for simple filtering
az resource list --resource-group "<rg>" --query "[?type!='Microsoft.App/containerApps']" -o json

# BAD: Do NOT improvise Resource Graph KQL operators
# az graph query -q "resources | where type !in~ ('microsoft.app/containerapps')"  <-- will fail
```

### KQL Operators Reference (Resource Graph subset)

Only use these operators in `az graph query` — other KQL operators may not be supported:

| Operator | Example | Notes |
|----------|---------|-------|
| `=~` | `where name =~ 'myapp'` | Case-insensitive equals |
| `==` | `where name == 'myApp'` | Case-sensitive equals |
| `!=` | `where type != 'Microsoft.Web/sites'` | Case-sensitive not equals |
| `!~` | `where type !~ 'microsoft.web/sites'` | Case-insensitive not equals |
| `contains` | `where type contains 'network'` | Case-insensitive substring |
| `!contains` | `where type !contains 'network'` | Case-insensitive not-contains |
| `startswith` | `where name startswith 'prod'` | Case-insensitive prefix |
| `and` / `or` | `where type =~ 'x' and resourceGroup =~ 'y'` | Logical operators |
| `project` | `| project name, type, location` | Select columns |
| `mv-expand` | `| mv-expand x = properties.arr` | Expand arrays |

**Do NOT use:** `!in~`, `!has`, `has`, `in~` with inline lists, `matches regex`, or other advanced KQL operators — they are unreliable in Resource Graph.

## Resource Graph Query Templates

Use these exact templates. Replace only the placeholder values in angle brackets.

### Find Resource by Name

```bash
az graph query -q "resources | where name =~ '<resource-name>'" --first 10 -o json
```

### Find Resource with Subscription Filter

```bash
az graph query -q "resources | where name =~ '<resource-name>'" --subscriptions "<subscription-id>" --first 10 -o json
```

### Find Private Endpoints for a Resource

```bash
az graph query -q "resources | where type =~ 'microsoft.network/privateendpoints' | mv-expand conn = properties.privateLinkServiceConnections | where conn.properties.privateLinkServiceId =~ '<resource-id>'" --first 50 -o json
```

### Find NSGs in a Resource Group

```bash
az graph query -q "resources | where type =~ 'microsoft.network/networksecuritygroups' and resourceGroup =~ '<resource-group>'" --first 20 -o json
```

### Find Resources in a Resource Group (excluding a type)

```bash
# Use az resource list with JMESPath — more reliable than Resource Graph for exclusion filters
az resource list --resource-group "<rg>" --query "[?type!='<type-to-exclude>']" -o json
```

### Find Managed Identity Role Assignments

```bash
az role assignment list --assignee "<principal-id>" -o json
```

### Find Resources by Tag

```bash
az graph query -q "resources | where tags['<tag-key>'] =~ '<tag-value>'" --first 50 -o json
```

## Dependency Tracers by Resource Type

Each tracer lists the `az` CLI commands to execute. Commands that fail (permission denied, resource not found) should be noted in the trace output but should not halt the overall trace.

---

### Container App Tracer

**Target type:** `Microsoft.App/containerApps`

**Key dependencies:** Container App Environment, VNet/Subnet, NSG, ACR, Managed Identity, Key Vault, Log Analytics, Private Endpoints

#### Commands

```bash
# 1. Get container app details (includes identity, ingress, registry, secrets)
az containerapp show --name "<name>" --resource-group "<rg>" -o json

# 2. Get the Container App Environment
az containerapp env show --name "<env-name>" --resource-group "<env-rg>" -o json
# Extract: vnetConfiguration.infrastructureSubnetId, appLogsConfiguration.logAnalyticsConfiguration.customerId

# 3. Get VNet and Subnet from environment's subnet ID
az network vnet subnet show --ids "<subnet-id>" -o json
# Extract: addressPrefix, networkSecurityGroup.id, routeTable.id

# 4. Get the parent VNet
az network vnet show --ids "<vnet-id>" -o json
# Extract: addressSpace.addressPrefixes, subnets

# 5. Get NSG rules (if NSG attached to subnet)
az network nsg show --ids "<nsg-id>" -o json
az network nsg rule list --nsg-name "<nsg-name>" --resource-group "<nsg-rg>" -o json

# 6. Get ACR (from container image registry)
# Parse registry from container image field (e.g., myacr.azurecr.io/app:tag → myacr)
az acr show --name "<acr-name>" -o json

# 7. Get managed identity details
# If systemAssigned: principal ID is in the containerapp show output
# If userAssigned: get each identity
az identity show --ids "<user-assigned-identity-id>" -o json

# 8. Get role assignments for the managed identity
az role assignment list --assignee "<principal-id>" --all -o json

# 9. Get Key Vault references (from secrets in containerapp show output)
# Parse Key Vault URI from secret references (e.g., https://myvault.vault.azure.net/secrets/...)
az keyvault show --name "<vault-name>" -o json

# 10. Get Log Analytics workspace (from environment's log config)
az monitor log-analytics workspace show --workspace-name "<workspace-name>" --resource-group "<la-rg>" -o json

# 11. Find private endpoints targeting this resource
az graph query -q "resources | where type =~ 'microsoft.network/privateendpoints' | mv-expand conn = properties.privateLinkServiceConnections | where conn.properties.privateLinkServiceId =~ '<container-app-id>'" --first 20 -o json

# 12. Get diagnostic settings
az monitor diagnostic-settings list --resource "<container-app-id>" -o json
```

---

### Virtual Machine Tracer

**Target type:** `Microsoft.Compute/virtualMachines`

**Key dependencies:** NIC, VNet/Subnet, NSG, Public IP, Disks, Load Balancer, Availability Set, VM Extensions

#### Commands

```bash
# 1. Get VM details (includes identity, OS, hardware profile)
az vm show --name "<name>" --resource-group "<rg>" -o json
# Extract: networkProfile.networkInterfaces, storageProfile.osDisk, storageProfile.dataDisks,
#          identity, availabilitySet, hardwareProfile.vmSize

# 2. Get each NIC
az network nic show --ids "<nic-id>" -o json
# Extract: ipConfigurations[].subnet.id, ipConfigurations[].publicIPAddress.id,
#          networkSecurityGroup.id, ipConfigurations[].loadBalancerBackendAddressPools

# 3. Get subnet from NIC
az network vnet subnet show --ids "<subnet-id>" -o json
# Extract: addressPrefix, networkSecurityGroup.id, ro

Related in Cloud & DevOps