Skip to main content

Azure Discovery

The Infracast Azure plugin authenticates using a service principal with read-only access assigned via Azure RBAC. It uses the Azure Resource Manager API and Microsoft Graph API to enumerate resources across your subscriptions.

How It Works

  1. Infracast authenticates as a service principal using client credentials (client ID + secret, or certificate)
  2. The plugin queries Azure Resource Manager for all resource types in scope
  3. Microsoft Graph is queried for Azure Active Directory objects (users, groups, apps)
  4. Resources are normalized and written to the Infracast graph

Service Principal Setup

Step 1: Create the Service Principal

Option A: Azure CLI (recommended)

# Log in to Azure
az login

# Create a service principal for Infracast
az ad sp create-for-rbac \
--name "infracast-discovery" \
--skip-assignment \
--output json

This outputs:

{
"appId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"displayName": "infracast-discovery",
"password": "your-client-secret",
"tenant": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"
}

Save the appId (client ID), password (client secret), and tenant (tenant ID). The client secret is shown only once.

Option B: Azure Portal

  1. Go to Azure Active Directory → App registrations → New registration
  2. Name: infracast-discovery, leave other settings as defaults
  3. Click Register
  4. Go to Certificates & secrets → New client secret
  5. Set expiry (recommend 24 months) and save the secret value

Step 2: Note Your IDs

# Get your tenant ID
az account show --query tenantId -o tsv

# Get the service principal object ID (needed for role assignments)
az ad sp show --id YOUR_APP_ID --query id -o tsv

Step 3: Assign RBAC Roles

Infracast needs the Reader role on each subscription, plus Directory Readers in Azure AD for identity discovery.

Assign Reader role per subscription:

# Assign Reader role to the service principal on a subscription
az role assignment create \
--assignee YOUR_APP_ID \
--role "Reader" \
--scope "/subscriptions/YOUR_SUBSCRIPTION_ID"

Assign Directory Readers for Azure AD:

# Assign Directory Readers role in Azure AD
az rest --method POST \
--uri "https://graph.microsoft.com/v1.0/directoryRoles/roleTemplateId=88d8e3e3-8f55-4a1e-953a-9b9898b8876b/members/\$ref" \
--body "{\"@odata.id\": \"https://graph.microsoft.com/v1.0/directoryObjects/SP_OBJECT_ID\"}"

Or via Portal: Azure AD → Roles and administrators → Directory Readers → Add assignments → Search for infracast-discovery

Required RBAC Roles Summary

RoleScopePurpose
ReaderSubscription (each)Read all ARM resources
Directory ReadersAzure AD tenantRead users, groups, apps, devices
Security ReaderSubscription (optional)Read Defender for Cloud findings
Key Vault ReaderKey Vaults (optional)Read Key Vault metadata
info

The Reader role is sufficient for most discovery use cases. Directory Readers is required if you want Azure AD identity discovery. Security Reader adds Defender for Cloud findings to the graph.

Step 4: Grant Microsoft Graph API Permissions (for AD discovery)

In Azure AD → App registrations → infracast-discovery → API permissions:

  1. Click Add a permission → Microsoft Graph → Application permissions
  2. Add the following permissions:
PermissionPurpose
Directory.Read.AllRead users, groups, OUs, devices
Group.Read.AllRead group memberships
User.Read.AllRead all user profiles
Application.Read.AllRead app registrations and service principals
Policy.Read.AllRead conditional access policies
AuditLog.Read.AllRead sign-in and audit logs
  1. Click Grant admin consent (requires Global Admin or Privileged Role Admin)

What Gets Discovered

ServiceResource Types
ComputeVirtual Machines, VM Scale Sets, Availability Sets, Proximity Placement Groups
NetworkingVirtual Networks, Subnets, Network Security Groups, Route Tables, Public IPs, Load Balancers, Application Gateways, VPN Gateways, ExpressRoute Circuits, Private Endpoints
StorageStorage Accounts, Blob containers (metadata), File shares, Queue/Table services
DatabasesAzure SQL servers/databases, Cosmos DB accounts, PostgreSQL/MySQL Flexible Servers
AKSKubernetes clusters, Node pools, Add-ons
App ServiceApp Service Plans, Web Apps, Function Apps, API Apps
Azure ADUsers, Groups, Service Principals, App Registrations, Managed Identities, Conditional Access Policies
SecurityKey Vaults, Defender for Cloud findings, Security contacts
IdentityManaged Identities (system and user-assigned), Role assignments
SubscriptionsSubscriptions, Management Groups, Resource Groups

