Skip to content

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:

  1. ARM (Azure Resource Manager) — RBAC role assignments on subscriptions
  2. Key Vault metadata — the metadata-only Key Vault Reader role when secret/key inventory is required
  3. Microsoft Graph API — Application or delegated permissions for Entra ID data

ARM Permissions ​

PermissionScopePurpose
ReaderSubscription(s), or the tenant-root management groupEnumerate resources and read ARM properties
Management Group ReaderTenant-root management groupEnumerate and expand the complete management-group hierarchy
Key Vault ReaderEach Key Vault, or an inherited scope that contains itList 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 Reader additionally grants Microsoft.Support/*, which includes support-ticket creation — a write, in a tool sold as read-only.
  • Cost Management Reader carries the identical Microsoft.Support/*.
  • Azure RBAC Security Reader additionally grants five IoT Defender /action permissions, one of which downloads a password-reset file. Scout calls none of them. (The EntraSecurity Reader role 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-AzSubscription return at least one subscription? (Fail if not)
  • Role Assignment Read — Can Get-AzRoleAssignment read Reader on each target subscription? (Fail per subscription if Reader is missing there — Reader is 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:

PermissionTypePurpose
Organization.Read.AllApplication or DelegatedRead tenant organization details
User.Read.AllApplication or DelegatedRead all user profiles
Group.Read.AllApplication or DelegatedRead all groups and memberships
Application.Read.AllApplication or DelegatedRead all app registrations and service principals
Directory.Read.AllApplication or DelegatedRead organization and hybrid-sync state
RoleManagement.Read.DirectoryApplication or DelegatedRead directory roles and PIM role assignments
RoleAssignmentSchedule.Read.DirectoryApplication or DelegatedDistinguish active/permanent directory-role schedules
RoleEligibilitySchedule.Read.DirectoryApplication or DelegatedRead PIM-eligible directory-role schedules
Policy.Read.AllApplication or DelegatedRead conditional access policies, named locations, authorization policy, cross-tenant access policy
Reports.Read.AllApplication or DelegatedRead per-user MFA registration/capability evidence
AuditLog.Read.AllApplication or DelegatedRead the last 30 days of sign-ins for report-only CA impact, legacy authentication, and privileged-access staleness
AccessReview.Read.AllApplication or DelegatedRead access-review definitions and instances
AdministrativeUnit.Read.AllApplication or DelegatedRead administrative units
Domain.Read.AllApplication or DelegatedRead verified domains
IdentityRiskyUser.Read.AllApplication or DelegatedRead risky-user signals — also requires an Entra ID P2 licence; a P1 tenant with the permission granted still returns nothing
Policy.Read.AuthenticationMethodApplication or DelegatedRead the Verified ID authentication-method configuration (AB#7097)
VerifiedId-Profile.Read.AllApplication or DelegatedRead 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 Reader and/or Security Reader as listed in the live query catalog; delegated OAuth scopes are still required.

  • Active-versus-eligible PIM schedules need Privileged Role Administrator or Global Reader.

  • Access reviews need Identity Governance Administrator or Global Reader.

  • CrossTenantAccess needs Security Administrator or Tenant Governance Administrator — evaluate both before reaching for Global Reader, which Microsoft classifies as a privileged role.

  • VerifiedIDConfiguration (reads Policy.Read.AuthenticationMethod, AB#7097) needs Authentication Policy Administrator (or Global Reader, but Authentication Policy Administrator is the less-privileged of the two, and Security Reader does not cover this endpoint despite covering most of the rest).

  • VerifiedIDProfiles (reads VerifiedId-Profile.Read.All, AB#7097) needs Authentication 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: -IncludeOkta needs 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: -IncludeOnPremisesIdentity needs 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.

CapabilityRequiresWithout it
Resource inventory, CAF/WAF assessment, policy & compliance, DefenderAzure Reader onlyFull coverage
Users, groups, apps, service principals, directory roles, domains, administrative unitsEntra ID FreeFull coverage
Conditional Access policies, named locations, cross-tenant accessEntra ID P1Reported Not assessed — Conditional Access does not exist to read on a Free tenant
Risky users / Identity Protection (IdentityRiskyUser.Read.All)Entra ID P2Reported Not assessed. Granting the permission does not help
PIM eligibility and activation (PrivilegedAccess.Read.AzureResources)Entra ID P2Reported 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.

CapabilityRequiresWithout it
Resource inventory, CAF/WAF assessment, policy & compliance, DefenderAzure Reader onlyFull coverage
Users, groups, apps, service principals, directory roles, domains, administrative unitsEntra ID FreeFull coverage
Conditional Access policies, named locations, cross-tenant accessEntra ID P1Reported Not assessed — Conditional Access does not exist to read on a Free tenant
Risky users / Identity Protection (IdentityRiskyUser.Read.All)Entra ID P2Reported Not assessed. Granting the permission does not help
PIM eligibility and activation (PrivilegedAccess.Read.AzureResources)Entra ID P2Reported 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):

CheckSeverityBehavior
ARM: Subscription EnumerationFailStops ARM extraction if no subscriptions accessible
ARM: Role Assignment Read (per subscription)FailThat subscription's inventory is incomplete without Reader
Graph: each permission with a consumerFailNames the exact collectors that will come back empty, and the permission to grant
Graph: licence-gated permission on an unlicensed tenantWarnNOT LICENSED — names the product; granting the permission would not help
Graph: each permission with no consumerWarnReports it as unused — "do not grant" — rather than requesting it

Reading the three verdicts ​

They look alike and mean different things:

VerdictMeaningAction
[FAIL] … DENIED — N collectors will be emptyA real gap; granting fixes the coverageGrant it
[WARN] … NOT LICENSED — requires <product>A licence boundary, not a misconfigurationNone, unless you intend to license that tier
[WARN] … queried but NO collector reads the resultScout probes something nothing consumesDo 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:

  1. For ARM: Ensure Reader role is assigned on target subscriptions
  2. For Graph: Grant the required Microsoft Graph API permissions to your app registration or user account
  3. 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 scopeReader on each target subscriptionReader at the tenant-root management group
GraphUp to 9 permissions, required for -Scope All/EntraOnlyNot 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 endpointsARM 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.

Released under the MIT License.