Public/Find-AzureUtilsPublicResource.ps1
|
function Find-AzureUtilsPublicResource { <# .SYNOPSIS Finds Azure resources that appear to be publicly accessible. .DESCRIPTION Uses Azure Resource Graph to surface resources exposed to the public internet and explains each in an 'Exposure' column. Returns one object per finding (also shown as a colored console table). Categories (all by default, narrow with -Type): PublicIp public IP addresses that are associated (in use) PublicNetworkAccess resources with properties.publicNetworkAccess = Enabled (managed disks are excluded: Enabled by default, not a real exposure) StorageOpen storage with anonymous blob access or open firewall NsgInternetInbound NSG inbound Allow rules from the Internet (* / 0.0.0.0/0) These are heuristics; review before acting. A resource may appear more than once when several categories apply. .PARAMETER SubscriptionId One or more subscription IDs. Default: every enabled subscription. .PARAMETER ManagementGroupId One or more management groups to scan (requires Az.ResourceGraph). .PARAMETER Type Limit the exposure categories to check. Defaults to all of them. .EXAMPLE Find-AzureUtilsPublicResource .EXAMPLE Find-AzureUtilsPublicResource -ManagementGroupId 'PLAT' -Type StorageOpen, NsgInternetInbound .EXAMPLE Find-AzureUtilsPublicResource | Export-Csv .\public-exposure.csv -NoTypeInformation .OUTPUTS AzureUtils.PublicResource #> [CmdletBinding(DefaultParameterSetName = 'Subscriptions')] [OutputType('AzureUtils.PublicResource')] param( [Parameter(ParameterSetName = 'Subscriptions')] [string[]] $SubscriptionId, [Parameter(ParameterSetName = 'ManagementGroup', Mandatory)] [string[]] $ManagementGroupId, [ValidateSet('PublicIp', 'PublicNetworkAccess', 'StorageOpen', 'NsgInternetInbound')] [string[]] $Type = @('PublicIp', 'PublicNetworkAccess', 'StorageOpen', 'NsgInternetInbound') ) $null = Assert-AzureUtilsContext $resolved = Resolve-AzureUtilsScope -SubscriptionId $SubscriptionId -ManagementGroupId $ManagementGroupId if ($resolved.Type -eq 'Subscription' -and -not $resolved.HasSubscriptions) { Write-Warning 'No accessible subscriptions in scope.' return } $query = New-AzureUtilsPublicResourceQuery -Type $Type $nameMap = $resolved.NameMap $scope = $resolved.Scope Write-Verbose "Public-resource query:`n$query" Invoke-AzureUtilsGraphQuery -Query $query @scope | ForEach-Object { $subId = [string]$_.subscriptionId [pscustomobject]@{ PSTypeName = 'AzureUtils.PublicResource' Name = $_.name ResourceType = $_.type ResourceGroup = $_.resourceGroup Location = $_.location SubscriptionName = if ($nameMap.ContainsKey($subId)) { $nameMap[$subId] } else { $subId } SubscriptionId = $subId Exposure = $_.exposure Tags = ConvertTo-AzureUtilsHashtable -InputObject $_.tags ResourceId = $_.id } } } |