Private/Auth/Invoke-MgcManagedIdentityAuth.ps1
|
function Invoke-MgcManagedIdentityAuth { <# .SYNOPSIS Acquires a token via Azure Managed Identity. .DESCRIPTION Detects the runtime in this order: 1. App Service / Functions / Container Apps (IDENTITY_ENDPOINT + IDENTITY_HEADER) 2. Azure Arc (IMDS_ENDPOINT) 3. IMDS - default Azure VM endpoint (169.254.169.254) For each, requests a token for the Graph resource. User-assigned identity is selected via -ManagedIdentityClientId. Returns a token response object normalized to the standard shape (access_token, expires_in, token_type, refresh_token=$null). #> [CmdletBinding()] param( [Parameter(Mandatory)][string]$GraphResource, [string]$ManagedIdentityClientId ) $resource = $GraphResource $apiVer = '2018-02-01' # 1. App Service / Functions / Container Apps if ($env:IDENTITY_ENDPOINT -and $env:IDENTITY_HEADER) { $uri = "$($env:IDENTITY_ENDPOINT)?resource=$([Uri]::EscapeDataString($resource))&api-version=2019-08-01" if ($ManagedIdentityClientId) { $uri += "&client_id=$([Uri]::EscapeDataString($ManagedIdentityClientId))" } $resp = Invoke-RestMethod -Uri $uri -Headers @{ 'X-IDENTITY-HEADER' = $env:IDENTITY_HEADER } -Method GET return [pscustomobject]@{ access_token = $resp.access_token expires_in = if ($resp.expires_in) { [int]$resp.expires_in } else { 3500 } token_type = if ($resp.token_type) { $resp.token_type } else { 'Bearer' } refresh_token = $null } } # 2. Azure Arc if ($env:IMDS_ENDPOINT -and $env:IDENTITY_ENDPOINT) { $uri = "$($env:IDENTITY_ENDPOINT)?resource=$([Uri]::EscapeDataString($resource))&api-version=2019-11-01" $first = Invoke-WebRequest -Uri $uri -Headers @{ Metadata = 'true' } -Method GET -SkipHttpErrorCheck # Arc returns 401 + WWW-Authenticate header pointing at a challenge file if ($first.StatusCode -eq 401) { $authHeader = $first.Headers['WWW-Authenticate'] if ($authHeader -match 'Basic realm=(.+)') { $challengePath = $Matches[1].Trim() $secret = Get-Content -Path $challengePath -Raw $resp = Invoke-RestMethod -Uri $uri -Headers @{ Metadata = 'true'; Authorization = "Basic $secret" } -Method GET return [pscustomobject]@{ access_token = $resp.access_token expires_in = if ($resp.expires_in) { [int]$resp.expires_in } else { 3500 } token_type = if ($resp.token_type) { $resp.token_type } else { 'Bearer' } refresh_token = $null } } } throw "Azure Arc managed identity challenge failed." } # 3. IMDS (Azure VM) $imds = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=$apiVer&resource=$([Uri]::EscapeDataString($resource))" if ($ManagedIdentityClientId) { $imds += "&client_id=$([Uri]::EscapeDataString($ManagedIdentityClientId))" } $resp = Invoke-RestMethod -Uri $imds -Headers @{ Metadata = 'true' } -Method GET -TimeoutSec 10 return [pscustomobject]@{ access_token = $resp.access_token expires_in = if ($resp.expires_in) { [int]$resp.expires_in } else { 3500 } token_type = if ($resp.token_type) { $resp.token_type } else { 'Bearer' } refresh_token = $null } } |