简体   繁体   中英

Migrate Python ADAL Custom Metrics Azure Function to support Managed Identity

I have a Python function using the preview option of sending custom metrics to Azure using the REST API https://docs.microsoft.com/en-us/azure/azure-monitor/platform/metrics-store-custom-rest-api , previously this was a C# function where authorisation and getting a bearer token was handled automagically by:

var azureServiceTokenProvider = new AzureServiceTokenProvider();
string bearerToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://monitoring.azure.com/").ConfigureAwait(false);

This worked in VS Code using the logged in user and in Azure when a Managed Identity was assigned to the Function.

I needed to convert this to Python but so far the best (working) I've been able to come up with is:

import logging, requests, os, adal
import azure.functions as func

def main(req: func.HttpRequest) -> func.HttpResponse:
    regional_monitoring_url = "https://eastus.monitoring.azure.com"
    monitored_resource_id = os.environ['RESOURCE_ID']
    full_endpoint = f"{regional_monitoring_url}{monitored_resource_id}/metrics"

    tenant_id = os.environ['AZURE_TENANT_ID']
    context = adal.AuthenticationContext(f'https://login.microsoftonline.com/{tenant_id}')
    token = context.acquire_token_with_client_credentials("https://monitoring.azure.com/", os.environ['AZURE_CLIENT_ID'], os.environ['AZURE_CLIENT_SECRET']    )
    bearer_token = token['accessToken']

    json = req.get_json()
    headers = {"Authorization": 'Bearer ' + bearer_token}
    result = requests.post(url = full_endpoint, headers = headers, json = json)

    return func.HttpResponse(f"Done - {result.status_code} {result.text}", status_code=200)

This obviously relies on me creating a Service Principal with the relevant permissions. I'm trying to work out how to use the automatic Managed Identity authorisation that the C# libraries have.

I know ADAL should be replaced by MSAL but I can't work out how/if that automagically handles Managed Identities so I tried azure-identity:

from azure.identity import DefaultAzureCredential

credential = DefaultAzureCredential()
token = credential.get_token("https://monitoring.azure.com/.default")
bearer_token = token.token

This gets me a token but because it requires a scope rather than a resource, which means adding .default to the resource URL, when I send the bearer token to the monitoring endpoint it complains the resource doesn't match and must be exactly "https://monitoring.azure.com/"

Is this just not currently possible or am I missing something with either azure-identity or the MSAL Python modules?

According to my research, when werequest an Azure AD token to emit custom metrics, ensure that the audience the token is requested for is https://monitoring.azure.com/ . For more details, please refer to here . So we should update scope as https://monitoring.azure.com//.default 在此处输入图片说明

For example

def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    credential = DefaultAzureCredential()
    token = credential.get_token("https://monitoring.azure.com//.default")
    bearer_token = token.token
    #full_endpoint=""
    json = req.get_json()
    headers = {"Authorization": 'Bearer ' + bearer_token}
    #result = requests.post(url = full_endpoint, headers = headers, json = json)
    return func.HttpResponse(f"Done - {bearer_token}", status_code=200)

在此处输入图片说明 在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM