Как использовать управляемые удостоверения для ресурсов Azure на виртуальной машине Azure для получения маркера доступа

Управляемые удостоверения для ресурсов Azure — это функция идентификатора Microsoft Entra. Каждая служба Azure, которая поддерживает управляемые удостоверения для ресурсов Azure, используется в соответствии с собственной временной шкалой. Прежде чем начать работу, обязательно проверьте состояние доступности управляемых удостоверений для своего ресурса и ознакомьтесь с известными проблемами.

Управляемые удостоверения для ресурсов Azure предоставляют службам Azure автоматически управляемое удостоверение, которое хранится в Microsoft Entra ID. Это удостоверение можно использовать для проверки подлинности в любой службе, поддерживающей проверку подлинности Microsoft Entra, без наличия учетных данных в коде.

В этой статье приведены различные примеры кода и сценариев для получения маркера. Она также содержит рекомендации по обработке ошибок, связанных с истечением срока действия маркера и HTTP.

Необходимые компоненты

Если вы планируете использовать примеры Azure PowerShell в этой статье, убедитесь, что установлена последняя версия Azure PowerShell.

Важно!

  • Во всех примерах кода или сценариев в этой статье предполагается, что клиент выполняется на виртуальной машине, на которой включены управляемые удостоверения для ресурсов Azure. Используйте функцию подключения виртуальной машины на портале Azure для удаленного подключения к своей виртуальной машине. Дополнительные сведения о включении управляемых удостоверений для ресурсов Azure на виртуальной машине см. в статье Настройка управляемых удостоверений для ресурсов Azure на виртуальной машине Azure с помощью Azure CLI или в одном из вариантов статьи (с использованием PowerShell, интерфейса командной строки, шаблона или пакета SDK для Azure).

Важно!

  • Граница безопасности управляемых удостоверений для ресурсов Azure — это ресурс, в котором используется удостоверение. Все примеры кода и сценариев, выполняемые на виртуальной машине, могут запрашивать и получать маркеры для любого управляемого удостоверения, доступного на ней.

Обзор

Клиентское приложение может запрашивать маркер доступа к приложению для управляемого удостоверения, чтобы получить доступ к заданному ресурсу. Этот маркер создан с помощью субъекта-службы управляемых удостоверений для ресурсов Azure. Таким образом, клиенту не нужно получать маркер доступа для собственного субъекта-службы. Маркер подходит для использования в качестве маркера носителя при выполнении вызовов между службами, требующих учетных данных клиента.

Ссылка Description
Получение маркера с использованием HTTP Сведения о протоколе для конечной точки маркера управляемых удостоверений для ресурсов Azure
Получение токена с помощью Azure.Identity Получение токена с помощью библиотеки Azure.Identity
Получение токена с помощью библиотеки Microsoft.Azure.Services.AppAuthentication для .NET Пример использования библиотеки Microsoft.Azure.Services.AppAuthentication из клиента .NET
Получение маркера с использованием C# Пример использования конечной точки REST управляемых удостоверений для ресурсов Azure из клиента C#
Получение маркера с использованием Java Пример использования конечной точки REST управляемых удостоверений для ресурсов Azure из клиента Java.
Получение маркера с использованием Go Пример использования конечной точки REST управляемых удостоверений для ресурсов Azure из клиента Go
Получение маркера с помощью PowerShell Пример использования конечной точки REST управляемых удостоверений для ресурсов Azure из клиента PowerShell
Получение маркера с использованием CURL Пример использования конечной точки REST управляемых удостоверений для ресурсов Azure из клиента Bash или CURL
Обработка кэширования маркеров Рекомендации по обработке срока действия маркера доступа
Обработка ошибок Рекомендации по обработке ошибок HTTP, возвращаемых из конечной точки маркера управляемых удостоверений для ресурсов Azure
Идентификаторы ресурсов для служб Azure Сведения о том, где можно получить идентификаторы ресурсов для поддерживаемых служб Azure

