Python 从Azure函数获取托管身份访问令牌时出错

Python 从Azure函数获取托管身份访问令牌时出错,python,azure,azure-functions,azure-managed-identity,Python,Azure,Azure Functions,Azure Managed Identity,从我的功能应用程序检索Azure托管身份访问令牌时遇到问题。函数获取一个令牌,然后使用该令牌作为密码访问Mysql数据库 我从函数中得到以下响应: 9103 HY000:验证访问令牌时出错。请获取新令牌并重试 代码: 在具有我的托管标识的VM上运行此代码的修改版本可以正常工作。似乎不允许函数应用程序获取访问令牌。任何帮助都将不胜感激 注意:我以前曾以AzureAD Manager的身份登录到数据库,并创建了具有此数据库所有权限的此用户 编辑:不再为VM调用端点 def get_access_to

从我的功能应用程序检索Azure托管身份访问令牌时遇到问题。函数获取一个令牌,然后使用该令牌作为密码访问Mysql数据库

我从函数中得到以下响应:

9103 HY000:验证访问令牌时出错。请获取新令牌并重试

代码:

在具有我的托管标识的VM上运行此代码的修改版本可以正常工作。似乎不允许函数应用程序获取访问令牌。任何帮助都将不胜感激

注意:我以前曾以AzureAD Manager的身份登录到数据库,并创建了具有此数据库所有权限的此用户

编辑:不再为VM调用端点

def get_access_token():

    identity_endpoint = os.environ["IDENTITY_ENDPOINT"] # Env var provided by Azure. Local to service doing the requesting.
    identity_header = os.environ["IDENTITY_HEADER"] # Env var provided by Azure. Local to service doing the requesting.
    api_version = "2019-08-01" # "2018-02-01" #"2019-03-01" #"2019-08-01"
    CLIENT_ID = "<client_id>"
    resource_requested = "https%3A%2F%2Fossrdbms-aad.database.windows.net"
    # resource_requested = "https://ossrdbms-aad.database.windows.net"


    URL = f"{identity_endpoint}?api-version={api_version}&resource={resource_requested}&client_id={CLIENT_ID}"
    headers = {"X-IDENTITY-HEADER":identity_header}

    try:
        req = requests.get(URL, headers=headers)
    except Exception as e:
        print(str(e))
        return str(e)
    else:
        try:
            password = req.json()["access_token"]
        except:
            password = str(req.text)

    return password
但现在我得到了这个错误:

{"error":{"code":"UnsupportedApiVersion","message":"The HTTP resource that matches the request URI 'http://localhost:8081/msi/token?api-version=2019-08-01&resource=https%3A%2F%2Fossrdbms-aad.database.windows.net&client_id=<client_idxxxxx>' does not support the API version '2019-08-01'.","innerError":null}}
经检查,这似乎是一个普遍错误。即使不是根本问题,也会传播此错误消息。在Github中多次注意到


我的端点现在正确吗?

对于此问题,它是由请求访问令牌的错误端点引起的。我们可以使用端点http://169.254.169.254/metadata/identity..... 在azure VM中,但如果在azure函数中,我们不能使用它

在azure函数中,我们需要从环境中获取IDENTITY_端点

identity_endpoint = os.environ["IDENTITY_ENDPOINT"]
端点类似于:

http://127.0.0.1:xxxxx/MSI/token/
您可以参考这篇文章,也可以在教程中找到python代码示例。

在我的函数代码中,我还添加了我在token_auth_uri中创建的托管标识的客户端id,但我不确定在这里是否需要客户端id。在我的情况下,我使用用户分配的标识,而不是系统分配的标识

token_auth_uri = f"{identity_endpoint}?resource={resource_uri}&api-version=2019-08-01&client_id={client_id}"
更新:


对于您最近的一期,您看到的是不受支持的版本,可能是这个版本:

以下是对我有效的几个选项:

我假设您正在Linux上托管函数应用程序。我注意到ApiVersion 2017-09-01可以工作,但是您需要进行额外的更改,而不是使用X-IDENTITY-HEADER,使用secret HEADER。并为功能应用程序使用系统分配的托管标识,而不是用户分配的标识

token_auth_uri = f"{identity_endpoint}?resource={resource_uri}&api-version=2019-08-01&client_id={client_id}"

当我在Windows上托管功能应用程序时,我没有同样的问题。因此,如果要使用用户分配的托管标识,可以尝试使用此选项。api版本=2019-08-01和X-IDENTITY-HEADER。

感谢@huryshen的回复。我更新了代码,得到上面列出的错误。这是正确的终点吗?@warnerm06是的,看来你的终点是正确的。但是我不知道为什么你的代码会显示你的端点被拒绝的UnsupportedAversion错误消息http://localhost:8081.....,在本地而不是azure上运行python代码是否重要。我已经在我的答案中分享了更新下的函数代码.net,供您参考。
#r "Newtonsoft.Json"

using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;

public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
    string resource="https://ossrdbms-aad.database.windows.net";
    string clientId="xxxxxxxx";
    log.LogInformation("C# HTTP trigger function processed a request.");
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(String.Format("{0}/?resource={1}&api-version=2019-08-01&client_id={2}", Environment.GetEnvironmentVariable("IDENTITY_ENDPOINT"), resource,clientId));
    request.Headers["X-IDENTITY-HEADER"] = Environment.GetEnvironmentVariable("IDENTITY_HEADER");
    request.Method = "GET";

    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    StreamReader streamResponse = new StreamReader(response.GetResponseStream());
    string stringResponse = streamResponse.ReadToEnd();
    log.LogInformation("test:"+stringResponse);

    string name = req.Query["name"];

    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
    dynamic data = JsonConvert.DeserializeObject(requestBody);
    name = name ?? data?.name;

    return name != null
        ? (ActionResult)new OkObjectResult($"Hello, {name}")
        : new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}