mirror of
https://dev.azure.com/effectory/Survey%20Software/_git/Cloud%20Engineering
synced 2026-02-27 18:52:18 +01:00
added documetation
This commit is contained in:
@@ -1,4 +1,74 @@
|
||||
#Connect-AzAccount
|
||||
<#
|
||||
.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 = ""
|
||||
@@ -22,77 +92,234 @@ class ResourceCheck {
|
||||
}
|
||||
|
||||
|
||||
# Initialize script execution
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
$startTime = Get-Date
|
||||
|
||||
Write-Host "======================================================================================================================================================================"
|
||||
Write-Host "Creating key vault resource overview."
|
||||
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 ""
|
||||
|
||||
$subscriptions = Get-AzSubscription | Where-Object State -eq "Enabled"
|
||||
|
||||
|
||||
[string] $date = Get-Date -Format "yyyy-MM-dd HHmm"
|
||||
$fileName = ".\$date azure_key_vaults.csv"
|
||||
|
||||
$managementGroups = Get-AzManagementGroup
|
||||
|
||||
foreach ($managementGroup in $managementGroups)
|
||||
{
|
||||
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------"
|
||||
Write-Host "Management group [$($managementGroup.Name)]"
|
||||
|
||||
$subscriptions = Get-AzManagementGroupSubscription -Group $managementGroup.Name | Where-Object State -eq "Active"
|
||||
|
||||
foreach ($subscription in $subscriptions)
|
||||
{
|
||||
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------"
|
||||
$scope = $subscription.Id.Substring($subscription.Parent.Length, $subscription.Id.Length - $subscription.Parent.Length)
|
||||
$subscriptionId = $scope.Replace("/subscriptions/", "")
|
||||
Write-Host "Subscription [$($subscription.DisplayName) - $subscriptionId]"
|
||||
Set-AzContext -SubscriptionId $subscriptionId | Out-Null
|
||||
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------"
|
||||
|
||||
$allResourceGroups = Get-AzResourceGroup
|
||||
[ResourceCheck[]]$Result = @()
|
||||
|
||||
foreach ($group in $allResourceGroups) {
|
||||
|
||||
Write-Host $group.ResourceGroupName
|
||||
|
||||
$allVaults = Get-AzKeyVault -ResourceGroupName $group.ResourceGroupName
|
||||
|
||||
foreach ($vault in $allVaults) {
|
||||
|
||||
$vaultWithAllProps = Get-AzKeyVault -ResourceGroupName $group.ResourceGroupName -Name $vault.VaultName
|
||||
|
||||
$enabledRBAC = $vaultWithAllProps.EnableRbacAuthorization -eq "TRUE"
|
||||
|
||||
[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
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
$Result | Export-Csv -Path $fileName -Append -NoTypeInformation
|
||||
try {
|
||||
# Validate Azure authentication
|
||||
$context = Get-AzContext
|
||||
if (-not $context) {
|
||||
throw "No Azure context found. Please run Connect-AzAccount first."
|
||||
}
|
||||
}
|
||||
Write-Host "======================================================================================================================================================================"
|
||||
Write-Host "Done."
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user