All scripts
Governance 599

Azure Key Vault Access Policy Report

Lists every Key Vault in a subscription along with its access policies or RBAC role assignments, so you can see who actually has access before an audit asks.

Get-AzureKeyVaultAccessPolicyReport.ps1
<#
.SYNOPSIS
Reports on access policies and RBAC role assignments for every Key Vault in a subscription.

.DESCRIPTION
Connects to Azure, enumerates every Key Vault in the current subscription (or a specified one),
and reports both the classic access policy assignments and any Azure RBAC role assignments scoped
to each vault. Useful for a quick audit of who can read or manage secrets, keys, and certificates
without opening each vault in the portal one at a time.

.AUTHOR
Shehryar Hassan

.EXAMPLE
.\Get-AzureKeyVaultAccessPolicyReport.ps1 -SubscriptionId "11111111-1111-1111-1111-111111111111" -OutputPath ".\KeyVaultAccessReport.csv"
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory = $false)]
    [string]$SubscriptionId,

    [Parameter(Mandatory = $false)]
    [string]$OutputPath = ".\KeyVaultAccessReport.csv"
)

if (-not (Get-Module -ListAvailable -Name Az.KeyVault)) {
    Write-Error "The Az.KeyVault module is required. Install it with: Install-Module Az.KeyVault -Scope CurrentUser"
    return
}

if (-not (Get-AzContext)) {
    Connect-AzAccount | Out-Null
}

if ($SubscriptionId) {
    Set-AzContext -SubscriptionId $SubscriptionId | Out-Null
}

$vaults = Get-AzKeyVault
$results = @()

foreach ($vaultRef in $vaults) {
    $vault = Get-AzKeyVault -VaultName $vaultRef.VaultName -ResourceGroupName $vaultRef.ResourceGroupName

    if ($vault.EnableRbacAuthorization) {
        $roleAssignments = Get-AzRoleAssignment -Scope $vault.ResourceId
        foreach ($role in $roleAssignments) {
            $results += [PSCustomObject]@{
                VaultName     = $vault.VaultName
                ResourceGroup = $vault.ResourceGroupName
                AuthModel     = "RBAC"
                PrincipalName = $role.DisplayName
                PrincipalType = $role.ObjectType
                RoleOrPolicy  = $role.RoleDefinitionName
                Permissions   = ""
            }
        }
    }
    else {
        foreach ($policy in $vault.AccessPolicies) {
            $results += [PSCustomObject]@{
                VaultName     = $vault.VaultName
                ResourceGroup = $vault.ResourceGroupName
                AuthModel     = "Access Policy"
                PrincipalName = $policy.DisplayName
                PrincipalType = $policy.ObjectId
                RoleOrPolicy  = ""
                Permissions   = ("Secrets: {0}, Keys: {1}, Certs: {2}" -f ($policy.PermissionsToSecrets -join ";"), ($policy.PermissionsToKeys -join ";"), ($policy.PermissionsToCertificates -join ";"))
            }
        }
    }
}

if ($results.Count -eq 0) {
    Write-Host "No Key Vaults with access assignments found in this subscription."
    return
}

$results | Sort-Object VaultName | Export-Csv -Path $OutputPath -NoTypeInformation
Write-Host "Report written to $OutputPath with $($results.Count) access entries across $($vaults.Count) vaults."

Read it before you run it, and test in a safe tenant first.