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

As identidades gerenciadas para recursos do Azure são um recurso do Microsoft Entra ID. Cada um dos serviços do Azure que suportam as identidades geridas para os recursos do Azure estão sujeitos à sua própria linha de tempo. Certifique-se de que revê o estado de disponibilidade das identidades geridas para o seu recurso e problemas conhecidos antes de começar.

As identidades geridas para os recursos do Azure proporcionam aos recursos do Azure uma identidade gerida automaticamente no Microsoft Entra ID. Você pode usar essa identidade para autenticar em qualquer serviço que ofereça suporte à autenticação do Microsoft Entra, sem ter credenciais em seu código.

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

Pré-requisitos

Se você planeja usar os exemplos do Azure PowerShell neste artigo, certifique-se de instalar a versão mais recente do Azure PowerShell.

Importante

  • Todo o código/script de exemplo neste artigo pressupõe que o cliente está sendo executado 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 se conectar remotamente à sua 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 da variante (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 onde 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 nela.

Descrição geral

Um aplicativo cliente pode solicitar um token de acesso somente de aplicativo de identidade gerenciada para acessar um determinado recurso. O token é baseado nas identidades gerenciadas para a entidade de serviço de recursos do Azure. Como tal, não há necessidade de o cliente obter um token de acesso sob 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.

Associar Descrição
Obter um token usando HTTP Detalhes do protocolo para identidades gerenciadas para o ponto de extremidade de token de recursos do Azure
Obter um token usando Azure.Identity Obter um token usando a biblioteca Azure.Identity
Obter um token usando a biblioteca Microsoft.Azure.Services.AppAuthentication para .NET Exemplo de utilização da biblioteca Microsoft.Azure.Services.AppAuthentication a partir de um cliente .NET
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#
Obter um token usando Java Exemplo de uso de identidades gerenciadas para o ponto de extremidade REST de recursos do Azure a partir de um cliente Java
Obter um token usando o Go Exemplo de uso de identidades gerenciadas para o ponto de extremidade REST de recursos do Azure a partir de um cliente Go
Obter um token usando o PowerShell Exemplo de uso de identidades gerenciadas para o ponto de extremidade 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 REST de recursos do Azure de um cliente Bash/CURL
Manipulando o cache de token Orientação para lidar com tokens de acesso expirados
Processamento de erros Orientação para lidar com erros HTTP retornados das identidades gerenciadas para o ponto de extremidade de token de recursos do Azure
IDs de recursos para serviços do Azure Onde obter IDs de recursos para serviços do Azure suportados

Obter um token usando HTTP

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

Exemplo de solicitação usando o ponto de extremidade do Serviço de Metadados de 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 dados do ponto de extremidade. Nesse caso, um token de acesso OAuth.
http://169.254.169.254/metadata/identity/oauth2/token As identidades gerenciadas para o 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 de consulta, indicando a versão da API para o ponto de extremidade IMDS. Use a versão 2018-02-01 da API ou superior.
resource Um parâmetro de cadeia de caracteres de consulta, indicando o URI da ID do Aplicativo do recurso de destino. Também aparece na aud reivindicação (audiência) do token emitido. Este exemplo solicita um token para acessar o Gerenciador de Recursos do Azure, que tem um URI de ID de 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 falsificação de solicitação do lado do servidor (SSRF). Este valor deve ser definido como "true", em todas as letras minúsculas.
object_id (Opcional) Um parâmetro de cadeia de caracteres de consulta, indicando a object_id da identidade gerenciada para a qual você deseja o token. Obrigatório, se sua VM tiver várias identidades gerenciadas atribuídas pelo usuário.
client_id (Opcional) Um parâmetro de cadeia de caracteres de consulta, indicando a client_id da identidade gerenciada para a qual você deseja o token. Obrigatório, se sua VM tiver várias identidades gerenciadas atribuídas pelo usuário.
msi_res_id (Opcional) Um parâmetro de cadeia de caracteres de consulta, indicando a msi_res_id (ID de Recursos do Azure) da identidade gerenciada para a qual você deseja o token. Obrigatório, se sua VM tiver várias identidades gerenciadas atribuídas pelo 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. Quando você chama uma API REST segura, o token é incorporado no campo de cabeçalho da Authorization solicitação 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 a ser válido, antes de expirar, a partir do momento da emissão. O momento da emissão pode ser encontrado na reivindicação do iat 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 à reivindicação do exp token).
not_before O período de tempo em que o token de acesso entra em vigor e pode ser aceito. A data é representada como o número de segundos de "1970-01-01T0:0:0Z UTC" (corresponde à reivindicação do nbf token).
resource O recurso para o qual o token de acesso foi solicitado, que corresponde ao resource parâmetro de cadeia de caracteres de consulta da solicitação.
token_type O tipo de token, que é um token de acesso "Portador", o que significa que o recurso pode dar acesso ao portador desse token.

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

Usar a biblioteca de cliente de identidade do Azure é a maneira recomendada de usar identidades gerenciadas. Todos os SDKs do Azure são integrados com a Azure.Identity biblioteca 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 de biblioteca necessários do SDK do Azure, como Azure.Security.KeyVault.Secrets.

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

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

