Azure Penetration Testing: Cloud Security Testing Guide

Microsoft Azure has become the backbone of enterprise infrastructure worldwide, and with that adoption comes an expanded attack surface that differs substantially from traditional on-premises environments. Azure penetration testing is not simply running your existing toolkit against cloud-hosted VMs — it requires understanding Azure-specific identity primitives, resource hierarchies, and the trust relationships that connect them.

This guide walks through how professional pentesters approach Azure engagements: from initial reconnaissance through Azure AD enumeration, storage account exposure, managed identity abuse, Key Vault access, and lateral movement across subscriptions. Every technique here assumes you have written authorisation from the target organisation and are operating within a defined scope.

Azure Penetration Testing Scope and Rules of Engagement

Before touching a single Azure resource, scope definition is critical. Microsoft's penetration testing rules of engagement require that you do not test infrastructure owned by Microsoft itself — you may only test resources within your own Azure subscription or one for which you hold explicit written authorisation. Denial-of-service attacks against Azure infrastructure, testing Microsoft's authentication portals, and probing resources outside your scope are prohibited and may result in account suspension or legal action.

Define scope in terms of Azure constructs: which subscriptions, which resource groups, which Azure AD tenants, and which service principals are in scope. Cloud engagements routinely involve a mix of in-scope and out-of-scope resources within the same tenant — ensure your engagement letter specifies this clearly.

Key information to obtain before starting:

  • Tenant ID and any linked tenants (B2B, B2C configurations)
  • In-scope subscription IDs
  • Initial credentials or service principal credentials for the assumed-breach starting point
  • Whether Azure AD conditional access policies are in scope for bypass testing
  • Emergency contact for the client's Azure administrator

Reconnaissance and Tenant Enumeration

Azure reconnaissance starts externally before you have any credentials. Microsoft exposes several unauthenticated endpoints that reveal tenant information and can confirm whether a domain is registered with Azure AD.

The login.microsoftonline.com OpenID Connect discovery endpoint and the tenant info endpoint leak the tenant ID for any registered domain:

# Resolve tenant ID from a domain
curl -s "https://login.microsoftonline.com/target-company.com/.well-known/openid-configuration" \
  | python3 -m json.tool | grep issuer

# Enumerate Azure services associated with a domain
python3 AADInternals.ps1  # or use the PowerShell module directly
Invoke-AADIntReconAsOutsider -DomainName target-company.com | Format-Table

# Check for federated identity (ADFS, third-party IdP)
curl -s "https://login.microsoftonline.com/getuserrealm.srf?login=user@target-company.com&xml=1"

# Enumerate public storage accounts via DNS brute-force
for name in $(cat common-storage-names.txt); do
  host "${name}.blob.core.windows.net" 2>/dev/null | grep "has address" && echo "FOUND: ${name}"
done

Tools like AADInternals, ROADtools, and BloodHound for Azure (AzureHound) are the standard toolkit for tenant enumeration. AADInternals in particular can enumerate users, groups, and applications from the tenant without authentication by abusing Microsoft's user-enumeration endpoint — a behaviour that Microsoft has repeatedly declined to fix.

Azure AD Enumeration and Privilege Escalation

Once you have credentials — even a low-privileged user account — Azure AD becomes a rich source of lateral movement paths. The key tools are AzureHound (which feeds data into BloodHound CE) and the Azure CLI (az) combined with Microsoft Graph API queries.

# Authenticate with the Azure CLI
az login --tenant <TENANT_ID>
az account list --output table

# Enumerate current identity permissions
az ad signed-in-user show
az role assignment list --assignee $(az ad signed-in-user show --query id -o tsv) --all

# List all service principals (app registrations)
az ad sp list --all --query "[].{displayName:displayName,appId:appId,id:id}" -o table

# Find service principals with secrets or certificates about to expire (or already expired)
az ad app list --all --query "[].{name:displayName,appId:appId}" -o table

# Run AzureHound to collect all AD relationships for BloodHound
./azurehound -u "user@target.com" -p "Password123" list --tenant "<TENANT_ID>" -o output.json

BloodHound CE with the AzureHound collector maps attack paths graphically. Common high-value paths include:

  • AZAddMembers — ability to add users to a privileged group
  • AZOwns — ownership of a service principal, which allows adding credentials
  • AZContributor / AZOwner on subscriptions — full resource control
  • AZGlobalAdmin — tenant-wide God mode
  • AZPrivilegedRoleAdministrator — ability to assign any Azure AD role

Privilege escalation in Azure AD frequently exploits the gap between Azure RBAC (subscription-level resource permissions) and Azure AD roles (tenant-level directory permissions). A user with Owner on a subscription can escalate to Azure AD Global Administrator by enabling the "Access management for Azure resources" toggle — a single checkbox in the Azure portal that grants the user User Access Administrator at root scope.

Storage Account Exposure

Azure Blob Storage is one of the most commonly misconfigured services in Azure environments. Public anonymous access, overly permissive SAS tokens, and misconfigured CORS rules are all vectors that pentesters find repeatedly in real engagements.

