Como usar identidades gerenciadas para recursos do Azure em uma VM do Azure para adquirir um token de acesso

Identidades gerenciadas para recursos do Azure é um recurso do Microsoft Entra ID. Cada um dos serviços do Azure que dão suporte a identidades gerenciadas para recursos do Azure está sujeito à própria linha do tempo. Não deixe de examinar o status de disponibilidade das identidades gerenciadas do seu recurso e os problemas conhecidos antes de começar.

As identidades gerenciadas dos recursos do Azure fornecem aos serviços do Azure uma identidade gerenciada automaticamente na ID do Microsoft Entra. Use essa identidade para autenticar qualquer serviço que dê suporte à autenticação do Microsoft Entra, sem a necessidade de ter as credenciais no código.

Este artigo fornece vários exemplos de código e script para aquisição de tokens. Ele também contém diretrizes sobre como lidar com a expiração de tokens e erros HTTP.

Pré-requisitos

  • Se você não estiver familiarizado com as identidades gerenciadas para funcionalidades de recursos do Azure, veja esta visão geral. Caso você ainda não tenha uma conta do Azure, inscreva-se em uma conta gratuita antes de continuar.

Se você planeja usar os exemplos do Azure PowerShell neste artigo, instale a versão mais recente do Azure PowerShell.

Importante

  • Todos os scripts/exemplos de código neste artigo assumem que o cliente está executando em uma máquina virtual com identidades gerenciadas para recursos do Azure. Use o recurso "Conectar" da máquina virtual no portal do Azure para conectar remotamente a VM. Para obter detalhes sobre como habilitar identidades gerenciadas para recursos do Azure em uma VM, consulte Configurar identidades gerenciadas para recursos do Azure em uma VM usando o portal do Azure ou um dos artigos variantes (usando PowerShell, CLI, um modelo ou um SDK do Azure).

Importante

  • O limite de segurança das identidades gerenciadas para recursos do Azure é o recurso em que a identidade é usada. Todos os códigos/scripts em execução em uma máquina virtual podem solicitar e recuperar tokens para quaisquer identidades gerenciadas disponíveis neles.

Visão geral

Um aplicativo cliente pode solicitar um token de acesso somente de aplicativo de identidade gerenciada para acessar um determinado recurso. O token é com base nas identidades gerenciadas para a entidade de serviço dos recursos do Azure. Sendo assim, o cliente não precisa obter um token de acesso em sua própria entidade de serviço. O token é adequado para uso como um token de portador em chamadas de serviço a serviço que exigem credenciais de cliente.

Link Descrição
Obter um token usando HTTP Detalhes do protocolo para identidades gerenciadas do ponto de extremidade do token de recursos do Azure
Obter um token usando o Azure.Identity Obter um token usando a biblioteca Azure.Identity
Obtenha um token usando a biblioteca Microsoft.Azure.Services.AppAuthentication para .NET Exemplo de como usar a biblioteca Microsoft.Azure.Services.AppAuthentication de um cliente .NET
Obter um token usando C# Exemplo de uso de identidades gerenciadas para o ponto de extremidade de REST de recursos do Azure de um cliente C#
Obter um token usando o Java Exemplo de uso de identidades gerenciadas para o ponto de extremidade de REST de recursos do Azure de um cliente Java
Obter um token usando Go Exemplo de uso de identidades gerenciadas para o ponto de extremidade de REST de recursos do Azure de um cliente Go
Obter um token usando PowerShell Exemplo de uso de identidades gerenciadas para o ponto de extremidade de REST de recursos do Azure de um cliente PowerShell
Obter um token usando CURL Exemplo de uso de identidades gerenciadas para o ponto de extremidade de REST de recursos do Azure de um cliente Bash/CURL
Tratamento de cache de token Diretrizes para manipular tokens de acesso expirados
Tratamento de erros Diretrizes para tratar erros HTTP retornados das identidades gerenciadas do ponto de extremidade de token de recursos do Azure
IDs de recurso para serviços do Azure Onde obter IDs de recurso para os serviços do Azure compatíveis

Obter um token usando HTTP