Получение маркера с использованием HTTP

Основной интерфейс для получения маркера доступа создан на основе REST, что делает его доступным для любого клиентского приложения, выполняющегося на виртуальной машине,которая может выполнять вызовы HTTP REST. Такой подход аналогичен модели программирования Microsoft Entra, за исключением того, что клиент использует конечную точку на виртуальной машине (и конечную точку Microsoft Entra).

Пример запроса с использованием конечной точки службы метаданных экземпляров (IMDS) Azure (рекомендуется).

GET 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/' HTTP/1.1 Metadata: true
Элемент Description
GET HTTP-команда, указывающая, что необходимо извлечь данные из конечной точки. В этом случае используется маркер доступа OAuth.
http://169.254.169.254/metadata/identity/oauth2/token Конечная точка управляемых удостоверений для ресурсов Azure для Службы метаданных экземпляров.
api-version Параметр строки запроса, указывающий версию API для конечной точки IMDS. Используйте версию API 2018-02-01 или более новую.
resource Параметр строки запроса, указывающий URI идентификатора приложения целевого ресурса. Он также отображается в утверждении (аудитории) aud выданного маркера. В этом примере запрашивается маркер для доступа к Azure Resource Manager, который имеет универсальный код ресурса (URI) идентификатора приложения https://management.azure.com/.
Metadata Поле заголовка HTTP-запроса, необходимое для управляемых удостоверений. Эти сведения используются в качестве решения проблем с атаками подделки запросов на стороне сервера (SSRF). Должно быть присвоено значение true (все в нижнем регистре).
object_id (Необязательно.) Параметр строки запроса, указывающий object_id управляемого удостоверения, для которого требуется токен. Требуется, если виртуальная машина имеет несколько управляемых удостоверений, назначаемых пользователем.
client_id (Необязательно.) Параметр строки запроса, указывающий client_id управляемого удостоверения, для которого требуется токен. Требуется, если виртуальная машина имеет несколько управляемых удостоверений, назначаемых пользователем.
msi_res_id (Необязательно) Параметр строки запроса, указывающий msi_res_id (идентификатор ресурса Azure) управляемого удостоверения, для которой требуется маркер. Требуется, если виртуальная машина имеет несколько управляемых удостоверений, назначаемых пользователем.

Пример ответа:

HTTP/1.1 200 OK
Content-Type: application/json
{
  "access_token": "eyJ0eXAi...",
  "refresh_token": "",
  "expires_in": "3599",
  "expires_on": "1506484173",
  "not_before": "1506480273",
  "resource": "https://management.azure.com/",
  "token_type": "Bearer"
}
Элемент Description
access_token Запрашиваемый маркер доступа. При вызове защищенного REST API маркер внедряется в поле заголовка запроса Authorization в качестве маркера носителя, позволяя API выполнить проверку подлинности вызывающего объекта.
refresh_token Не используется управляемыми удостоверениями для ресурсов Azure.
expires_in Количество секунд, в течение которых маркер доступа является действительным, прежде чем его срок действия истечет (с момента выдачи). Время выдачи можно найти в утверждении iat маркера.
expires_on Период времени после истечения срока действия маркера доступа. Дата представляется как количество секунд с 1970-01-01T0:0:0Z в формате UTC (соответствует утверждению exp маркера).
not_before Период времени, когда маркер доступа вступает в силу и может быть принят. Дата представляется как количество секунд с 1970-01-01T0:0:0Z в формате UTC (соответствует утверждению nbf маркера).
resource Ресурс, для которого был запрошен маркер доступа, соответствует параметру строки запроса resource.
token_type Тип маркера, который является маркером доступа носителя, что значит, что ресурс может предоставлять доступ носителю этого маркера.

Получение маркера с помощью клиентской библиотеки удостоверений Azure