When anonymous access is enabled at the container level, any unauthenticated user can list and download blobs. Even when anonymous access is disabled, SAS tokens may be embedded in application configuration files, source code repositories, or leaked via server-side request forgery vulnerabilities.

Misconfiguration Risk Level Impact Detection Method
Anonymous blob read access Critical Public data exposure — no auth required HTTP GET to blob URL without credentials
Account-level SAS token with write + delete High Data destruction or exfiltration SAS token in app config, env vars, or Git history
Overly permissive CORS (wildcard origin) High Cross-origin data theft from authenticated sessions CORS preflight response analysis
Storage account key exposure Critical Full control of all containers and queues Secrets scanning, SSRF to IMDS endpoint
No soft delete / versioning enabled Medium Ransomware can permanently destroy data Storage account properties enumeration
# Enumerate storage accounts in a subscription
az storage account list --query "[].{name:name,rg:resourceGroup,publicAccess:allowBlobPublicAccess}" -o table

# Check for public containers in a specific storage account
az storage container list --account-name <STORAGE_ACCOUNT> \
  --auth-mode login \
  --query "[].{name:name,publicAccess:properties.publicAccess}" -o table

# Try listing blobs without authentication (anonymous access test)
curl -s "https://<STORAGE_ACCOUNT>.blob.core.windows.net/<CONTAINER>?restype=container&comp=list"

# Check CORS configuration
az storage cors list --services b --account-name <STORAGE_ACCOUNT> --auth-mode login

Beyond Blob storage, pentesters should check Azure File shares (SMB exposure, particularly on older accounts with SMB 1.0 enabled), Azure Queue storage for sensitive messages, and Azure Table storage which sometimes holds application data with weaker access controls than blob containers.

Managed Identity Abuse

Managed identities are Azure's mechanism for giving compute resources (VMs, App Services, Functions, AKS pods) an identity without storing credentials. When a resource has a managed identity assigned, it can obtain OAuth tokens from the Azure Instance Metadata Service (IMDS) endpoint at 169.254.169.254 — a link-local address only accessible from within the resource itself.

The abuse scenario: gain code execution on an Azure VM or App Service (via RCE, SSRF, or compromised deployment credentials), then query the IMDS endpoint to obtain a bearer token for the managed identity. If that identity has been granted roles beyond the minimum required — a common misconfiguration — an attacker can pivot across the entire subscription.

# From within an Azure VM or App Service — query IMDS for a token
curl -s -H "Metadata: true" \
  "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" \
  | python3 -m json.tool

# Use the token to enumerate what the managed identity can access
TOKEN=$(curl -s -H "Metadata: true" \
  "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")

# List subscriptions accessible to the managed identity
curl -s -H "Authorization: Bearer $TOKEN" \
  "https://management.azure.com/subscriptions?api-version=2020-01-01" | python3 -m json.tool

# List role assignments for the managed identity
curl -s -H "Authorization: Bearer $TOKEN" \
  "https://management.azure.com/subscriptions/<SUB_ID>/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01&\$filter=principalId%20eq%20'<PRINCIPAL_ID>'" \
  | python3 -m json.tool

From an SSRF vulnerability in a web application hosted on Azure, you can often reach the IMDS endpoint. The critical header Metadata: true is required — this is a rudimentary SSRF protection that prevents browser-based CSRF attacks from reaching IMDS, but it does not stop server-side SSRF. Tools like Microburst and PowerZure automate managed identity token abuse once initial access is obtained.

Azure Key Vault Access Testing

Azure Key Vault stores secrets, keys, and certificates for applications. Misconfigured access policies or excessive RBAC assignments on Key Vault are a high-impact finding — gaining read access to a production Key Vault typically means instant access to database connection strings, API keys, TLS private keys, and signing certificates.

Key Vault has two access models: the legacy Vault Access Policy model (per-principal allow-lists configured directly on the vault) and the newer Azure RBAC model. Many older deployments use Access Policies, which are not visible through standard Azure RBAC enumeration — you need to query the vault-level policies separately.

# List Key Vaults in scope
az keyvault list --query "[].{name:name,rg:resourceGroup,uri:properties.vaultUri}" -o table

# Check access policies on a Key Vault (legacy model)
az keyvault show --name <VAULT_NAME> \
  --query "properties.accessPolicies[].{objectId:objectId,permissions:permissions}" -o table

# If the current identity has list+get on secrets — dump them
az keyvault secret list --vault-name <VAULT_NAME> -o table
az keyvault secret show --vault-name <VAULT_NAME> --name <SECRET_NAME> --query "value" -o tsv

# Check Key Vault network rules — is it accessible from all networks?
az keyvault show --name <VAULT_NAME> \
  --query "properties.networkAcls" -o table

# Enumerate RBAC assignments on the Key Vault (RBAC model)
az role assignment list --scope "/subscriptions/<SUB_ID>/resourceGroups/<RG>/providers/Microsoft.KeyVault/vaults/<VAULT_NAME>" \
  --query "[].{principal:principalName,role:roleDefinitionName}" -o table