A interface fundamental para adquirir um token de acesso é baseada em REST, tornando-a acessível para qualquer aplicativo cliente em execução na VM que pode fazer chamadas REST HTTP. A abordagem é semelhante ao modelo de programação do Microsoft Entra, exceto que o cliente usa um ponto de extremidade na máquina virtual (em vez de um ponto de extremidade do Microsoft Entra).

Exemplo de solicitação usando o ponto de extremidade do serviço de metadados na instância do Azure (IMDS) (recomendado):

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
Elemento Descrição
GET O verbo HTTP, indicando que você deseja recuperar os dados do ponto de extremidade. Neste caso, um token de acesso OAuth.
http://169.254.169.254/metadata/identity/oauth2/token As identidades gerenciadas do ponto de extremidade de recursos do Azure para o Serviço de Metadados de Instância.
api-version Um parâmetro de cadeia de caracteres, que indica a versão de API para o ponto de extremidade IMDS. Use a versão de API 2018-02-01 ou superior.
resource Um parâmetro de cadeia de caracteres de consulta que indica o URI da ID do aplicativo do recurso de destino. Ele também aparece na declaração aud (público) do token emitido. Este exemplo solicita um token para acessar o Azure Resource Manager, que tem um URI de ID do aplicativo de https://management.azure.com/.
Metadata Um campo de cabeçalho de solicitação HTTP exigido por identidades gerenciadas. Essas informações são usadas como uma mitigação contra ataques de SSRF (solicitação do servidor forjada). Esse valor deve ser definido como "true", com todas as letras minúsculas.
object_id (Opcional) Um parâmetro de string de consulta, indicando o object_id da identidade gerenciada para a qual você deseja o token. Obrigatório, se a VM tiver várias identidades gerenciadas atribuídas ao usuário.
client_id (Opcional) Um parâmetro de cadeia de consulta, indicando o client_id da identidade gerenciada para a qual você deseja o token. Obrigatório, se a VM tiver várias identidades gerenciadas atribuídas ao usuário.
msi_res_id (Opcional) Um parâmetro da cadeia de caracteres de consulta, indicando omsi_res_id (ID do Recurso do Azure) da identidade gerenciada para a qual você deseja o token. Obrigatório, se a VM tiver várias identidades gerenciadas atribuídas ao usuário.

Exemplo de resposta:

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"
}
Elemento Descrição
access_token O token de acesso solicitado. Ao chamar uma API REST protegida, o token é inserido no campo de cabeçalho de solicitação Authorization como um token "portador", permitindo que a API autentique o chamador.
refresh_token Não usado por identidades gerenciadas para recursos do Azure.
expires_in O número de segundos que o token de acesso continua sendo válido antes da expiração desde o momento da emissão. A hora da emissão pode ser encontrada na declaração iat do token.
expires_on O período de expiração do token de acesso. A data é representada como o número de segundos de “1970-01-01T0:0:0Z UTC” (corresponde à declaração exp do token).
not_before O período para o token de acesso entrar em vigor e poder ser aceito. A data é representada como o número de segundos de “1970-01-01T0:0:0Z UTC” (corresponde à declaração nbf do token).
resource O recurso para o qual o token de acesso foi solicitado, que corresponde ao parâmetro de cadeia de consulta resource da solicitação.
token_type O tipo de token, que é um token de acesso "Portador", o que significa que o recurso pode conceder acesso ao portador desse token.

Obter um token usando a biblioteca de clientes de identidade do Azure

Usar a biblioteca de clientes de identidade do Azure é a maneira recomendada de usar identidades gerenciadas. Todos os SDKs do Azure são integrados à biblioteca Azure.Identity que fornece suporte para DefaultAzureCredential. Essa classe facilita o uso de Identidades Gerenciadas com SDKs do Azure. Saiba mais

  1. Instale o pacote Azure.Identity e outros pacotes necessários da biblioteca do SDK do Azure, como o Azure.Security.KeyVault.Secrets.

  2. Use o código de exemplo abaixo. Você não precisa se preocupar em obter os tokens. Você pode usar diretamente os clientes do SDK do Azure. O código serve para demonstrar como obter o token, se necessário.

    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);
    

Obtenha um token usando a biblioteca Microsoft.Azure.Services.AppAuthentication para .NET

