Azure / azure-powershell

Microsoft Azure PowerShell
Other
4.1k stars 3.73k forks source link

Connect-AzAccount support for Azure Arc managed identities #13618

Open rpsqrd opened 3 years ago

rpsqrd commented 3 years ago

Description of the new feature

Today, you can use Connect-AzAccount -Identity on an Azure VM to request a token for the system-assigned managed identity from the Instance Metadata Service (IMDS) and use that identity for your AzPS context. Azure Arc enabled servers has introduced a managed identity for on-premises and multicloud servers. Due to a slightly different IMDS implementation, the existing behavior doesn't work on hybrid servers.

This issue proposes changes to Connect-AzAccount -Identity to support both Azure VMs and Arc enabled servers.

Proposed implementation details (optional)

There are two changes to how the hybrid IMDS works on an Arc enabled server:

  1. The IMDS server is exposed at http://localhost:40342/ instead of http://169.254.169.254. On Windows, you can query the IDENTITY_ENDPOINT environment variable to get the base URL for the token endpoint. Today, it will always return http://localhost:40342/metadata/identity/oauth2/token. There is not an equivalent on Linux, nor are there plans to support other ports at this time.
  2. Hybrid IMDS requires that callers prove they are administrators to access the AAD token. To achieve this, there is an additional challenge-response mechanism added to the token request. A successful flow goes as follows:
    1. Make the initial request to Hybrid IMDS for the access token
    2. HIMDS will return a 403 response, with a "Www-Authenticate" header that contains a file path. This file contains randomly generated content in a directory restricted to administrator access.
    3. The code should read the contents of that file (proving it has admin privileges) and include it in the access token request again with an authentication header: Authentication: Basic <randomstring>. HIMDS will return the access token per usual after verifying the authentication header.

The code should always try Azure IMDS before Hybrid IMDS in case an Arc server has been migrated to Azure without removing the HIMDS agent first.

erich-wang commented 3 years ago

The underlying Azure.Identity is going to support this feature in Jan release(beta), we'll try to pick up the version then.

erich-wang commented 3 years ago

Postpone because of Azure.Identity is not ready yet.

erich-wang commented 3 years ago

@rpsqrd, Azure.Identity 1.4 has been released and should contain Azure Arc managed identity support, new version of Az will contain Azure.Identity 1.4 and will be released on May 25, could you please verify at that time?

quilleo commented 3 years ago

I am still hitting this issue with powershell core 7.1.3 with az.accounts 2.3.0 with azure.identity I think at version 1.400.21.26202

(Get-Item ./Az.Accounts/2.3.0/NetCoreAssemblies/Azure.Identity.dll).VersionInfo.FileVersion 1.400.21.26202

Should this be fixed in this version?

Thanks Ed

psinnathurai commented 1 year ago

Is there an update to this? I think this feature will be a big improve for Azure Arc.

rajagopalan-trimble commented 4 months ago

Is there any update on this?

isra-fel commented 2 weeks ago

The version of Azure.Identity SDK that Azure PowerShell depends on has supported managed identiy for arc managed server. @msJinLei can you verify that scenario works before we officially announce this?

GitHed commented 2 weeks ago

The issue as far as I see is that the $env:IDENTITY_ENDPOINT variable isn't set in pwsh on arc enabled servers, and so connect-azaccount defaults to trying to use the IMDS service instead of the HIMDS service that's locally installed via the Arc agent.

    $VaultAPIVersion = '2019-11-01'
    $VaultRestAPIVersion = '7.4'

    # Arc Linux machines don't have the environment variable set, and so they fail using connect-azaccount -identity by trying to connect to IMDS instead of HIMDS.
    # IMDS is only available within the Azure environments, and only works on Azure VM's.
    # HIMDS is available for Arc enabled servers, it's part of the Arc agent install.

    # We can attempt to login to the endpoint, and it will return a file path as an error.
    # With access to the file, we can read a token from within it.
    # The file is managed by the Arc Agent, it is for the machine's managed identity.
    $IDENTITY_ENDPOINT = [string]::IsNullOrEmpty($env:IDENTITY_ENDPOINT) ? 'http://127.0.0.1:40342/metadata/identity/oauth2/token' : $env:IDENTITY_ENDPOINT
    $VaultResource = [uri]::EscapeUriString('https://vault.azure.net')
    $AuthURI = '{0}?resource={1}&api-version={2}' -f $IDENTITY_ENDPOINT,$VaultResource,$VaultAPIVersion
    $challengeTokenPath = ""
    try {
        Invoke-WebRequest -Method GET -Uri $AuthURI -Headers @{Metadata='true'}
    } catch {
        $wwwAuthHeader = $_.Exception.Response.Headers.GetValues('WWW-Authenticate')
        if ($wwwAuthHeader -match "Basic realm=.+") {
            $challengeTokenPath = ($wwwAuthHeader -split 'Basic realm=')[1]
        }
    }
    Write-Verbose "Secret file path: $challengeTokenPath"
    $challengeToken = Get-Content -Raw $challengeTokenPath

    # After reading the file, we can get an access token to the keyvault service, using the (H)IMDS service.
    $vaultTokenRequest = Invoke-WebRequest -Method GET -Uri $AuthURI -Headers @{Metadata='True';Authorization="Basic $challengeToken"} -ContentType 'application/json'
    $vaultToken = ConvertTo-SecureString -AsPlainText -Force -String (ConvertFrom-Json $vaultTokenRequest.Content).access_token

    # Then we can use that token to access the keyvault.
    $SecretContentJSON = (Invoke-WebRequest -Authentication Bearer -Token $vaultToken -Method GET -Uri "https://$VaultName.vault.azure.net/secrets/$VaultCertName/?api-version=$VaultRestAPIVersion" -ContentType 'application/json').Content | ConvertFrom-Json
    $SecretContentType = $SecretContentJSON.contentType
    $SecretContent = $SecretContentJSON.value