Obter 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 sua máquina de desenvolvimento. Você pode testar seu código usando sua conta de usuário do Visual Studio, da CLI do Azure ou da Autenticação Integrada do Ative Directory. Para obter mais informações sobre opções de desenvolvimento local com esta biblioteca, consulte a referência Microsoft.Azure.Services.AppAuthentication. Esta seção mostra como começar a usar a biblioteca em seu código.

  1. Adicione referências aos pacotes NuGet Microsoft.Azure.Services.AppAuthentication e Microsoft.Azure.KeyVault ao seu aplicativo.

  2. Adicione o seguinte código ao seu aplicativo:

    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 Microsoft.Azure.Services.AppAuthentication e as operações que expõe, consulte a referência Microsoft.Azure.Services.AppAuthentication e o Exemplo de Serviço de Aplicativo e KeyVault com identidades gerenciadas para recursos do Azure .NET.

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 Java

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

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

  1. Adquira 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. Certifique-se de substituir a ID da assinatura, o nome do grupo de recursos e o nome da máquina virtual por <SUBSCRIPTION-ID>, e <VM-NAME>, <RESOURCE-GROUP>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 de como analisar o token de acesso a partir 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 de como analisar o token de acesso a partir 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

Cache de token

O subsistema de identidades gerenciadas armazena tokens em cache, mas ainda recomendamos que você implemente o cache de tokens 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 apenas quando:

  • A perda de cache ocorre devido a nenhum token nas identidades gerenciadas para o cache do subsistema de recursos do Azure.
  • O token armazenado em cache expirou.

Processamento de erros

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

Código de Estado Motivo do erro Como lidar
404 Não encontrado. O ponto de extremidade IMDS está sendo atualizado. Tente novamente com Backoff Exponencial. Consulte as orientações abaixo.
410 O IMDS está passando por atualizações IMDS estará disponível dentro de 70 segundos
429 Demasiados pedidos. IMDS Limite de aceleração atingido. Tente novamente com Backoff Exponencial. Consulte as orientações abaixo.
4xx Erro na solicitação. Um ou mais parâmetros de solicitação estavam incorretos. Não tente novamente. Examine os detalhes do erro para obter mais informações. Os erros 4xx são erros de tempo de design.
5xx Erro transitório do serviço. As identidades gerenciadas para o subsistema de recursos do Azure ou ID do Microsoft Entra retornaram um erro transitório. É seguro tentar novamente depois de esperar pelo menos 1 segundo. Se você repetir muito rapidamente ou com muita frequência, o IMDS e/ou o Microsoft Entra ID podem retornar um erro de limite de taxa (429).
tempo limite O ponto de extremidade IMDS está sendo atualizado. Tente novamente com Backoff Exponencial. Consulte as orientações abaixo.

Se ocorrer um erro, o corpo de resposta HTTP correspondente contém JSON com os detalhes do erro:

Elemento Descrição
error Identificador de erro.
error_description Descrição detalhada do erro. As descrições de erros podem ser alteradas a qualquer momento. Não escreva código que ramifica com base em 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 corpo da resposta JSON, no elemento access_token.

Código de estado Erro Descrição do Erro Solução
400 Pedido Incorreto invalid_resource AADSTS50001: O aplicativo chamado URI> não foi encontrado no locatário chamado<< TENANT-ID>. Esta mensagem mostra se o administrador do locatário não instalou o aplicativo ou se nenhum usuário locatário consentiu com ele. Você pode ter enviado sua solicitação de autenticação para o locatário errado.\ (Apenas Linux)
400 Pedido Incorreto bad_request_102 Cabeçalho de metadados obrigatório não especificado O campo de cabeçalho da Metadata solicitação está ausente da sua solicitação ou está formatado incorretamente. O valor deve ser especificado como true, em 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 scheme:host/resource-path porção 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 está faltando um parâmetro necessá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 esse método. Causada por uma solicitação em uma VM que não tem 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 assistência 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 suporta a obtenção de um token de acesso usando esse método.
invalid_scope O escopo solicitado é inválido, desconhecido ou malformado.
Erro interno do servidor 500 desconhecido Falha ao recuperar token do Ative Directory. Para obter detalhes, consulte logs no <caminho do arquivo> Verifique se a VM tem identidades gerenciadas para recursos do Azure habilitadas. Consulte Configurar identidades gerenciadas para recursos do Azure em uma VM usando o portal do Azure se precisar de assistência com a configuração da VM.

Verifique também se o URI da solicitação HTTP GET está formatado corretamente, particularmente 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 os serviços do Azure que oferecem suporte à autenticação do Microsoft Entra para obter uma lista de serviços e suas respetivas IDs de recursos.

Importante

  • O IMDS não se destina a ser usado atrás de um proxy e isso não é suportado. Para obter exemplos de como ignorar proxies, consulte os Exemplos de metadados de instância do Azure.

Orientação de repetição

Recomenda-se repetir novamente se receber um código de erro 404, 429 ou 5xx (consulte Tratamento de erros acima). Se você receber um erro 410, isso indica que o IMDS está passando por atualizações e estará disponível em no máximo 70 segundos.

Os limites de limitação aplicam-se ao número de chamadas efetuadas para o ponto de extremidade IMDS. Quando o limite de limitação é excedido, o ponto de extremidade do IMDS limita quaisquer solicitações adicionais enquanto o acelerador estiver em vigor. Durante esse período, o ponto de extremidade do IMDS retorna o código de status HTTP 429 ("Muitas solicitações") e as solicitações falham.

Para novas tentativas, recomendamos a seguinte estratégia:

Estratégia de repetição Definições Valores Como funciona
ExponentialBackoff Contagem de repetições
Término mín.
Término máx.
Término delta
Primeira repetição rápida
5
0 s
60 s
2 s
false
Tentativa 1 – atraso de 0 s
Tentativa 2 – atraso de ~2 s
Tentativa 3 – atraso de ~6 s
Tentativa 4 – atraso de ~14 s
Tentativa 5 – atraso de ~30 s

IDs de recursos para serviços do Azure

Consulte Serviços do Azure com suporte a identidades gerenciadas para obter uma lista de recursos que dão suporte a identidades gerenciadas para recursos do Azure.

Próximos passos