Para aplicativos e funções .NET, a maneira mais simples de trabalhar com identidades gerenciadas para recursos do Azure é por meio do pacote Microsoft.Azure.Services.AppAuthentication. Essa biblioteca também permitirá que você teste seu código localmente em seu computador de desenvolvimento. Você pode testar o código usando sua conta de usuário do Visual Studio, a CLI do Azure ou a Autenticação Integrada do Active Directory. Para obter mais informações sobre as opções de desenvolvimento local com essa biblioteca, consulte a Referência Microsoft.Azure.Services.AppAuthentication. Esta seção mostra a você como começar a usar a biblioteca no seu código.

  1. Adicione uma referência aos pacotes NuGet Microsoft.Azure.Services.AppAuthentication e Microsoft.Azure.KeyVault no aplicativo.

  2. Adicione o código a seguir à sua página:

    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));
    

Para saber mais sobre o Microsoft.Azure.Services.AppAuthentication e as operações que ele expõe, consulte a Referência do Microsoft.Azure.Services.AppAuthentication e o Serviço de Aplicativo e KeyVault com identidades gerenciadas para exemplo .NET de recursos do Azure .

Obter um token usando 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");
}

Obter um token usando o Java

Use esta biblioteca JSON para recuperar um token usando o 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;
                }
            }
        }
    }
}

Obter um token usando 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)
}

Obter um token usando PowerShell

O exemplo a seguir demonstra como usar as identidades gerenciadas do ponto de extremidade de REST de recursos do Azure de um cliente do PowerShell para:

  1. Adquirir um token de acesso.
  2. Use o token de acesso para chamar uma API REST do Azure Resource Manager e obter informações sobre a VM. Substitua sua ID de assinatura, o nome do grupo de recursos e o nome da máquina virtual para <SUBSCRIPTION-ID>, <RESOURCE-GROUP> e <VM-NAME>, respectivamente.
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"}

Exemplo sobre como analisar o token de acesso da resposta:

# 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

Obter um token usando 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

Exemplo sobre como analisar o token de acesso da resposta:

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

Armazenamento de token em cache

O subsistema de identidades gerenciadas armazena em cache tokens, mas ainda recomendamos que você implemente o cache de token em seu código. Você deve se preparar para cenários em que o recurso indica que o token expirou.

As chamadas on-the-wire para o Microsoft Entra ID resultam somente quando:

  • A perda no cache ocorre porque não há tokens nas identidades gerenciadas do cache do subsistema de recursos do Azure.
  • O token está expirado.

Tratamento de erros

O ponto de extremidade de identidades gerenciadas sinaliza os erros por meio do campo de código de status do cabeçalho da mensagem de resposta HTTP, como erros 4xx ou 5xx:

Código de status Motivo do erro Como tratar
404 Não Encontrado: Ponto de extremidade IMDS está atualizando. Tentar novamente com Retirada Exponencial. Consulte as diretrizes abaixo.
410 O IMDS está passando por atualizações O IMDS estará disponível dentro de 70 segundos
429 Número excessivo de solicitações. Atingido o limite de restrição IMDS. Tentar novamente com Retirada Exponencial. Consulte as diretrizes abaixo.
o erro 4xx na solicitação. Um ou mais parâmetros de solicitação estava incorreto. Não tente novamente. Examine os detalhes do erro para obter mais informações. Os erros 4xx são erros de tempo de design.
Erro 5xx transitório do serviço. As identidades gerenciadas para o subsistema de recursos Azure ou do Microsoft Entra ID devolveram um erro transitório. É seguro tentar novamente depois de aguardar pelo menos 1 segundo. Se tentar novamente muito rápido ou com muita frequência, o IMDS e/ou o Microsoft Entra ID poderá retornar um erro de limite de taxa (429).
timeout Ponto de extremidade IMDS está atualizando. Tentar novamente com Retirada Exponencial. Consulte as diretrizes abaixo.

Se ocorrer um erro, o corpo da resposta HTTP correspondente conterá o JSON com os detalhes do erro:

Elemento Descrição
erro Identificador do erro.
error_description Descrição detalhada do erro. Descrições de erro podem ser alteradas a qualquer momento. Não escreva código que se ramifique com base nos valores na descrição do erro.

Referência de resposta HTTP

