Required Permissions
This page covers inventory mode
This page describes the permission model for inventory mode (Invoke-AzureScout / Test-AZSCPermissions). Assessment mode (-Assessment / Test-ScoutPermission) uses a different, narrower model — see the note at the bottom of this page, or go straight to Assessment Permissions. New here? See the Overview.
Overview
AzureScout requires three categories of permissions:
- ARM (Azure Resource Manager) — RBAC role assignments on subscriptions
- Key Vault metadata — the metadata-only
Key Vault Readerrole when secret/key inventory is required - Microsoft Graph API — Application or delegated permissions for Entra ID data
ARM Permissions
| Permission | Scope | Purpose |
|---|---|---|
Reader | Subscription(s), or the tenant-root management group | Enumerate resources and read ARM properties |
Management Group Reader | Tenant-root management group | Enumerate and expand the complete management-group hierarchy |
Key Vault Reader | Each Key Vault, or an inherited scope that contains it | List secret/key metadata (names, tags, lifecycle attributes); cannot read secret values |
Azure's Reader role is the whole ARM control-plane ask. It is Actions: */read with an empty NotActions — a single wildcard over every control-plane read. There is no ARM collector in Scout that needs more than this, including roughly 130 of them that reach Azure through Azure Resource Graph (Microsoft.ResourceGraph/resources/read — also inside Reader's */read, so the conclusion doesn't change, but a role list that names only the per-service actions is understating the ask by that one action).
Assign Reader at management-group scope for the management-group and cross-subscription data
Subscription-scoped Reader silently returns an empty or flattened management-group hierarchy — no error, no warning. Assign it at the tenant-root management group if you want that data, or if you're running any assessment (assessment mode requires MG-root scope unconditionally — see Assessment Permissions).
The management-group hierarchy uses Get-AzManagementGroup -Expand -Recurse. A live minimum-permission run confirmed that subscription-scoped Reader does not authorize that tenant operation. Assign Management Group Reader at the tenant-root management group when the full hierarchy is required. Scout records the missing hierarchy as a coverage gap and continues; it does not treat zero visible management groups as proof that none exist.
Do not grant these three roles — they were removed from the ask
Security Reader, Monitoring Reader, and Cost Management Reader (all Azure RBAC roles, not the Entra roles of the same name) used to be listed here as optional extras. They are not strict subsets of Reader — the precise statement is narrower: none of them grants anything Scout calls that Reader does not already grant.
Monitoring Readeradditionally grantsMicrosoft.Support/*, which includes support-ticket creation — a write, in a tool sold as read-only.Cost Management Readercarries the identicalMicrosoft.Support/*.- Azure RBAC
Security Readeradditionally grants five IoT Defender/actionpermissions, one of which downloads a password-reset file. Scout calls none of them. (The EntraSecurity Readerrole is unrelated and genuinely required for four Identity collectors — see the Graph table below.)
The pre-flight checker no longer asks for any of the three, and Test-AZSCPermissions no longer reports them as missing.
Key Vault object inventory needs metadata permission, never secret-value permission
KeyVaultSecrets and KeyVaultKeys use the Key Vault LIST operations, which return metadata only: id, contentType, tags and the attributes block (enabled, exp, nbf, created, updated). Generic ARM Reader is not sufficient for a complete list: ARM sees only objects created as deployable ARM child resources. Assign built-in Key Vault Reader to supply Microsoft.KeyVault/vaults/secrets/readMetadata/action and the equivalent key metadata read. That role explicitly cannot read secret contents or private key material. Scout never invokes GET-secret, and it whitelists list-response fields before writing raw inventory. A Key Vault certificate has no separate list in Scout — it is materialised as a secret whose contentType is application/x-pkcs12 or application/x-pem-file, and that secret's attributes.exp is the certificate's expiry, so certificate expiry is already present in the KeyVaultSecrets worksheet's Kind/Expires columns rather than a separate collector. See src/collect/Get-ScoutArmChildResource.ps1 for the exact calls.
Cost data needs no additional role beyond Reader
Microsoft.CostManagement/query/read is inside Reader's */read. If cost data still comes back empty with Reader assigned, the cause is a billing setting, not a permission: EA "AO view charges" or MCA "Azure charges" (the current name; older documentation calls it "Allow Azure subscription users to view and optimize costs"). Only an Enterprise Administrator (EA) or a Billing Profile Owner (MCA) can enable it — no Azure RBAC role, including Cost Management Reader, substitutes for it. See Troubleshooting.
The pre-flight checker validates:
- Subscription Enumeration — Can
Get-AzSubscriptionreturn at least one subscription? (Fail if not) - Role Assignment Read — Can
Get-AzRoleAssignmentreadReaderon each target subscription? (Fail per subscription ifReaderis missing there —Readeris the whole ARM ask, so there is no separate "optional role missing" Warn state any more)
Microsoft Graph Permissions
These are the Microsoft Graph application permissions a service principal needs for Entra ID inventory (-Scope All or -Scope EntraOnly). They are derived directly from the queries Scout's Entra collectors actually issue — not a hand-maintained list — so a permission with no consumer is called out rather than requested:
| Permission | Type | Purpose |
|---|---|---|
Organization.Read.All | Application or Delegated | Read tenant organization details |
User.Read.All | Application or Delegated | Read all user profiles |
Group.Read.All | Application or Delegated | Read all groups and memberships |
Application.Read.All | Application or Delegated | Read all app registrations and service principals |
Directory.Read.All | Application or Delegated | Read organization and hybrid-sync state |
RoleManagement.Read.Directory | Application or Delegated | Read directory roles and PIM role assignments |
RoleAssignmentSchedule.Read.Directory | Application or Delegated | Distinguish active/permanent directory-role schedules |
RoleEligibilitySchedule.Read.Directory | Application or Delegated | Read PIM-eligible directory-role schedules |
Policy.Read.All | Application or Delegated | Read conditional access policies, named locations, authorization policy, cross-tenant access policy |
Reports.Read.All | Application or Delegated | Read per-user MFA registration/capability evidence |
AuditLog.Read.All | Application or Delegated | Read the last 30 days of sign-ins for report-only CA impact, legacy authentication, and privileged-access staleness |
AccessReview.Read.All | Application or Delegated | Read access-review definitions and instances |
AdministrativeUnit.Read.All | Application or Delegated | Read administrative units |
Domain.Read.All | Application or Delegated | Read verified domains |
IdentityRiskyUser.Read.All | Application or Delegated | Read risky-user signals — also requires an Entra ID P2 licence; a P1 tenant with the permission granted still returns nothing |
Policy.Read.AuthenticationMethod | Application or Delegated | Read the Verified ID authentication-method configuration (AB#7097) |
VerifiedId-Profile.Read.All | Application or Delegated | Read Verified ID profiles (AB#7097) |
IdentityProvider.Read.All is catalogued but disabled because no collector reads it
Scout's pre-flight now derives criticality from which collectors actually consume a permission, not from a fixed list. IdentityProvider.Read.All still shows up as a disabled coverage record, but nothing downstream reads its output, so the pre-flight reports it Warn — "queried but NO collector reads the result. Do not grant it." — rather than asking for it. Sign-in logs are now consumed by Conditional Access impact, legacy-authentication, emergency-access, and privileged-access evidence, so AuditLog.Read.All is part of the full Entra scan.
If you're signing in as a user instead of a service principal, the equivalent least-privilege grant is Entra directory roles — not the application permissions above. Azure RBAC, Entra directory roles, and Graph application permissions are three separate systems with different scoping and approvers; pick the directory roles or the app permissions based on whether Scout runs as a user or a service principal, don't mix them.
Directory Readers + Security Reader covers most Entra collectors; the following need additional roles of their own, evaluated least-privileged first:
MFA registration and sign-in-log evidence needs
Reports Readerand/orSecurity Readeras listed in the live query catalog; delegated OAuth scopes are still required.Active-versus-eligible PIM schedules need
Privileged Role AdministratororGlobal Reader.Access reviews need
Identity Governance AdministratororGlobal Reader.CrossTenantAccessneedsSecurity AdministratororTenant Governance Administrator— evaluate both before reaching forGlobal Reader, which Microsoft classifies as a privileged role.VerifiedIDConfiguration(readsPolicy.Read.AuthenticationMethod, AB#7097) needsAuthentication Policy Administrator(orGlobal Reader, butAuthentication Policy Administratoris the less-privileged of the two, andSecurity Readerdoes not cover this endpoint despite covering most of the rest).VerifiedIDProfiles(readsVerifiedId-Profile.Read.All, AB#7097) needsAuthentication Policy Administrator— Microsoft's documented least-privileged role for this endpoint.
Authentication Policy Administrator covers both Verified ID collectors, so the full user-auth grant depends on the selected evidence surfaces. Run -PermissionAudit -IncludeEntraPermissions to obtain the exact per-collector impact for the current token rather than treating one broad role bundle as universally sufficient. See Assessment Permissions.
Optional non-Azure identity sources
- Okta:
-IncludeOktaneeds a read-only Okta API token or OAuth grant able to read apps and assignments, policies/rules, zones, factors/users, administrator roles, directories/agents, ThreatInsight, and System Log SSO events. Each denied endpoint is isolated and recorded. The token itself is never persisted. - Entra Connect / AD:
-IncludeOnPremisesIdentityneeds local read access to ADSync cmdlets, the ADSync/Connect Health services, and the ActiveDirectory cmdlets. It grants nothing and makes no changes; missing modules or host access are recorded as Not assessed.
Complete delegated Entra collection can require a second device-code confirmation
Get-AzAccessToken can select the Microsoft Graph audience but cannot request arbitrary delegated scopes. When an interactive user run selects Entra evidence, Scout therefore uses the official Microsoft.Graph.Authentication module to request the enabled catalog's exact read scopes through device code. Bearer and refresh tokens stay in the SDK cache; Scout retains only provider/scope metadata keyed by tenant, account, cloud, and scope set. Service principals and managed identities do not use device code; they continue to use the selected Az context and must have the equivalent Graph application permissions admin-consented. Directory roles and OAuth scopes are both enforced—neither one substitutes for the other.
Licence tiers — what a permission cannot buy you
Scout runs, and produces its full report, on a tenant with no premium Entra licence at all. Licence tier changes how much of the identity picture can be filled in. It changes nothing about the Azure resource inventory, the CAF/WAF assessment, policy and compliance state, or Defender findings — those are Azure control-plane reads governed by Reader, not by Entra licensing.
| Capability | Requires | Without it |
|---|---|---|
| Resource inventory, CAF/WAF assessment, policy & compliance, Defender | Azure Reader only | Full coverage |
| Users, groups, apps, service principals, directory roles, domains, administrative units | Entra ID Free | Full coverage |
| Conditional Access policies, named locations, cross-tenant access | Entra ID P1 | Reported Not assessed — Conditional Access does not exist to read on a Free tenant |
Risky users / Identity Protection (IdentityRiskyUser.Read.All) | Entra ID P2 | Reported Not assessed. Granting the permission does not help |
PIM eligibility and activation (PrivilegedAccess.Read.AzureResources) | Entra ID P2 | Reported Not assessed; standing role assignments are still read |
A licence boundary is not a permission failure
Scout reads subscribedSkus and checks the tenant's licence before deciding a verdict. A licence-gated permission on an unlicensed tenant reports NOT LICENSED, names the product, and states that granting the permission will not populate those collectors — it does not report DENIED and send you to grant something that cannot work.
Most tenants do not carry P2, so this was previously the common case being reported as an error.
The licence check is three-state — licensed / not licensed / could not tell. Only a definitive "not licensed" softens the verdict; if subscribedSkus itself cannot be read the verdict stays Fail, because silently downgrading a genuine denial would hide a real problem.
Either way the affected collectors are reported as Not assessed and named in the report. A gap you chose not to license is still a gap — it is never a pass and never a zero.
Licence tiers — what a permission cannot buy you
Scout runs, and produces its full report, on a tenant with no premium Entra licence at all. Licence tier changes how much of the identity picture can be filled in. It changes nothing about the Azure resource inventory, the CAF/WAF assessment, policy and compliance state, or Defender findings — those are Azure control-plane reads governed by Reader, not by Entra licensing.
| Capability | Requires | Without it |
|---|---|---|
| Resource inventory, CAF/WAF assessment, policy & compliance, Defender | Azure Reader only | Full coverage |
| Users, groups, apps, service principals, directory roles, domains, administrative units | Entra ID Free | Full coverage |
| Conditional Access policies, named locations, cross-tenant access | Entra ID P1 | Reported Not assessed — Conditional Access does not exist to read on a Free tenant |
Risky users / Identity Protection (IdentityRiskyUser.Read.All) | Entra ID P2 | Reported Not assessed. Granting the permission does not help |
PIM eligibility and activation (PrivilegedAccess.Read.AzureResources) | Entra ID P2 | Reported Not assessed; standing role assignments are still read |
A licence boundary is not a permission failure
Scout reads subscribedSkus and checks the tenant's licence before deciding a verdict. A licence-gated permission on an unlicensed tenant reports NOT LICENSED, names the product, and states that granting the permission will not populate those collectors — it does not report DENIED and send you to grant something that cannot work.
Most tenants do not carry P2, so this was previously the common case being reported as an error.
The licence check is three-state — licensed / not licensed / could not tell. Only a definitive "not licensed" softens the verdict; if subscribedSkus itself cannot be read the verdict stays Fail, because silently downgrading a genuine denial would hide a real problem.
Either way the affected collectors are reported as Not assessed and named in the report. A gap you chose not to license is still a gap — it is never a pass and never a zero.
Pre-flight Validation
The Test-AZSCPermissions function runs automatically before extraction (unless -SkipPermissionCheck is set):
| Check | Severity | Behavior |
|---|---|---|
| ARM: Subscription Enumeration | Fail | Stops ARM extraction if no subscriptions accessible |
| ARM: Role Assignment Read (per subscription) | Fail | That subscription's inventory is incomplete without Reader |
| Graph: each permission with a consumer | Fail | Names the exact collectors that will come back empty, and the permission to grant |
| Graph: licence-gated permission on an unlicensed tenant | Warn | NOT LICENSED — names the product; granting the permission would not help |
| Graph: each permission with no consumer | Warn | Reports it as unused — "do not grant" — rather than requesting it |
Reading the three verdicts
They look alike and mean different things:
| Verdict | Meaning | Action |
|---|---|---|
[FAIL] … DENIED — N collectors will be empty | A real gap; granting fixes the coverage | Grant it |
[WARN] … NOT LICENSED — requires <product> | A licence boundary, not a misconfiguration | None, unless you intend to license that tier |
[WARN] … queried but NO collector reads the result | Scout probes something nothing consumes | Do not grant it |
The output is a per-collector impact table, not a bare READY / PARTIAL / INSUFFICIENT verdict. Criticality is derived from which collectors consume which permission, so there is no separate hardcoded list of "critical" permissions to fall out of date. A denied Graph permission also reaches PowerShell's warning stream now, not only a coloured console write — so an automated caller (CI, a scheduled Automation Account run) can detect and act on it, not just a human watching the console. See Troubleshooting for what to do with a Fail.
Scope-Based Gating
Permission checks respect the -Scope parameter:
ArmOnly— Only ARM checks run (Graph checks are skipped entirely)EntraOnly— Only Graph checks run (ARM checks are skipped entirely)All— Both ARM and Graph checks run
Remediation
If the permission checker reports failures:
- For ARM: Ensure
Readerrole is assigned on target subscriptions - For Graph: Grant the required Microsoft Graph API permissions to your app registration or user account
- Re-run with the appropriate credentials
Verification status
This page is documentation analysis backed by Microsoft's published role and permission references, not a tested result. No run has been performed against a Reader-only principal (or the Entra/Graph minimum-privilege grants above) to confirm every collector still returns data. The reasoning is sound and Microsoft-doc-backed, but treat it as probable, not proven until a live comparison run exists.
A different, narrower model for the CAF/WAF assessment platform
Everything above is the inventory mode permission model (Invoke-AzureScout / Test-AZSCPermissions). Assessment mode (-Assessment / Test-ScoutPermission) uses a different, narrower model — do not conflate the two:
Inventory mode (Test-AZSCPermissions) | Assessment mode (Test-ScoutPermission) | |
|---|---|---|
| ARM scope | Reader on each target subscription | Reader at the tenant-root management group |
| Graph | Up to 9 permissions, required for -Scope All/EntraOnly | Not required by any assessment out of the box — governance data (CAF: Azure Landing Zone, Management, Identity, Scout: Governance Baseline, Policy) is collected natively via ARM/Resource Graph. 4 Graph permissions apply only if you opt one of those 5 into the legacy AzGovViz ingestor instead |
| Live-validated? | Yes — both ARM and Graph checks call live endpoints | ARM check is live; the 4 Graph permissions are listed as an unverified checklist (Ok = $null), not actually tested |
Full matrix (every assessment, minimum RBAC, which need Graph, and the PrivilegedAccess.Read.AzureResources / Entra P2 nuance): Auth & permissions per scan type.