A frequently overlooked attack vector is the Key Vault firewall bypass. When a Key Vault is configured to allow access from "Selected networks," but the Azure portal's "Allow trusted Microsoft services to bypass this firewall" option is enabled, any managed identity on a trusted Azure service within the tenant may be able to access it. Validate this by attempting vault access from an in-scope App Service or Function App managed identity.

Lateral Movement Across Subscriptions and Resource Groups

Enterprise Azure environments typically have multiple subscriptions — development, staging, production — linked under a single Azure AD tenant via a Management Group hierarchy. A low-privileged foothold in one subscription can escalate to others through several paths:

  • Shared service principals — app registrations created in the home tenant often have assignments across multiple subscriptions. A compromised service principal credential may be scoped to production even though it was discovered in a dev environment.
  • Cross-subscription managed identity assignments — a VM's managed identity can be granted roles on resources in a different subscription. This is rarely audited and frequently over-provisioned.
  • Azure DevOps service connections — pipelines connected to Azure via service connections often hold Contributor-level access to production subscriptions. Compromising an Azure DevOps organisation's pipeline YAML can execute arbitrary ARM deployments.
  • Shared Key Vault across environments — organisations sometimes use a single Key Vault for multiple environments, meaning access gained in dev exposes production secrets.

When enumerating cross-subscription paths, always check Management Group-level role assignments — these propagate down to all child subscriptions and are often set up once and forgotten:

# List management groups the current identity can see
az account management-group list -o table

# Check role assignments at management group scope
az role assignment list \
  --scope "/providers/Microsoft.Management/managementGroups/<MG_ID>" \
  --query "[].{principal:principalName,role:roleDefinitionName}" -o table

# List all subscriptions in tenant (if you have directory reader)
az account list --all -o table

# Enumerate Azure DevOps service connections (requires ADO access)
az devops service-endpoint list --org https://dev.azure.com/<ORG> --project <PROJECT> -o table

Azure-Specific Tools Reference

The Azure penetration testing toolset has matured significantly. Most practitioners combine the official Azure CLI with a set of purpose-built offensive tools. The table below covers the primary tools used in engagements:

Tool Primary Use Language / Platform
AzureHound Azure AD relationship collection for BloodHound CE Go binary
AADInternals Tenant recon, token manipulation, user enumeration PowerShell module
ROADtools Azure AD Graph enumeration and offline analysis Python
Microburst Storage enumeration, managed identity testing, recon PowerShell module
PowerZure Post-exploitation across Azure resources and Azure AD PowerShell module
ScoutSuite Multi-cloud security posture review and misconfiguration audit Python
Stormspotter Azure resource graph visualisation for attack path analysis Python / Docker
Azure CLI (az) General-purpose enumeration and resource interaction Python (cross-platform)

Common High-Impact Findings and Remediation

Across Azure penetration tests, a consistent set of findings appears repeatedly. Understanding these patterns helps both testers prioritise their work and defenders understand where to focus hardening efforts.

Over-privileged service principals are the single most common critical finding. App registrations accumulate roles over time — Owner or Contributor roles on subscriptions that were granted for a specific migration task and never removed. Remediation is straightforward: apply the principle of least privilege, use built-in roles where possible, and audit role assignments quarterly.

Legacy authentication protocols (SMTP AUTH, IMAP, POP3, Basic Auth via Exchange Online) bypass modern conditional access policies entirely. If Azure AD conditional access requires MFA for interactive logins but legacy authentication is not blocked, an attacker with a valid username and password can authenticate directly to Exchange Online without any MFA prompt. Microsoft has disabled Basic Auth for most Exchange Online protocols as of 2023, but organisations with on-premises hybrid setups may still expose this path.

Unrestricted Azure AD application registration — by default, any user in the tenant can register new applications. This allows a low-privileged attacker to create a malicious OAuth app and use it for consent phishing: tricking users into granting the app access to their email, calendar, and files without the app ever needing to bypass MFA. Disable user application registration in Azure AD settings and enforce admin consent for all OAuth application permissions above basic profile read.

Exposed automation accounts and runbooks are frequently overlooked. Azure Automation Accounts used for operational scripts often hold credentials in variables or run under a Run As account with Contributor access. Gaining access to an Automation Account allows arbitrary PowerShell execution within the Azure environment under that elevated identity.


Azure penetration testing rewards methodical enumeration over noisy scanning. The attack surface is primarily the control plane — the APIs, identity system, and configuration layer — rather than network services. Mastering Azure AD relationships, understanding how managed identities propagate trust, and mapping the storage and secret layer is what separates an effective Azure engagement from a generic vulnerability scan.

Ironimo automates continuous security testing across your Azure-hosted web applications — detecting exposed storage endpoints, CORS misconfigurations, authentication weaknesses, and SSRF vulnerabilities that could expose your managed identity tokens or Key Vault secrets.

Stop relying on point-in-time assessments. Get the same professional-grade scanning capabilities your pentesters use, running on demand against every deployment.

Start free scan
← Back to blog