【问题标题】:Error Getting Managed Identity Access Token from Azure Function从 Azure 函数获取托管标识访问令牌时出错
【发布时间】:2020-06-18 17:07:00
【问题描述】:

我在从我的 Function App 检索 Azure 托管标识访问令牌时遇到问题。该函数获取一个令牌,然后使用该令牌作为密码访问 Mysql 数据库。

我从函数中得到这个响应:

9103 (HY000): An error occurred while validating the access token. Please acquire a new token and retry.

代码:

import logging
import mysql.connector
import requests
import azure.functions as func


def main(req: func.HttpRequest) -> func.HttpResponse:
    
    def get_access_token():

        URL = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fossrdbms-aad.database.windows.net&client_id=<client_id>"
        headers = {"Metadata":"true"}

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

        return password

    def get_mysql_connection(password):
        """
        Get a Mysql Connection.
        """
        try:
            con = mysql.connector.connect(

            host='<host>.mysql.database.azure.com', 
            user='<user>@<db>',
            password=password,
            database = 'materials_db',
            auth_plugin='mysql_clear_password'
            )
        except Exception as e:

            print(str(e))
            return str(e)

        else:
            return "Connected to DB!"

    password = get_access_token()

    return func.HttpResponse(get_mysql_connection(password))

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

注意:我之前以 AzureAD 经理的身份登录到数据库,并创建了拥有此数据库所有权限的用户。

编辑:不再为虚拟机调用端点。

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 中多次提及。

我的端点现在正确吗?

【问题讨论】:

    标签: python azure azure-functions azure-managed-identity


    【解决方案1】:

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

    在azure函数中,我们需要从环境中获取IDENTITY_ENDPOINT

    identity_endpoint = os.environ["IDENTITY_ENDPOINT"]
    

    端点是这样的:

    http://127.0.0.1:xxxxx/MSI/token/
    

    你可以参考这个tutorial关于它,你也可以在教程中找到python代码示例。

    在我的函数代码中,我还添加了在 token_auth_uri 中创建的托管标识的客户端 ID,但我不确定此处是否需要 client_id(在我的情况下,我使用用户分配的标识但不是系统分配的身份)。

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

    更新:

    #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");
    }
    

    【讨论】:

    • 感谢@huryshen 的回复。我更新了代码并收到上面列出的错误。现在这是正确的端点吗?
    • @warnerm06 是的,看来您的端点是正确的。但是我不知道为什么您的代码会显示“UnsupportedApiVersion”错误消息(您的端点是http://localhost:8081.....,您在本地运行python 代码但不是天蓝色有关系吗?)。我在回答中的“更新”下分享了我的功能代码(.net),供您参考。
    • @HuryShen, 为什么我收到KeyError: 'IDENTITY_ENDPOINT' 错误,需要额外添加任何配置吗?
    【解决方案2】:

    对于您看到 UnsupportedApiVersion 的最新一期,可能是这个问题:https://github.com/MicrosoftDocs/azure-docs/issues/53726

    以下是一些对我有用的选项:

    我假设您在 Linux 上托管 Function 应用程序。我注意到 ApiVersion 2017-09-01 有效,但您需要进行额外的更改(而不是“X-IDENTITY-HEADER”,使用“秘密”标题)。并且还为您的函数应用使用系统分配的托管标识,而不是用户分配的标识。

    当我在 Windows 上托管函数应用时,我没有遇到同样的问题。因此,如果您想使用用户分配的托管标识,您可以尝试使用此选项。 (使用 api-version=2019-08-01 和 X-IDENTITY-HEADER。

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-07
    • 1970-01-01
    • 2019-03-11
    • 2020-07-14
    • 2022-11-10
    相关资源
    最近更新 更多