Esta seção documenta as possíveis respostas de erro. Um status "200 OK" é uma resposta bem-sucedida, e o token de acesso está contido no JSON do corpo de resposta, no elemento access_token.

Código de status Erro Descrição do erro Solução
400 Solicitação Inválida invalid_resource AADSTS50001: o aplicativo chamado <URI> não foi encontrado no locatário chamado <TENANT-ID>. Essa mensagem mostra se o administrador de locatários não instalou o aplicativo ou nenhum usuário de locatário consentiu a ele. Talvez você tenha enviado a solicitação de autenticação ao locatário errado.\ (Apenas Linux)
400 Solicitação Inválida bad_request_102 Cabeçalho de metadados necessário não especificado O campo de cabeçalho de solicitação Metadata está ausente da solicitação ou está formatado incorretamente. O valor deve ser especificado como true, com todas as letras minúsculas. Consulte a "Solicitação de exemplo" na seção REST anterior para obter um exemplo.
401 Não Autorizado unknown_source <URI> de origem desconhecida Verifique se o URI da solicitação HTTP GET está formatado corretamente. A parte scheme:host/resource-path deve ser especificada como http://localhost:50342/oauth2/token. Consulte a "Solicitação de exemplo" na seção REST anterior para obter um exemplo.
invalid_request A solicitação não tem um parâmetro obrigatório, inclui um valor de parâmetro inválido, inclui um parâmetro mais de uma vez ou está malformada.
unauthorized_client O cliente não está autorizado a solicitar um token de acesso usando este método. Causado por uma solicitação em uma VM que não tenha identidades gerenciadas para recursos do Azure configuradas corretamente. Consulte Configurar identidades gerenciadas para recursos do Azure em uma VM usando o portal do Azure, se precisar de ajuda com a configuração da VM.
access_denied O proprietário do recurso ou o servidor de autorização negou a solicitação.
unsupported_response_type O servidor de autorização não dá suporte à obtenção de um token de acesso usando este método.
invalid_scope O escopo solicitado é inválido, desconhecido ou malformado.
Erro interno do servidor 500 unknown Falha ao recuperar o token do Active Directory. Para obter detalhes, consulte os logs no <caminho do arquivo> Verifique se as identidades gerenciadas para recursos do Azure foram habilitadas na VM. Consulte Configurar identidades gerenciadas para recursos do Azure em uma VM usando o portal do Azure, se precisar de ajuda com a configuração da VM.

Verifique também se seu URI de solicitação GET HTTP foi formatado corretamente, principalmente o URI do recurso especificado na cadeia de caracteres de consulta. Consulte a "Solicitação de exemplo" na seção REST anterior para obter um exemplo ou Serviços do Azure compatíveis com a autenticação do Microsoft Entra para obter uma lista de serviços e suas respectivas IDs de recurso.

Importante

Repita a orientação

É recomendável tentar novamente se você receber o código de erro 404, 429 ou 5xx (confira Tratamento de erros acima). Se você receber um erro 410, ele indicará que o IMDS está passando por atualizações e estará disponível em no máximo 70 segundos.

Limitação limites se aplicam ao número de chamadas feitas para o ponto de extremidade IMDS. Quando o limite de limitação é excedido, o ponto de extremidade IMDS limita qualquer solicitação adicional enquanto a limitação está em vigor. Durante esse período, o ponto de extremidade de IMDS da MSI retornará o código de status HTTP 429 ("Muitas solicitações") e as solicitações falharão.

Para tentar novamente, é recomendável a estratégia a seguir:

Estratégia de repetição Configurações Valores Como funciona
ExponentialBackoff Contagem de repetição
Retirada mín.
Retirada máx.
Retirada delta
Primeira repetição rápida
5
0 s
60 s
2 s
false
1ª tentativa — intervalo de 0 s
2ª tentativa — intervalo de ~2 s
3ª tentativa — intervalo de ~6 s
4ª tentativa — intervalo de ~14 s
5ª tentativa — intervalo de ~30 s

IDs de recurso para serviços do Azure

Para obter uma lista de serviços do Azure que dão suporte a identidades gerenciadas, veja Serviços do Azure com suporte a identidades gerenciadas.

Próximas etapas