Azure ARM 访问令牌错误的受众

Azure ARM access token wrong audience

我正在尝试从 Azure ARM 获取有关特定资源的信息。目前我可以使用以下文章 https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow 从 oAuth2 获取访问令牌,但是当我尝试使用它时出现以下错误:

Invoke-RestMethod : {"error":{"code":"InvalidAuthenticationTokenAudience","message":"The access token has been obtained for wrong audience or resource '00000002-0000-0000-c000-000000000000'. It should exactly match with one of the allowed audiences 'https://management.core.windows.net/','https://management.core.windows.net','https://management.azure.com/','https://management.azure.com'."}}

下面是我正在尝试的代码 运行:

param
(
    [Parameter(Mandatory=$true)][System.String] $ResourceId,
    [Parameter(Mandatory=$true)][System.String] $APIVersion
)
function Urls-Authorization
{
    [OutputType([System.Uri])]
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$false)] [System.Guid] $TenantId
    )
    return [System.Uri]::new("https://login.microsoftonline.com/$($TenantId)/oauth2/token")
}
function Urls-Management
{
    [OutputType([System.Uri])]
    [CmdletBinding()]
    param()
    return [System.Uri]::new("https://management.azure.com")
}
function Urls-Resource
{
    [OutputType([System.Uri])]
    [CmdletBinding()]
    param()
    return [System.Uri]::new((Urls-Management), "$($ResourceId)?api-version=$($APIVersion)")
}
function ConvertFrom-SecureString
{
    [OutputType([System.String])]
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true)] [SecureString] $SecureString
    )
    return [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString))
}
function New-AccessToken
{
    [OutputType([System.String])]
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true)] [System.Uri] $ResourceUrl,
        [Parameter(Mandatory=$true)] [System.Guid] $TenantId,
        [Parameter(Mandatory=$true)] [System.Guid] $ClientId,
        [Parameter(Mandatory=$true)] [SecureString] $Password,
        [Parameter(Mandatory=$false)] [System.DateTime] $Expires = ($(Get-Date).AddMinutes(60).ToUniversalTime()),
        [Parameter(Mandatory=$false)] [System.DateTime] $NotBefore = ([System.DateTime]::UtcNow)
    )
    #https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
    $AuthorityUrl = Urls-Authorization -TenantId $TenantId
    try
    {
        $RequestBody = [ordered]@{
                                        'grant_type'    = 'client_credentials';
                                        'client_id'     = $ClientId;
                                        'scope   '      = $ResourceUrl;
                                        'client_secret' = "$(ConvertFrom-SecureString -SecureString $Password)";
                                    }
        $Response = Invoke-RestMethod -Uri $AuthorityUrl -Method Post -Body $RequestBody -ErrorAction Stop
    }
    catch
    {
        Write-Log -Type ERROR -Message "Token could not be acquired"
        throw
    }
    return $Response.access_token
}
function Headers
{
    [OutputType([Hashtable])]
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$false)] [System.String] $ContentType,
        [Parameter(Mandatory=$true)] [System.String] $AccessToken
    )
    $Headers = @{}
    if ($ContentType -ne $null) {$Headers.Add("Content-Type", $ContentType)}
    $Headers.Add("Authorization", "Bearer $($AccessToken)")
    return $Headers
}
Invoke-RestMethod -Method Get -Uri (Urls-Resource) -Headers (Headers -ContentType "application/json" -AccessToken (New-AccessToken -ResourceUrl (Urls-Management) -TenantId $env:AZURE_TENANT_ID -ClientId $env:AZURE_CLIENT_ID -Password (ConvertTo-SecureString -String $env:AZURE_CLIENT_SECRET -AsPlainText -Force))) | ConvertFrom-Json

如前所述,我使用 New-AccessToken 函数获取访问令牌。我什至尝试了以下操作,但我得到了同样的错误:

  1. 将 New-AccessToken 中的 ResourceUrl 参数从 Urls-Management 更改为 Urls-Resource
  2. 添加 /.default 到 Urls-管理地址
  3. https://management.azure.com to https://management.azure.com/
  4. 添加更改 Urls-Management

你知道会发生什么吗?知道我应该如何面对这个错误吗?

我认为这个错误提供了一些很好的见解。我会将 New-AccessToken 更改为:

function New-AccessToken
{
    [OutputType([System.String])]
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true)] [System.Uri] $ResourceUrl,
        [Parameter(Mandatory=$true)] [System.Guid] $TenantId,
        [Parameter(Mandatory=$true)] [System.Guid] $ClientId,
        [Parameter(Mandatory=$true)] [SecureString] $Password,
        [Parameter(Mandatory=$false)] [System.DateTime] $Expires = ($(Get-Date).AddMinutes(60).ToUniversalTime()),
        [Parameter(Mandatory=$false)] [System.DateTime] $NotBefore = ([System.DateTime]::UtcNow)
    )
    #https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
    $AuthorityUrl = Urls-Authorization -TenantId $TenantId
    try
    {
        $RequestBody = [ordered]@{
                                        'grant_type'    = 'client_credentials';
                                        'client_id'     = $ClientId;
                                        'scope   '      = $ResourceUrl;
                                        'client_secret' = "$(ConvertFrom-SecureString -SecureString $Password)";
                                        'resource'      = 'https://management.azure.com/';
                                    }
        $Response = Invoke-RestMethod -Uri $AuthorityUrl -Method Post -Body $RequestBody -ErrorAction Stop
    }
    catch
    {
        Write-Log -Type ERROR -Message "Token could not be acquired"
        throw
    }
    return $Response.access_token
}

基本上,在$RequestBody中添加'resource' = 'https://management.azure.com/';。我在这个 repository 中有几个 Azure Rest 调用,但它在 groovy 中(虽然这不应该是一个问题)。

此外,您是否考虑过使用Az模块?它在幕后实现所有其余逻辑,并提供随时可用的 cmdlet 与 Azure 资源进行通信。