A few ways to acquire Azure access token with scripting languages

Whether you are a sysadmin, DevOps guy, Blue/Red team your work will likely require to acquire Azure access token to work with Azure resources via Azure REST API. Moreover, not all things can be done with compiled command packages like Azure CLI or PowerShell.

In this article, let’s explore a few common ways to quickly get Azure access token.

Azure CLI

Microsoft developed a command specific to getting Azure access token.  You just simply run

az login
az account get-access-token

Condition: you must be authorized before you can gain access token.

Below is kind of dirty script to test access token by calling VM REST API

ACCESS_TOKEN=$(az account get-access-token --query 'accessToken' -o tsv)
AUTH_HEADER="Authorization: Bearer $ACCESS_TOKEN"
CONTENT_TYPE="Content-Type: application/json"
SUBSCRIPTION_ID="67d6179d-a99d-4ccd-8c56-4d3ff2e13349"
RG_NAME='off-rg'
RM_ENDPOINT='https://management.azure.com'
URI="$RM_ENDPOINT/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RG_NAME/providers/Microsoft.Compute/virtualMachines?api-version=2019-03-01"

curl -X GET -H "$AUTH_HEADER" -H "$CONTENT_TYPE" $URI

PowerShell

There is not any built-in cmdlet like Azure CLI above but you can make one for you by initializing RmProfileClient object.

Condition: you must be authorized before you can gain access token.

See sample below

function Get-AccessToken {
    $context = Get-AzContext
    $profile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
    $profileClient = New-Object -TypeName Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient -ArgumentList ($profile)
    $token = $profileClient.AcquireAccessToken($context.Subscription.TenantId)
    return $token.AccessToken
}
$subscriptionid = "67d6179d-a99d-4ccd-8c56-4d3ff2e13349"
$rg_name = "off-rg"
$rm_endpoint = "https://management.azure.com"
$authHeader = @{
    'Content-Type'  = 'application/json'
    'Authorization' = 'Bearer ' + (Get-AccessToken)
}

$uri = "$rm_endpoint/subscriptions/$subscriptionid/resourceGroups/$rg_name/providers/Microsoft.Compute/virtualMachines?api-version=2019-03-01"

$respone = Invoke-RestMethod -Method Get -Headers $authHeader -Uri $uri
$response

Python

There are a few ways here. It depends on your situation for example you don’t want to put plain-text username/password or service principal info (client_secret). Instead you want interactive authorization like using device code input. Below is sample code to acquire access token using method acquire_token_with_device_code()

import adal
import requests
import json

TENANT_ID = "03987603-0fa0-1103-bd94-cdffbefb2226"
# Azure CLI Client ID - fixed ID 
CLIENT_ID = "04b07795-8ddb-461a-bbee-02f9e1bf7b46"
AUTH_URI = "https://login.microsoftonline.com" + "/" + TENANT_ID
SUBSCRIPTION_ID = "67d6179d-a99d-4acc-8c51-4d3ff2e13349"
RG_NAME = "off-rg"

def get_auth_header():
    context = adal.AuthenticationContext(AUTH_URI)
    code = context.acquire_user_code('https://management.core.windows.net/', CLIENT_ID)
    message = code['message']
    #You must print message
    print(message)
    token = context.acquire_token_with_device_code('https://management.core.windows.net/',
                                                code,
                                                CLIENT_ID)
    authHeader = {
        'Authorization': 'Bearer ' + token['accessToken'],
        'Content-Type': 'application/json'
    }
    return authHeader

uri = RM_ENDPOINT + '/subscriptions/' + SUBSCRIPTION_ID + '/resourceGroups/' + RG_NAME + '/providers/Microsoft.Compute/virtualMachines?api-version=2019-03-01'
response = requests.get(uri, headers=(get_auth_header()))
jsonData = response.json()
print(json.dumps(jsonData, indent=4))

Condition: you must be authorized before you can gain access token.

If you already have client id and client secret of your service principal you can use acquire_token_with_client_credentials() . This is a common way when working with CICD pipeline. Below is the simple function to acquire access token

import adal
import requests
import json

TENANT_ID = "03987603-0fa0-1103-bd94-cdffbefb2226"
SERVICE_PRINCIPAL_CLIENT_ID = "04b07795-8ddb-461a-bbee-02f9e1bf7b46"
SERVICE_PRINCIPAL_PASSWORD = "your_password_of_service_principal"
AUTH_URI = "https://login.microsoftonline.com" + "/" + TENANT_ID
RM_ENDPOINT = "https://management.azure.com"
SUBSCRIPTION_ID = "67d6179d-a99d-4acc-8c51-4d3ff2e13349"
RG_NAME = "off-rg"

def get_auth_header():
    context = adal.AuthenticationContext(AUTH_URI)
    token = context.acquire_token_with_client_credentials('https://management.core.windows.net/',
                                                           SERVICE_PRINCIPAL_CLIENT_ID,
                                                           SERVICE_PRINCIPAL_PASSWORD)
    authHeader = {
        'Authorization': 'Bearer ' + token['accessToken'],
        'Content-Type': 'application/json'
    }
    return authHeader

uri = RM_ENDPOINT + '/subscriptions/' + SUBSCRIPTION_ID + '/resourceGroups/' + RG_NAME + '/providers/Microsoft.Compute/virtualMachines?api-version=2019-03-01'
response = requests.get(uri, headers=(get_auth_header()))
jsonData = response.json()
print(json.dumps(jsonData, indent=4))

Managed Identity

If your virtual machine enables System Assigned Identity you can go execute the following PowerShell script on it to get access token.

Condition: you must have access or privilege to execute script in that virtual machine.

$aimsUri = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F"
$header = @{
    Metadata = "true"
}
$response = Invoke-WebRequest -Uri $aimsUri `
                              -Headers $header `
                              -UseBasicParsing

$content =$response.Content | ConvertFrom-Json
$access_token = $content.access_token

Not only PowerShell, Bash or Python can be done easily too.

This entry was posted in Security Automation and tagged , . Bookmark the permalink.

1 Response to A few ways to acquire Azure access token with scripting languages

  1. Pingback: Security Monitoring and Detection Tips for your Storage Account – Part 4

Leave a Reply