Клиентская библиотека удостоверений Azure является рекомендуемым способом использования управляемых удостоверений. Все пакеты средств разработки Azure интегрированы с библиотекой Azure.Identity, обеспечивающей поддержку DefaultAzureCredential. Этот класс упрощает использование управляемых удостоверений с помощью пакетов SDK для Azure.Дополнительные сведения

  1. Установите пакет Azure.Identity и другие необходимые пакеты библиотеки пакетов SDK Azure, например Azure.Security.KeyVault.Secrets.

  2. Используйте пример кода ниже. Не следует беспокоиться о получении маркеров. Можно напрямую использовать клиенты пакета средств разработки для Azure. Код предназначен для демонстрации способа получения маркера при необходимости.

    using Azure.Core;
    using Azure.Identity;
    
    string userAssignedClientId = "<your managed identity client Id>";
    var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { ManagedIdentityClientId = userAssignedClientId });
    var accessToken = credential.GetToken(new TokenRequestContext(new[] { "https://vault.azure.net" }));
    // To print the token, you can convert it to string 
    String accessTokenString = accessToken.Token.ToString();
    
    //You can use the credential object directly with Key Vault client.     
    var client = new SecretClient(new Uri("https://myvault.vault.azure.net/"), credential);
    

Получение токена с помощью библиотеки Microsoft.Azure.Services.AppAuthentication для .NET

Самый простой способ для приложений и функций .NET работать с управляемыми удостоверениями для ресурсов Azure заключается в использовании пакета Microsoft.Azure.Services.AppAuthentication. Эта библиотека также позволит протестировать код локально на компьютере, на котором ведется разработка. Можете протестировать код, используя учетную запись пользователя, из Visual Studio, интерфейса командной строки Azureили встроенной проверки подлинности Active Directory. Дополнительные сведения о параметрах локальной разработки с помощью этой библиотеки см. в справочнике Microsoft.Azure.Services.AppAuthentication. В этом разделе показано, как начать работу с библиотекой в коде.

  1. Добавьте ссылки на пакеты NuGet Microsoft.Azure.Services.AppAuthentication и Microsoft.Azure.KeyVault в приложение.

  2. Добавьте в приложение следующий код:

    using Microsoft.Azure.Services.AppAuthentication;
    using Microsoft.Azure.KeyVault;
    // ...
    var azureServiceTokenProvider = new AzureServiceTokenProvider();
    string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://management.azure.com/");
    // OR
    var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
    

Дополнительные сведения о пакете Microsoft.Azure.Services.AppAuthentication и операциях, которые он предоставляет, приведены в справочнике по Microsoft.Azure.Services.AppAuthentication и примере .NET, использующем службу приложений и хранилище ключей с управляемыми удостоверениями для ресурсов Azure.

Получение маркера с использованием C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Web.Script.Serialization; 

// Build request to acquire managed identities for Azure resources token
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/");
request.Headers["Metadata"] = "true";
request.Method = "GET";

try
{
    // Call /token endpoint
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();

    // Pipe response Stream to a StreamReader, and extract access token
    StreamReader streamResponse = new StreamReader(response.GetResponseStream()); 
    string stringResponse = streamResponse.ReadToEnd();
    JavaScriptSerializer j = new JavaScriptSerializer();
    Dictionary<string, string> list = (Dictionary<string, string>) j.Deserialize(stringResponse, typeof(Dictionary<string, string>));
    string accessToken = list["access_token"];
}
catch (Exception e)
{
    string errorText = String.Format("{0} \n\n{1}", e.Message, e.InnerException != null ? e.InnerException.Message : "Acquire token failed");
}

Получение маркера с использованием Java

Используйте эту библиотеку JSON для получения маркера с помощью Java.

import java.io.*;
import java.net.*;
import com.fasterxml.jackson.core.*;
 
