modules/Devolutions.CIEM.Checks/Public/Get-CIEMRequiredPermission.ps1
|
function Get-CIEMRequiredPermission { <# .SYNOPSIS Gets the required permissions for running CIEM security checks and discovery endpoints. .DESCRIPTION Aggregates all unique permissions required across all enabled checks and discovery endpoints registered in azure_provider_apis. Returns permissions grouped by type, depending on the provider: - Azure: Microsoft Graph API, Azure Resource Manager RBAC, Key Vault data plane, Azure Roles - AWS: IAM actions (e.g., iam:ListUsers, s3:GetBucketPolicy) Discovery endpoint permissions (e.g., Directory.Read.All for Entra entity collection) are always included for the relevant provider, regardless of check filters. .PARAMETER Provider Filter to permissions for a specific cloud provider (Azure, AWS). .PARAMETER Service Filter to permissions required for a specific service (e.g., Entra, IAM, KeyVault, Storage, iam, s3). .PARAMETER CheckId Filter to permissions required for specific check IDs. .OUTPUTS [PSCustomObject] Object containing provider-appropriate permission properties: Azure: Graph, ARM, KeyVaultDataPlane, AzureRoles, CheckCount, DiscoveryEndpointCount, Summary AWS: IAM, CheckCount, Summary .EXAMPLE Get-CIEMRequiredPermission -Provider Azure # Returns all Azure permissions required for Azure checks and discovery endpoints .EXAMPLE Get-CIEMRequiredPermission -Provider AWS # Returns all IAM actions required for AWS checks .EXAMPLE Get-CIEMRequiredPermission -Service Entra # Returns permissions required for Entra ID checks and discovery endpoints #> [CmdletBinding()] [OutputType([PSCustomObject])] param( [Parameter()] [ValidateSet('Azure', 'AWS')] [string]$Provider, [Parameter()] [string]$Service, [Parameter()] [string[]]$CheckId ) $ErrorActionPreference = 'Stop' # Get checks based on filters $getCheckParams = @{} if ($Provider) { $getCheckParams.Provider = $Provider } if ($Service) { $getCheckParams.Service = $Service } $checks = Get-CIEMCheck @getCheckParams if ($CheckId) { $checks = $checks | Where-Object { $CheckId -contains $_.Id } } # Aggregate unique permissions using List for efficient collection $graphPermissions = [System.Collections.Generic.List[string]]::new() $armPermissions = [System.Collections.Generic.List[string]]::new() $kvPermissions = [System.Collections.Generic.List[string]]::new() $iamPermissions = [System.Collections.Generic.List[string]]::new() $endpointAzureRoles = [System.Collections.Generic.List[string]]::new() # Aggregate from checks $checkCount = 0 if ($checks) { $checkCount = @($checks).Count foreach ($check in $checks) { $perms = $check.Permissions if ($perms.Graph) { foreach ($p in $perms.Graph) { $graphPermissions.Add($p) } } if ($perms.ARM) { foreach ($p in $perms.ARM) { $armPermissions.Add($p) } } if ($perms.KeyVaultDataPlane) { foreach ($p in $perms.KeyVaultDataPlane) { $kvPermissions.Add($p) } } if ($perms.IAM) { foreach ($p in $perms.IAM) { $iamPermissions.Add($p) } } } } # Aggregate discovery endpoint permissions from azure_provider_apis (scoped rows) $discoveryEndpointCount = 0 if ($Provider -ne 'AWS') { $endpointParams = @{ HasPermissions = $true } if ($Service) { $endpointParams.Service = $Service } $endpoints = @(Get-CIEMAzureProviderApi @endpointParams) $discoveryEndpointCount = $endpoints.Count foreach ($endpoint in $endpoints) { $perms = $endpoint.Permissions if ($perms.Graph) { foreach ($p in $perms.Graph) { $graphPermissions.Add($p) } } if ($perms.ARM) { foreach ($p in $perms.ARM) { $armPermissions.Add($p) } } if ($perms.KeyVaultDataPlane) { foreach ($p in $perms.KeyVaultDataPlane) { $kvPermissions.Add($p) } } if ($perms.AzureRoles) { foreach ($p in $perms.AzureRoles) { $endpointAzureRoles.Add($p) } } } } if (-not $checks -and $discoveryEndpointCount -eq 0) { Write-Warning "No checks or discovery endpoints found matching the specified criteria." return [PSCustomObject]@{ Graph = @() ARM = @() KeyVaultDataPlane = @() AzureRoles = @() IAM = @() CheckCount = 0 DiscoveryEndpointCount = 0 Summary = "No checks or discovery endpoints found." } } # Get unique and sort (wrap in @() to ensure arrays) $graphPermissions = @($graphPermissions | Select-Object -Unique | Sort-Object) $armPermissions = @($armPermissions | Select-Object -Unique | Sort-Object) $kvPermissions = @($kvPermissions | Select-Object -Unique | Sort-Object) $iamPermissions = @($iamPermissions | Select-Object -Unique | Sort-Object) # Determine required Azure RBAC roles based on check permissions + endpoint permissions $azureRoles = @() if ($graphPermissions.Count -gt 0 -or $armPermissions.Count -gt 0 -or $kvPermissions.Count -gt 0 -or $endpointAzureRoles.Count -gt 0) { # Subscription Reader is always required for subscription discovery (ARM REST API) $azureRoles = @('Reader') # ARM permissions: Reader role covers all */read actions if ($armPermissions.Count -gt 0) { $nonReadPermissions = @($armPermissions | Where-Object { $_ -notmatch '/read$' }) if ($nonReadPermissions.Count -gt 0) { Write-Warning "Some ARM permissions require write access. Review permissions and assign appropriate roles." } } # Key Vault data plane permissions: Map to specific RBAC roles if ($kvPermissions -contains 'secrets/list' -or $kvPermissions -contains 'secrets/get') { $azureRoles += 'Key Vault Secrets User' } if ($kvPermissions -contains 'keys/list' -or $kvPermissions -contains 'keys/get') { $azureRoles += 'Key Vault Crypto User' } # Merge explicit AzureRoles from discovery endpoints foreach ($role in $endpointAzureRoles) { $azureRoles += $role } $azureRoles = @($azureRoles | Select-Object -Unique | Sort-Object) } # Build summary $summaryParts = @() $summaryParts += "Permissions required for $checkCount check(s) and $discoveryEndpointCount discovery endpoint(s):" if ($graphPermissions.Count -gt 0) { $summaryParts += "" $summaryParts += "Microsoft Graph API Permissions (Application):" foreach ($perm in $graphPermissions) { $summaryParts += " - $perm" } } if ($armPermissions.Count -gt 0) { $summaryParts += "" $summaryParts += "Azure Resource Manager RBAC Actions:" foreach ($perm in $armPermissions) { $summaryParts += " - $perm" } } if ($kvPermissions.Count -gt 0) { $summaryParts += "" $summaryParts += "Key Vault Data Plane Permissions:" foreach ($perm in $kvPermissions) { $summaryParts += " - $perm" } } if ($azureRoles.Count -gt 0) { $summaryParts += "" $summaryParts += "Required Azure RBAC Roles (assign at subscription scope):" $summaryParts += " - Reader (required for subscription discovery)" foreach ($role in @($azureRoles | Where-Object { $_ -ne 'Reader' })) { $summaryParts += " - $role" } } if ($discoveryEndpointCount -gt 0) { $summaryParts += "" $summaryParts += "Discovery Endpoint Permissions ($discoveryEndpointCount endpoints):" $summaryParts += " Permissions above include requirements for data collection endpoints" $summaryParts += " registered in azure_provider_apis (Entra, ResourceGraph, IAM)." } if ($iamPermissions.Count -gt 0) { $summaryParts += "" $summaryParts += "AWS IAM Actions:" foreach ($perm in $iamPermissions) { $summaryParts += " - $perm" } } [PSCustomObject]@{ Graph = @($graphPermissions) ARM = @($armPermissions) KeyVaultDataPlane = @($kvPermissions) AzureRoles = @($azureRoles) IAM = @($iamPermissions) CheckCount = $checkCount DiscoveryEndpointCount = $discoveryEndpointCount Summary = $summaryParts -join "`n" } } |