Reputation: 649
I am trying to get information from Azure ARM about a specific resource. Currently I was able to get the access token from oAuth2 using the following article https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow, however when I try to use it I get the following error:
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'."}}
Below is the code that I am attempting to run:
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://learn.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
As I mentioned before, I get the access token with New-AccessToken function. I even attempt the following and I get the same error:
Do you know what can be happening? Any idea about how should I face this error?
Upvotes: 0
Views: 1096
Reputation: 2280
I think the error is providing some good insights. I would change New-AccessToken
to:
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://learn.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
}
Basically, add 'resource' = 'https://management.azure.com/';
in the $RequestBody
. I have a couple of Azure Rest calls in this repository, but it is in groovy (though this shouldn't be an issue).
Moreover, have you considered using the Az module? It implements all the rest logic behind the scenes and provides ready to use cmdlets that communicate with the Azure Resources.
Upvotes: 1