class GetMSIToken {
    public static void main(String[] args) throws Exception {
 
        URL msiEndpoint = new URL("http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/");
        HttpURLConnection con = (HttpURLConnection) msiEndpoint.openConnection();
        con.setRequestMethod("GET");
        con.setRequestProperty("Metadata", "true");
 
        if (con.getResponseCode()!=200) {
            throw new Exception("Error calling managed identity token endpoint.");
        }
 
        InputStream responseStream = con.getInputStream();
 
        JsonFactory factory = new JsonFactory();
        JsonParser parser = factory.createParser(responseStream);
 
        while(!parser.isClosed()){
            JsonToken jsonToken = parser.nextToken();
 
            if(JsonToken.FIELD_NAME.equals(jsonToken)){
                String fieldName = parser.getCurrentName();
                jsonToken = parser.nextToken();
 
                if("access_token".equals(fieldName)){
                    String accesstoken = parser.getValueAsString();
                    System.out.println("Access Token: " + accesstoken.substring(0,5)+ "..." + accesstoken.substring(accesstoken.length()-5));
                    return;
                }
            }
        }
    }
}

Получение маркера с использованием Go

package main

import (
  "fmt"
  "io/ioutil"
  "net/http"
  "net/url"
  "encoding/json"
)

type responseJson struct {
  AccessToken string `json:"access_token"`
  RefreshToken string `json:"refresh_token"`
  ExpiresIn string `json:"expires_in"`
  ExpiresOn string `json:"expires_on"`
  NotBefore string `json:"not_before"`
  Resource string `json:"resource"`
  TokenType string `json:"token_type"`
}

func main() {
    
    // Create HTTP request for a managed services for Azure resources token to access Azure Resource Manager
    var msi_endpoint *url.URL
    msi_endpoint, err := url.Parse("http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01")
    if err != nil {
      fmt.Println("Error creating URL: ", err)
      return 
    }
    msi_parameters := msi_endpoint.Query()
    msi_parameters.Add("resource", "https://management.azure.com/")
    msi_endpoint.RawQuery = msi_parameters.Encode()
    req, err := http.NewRequest("GET", msi_endpoint.String(), nil)
    if err != nil {
      fmt.Println("Error creating HTTP request: ", err)
      return 
    }
    req.Header.Add("Metadata", "true")

    // Call managed services for Azure resources token endpoint
    client := &http.Client{}
    resp, err := client.Do(req) 
    if err != nil{
      fmt.Println("Error calling token endpoint: ", err)
      return
    }

    // Pull out response body
    responseBytes,err := ioutil.ReadAll(resp.Body)
    defer resp.Body.Close()
    if err != nil {
      fmt.Println("Error reading response body : ", err)
      return
    }

    // Unmarshall response body into struct
    var r responseJson
    err = json.Unmarshal(responseBytes, &r)
    if err != nil {
      fmt.Println("Error unmarshalling the response:", err)
      return
    }

    // Print HTTP response and marshalled response body elements to console
    fmt.Println("Response status:", resp.Status)
    fmt.Println("access_token: ", r.AccessToken)
    fmt.Println("refresh_token: ", r.RefreshToken)
    fmt.Println("expires_in: ", r.ExpiresIn)
    fmt.Println("expires_on: ", r.ExpiresOn)
    fmt.Println("not_before: ", r.NotBefore)
    fmt.Println("resource: ", r.Resource)
    fmt.Println("token_type: ", r.TokenType)
}

Получение маркера с помощью PowerShell

В следующем примере демонстрируется использование конечной точки REST управляемых удостоверений для ресурсов Azure из клиента PowerShell для выполнения следующих задач.

  1. Получение маркера доступа.
  2. Использование маркера доступа для вызова REST API Azure Resource Manager и получения информации о виртуальной машине. Не забудьте указать свой идентификатор подписки, имя группы ресурсов и имя виртуальной машины для <SUBSCRIPTION-ID>, <RESOURCE-GROUP> и <VM-NAME> соответственно.
Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' -Headers @{Metadata="true"}