Registering the Credential in Infracast

# Register using client secret
infracast creds add \
--plugin azure \
--name "contoso-subscription" \
--type service-principal \
--tenant-id "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" \
--client-id "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
--client-secret-file /run/secrets/azure-sp-secret

# Register using certificate (more secure)
infracast creds add \
--plugin azure \
--name "contoso-subscription-cert" \
--type service-principal-cert \
--tenant-id "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" \
--client-id "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
--certificate-file /run/secrets/azure-sp-cert.pem

Configuring the Discovery Job

infracast.yaml
discovery:
jobs:
- name: azure-contoso
plugin: azure
credential: contoso-subscription
schedule: "0 */6 * * *"
config:
tenant_id: "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"
subscriptions:
- id: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
name: "production"
- id: "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
name: "development"
# Discover Azure AD objects (requires Directory Readers)
discover_azure_ad: true
# Include specific resource types only (optional)
include_resource_types:
- Microsoft.Compute/virtualMachines
- Microsoft.Network/virtualNetworks
- Microsoft.Storage/storageAccounts

Multi-Subscription Setup

Option 1: Single Service Principal, Multiple Subscriptions

Assign the Reader role to the same service principal on multiple subscriptions. List all subscription IDs in the job config:

# Assign Reader to multiple subscriptions with a loop
for SUB_ID in sub-id-1 sub-id-2 sub-id-3; do
az role assignment create \
--assignee YOUR_APP_ID \
--role "Reader" \
--scope "/subscriptions/$SUB_ID"
done
config:
subscriptions:
- id: "sub-id-1"
name: "production"
- id: "sub-id-2"
name: "staging"
- id: "sub-id-3"
name: "development"

Option 2: Management Group Scope

Assign the Reader role at the Management Group level to cover all child subscriptions automatically:

az role assignment create \
--assignee YOUR_APP_ID \
--role "Reader" \
--scope "/providers/Microsoft.Management/managementGroups/YOUR_MGMT_GROUP_ID"
config:
mode: management-group
management_group_id: "your-mgmt-group-id"
discover_azure_ad: true
tip

Management Group scope is the recommended approach for large organizations. New subscriptions added under the management group are automatically picked up without any Infracast configuration changes.

Troubleshooting

AuthenticationFailed: AADSTS7000215

Symptom: Invalid client secret provided

Cause: The client secret has expired or was entered incorrectly.

Fix:

# Create a new secret
az ad app credential reset --id YOUR_APP_ID --years 2

# Update the credential in Infracast
infracast creds update --name "contoso-subscription" \
--client-secret-file /run/secrets/new-azure-sp-secret

AuthorizationFailed on specific resource types

Symptom: Some resources appear but others are missing; logs show 403 AuthorizationFailed

Cause: The Reader role may not cover certain resource types (e.g., Key Vaults with access policies).

Fix: Add specific role assignments:

# Example: Add Key Vault Reader
az role assignment create \
--assignee YOUR_APP_ID \
--role "Key Vault Reader" \
--scope "/subscriptions/SUB_ID/resourceGroups/RG_NAME/providers/Microsoft.KeyVault/vaults/VAULT_NAME"

Azure AD objects not discovered

Symptom: No users/groups in the Infracast graph from Azure AD

Checks:

  1. Verify Directory Readers role is assigned to the service principal in Azure AD
  2. Verify Microsoft Graph API permissions are granted (admin consent required)
  3. Check that discover_azure_ad: true is set in the job config
  4. Verify the service principal has Directory.Read.All permission (not just delegated)
# Check current app permissions
az ad app permission list --id YOUR_APP_ID

Too many requests / throttling

Symptom: Discovery runs partially complete before failing with HTTP 429

Fix: Adjust the rate limiting config:

config:
api_rate_limit_rps: 5 # reduce from default 20
retry_on_throttle: true
retry_max_attempts: 5
retry_backoff_seconds: 30

Service principal expiry warnings

Symptom: Infracast UI shows warning about expiring credentials

Infracast monitors client secret expiry dates and warns 30 days before expiration. Rotate secrets before they expire:

az ad app credential reset \
--id YOUR_APP_ID \
--years 2 \
--display-name "infracast-$(date +%Y)"