In cloud penetration testing, one of the most underestimated scenarios is what an attacker can accomplish with a low-privileged account. On Microsoft Azure, the built-in Reader role is often handed out liberally, as it appears harmless. No write access. No delete permissions. No ability to modify configurations.
But Reader access is far from harmless.
In the hands of a skilled attacker or penetration tester, Reader-level permissions can expose a significant portion of an organization's cloud infrastructure. Subscription structures, virtual machine configurations, network layouts, key vault names, storage account endpoints, service principal details, and application registrations can all be surfaced without ever touching a single privileged action.
This post walks through exactly how that enumeration happens, command by command, so blue teams can understand what they are defending against and red teams can sharpen their methodology.
If your organization wants a real-world assessment of what an attacker could do inside your Azure environment, Redfox Cybersecurity offers specialized cloud pentesting services built for exactly this threat model.
The Azure Reader role grants read access to all resources within a given scope, which may be a management group, subscription, resource group, or individual resource. This means an authenticated user with Reader access can query the Azure Resource Manager API for nearly all resource metadata.
From an attacker's perspective, the goals at this stage are:
None of this requires write access. All of it is achievable with Reader.
Before running any commands, ensure you have the Azure CLI installed and authenticated.
# Install Azure CLI (Linux/macOS)
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
# Authenticate with a target account
az login
# Or use a service principal
az login --service-principal -u <appId> -p <password> --tenant <tenantId>
# Verify current identity
az account show
[cta]
Also install the Az PowerShell module for situations where the CLI does not expose certain metadata:
# Install Az PowerShell module
Install-Module -Name Az -AllowClobber -Scope CurrentUser
# Connect
Connect-AzAccount
[cta]
The first step is understanding the scope of your access. Even Reader access at one subscription may provide visibility into tenant-wide configurations.
# List all subscriptions accessible to the current account
az account list --output table
# Get the current subscription details
az account show --query "{Name:name, ID:id, TenantID:tenantId, State:state}"
# Switch between subscriptions if multiple are accessible
az account set --subscription "<subscription-id>"
[cta]
With PowerShell:
# Get all subscriptions
Get-AzSubscription
# Get tenant ID
(Get-AzContext).Tenant.Id
[cta]
This initial enumeration establishes whether you have access to one subscription or many, which significantly expands the attack surface.
Resource groups are logical containers that reveal how the organization structures its workloads. Their naming conventions often expose environment types (prod, dev, staging), application names, team names, and geographic regions.
# List all resource groups
az group list --output table
# Get resource groups with location and tags
az group list --query "[].{Name:name, Location:location, Tags:tags}" --output table
# List all resource types deployed in the subscription
az resource list --output table
# Filter resources by type
az resource list --resource-type "Microsoft.Compute/virtualMachines" --output table
# List resources in a specific resource group
az resource list --resource-group <resource-group-name> --output table
[cta]
Tags are particularly valuable. Organizations frequently tag resources with environment labels, cost centers, owner emails, and project identifiers, which gives an attacker meaningful intelligence about target priority and ownership.
# Extract all resource tags across the subscription
az resource list --query "[].{Name:name, Type:type, Tags:tags}" --output json
[cta]
Virtual machines are obvious targets for lateral movement. With Reader access, you can pull full VM metadata including OS type, image version, network interfaces, extensions installed, and whether boot diagnostics are enabled.
# List all VMs
az vm list --output table
# Get detailed VM information including network and OS details
az vm list -d --output table
# Get a specific VM's full configuration
az vm show --resource-group <rg-name> --name <vm-name>
# List VM extensions (reveals agents, monitoring tools, script execution history)
az vm extension list --resource-group <rg-name> --vm-name <vm-name> --output table
# Check if managed identity is assigned to VMs
az vm list --query "[].{Name:name, Identity:identity}" --output table
[cta]
VMs with managed identities assigned are particularly interesting escalation targets. If you can get code execution on such a VM, even as a low-privileged OS user, you may be able to query the Instance Metadata Service and obtain Azure tokens without any credentials.
Understanding the network layout reveals segmentation gaps, exposed services, and potential paths for lateral movement.
# List all virtual networks
az network vnet list --output table
# List subnets within a VNet
az network vnet subnet list --resource-group <rg-name> --vnet-name <vnet-name> --output table
# List all network security groups
az network nsg list --output table
# Inspect NSG rules (look for overly permissive inbound rules)
az network nsg rule list --resource-group <rg-name> --nsg-name <nsg-name> --output table
# List public IP addresses
az network public-ip list --output table
# List all load balancers
az network lb list --output table
# List application gateways
az network application-gateway list --output table
[cta]
NSG rules with source set to * (any) and destination port ranges like 22, 3389, 80, or 443 are worth flagging. These represent exposed management interfaces or web services that may be directly reachable from the internet.
Want to know how these misconfigurations translate to real-world risk? The Redfox Cybersecurity pentesting team performs full Azure network assessments to map your exposure before attackers do.
Storage accounts are a goldmine for sensitive data and a frequent source of data breach incidents in Azure environments.
# List all storage accounts
az storage account list --output table
# Get detailed storage account properties
az storage account list --query "[].{Name:name, Kind:kind, Sku:sku.name, AllowPublicAccess:allowBlobPublicAccess, HTTPS:enableHttpsTrafficOnly}" --output table
# Check for accounts that allow public blob access
az storage account list --query "[?allowBlobPublicAccess==true].name" --output table
# List blob containers using a storage account key or SAS (if accessible)
az storage container list --account-name <storage-account-name> --auth-mode login --output table
[cta]
The allowBlobPublicAccess property is a critical flag. If it is set to true, individual containers within the account may be configured for anonymous read or anonymous full access, meaning no credentials are needed to download data.
Even if direct container listing fails, the existence of a storage account and its endpoint URL can be used to probe containers through unauthenticated HTTP requests.
Azure Key Vaults store secrets, certificates, and encryption keys. With Reader access, you cannot read the actual secret values, but you can enumerate vault names, their endpoints, and often their access policies.
# List all key vaults
az keyvault list --output table
# Get key vault properties and access policies
az keyvault show --name <vault-name>
# List secret names (not values) if secret list permission is granted
az keyvault secret list --vault-name <vault-name> --output table
# List certificate names
az keyvault certificate list --vault-name <vault-name> --output table
# List key names
az keyvault key list --vault-name <vault-name> --output table
[cta]
Even if you cannot read secrets, knowing that a vault named prod-db-credentials or api-keys-vault exists tells you exactly what to target if you escalate privileges later. Vault access policies may also reveal which service principals and managed identities have Get or List permissions, giving you a map of privileged identities in the environment.
Enumerating identities and role assignments is one of the highest-value activities from a Reader perspective. This information directly informs privilege escalation paths.
# List all role assignments in the subscription
az role assignment list --all --output table
# Filter by a specific user or service principal
az role assignment list --assignee <objectId-or-email> --output table
# List all custom roles
az role definition list --custom-role-only true --output table
# List all service principals
az ad sp list --all --query "[].{DisplayName:displayName, AppId:appId, ObjectId:id}" --output table
# Get details of a specific service principal
az ad sp show --id <appId>
# List all managed identities
az identity list --output table
[cta]
With PowerShell and the AzureAD or Microsoft.Graph module:
# List all users in the tenant
Get-AzADUser | Select-Object DisplayName, UserPrincipalName, Id
# List all groups
Get-AzADGroup | Select-Object DisplayName, Id
# List members of a specific group
Get-AzADGroupMember -GroupObjectId <group-object-id>
# List all app registrations
Get-AzADApplication | Select-Object DisplayName, AppId, Id
[cta]
Overly permissive role assignments, particularly any identity with Owner or Contributor at the subscription scope, are critical findings. Service principals with credentials stored in key vaults or environment variables are escalation vectors waiting to be exploited.
Manual enumeration works but scales poorly. Several purpose-built tools accelerate this phase of a cloud penetration test.
ROADtools is particularly effective for Azure AD enumeration:
pip install roadrecon
# Gather all Azure AD data using current credentials
roadrecon gather
# Launch the GUI for interactive exploration
roadrecon gui
[cta]
AzureHound (part of the BloodHound ecosystem) maps attack paths visually:
# Run AzureHound with current credentials
./azurehound -u "<username>" -p "<password>" -t "<tenantId>" list --output azurehound-output.json
[cta]
PowerZure provides PowerShell-based enumeration:
Import-Module .\PowerZure.ps1
# Enumerate all resources
Show-AzureResources
# Get all role assignments
Get-AzureRoleAssignments
[cta]
These tools compile what would take hours of manual CLI work into automated output that can be fed directly into a reporting workflow or visualization tool.
If your security team wants a structured assessment using these methodologies against your live Azure environment, reach out to Redfox Cybersecurity for a professional cloud penetration test.
Beyond pure enumeration, Reader-level access lets testers validate specific misconfigurations that are commonly overlooked:
# Check if MFA is enforced (requires Azure AD reader)
az ad user list --query "[].{UPN:userPrincipalName, StrongAuth:strongAuthenticationMethods}" --output table
# Check diagnostic settings (are logs being collected?)
az monitor diagnostic-settings list --resource <resource-id>
# Check if Azure Defender / Defender for Cloud is enabled
az security pricing list --output table
# Check Azure Policy assignments (what policies are enforced?)
az policy assignment list --output table
# Check for automation accounts and runbooks
az automation account list --output table
az automation runbook list --automation-account-name <account-name> --resource-group <rg-name> --output table
[cta]
Automation accounts with runbooks often contain credentials embedded in scripts. Even if you cannot execute the runbooks, you can sometimes read their source code with Reader permissions, which may expose connection strings, service account credentials, or API keys.
Understanding what an attacker can accomplish with Reader access should reshape how organizations think about access control in Azure. Handing out Reader roles broadly is not a safe default.
Key hardening steps include:
Applying the principle of least privilege by scoping Reader access to the minimum necessary resource group rather than the entire subscription. Enabling Azure Defender for Cloud and reviewing its recommendations regularly. Auditing role assignments quarterly and removing stale identities. Enabling Azure Monitor and Microsoft Sentinel to alert on unusual read-pattern activity. Using Conditional Access policies to restrict authentication to trusted devices and locations.
Most organizations do not discover these exposures until after an incident. A proactive penetration test surfaces them before that point. Redfox Cybersecurity's cloud security services are designed to simulate exactly this type of Reader-level attacker to give you a realistic picture of your exposure.
Reader access in Azure is not a security boundary. It is a reconnaissance platform. An attacker who compromises a low-privileged account in your Azure tenant can map your entire infrastructure, identify high-value targets, collect intelligence on your identity model, and build a privilege escalation roadmap without triggering a single write-based alert.
The commands and techniques covered in this post represent standard methodology for Azure penetration testing. They are well understood in offensive security communities and actively used in real-world attacks. If you have not tested your environment against this threat model, you do not know what is visible to an attacker who gets inside.
Get in touch with Redfox Cybersecurity to schedule a cloud penetration test and find out what your Azure environment looks like from the inside.