Пример анализа маркера доступа, полученного из ответа:

# Get an access token for managed identities for Azure resources
$response = Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' `
                              -Headers @{Metadata="true"}
$content =$response.Content | ConvertFrom-Json
$access_token = $content.access_token
echo "The managed identities for Azure resources access token is $access_token"

# Use the access token to get resource information for the VM
$vmInfoRest = (Invoke-WebRequest -Uri 'https://management.azure.com/subscriptions/<SUBSCRIPTION-ID>/resourceGroups/<RESOURCE-GROUP>/providers/Microsoft.Compute/virtualMachines/<VM-NAME>?api-version=2017-12-01' -Method GET -ContentType "application/json" -Headers @{ Authorization ="Bearer $access_token"}).content
echo "JSON returned from call to get VM info:"
echo $vmInfoRest

Получение маркера с использованием CURL

curl 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' -H Metadata:true -s

Пример анализа маркера доступа, полученного из ответа:

response=$(curl 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' -H Metadata:true -s)
access_token=$(echo $response | python -c 'import sys, json; print (json.load(sys.stdin)["access_token"])')
echo The managed identities for Azure resources access token is $access_token

кэшировании маркеров

Подсистема управляемых удостоверений кэширует токены, однако по-прежнему рекомендуется реализовать кэширование маркеров в коде. Поэтому следует подготовиться к сценариям, когда ресурс указывает, что срок действия маркера истек.

По проводным вызовам идентификатора Microsoft Entra id результат только в следующих случаях:

  • произошел промах кэша из-за отсутствия маркера в кэше подсистемы управляемых удостоверений для ресурсов Azure;
  • истек срок действия маркера в кэше.

Обработка ошибок

Конечная точка управляемых удостоверений службы сообщает об ошибках в поле кода состояния заголовка ответного сообщения HTTP в виде ошибок 4xx или 5xx.

Код состояния Причина ошибки Способ устранения
404. Не найдено. Конечная точка IMDS обновляется. Повторите попытку с экспоненциальным увеличением задержки. См. инструкции ниже.
410 IMDS проходит через обновления IMDS будет доступен в течение 70 секунд
429 — слишком много запросов Достигнут предел регулирования IMDS. Повторите попытку с экспоненциальным увеличением задержки. См. инструкции ниже.
Ошибка 4xx в запросе. Один или несколько параметров запроса неверные. Не повторять попытку. Для получения дополнительной информации просмотрите сведения об ошибке. Ошибки 4xx — это ошибки времени разработки.
Временная ошибка 5xx службы. Управляемые удостоверения подсистемы ресурсов Azure или идентификатор Microsoft Entra возвращают временную ошибку. По прошествии 1 секунды можно безопасно повторить попытку. Если вы слишком быстро или слишком часто повторите попытку, IMDS и /или идентификатор Microsoft Entra может вернуть ошибку ограничения скорости (429).
timeout Конечная точка IMDS обновляется. Повторите попытку с экспоненциальным увеличением задержки. См. инструкции ниже.

Если возникает ошибка, в соответствующем тексте ответа HTTP содержится код JSON с подробностями об ошибке:

Элемент Description
error Идентификатор ошибки.
error_description Подробное описание ошибки. Описания ошибок могут в любое время измениться. Не записывайте код, который создает ветвь на основе значений в описании ошибки.

Ссылка ответа HTTP

В этом разделе описываются возможные сообщения об ошибках. Состояние "200 ОК" — это успешный ответ, а маркер доступа содержится в коде JSON текста ответа в элементе access_token.

Код состояния Ошибка Описание ошибки Решение
400 Bad Request (Неверный запрос) invalid_resource AADSTS50001: приложение с именем <URI> не найдено в клиенте с именем <TENANT-ID>. Это сообщение появляется, если администратор клиента не установил приложение или ни один пользователь клиента не дал на него согласия. Возможно, вы отправили запрос на проверку подлинности не тому клиенту. (только для Linux)
400 Bad Request (Неверный запрос) bad_request_102 Необходимый заголовок метаданных не указан Поле заголовка запроса Metadata отсутствует или имеет неправильный формат. Должно быть указано значение true в нижнем регистре. В качестве примера см. "Пример запроса" в предыдущем разделе для REST.
401 Unauthorized (Не авторизовано) unknown_source Неизвестный <URI> источника Убедитесь, что универсальный код ресурса (URI) запроса HTTP GET имеет правильный формат. Часть scheme:host/resource-path должна быть указана как http://localhost:50342/oauth2/token. В качестве примера см. "Пример запроса" в предыдущем разделе для REST.
invalid_request В запросе отсутствует требуемый параметр, он включает недопустимое значение параметра, параметр указан несколько раз или как-то искажен.
unauthorized_client Клиент не авторизован для запроса маркера доступа с помощью этого метода. Возникает из-за того, что в запросе на виртуальной машине неправильно настроены управляемые удостоверения для ресурсов Azure. Если вам нужна помощь с конфигурацией виртуальной машины, ознакомьтесь с разделом Настройка управляемых удостоверений для ресурсов Azure на виртуальной машине с помощью портала Azure.
access_denied Владелец ресурса или сервер авторизации отклонил запрос.
unsupported_response_type Сервер авторизации не поддерживает получение маркера доступа с помощью этого метода.
invalid_scope Запрошенная область недопустима, неизвестна или неверна.
500 — внутренняя ошибка сервера неизвестно Не удалось извлечь маркер из Active Directory. Дополнительные сведения см. в журналах в <путь к файлу>. Убедитесь, что на виртуальной машине включены управляемые удостоверения для ресурсов Azure. Если вам нужна помощь с конфигурацией виртуальной машины, ознакомьтесь с разделом Настройка управляемых удостоверений для ресурсов Azure на виртуальной машине с помощью портала Azure.

Кроме того, убедитесь, что универсальный код ресурса (URI) запроса HTTP GET отформатирован правильно, в частности универсальный код ресурса (URI), указанный в строке запроса. Пример запроса см. в предыдущем разделе REST, например, или службы Azure, поддерживающие проверку подлинности Microsoft Entra, для списка служб и соответствующих идентификаторов ресурсов.

Важно!

  • Служба IMDS не предназначена для работы за прокси-сервером, и эта функция не поддерживается. Примеры обхода прокси-сервера см. здесь.

Рекомендации по использованию механизма повторов

Если вы получите код с ошибкой 404, 429 или 5xx, советуем повторить попытку (сведения см. в разделе Обработка ошибок выше). Если вы получаете ошибку 410, это означает, что IMDS проходит через обновления и будет доступен не более 70 секунд.

Ограничения регулирования применяются к числу вызовов к конечной точке IMDS. Если превышен порог регулирования, конечная точка IMDS ограничивает каждый последующий запрос, пока действует регулирование. В течение этого периода конечная точка IMDS возвращает код состояния HTTP 429 ("Слишком много запросов"), а запросы завершаются сбоем.

Для повторных попыток рекомендуем следующую стратегию:

Стратегия повторов Параметры Значения Принцип работы
ExponentialBackoff Счетчик повторов
Минимальная задержка
Максимальная задержка
Разностная задержка
Первый быстрый повтор
5
0 с
60 с
2 с
false
Попытка 1 — задержка 0 с
Попытка 2 — задержка 2 с
Попытка 3 — задержка 6 с
Попытка 4 — задержка 14 с
Попытка 5 — задержка 30 с

Идентификаторы ресурсов для служб Azure

Список ресурсов, поддерживающих управляемые удостоверения для ресурсов Azure, см. в статье Службы Azure с поддержкой управляемых удостоверений.

Следующие шаги