Compartilhar via


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

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 de 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.

Ligação 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 Exemplo de uso de identidades gerenciadas para o endpoint REST de recursos no Azure de um cliente em C# usando Azure.Identity
Obter um token usando C# Exemplo de uso de identidades gerenciadas para o ponto de extremidade REST de recursos do Azure de um cliente C# usando HttpClient
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
Manipulação de erro 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 IMDS (Serviço de Metadados de Instância) do Azure (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.

Resposta de exemplo:

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 em que o token de acesso continua a ser válido, antes de expirar, a partir do tempo de emissão. A data e hora de emissão pode ser encontrada na declaração iat do token.
expires_on O período de tempo em que o token de acesso expira. 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 do tipo "Portador", 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 managedIdentityClientId = "<your managed identity client Id>";
    var credential = new ManagedIdentityCredential(managedIdentityClientId);
    var accessToken = await credential.GetTokenAsync(new TokenRequestContext(["https://vault.azure.net"]));
    // To print the token, you can convert it to string 
    var accessTokenString = accessToken.Token;
    
    // You can use the credential object directly with Key Vault client.     
    var client = new SecretClient(new Uri("https://myvault.vault.azure.net/"), credential);
    

Obter um token usando C#

using System;
using System.Net.Http;
using Newtonsoft.Json.Linq;

// Construct HttpClient
var httpClient = new HttpClient
{
    DefaultRequestHeaders =
    {
        { "Metadata", Boolean.TrueString }
    }
};

// Construct URI to call
var resource = "https://management.azure.com/";
var uri = $"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource={resource}";

// Make call
var response = await httpClient.GetAsync(uri);
try
{
    response.EnsureSuccessStatusCode();
}
catch (HttpRequestException)
{
    var error = await response.Content.ReadAsStringAsync();
    Console.WriteLine(error);
    throw;
}

// Parse response using Newtonsoft.Json
var content = await response.Content.ReadAsStringAsync();
var obj = JObject.Parse(content);
var accessToken = obj["access_token"];

Console.WriteLine(accessToken);

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-RestMeth -Method GET -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
$resource = 'https://management.azure.com'
$response = Invoke-RestMeth -Method GET `
                            -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$resource' `
                            -Headers @{ Metadata="true" }
$content = $response.Content | ConvertFrom-Json
$accessToken = $content.access_token
Write-Host "Access token using a User-Assigned Managed Identity is $accessToken"

# Use the access token to get resource information for the VM
$secureToken = $accessToken | ConvertTo-SecureString -AsPlainText
$vmInfoRest = Invoke-RestMeth -Method GET `
                              -Uri 'https://management.azure.com/subscriptions/<SUBSCRIPTION-ID>/resourceGroups/<RESOURCE-GROUP>/providers/Microsoft.Compute/virtualMachines/<VM-NAME>?api-version=2017-12-01' `
                              -ContentType 'application/json' `
                              -Authentication Bearer `
                              -Token $secureToken
Write-Host "JSON returned from call to get VM info: $($vmInfoRest.content)"

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 Access token using a User-Assigned Managed Identity 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).
atingir tempo limite Ponto de extremidade IMDS está atualizando. Tentar novamente com Retirada Exponencial. Consulte as diretrizes mais tarde.

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.
descrição_do_erro 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 recurso_inválido 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 solicitação_incorreta_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 fonte_desconhecida 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.
solicitação_inválida 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.
cliente_não_autorizado 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.
acesso_negado O proprietário do recurso ou o servidor de autorização negou a solicitação.
tipo_de_resposta_não_suportado 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 desconhecido 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

Tente novamente se receber um código de erro 404, 429 ou 5xx (consulte Tratamento de erro). 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
falso
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