Private/Test-AzLocalAzurePrerequisites.ps1
|
Function Test-AzLocalAzurePrerequisites { <# .SYNOPSIS Checks Azure prerequisites for Azure Local deployment. .DESCRIPTION Validates that required Azure resource providers are registered and that the deploying identity has the required RBAC role assignments. Resource providers that are not registered will be automatically registered with a warning message. Registration may take a few minutes to propagate. RBAC role assignments are checked on a best-effort basis and reported as warnings (advisory) rather than hard failures, because roles may be inherited through Azure AD group membership or custom role definitions that cannot be reliably detected. Reference: https://learn.microsoft.com/azure/azure-local/deploy/deployment-arc-register-server-permissions .PARAMETER SubscriptionId The Azure subscription ID to check resource provider registrations against. .PARAMETER ResourceGroupName The resource group name to check for RBAC role assignments. #> [OutputType([PSCustomObject])] [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] [string]$SubscriptionId, [Parameter(Mandatory = $true, Position = 1)] [string]$ResourceGroupName ) $messages = @() $status = 'Passed' Write-AzLocalLog "Checking Azure prerequisites (resource providers and RBAC roles)..." -Level Info # --------------------------------------------------------------- # 1. Resource Provider Registration # Reference: https://learn.microsoft.com/azure/azure-local/deploy/deployment-arc-register-server-permissions # --------------------------------------------------------------- $requiredProviders = @( 'Microsoft.HybridCompute', 'Microsoft.GuestConfiguration', 'Microsoft.HybridConnectivity', 'Microsoft.AzureStackHCI', 'Microsoft.Kubernetes', 'Microsoft.KubernetesConfiguration', 'Microsoft.ExtendedLocation', 'Microsoft.ResourceConnector', 'Microsoft.HybridContainerService', 'Microsoft.Attestation', 'Microsoft.Storage', 'Microsoft.Insights' ) Write-AzLocalLog "Checking $($requiredProviders.Count) required resource providers..." -Level Info $rpFailed = $false foreach ($provider in $requiredProviders) { try { $rp = Get-AzResourceProvider -ProviderNamespace $provider -ErrorAction Stop $regState = $rp[0].RegistrationState if ($regState -eq 'Registered') { $messages += "Resource provider '$provider': REGISTERED" Write-AzLocalLog "Resource provider '$provider': Registered" -Level Success } else { # Auto-register the missing provider Write-AzLocalLog "Resource provider '$provider' is '$regState'. Attempting auto-registration..." -Level Warning try { Register-AzResourceProvider -ProviderNamespace $provider -ErrorAction Stop | Out-Null $messages += "Resource provider '$provider': AUTO-REGISTERED (was $regState) - registration may take 5-15 minutes to propagate" Write-AzLocalLog "Resource provider '$provider': Auto-registered. WARNING: Registration may take 5-15 minutes to propagate. If subsequent checks fail, wait and retry." -Level Warning } catch { $messages += "Resource provider '$provider': FAILED TO REGISTER - $($_.Exception.Message)" Write-AzLocalLog "Resource provider '$provider': Failed to register - $($_.Exception.Message)" -Level Error $rpFailed = $true } } } catch { $messages += "Resource provider '$provider': ERROR checking status - $($_.Exception.Message)" Write-AzLocalLog "Resource provider '$provider': Error checking status - $($_.Exception.Message)" -Level Error $rpFailed = $true } } if ($rpFailed) { $status = 'Failed' $messages += "Resource provider check: FAILED - one or more providers could not be registered." Write-AzLocalLog "Resource provider checks FAILED." -Level Error } else { $messages += "Resource provider check: PASSED - all $($requiredProviders.Count) providers registered." Write-AzLocalLog "All $($requiredProviders.Count) required resource providers are registered." -Level Success } # --------------------------------------------------------------- # 2. RBAC Role Assignment Checks (advisory) # Reference: https://learn.microsoft.com/azure/azure-local/deploy/deployment-arc-register-server-permissions # --------------------------------------------------------------- $subscriptionScope = "/subscriptions/$SubscriptionId" $rgScope = "/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroupName" $requiredSubRoles = @('Azure Stack HCI Administrator', 'Reader') $requiredRgRoles = @( 'Key Vault Data Access Administrator', 'Key Vault Secrets Officer', 'Key Vault Contributor', 'Storage Account Contributor' ) Write-AzLocalLog "Checking RBAC role assignments for the current identity..." -Level Info try { $context = Get-AzContext $accountId = $context.Account.Id $accountType = $context.Account.Type Write-AzLocalLog "Current identity: $accountId (Type: $accountType)" -Level Info # Get role assignments based on account type $subAssignments = @() $rgAssignments = @() if ($accountType -eq 'User') { $subAssignments = @(Get-AzRoleAssignment -SignInName $accountId -Scope $subscriptionScope -ErrorAction Stop) $rgAssignments = @(Get-AzRoleAssignment -SignInName $accountId -Scope $rgScope -ErrorAction Stop) } else { # Service Principal or Managed Identity - resolve Object ID from Application ID $sp = Get-AzADServicePrincipal -ApplicationId $accountId -ErrorAction Stop if ($sp) { $subAssignments = @(Get-AzRoleAssignment -ObjectId $sp.Id -Scope $subscriptionScope -ErrorAction Stop) $rgAssignments = @(Get-AzRoleAssignment -ObjectId $sp.Id -Scope $rgScope -ErrorAction Stop) } } $subRoleNames = @($subAssignments | Select-Object -ExpandProperty RoleDefinitionName -Unique) $rgRoleNames = @($rgAssignments | Select-Object -ExpandProperty RoleDefinitionName -Unique) # Check for Owner (covers all permissions at all child scopes) if ($subRoleNames -contains 'Owner') { $messages += "RBAC: Identity has 'Owner' at subscription scope (all role requirements satisfied)." Write-AzLocalLog "Identity has 'Owner' at subscription scope - all RBAC requirements satisfied." -Level Success } else { # Check subscription-level roles foreach ($role in $requiredSubRoles) { if ($subRoleNames -contains $role) { $messages += "RBAC subscription role '$role': ASSIGNED" Write-AzLocalLog "RBAC subscription role '$role': Assigned" -Level Success } else { $messages += "RBAC subscription role '$role': NOT FOUND (required for deployment)" Write-AzLocalLog "RBAC subscription role '$role': Not found - required for Azure Local deployment." -Level Warning } } # Check resource-group-level roles (rgAssignments includes inherited from subscription) foreach ($role in $requiredRgRoles) { if ($rgRoleNames -contains $role) { $messages += "RBAC resource group role '$role': ASSIGNED" Write-AzLocalLog "RBAC resource group role '$role': Assigned" -Level Success } else { $messages += "RBAC resource group role '$role': NOT FOUND (required for deployment)" Write-AzLocalLog "RBAC resource group role '$role': Not found - required for Azure Local deployment." -Level Warning } } } $messages += "RBAC check: COMPLETE (advisory - see warnings above for any missing roles)." Write-AzLocalLog "RBAC role assignment check complete. See above for results." -Level Info } catch { $messages += "RBAC check: SKIPPED - unable to retrieve role assignments ($($_.Exception.Message)). Verify manually." Write-AzLocalLog "Unable to retrieve RBAC role assignments: $($_.Exception.Message). Verify permissions manually." -Level Warning Write-AzLocalLog "Reference: https://learn.microsoft.com/azure/azure-local/deploy/deployment-arc-register-server-permissions" -Level Warning } return [PSCustomObject]@{ Status = $status Messages = $messages } } |