Private/RoleManagement/Azure/Get-AzureResourcePIMPolicy.ps1
|
function Get-AzureResourcePIMPolicy { <# .SYNOPSIS Retrieves Azure Resource PIM policy settings for a specific role. .DESCRIPTION Gets the actual PIM policy configuration for Azure Resource roles including activation requirements, maximum duration, approval settings, etc. .PARAMETER RoleDefinitionId The Azure role definition ID. .PARAMETER SubscriptionId The subscription ID where the role is assigned. .PARAMETER Scope The specific scope of the role assignment. .OUTPUTS PSCustomObject containing policy information #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$RoleDefinitionId, [Parameter(Mandatory)] [string]$SubscriptionId, [Parameter()] [string]$Scope ) Write-Verbose "Fetching Azure Resource PIM policy for role: $RoleDefinitionId in subscription: $SubscriptionId" try { # Azure Resource PIM policies are retrieved differently than Entra ID # They use the Azure Management API directly $context = Get-AzContext if (-not $context) { Write-Warning "No Azure context available for policy retrieval" return $null } # Get access token for Azure Management API $token = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id, $null, "Never", $null, "https://management.azure.com/").AccessToken # Azure Resource PIM policies are scoped to the resource scope $policyScope = if ($Scope) { $Scope } else { "/subscriptions/$SubscriptionId" } # Normalize role definition ID to GUID and construct correct path based on scope type $roleDefGuid = $RoleDefinitionId if ($roleDefGuid -match "/providers/Microsoft\.Authorization/roleDefinitions/([a-fA-F0-9\-]{36})") { $roleDefGuid = $matches[1] } $isManagementGroupScope = ($policyScope -match "^/providers/Microsoft\.Management/managementGroups/") $roleDefPath = if ($isManagementGroupScope) { "/providers/Microsoft.Authorization/roleDefinitions/$roleDefGuid" } else { "/subscriptions/$SubscriptionId/providers/Microsoft.Authorization/roleDefinitions/$roleDefGuid" } # Call Azure REST API to get PIM role settings $headers = @{ 'Authorization' = "Bearer $token" 'Content-Type' = 'application/json' } # Try to get the role setting for this specific role definition at this scope $uri = "https://management.azure.com$policyScope/providers/Microsoft.Authorization/roleManagementPolicyAssignments?api-version=2020-10-01&`$filter=roleDefinitionId eq '$roleDefPath'" $response = Invoke-RestMethod -Uri $uri -Headers $headers -Method Get -ErrorAction SilentlyContinue if ($response -and $response.value -and $response.value.Count -gt 0) { $policyAssignment = $response.value[0] $policyId = $policyAssignment.properties.policyId # Get the actual policy definition $policyUri = "https://management.azure.com$policyScope/providers/Microsoft.Authorization/roleManagementPolicies/${policyId}?api-version=2020-10-01" $policyResponse = Invoke-RestMethod -Uri $policyUri -Headers $headers -Method Get -ErrorAction SilentlyContinue if ($policyResponse -and $policyResponse.properties) { $policy = $policyResponse.properties # Parse the policy rules to extract relevant settings $maxDuration = 8 # Default $requiresMfa = $false # Azure Resource roles typically don't require MFA activation $requiresJustification = $true # Default $requiresApproval = $false if ($policy.rules) { foreach ($rule in $policy.rules) { switch ($rule.id) { 'Activation_Admin_Duration' { if ($rule.maximumDuration) { # Parse duration (format: PT8H for 8 hours) if ($rule.maximumDuration -match "PT(\d+)H") { $maxDuration = [int]$matches[1] } } } 'Activation_Admin_MFA' { $requiresMfa = $rule.setting.mfaRequired -eq $true } 'Activation_Admin_Justification' { $requiresJustification = $rule.setting.justificationRequired -eq $true } 'Activation_Admin_Approval' { $requiresApproval = $rule.setting.approvalRequired -eq $true } } } } Write-Verbose "Retrieved Azure Resource PIM policy: MaxDuration=$maxDuration, MFA=$requiresMfa, Justification=$requiresJustification, Approval=$requiresApproval" return [PSCustomObject]@{ MaxDuration = $maxDuration RequiresMfa = $requiresMfa RequiresJustification = $requiresJustification RequiresTicket = $false # Azure Resource roles don't typically use tickets RequiresApproval = $requiresApproval RequiresAuthenticationContext = $false # Not used for Azure Resource roles AuthenticationContextId = $null AuthenticationContextDisplayName = $null AuthenticationContextDescription = $null AuthenticationContextDetails = $null NotificationSettings = $policy.notificationSettings ApprovalSettings = if ($requiresApproval) { $policy.approvalSettings } else { $null } } } } # Fallback: enumerate all policy assignments at scope and match locally when server-side filter fails try { $listUri = "https://management.azure.com$policyScope/providers/Microsoft.Authorization/roleManagementPolicyAssignments?api-version=2020-10-01" $listResponse = Invoke-RestMethod -Uri $listUri -Headers $headers -Method Get -ErrorAction SilentlyContinue if ($listResponse -and $listResponse.value -and $listResponse.value.Count -gt 0) { $matched = $listResponse.value | Where-Object { $_.properties.roleDefinitionId -eq $roleDefPath -or ($_.properties.roleDefinitionId -match "([a-fA-F0-9\-]{36})" -and $matches[1] -eq $roleDefGuid) } | Select-Object -First 1 if ($matched) { $policyId = $matched.properties.policyId $policyUri = "https://management.azure.com$policyScope/providers/Microsoft.Authorization/roleManagementPolicies/${policyId}?api-version=2020-10-01" $policyResponse = Invoke-RestMethod -Uri $policyUri -Headers $headers -Method Get -ErrorAction SilentlyContinue if ($policyResponse -and $policyResponse.properties) { $policy = $policyResponse.properties # Parse the policy rules to extract relevant settings $maxDuration = 8 # Default $requiresMfa = $false $requiresJustification = $true $requiresApproval = $false if ($policy.rules) { foreach ($rule in $policy.rules) { switch ($rule.id) { 'Activation_Admin_Duration' { if ($rule.maximumDuration -and ($rule.maximumDuration -match "PT(\d+)H")) { $maxDuration = [int]$matches[1] } } 'Activation_Admin_MFA' { $requiresMfa = $rule.setting.mfaRequired -eq $true } 'Activation_Admin_Justification' { $requiresJustification = $rule.setting.justificationRequired -eq $true } 'Activation_Admin_Approval' { $requiresApproval = $rule.setting.approvalRequired -eq $true } } } } Write-Verbose "Retrieved Azure Resource PIM policy via fallback: MaxDuration=$maxDuration, MFA=$requiresMfa, Justification=$requiresJustification, Approval=$requiresApproval" return [PSCustomObject]@{ MaxDuration = $maxDuration RequiresMfa = $requiresMfa RequiresJustification = $requiresJustification RequiresTicket = $false RequiresApproval = $requiresApproval RequiresAuthenticationContext = $false AuthenticationContextId = $null AuthenticationContextDisplayName = $null AuthenticationContextDescription = $null AuthenticationContextDetails = $null NotificationSettings = $policy.notificationSettings ApprovalSettings = if ($requiresApproval) { $policy.approvalSettings } else { $null } } } } } } catch { Write-Verbose "Fallback Azure Resource PIM policy enumeration failed: $($_.Exception.Message)" } Write-Verbose "Could not retrieve Azure Resource PIM policy; returning null to use defaults upstream" return $null } catch { Write-Verbose "Failed to retrieve Azure Resource PIM policy: $($_.Exception.Message)" return $null } } |