mirror of
https://dev.azure.com/effectory/Survey%20Software/_git/Cloud%20Engineering
synced 2026-02-27 18:52:18 +01:00
326 lines
17 KiB
PowerShell
326 lines
17 KiB
PowerShell
<#
|
||
.SYNOPSIS
|
||
Generates a comprehensive inventory of Azure Key Vaults across all management groups and subscriptions.
|
||
|
||
.DESCRIPTION
|
||
This script enumerates all Azure Key Vaults within enabled subscriptions across the entire Azure tenant,
|
||
collecting detailed configuration properties, security settings, and governance tags. The results are
|
||
exported to a timestamped CSV file for analysis, compliance reporting, and security auditing.
|
||
|
||
Key capabilities:
|
||
- Multi-tenant Key Vault discovery across all management groups
|
||
- Configuration analysis including RBAC, purge protection, and soft delete settings
|
||
- Governance tag extraction for team ownership and compliance tracking
|
||
- Public network access configuration reporting
|
||
- Timestamped CSV export for audit trails and trend analysis
|
||
|
||
.PARAMETER None
|
||
This script does not accept parameters and will process all accessible Key Vaults.
|
||
|
||
.OUTPUTS
|
||
CSV File: "<date> azure_key_vaults.csv"
|
||
Contains columns for:
|
||
- Resource identification (ID, name, resource group, location)
|
||
- Management hierarchy (management group, subscription)
|
||
- Governance tags (team, product, environment, data classification)
|
||
- Security configuration (RBAC, purge protection, soft delete, network access)
|
||
|
||
.EXAMPLE
|
||
.\KeyVaults.ps1
|
||
|
||
Discovers all Key Vaults and generates: "2024-10-30 1435 azure_key_vaults.csv"
|
||
|
||
.NOTES
|
||
File Name : KeyVaults.ps1
|
||
Author : Cloud Engineering Team
|
||
Prerequisite : Azure PowerShell module (Az.KeyVault, Az.Resources, Az.Accounts)
|
||
Copyright : (c) 2024 Effectory. All rights reserved.
|
||
|
||
Version History:
|
||
1.0 - Initial release with comprehensive Key Vault inventory functionality
|
||
|
||
.LINK
|
||
https://docs.microsoft.com/en-us/azure/key-vault/
|
||
https://docs.microsoft.com/en-us/powershell/module/az.keyvault/
|
||
|
||
.COMPONENT
|
||
Requires Azure PowerShell modules:
|
||
- Az.KeyVault (for Key Vault enumeration and property retrieval)
|
||
- Az.Resources (for resource group and management group access)
|
||
- Az.Accounts (for authentication and subscription management)
|
||
|
||
.ROLE
|
||
Required Azure permissions:
|
||
- Key Vault Reader or higher on all subscriptions
|
||
- Management Group Reader for organizational hierarchy access
|
||
|
||
.FUNCTIONALITY
|
||
- Multi-subscription Key Vault discovery
|
||
- Security configuration analysis and reporting
|
||
- Governance tag extraction and compliance tracking
|
||
- CSV export with comprehensive audit trail
|
||
#>
|
||
|
||
#Requires -Modules Az.KeyVault, Az.Resources, Az.Accounts
|
||
#Requires -Version 5.1
|
||
|
||
[CmdletBinding()]
|
||
param()
|
||
|
||
# Uncomment the following line if authentication is required
|
||
#Connect-AzAccount
|
||
|
||
class ResourceCheck {
|
||
[string] $ResourceId = ""
|
||
[string] $ManagementGroupId = ""
|
||
[string] $ManagementGroupName = ""
|
||
[string] $SubscriptionId = ""
|
||
[string] $SubscriptionName = ""
|
||
[string] $ResourceGroup = ""
|
||
[string] $ResourceName = ""
|
||
[string] $Location = ""
|
||
[string] $Tag_Team = ""
|
||
[string] $Tag_Product = ""
|
||
[string] $Tag_Environment = ""
|
||
[string] $Tag_Data = ""
|
||
[string] $Tag_Deployment = ""
|
||
[string] $Tag_CreatedOnDate = ""
|
||
[string] $Prop_EnablePurgeProtection = ""
|
||
[string] $Prop_EnableRbacAuthorization = ""
|
||
[string] $Prop_EnableSoftDelete = ""
|
||
[string] $Prop_PublicNetworkAccess = ""
|
||
}
|
||
|
||
|
||
# Initialize script execution
|
||
$ErrorActionPreference = "Stop"
|
||
$ProgressPreference = "SilentlyContinue"
|
||
$startTime = Get-Date
|
||
|
||
Write-Host "======================================================================================================================================================================"
|
||
Write-Host "🔐 AZURE KEY VAULT INVENTORY GENERATOR" -ForegroundColor Cyan
|
||
Write-Host "======================================================================================================================================================================"
|
||
Write-Host "⏰ Started: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Green
|
||
Write-Host ""
|
||
|
||
try {
|
||
# Validate Azure authentication
|
||
$context = Get-AzContext
|
||
if (-not $context) {
|
||
throw "No Azure context found. Please run Connect-AzAccount first."
|
||
}
|
||
|
||
Write-Host "🔐 Authenticated as: $($context.Account.Id)" -ForegroundColor Green
|
||
Write-Host "🏢 Tenant: $($context.Tenant.Id)" -ForegroundColor Green
|
||
Write-Host ""
|
||
|
||
# Initialize output file
|
||
[string] $date = Get-Date -Format "yyyy-MM-dd HHmm"
|
||
$fileName = ".\$date azure_key_vaults.csv"
|
||
Write-Host "📄 Output file: $fileName" -ForegroundColor Yellow
|
||
Write-Host ""
|
||
|
||
# Get management groups for organizational structure
|
||
Write-Host "🏗️ Discovering management group structure..." -ForegroundColor Cyan
|
||
$managementGroups = Get-AzManagementGroup
|
||
Write-Host "✅ Found $($managementGroups.Count) management groups" -ForegroundColor Green
|
||
Write-Host ""
|
||
|
||
# Initialize counters for progress tracking
|
||
$totalKeyVaults = 0
|
||
$processedManagementGroups = 0
|
||
$processedSubscriptions = 0
|
||
$securityIssues = @()
|
||
|
||
# Process each management group
|
||
foreach ($managementGroup in $managementGroups) {
|
||
$processedManagementGroups++
|
||
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------"
|
||
Write-Host "🏗️ Management Group [$($managementGroup.DisplayName)]" -ForegroundColor Cyan
|
||
Write-Host " ID: $($managementGroup.Id)" -ForegroundColor DarkGray
|
||
|
||
try {
|
||
# Get active subscriptions in this management group
|
||
$subscriptions = Get-AzManagementGroupSubscription -Group $managementGroup.Name | Where-Object State -eq "Active"
|
||
Write-Host " 📋 Found $($subscriptions.Count) active subscriptions" -ForegroundColor Green
|
||
|
||
foreach ($subscription in $subscriptions) {
|
||
$processedSubscriptions++
|
||
Write-Host ""
|
||
Write-Host " 🔄 Processing Subscription: $($subscription.DisplayName)" -ForegroundColor Yellow
|
||
|
||
try {
|
||
# Extract subscription ID and set context
|
||
$scope = $subscription.Id.Substring($subscription.Parent.Length, $subscription.Id.Length - $subscription.Parent.Length)
|
||
$subscriptionId = $scope.Replace("/subscriptions/", "")
|
||
Write-Host " ID: $subscriptionId" -ForegroundColor DarkGray
|
||
|
||
Set-AzContext -SubscriptionId $subscriptionId | Out-Null
|
||
|
||
# Get all resource groups in the subscription
|
||
$allResourceGroups = Get-AzResourceGroup
|
||
[ResourceCheck[]]$Result = @()
|
||
$subscriptionKeyVaults = 0
|
||
|
||
foreach ($group in $allResourceGroups) {
|
||
Write-Host " 📁 Resource Group: $($group.ResourceGroupName)" -ForegroundColor DarkCyan -NoNewline
|
||
|
||
try {
|
||
# Get Key Vaults in this resource group
|
||
$allVaults = Get-AzKeyVault -ResourceGroupName $group.ResourceGroupName -ErrorAction SilentlyContinue
|
||
|
||
if ($allVaults.Count -gt 0) {
|
||
Write-Host " - Found $($allVaults.Count) Key Vaults" -ForegroundColor Green
|
||
$subscriptionKeyVaults += $allVaults.Count
|
||
} else {
|
||
Write-Host " - No Key Vaults" -ForegroundColor DarkGray
|
||
}
|
||
|
||
foreach ($vault in $allVaults) {
|
||
try {
|
||
# Get detailed Key Vault properties
|
||
$vaultWithAllProps = Get-AzKeyVault -ResourceGroupName $group.ResourceGroupName -Name $vault.VaultName
|
||
|
||
# Analyze security configuration
|
||
$enabledRBAC = $vaultWithAllProps.EnableRbacAuthorization -eq "TRUE"
|
||
|
||
# Check for security concerns
|
||
if (-not $vaultWithAllProps.EnablePurgeProtection) {
|
||
$securityIssues += "⚠️ Purge protection disabled: $($vaultWithAllProps.VaultName) in $($group.ResourceGroupName)"
|
||
}
|
||
if (-not $vaultWithAllProps.EnableSoftDelete) {
|
||
$securityIssues += "⚠️ Soft delete disabled: $($vaultWithAllProps.VaultName) in $($group.ResourceGroupName)"
|
||
}
|
||
if ($vaultWithAllProps.PublicNetworkAccess -eq "Enabled") {
|
||
$securityIssues += "🌐 Public network access enabled: $($vaultWithAllProps.VaultName) in $($group.ResourceGroupName)"
|
||
}
|
||
|
||
# Create resource check object
|
||
[ResourceCheck] $resourceCheck = [ResourceCheck]::new()
|
||
$resourceCheck.ManagementGroupId = $managementGroup.Id
|
||
$resourceCheck.ManagementGroupName = $managementGroup.DisplayName
|
||
$resourceCheck.ResourceId = $vaultWithAllProps.ResourceId
|
||
$resourceCheck.Location = $vaultWithAllProps.Location
|
||
$resourceCheck.ResourceName = $vaultWithAllProps.VaultName
|
||
$resourceCheck.ResourceGroup = $vaultWithAllProps.ResourceGroupName
|
||
$resourceCheck.SubscriptionId = $subscription.Id
|
||
$resourceCheck.SubscriptionName = $subscription.DisplayName
|
||
$resourceCheck.Tag_Team = $vaultWithAllProps.Tags.team
|
||
$resourceCheck.Tag_Product = $vaultWithAllProps.Tags.product
|
||
$resourceCheck.Tag_Environment = $vaultWithAllProps.Tags.environment
|
||
$resourceCheck.Tag_Data = $vaultWithAllProps.Tags.data
|
||
$resourceCheck.Tag_CreatedOnDate = $vaultWithAllProps.Tags.CreatedOnDate
|
||
$resourceCheck.Tag_Deployment = $vaultWithAllProps.Tags.drp_deployment
|
||
$resourceCheck.Prop_EnablePurgeProtection = $vaultWithAllProps.EnablePurgeProtection
|
||
$resourceCheck.Prop_EnableRbacAuthorization = $enabledRBAC
|
||
$resourceCheck.Prop_EnableSoftDelete = $vaultWithAllProps.EnableSoftDelete
|
||
$resourceCheck.Prop_PublicNetworkAccess = $vaultWithAllProps.PublicNetworkAccess
|
||
|
||
$Result += $resourceCheck
|
||
$totalKeyVaults++
|
||
|
||
} catch {
|
||
Write-Host " ❌ Error processing vault $($vault.VaultName): $($_.Exception.Message)" -ForegroundColor Red
|
||
}
|
||
}
|
||
} catch {
|
||
Write-Host " - ❌ Error accessing resource group: $($_.Exception.Message)" -ForegroundColor Red
|
||
}
|
||
}
|
||
|
||
# Export results for this subscription
|
||
if ($Result.Count -gt 0) {
|
||
$Result | Export-Csv -Path $fileName -Append -NoTypeInformation
|
||
Write-Host " ✅ Exported $($Result.Count) Key Vaults from subscription" -ForegroundColor Green
|
||
} else {
|
||
Write-Host " ℹ️ No Key Vaults found in subscription" -ForegroundColor DarkYellow
|
||
}
|
||
|
||
} catch {
|
||
Write-Host " ❌ Error processing subscription: $($_.Exception.Message)" -ForegroundColor Red
|
||
}
|
||
}
|
||
} catch {
|
||
Write-Host " ❌ Error accessing management group: $($_.Exception.Message)" -ForegroundColor Red
|
||
}
|
||
|
||
Write-Host ""
|
||
}
|
||
# Calculate execution time and generate summary report
|
||
$endTime = Get-Date
|
||
$executionTime = $endTime - $startTime
|
||
|
||
Write-Host "======================================================================================================================================================================"
|
||
Write-Host "📊 AZURE KEY VAULT INVENTORY SUMMARY" -ForegroundColor Cyan
|
||
Write-Host "======================================================================================================================================================================"
|
||
Write-Host "⏰ Execution Time: $($executionTime.ToString('hh\:mm\:ss'))" -ForegroundColor Green
|
||
Write-Host "🏗️ Management Groups Processed: $processedManagementGroups" -ForegroundColor Green
|
||
Write-Host "📋 Subscriptions Processed: $processedSubscriptions" -ForegroundColor Green
|
||
Write-Host "🔐 Total Key Vaults Discovered: $totalKeyVaults" -ForegroundColor Green
|
||
Write-Host "📄 Results Exported To: $fileName" -ForegroundColor Yellow
|
||
|
||
if (Test-Path $fileName) {
|
||
$fileSize = (Get-Item $fileName).Length
|
||
Write-Host "💾 File Size: $([math]::Round($fileSize/1KB, 2)) KB" -ForegroundColor Green
|
||
}
|
||
|
||
# Display security analysis summary
|
||
if ($securityIssues.Count -gt 0) {
|
||
Write-Host ""
|
||
Write-Host "🚨 SECURITY ANALYSIS SUMMARY" -ForegroundColor Red
|
||
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------"
|
||
Write-Host "Found $($securityIssues.Count) potential security concerns:" -ForegroundColor Yellow
|
||
foreach ($issue in $securityIssues | Select-Object -First 10) {
|
||
Write-Host " $issue" -ForegroundColor Yellow
|
||
}
|
||
if ($securityIssues.Count -gt 10) {
|
||
Write-Host " ... and $($securityIssues.Count - 10) more issues (see CSV for complete details)" -ForegroundColor DarkYellow
|
||
}
|
||
Write-Host ""
|
||
Write-Host "📋 Recommendations:" -ForegroundColor Cyan
|
||
Write-Host " • Enable purge protection on production Key Vaults" -ForegroundColor White
|
||
Write-Host " • Ensure soft delete is enabled for data recovery capabilities" -ForegroundColor White
|
||
Write-Host " • Consider disabling public network access where possible" -ForegroundColor White
|
||
Write-Host " • Implement RBAC authorization for enhanced security" -ForegroundColor White
|
||
} else {
|
||
Write-Host ""
|
||
Write-Host "✅ SECURITY ANALYSIS: No major security concerns detected" -ForegroundColor Green
|
||
}
|
||
|
||
Write-Host ""
|
||
Write-Host "📈 NEXT STEPS:" -ForegroundColor Cyan
|
||
Write-Host " 1. Review the generated CSV file for detailed Key Vault configurations" -ForegroundColor White
|
||
Write-Host " 2. Analyze governance tags for compliance with organizational standards" -ForegroundColor White
|
||
Write-Host " 3. Address any security recommendations identified above" -ForegroundColor White
|
||
Write-Host " 4. Consider implementing automated monitoring for Key Vault configurations" -ForegroundColor White
|
||
|
||
Write-Host ""
|
||
Write-Host "✅ Azure Key Vault inventory completed successfully!" -ForegroundColor Green
|
||
Write-Host "======================================================================================================================================================================"
|
||
|
||
} catch {
|
||
Write-Host ""
|
||
Write-Host "❌ CRITICAL ERROR OCCURRED" -ForegroundColor Red
|
||
Write-Host "======================================================================================================================================================================"
|
||
Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red
|
||
Write-Host "Line: $($_.InvocationInfo.ScriptLineNumber)" -ForegroundColor Red
|
||
Write-Host "Position: $($_.InvocationInfo.OffsetInLine)" -ForegroundColor Red
|
||
Write-Host ""
|
||
Write-Host "🔧 TROUBLESHOOTING STEPS:" -ForegroundColor Yellow
|
||
Write-Host " 1. Verify you are authenticated to Azure (Connect-AzAccount)" -ForegroundColor White
|
||
Write-Host " 2. Ensure you have Key Vault Reader permissions on target subscriptions" -ForegroundColor White
|
||
Write-Host " 3. Check that the Management Group Reader role is assigned" -ForegroundColor White
|
||
Write-Host " 4. Verify Azure PowerShell modules are installed and up to date" -ForegroundColor White
|
||
Write-Host " 5. Try running the script with -Verbose for additional diagnostic information" -ForegroundColor White
|
||
Write-Host ""
|
||
Write-Host "📞 For additional support, contact the Cloud Engineering team" -ForegroundColor Cyan
|
||
Write-Host "======================================================================================================================================================================"
|
||
|
||
# Ensure we exit with error code for automation scenarios
|
||
exit 1
|
||
} finally {
|
||
# Reset progress preference
|
||
$ProgressPreference = "Continue"
|
||
}
|
||
|