Cómo usar identidades administradas de recursos de Azure en una máquina virtual de Azure para adquirir un token de acceso

Identidades administradas para recursos de Azure es una característica de Microsoft Entra ID. Cada servicio de Azure compatible con Managed Identities for Azure Resources está sujeto a su propia escala de tiempo. Asegúrese de revisar el estado de disponibilidad de las identidades administradas para el recurso y los problemas conocidos antes de comenzar.

Las identidades administradas de los recursos de Azure proporcionan a los servicios de Azure una identidad administrada automáticamente en Microsoft Entra ID. Puede usar esta identidad para autenticar a cualquier servicio que admita la autenticación de Microsoft Entra, sin necesidad de tener credenciales en el código.

En este artículo se proporcionan varios ejemplos de código y script para la adquisición de tokens. También contiene instrucciones sobre cómo controlar la expiración del token y los errores HTTP.

Prerrequisitos

Si tiene previsto usar los ejemplos de Azure PowerShell de este artículo, no se olvide de instalar la última versión de Azure PowerShell.

Importante

  • En todo el código y scripts de ejemplo de este artículo, se da por supuesto que el cliente se ejecuta en una máquina virtual con identidades administradas de recursos de Azure. Use la característica "Conectar" de la máquina virtual en Azure Portal para conectarse a la máquina virtual de forma remota. Para más información sobre la habilitación de identidades administradas de recursos de Azure en una VM, consulte Configure managed identities for Azure resources on a VM using the Azure portal (Configuración de identidades administradas de recursos de Azure en una VM mediante Azure Portal) o uno de los artículos derivados (mediante PowerShell, la CLI, una plantilla o un SDK de Azure).

Importante

  • El límite de seguridad de las identidades administradas para recursos de Azure es el recurso donde se usa la identidad. Todo el código o scripts que se ejecutan en una máquina virtual pueden solicitar y recuperar tokens para cualquier identidad administrada disponible.

Información general

Una aplicación cliente puede solicitar un token de acceso de solo aplicación de identidad administrada para acceder a un recurso determinado. El token se basa en la entidad de servicio de identidades administradas de recursos de Azure. Por lo tanto, no es necesario que el cliente obtenga un token de acceso en su propia entidad de servicio. El token es adecuado para utilizarse como un token de portador en llamadas de servicio a servicio que requieren credenciales de cliente.

Vínculo Descripción
Obtención de un token con HTTP Detalles del protocolo del punto de conexión del token de las identidades administradas de recursos de Azure
Obtención de un token mediante Azure.Identity Obtención de un token mediante la biblioteca Azure.Identity
Obtención de un token con la biblioteca Microsoft.Azure.Services.AppAuthentication para .NET Ejemplo del uso de la biblioteca Microsoft.Azure.Services.AppAuthentication desde un cliente .NET
Obtención de un token con C# Ejemplo del uso del punto de conexión REST de identidades administradas de recursos de Azure desde un cliente de C#
Obtención de un token con Java Ejemplo del uso del punto de conexión REST de identidades administradas de recursos de Azure desde un cliente de Java
Obtención de un token con Go Ejemplo del uso del punto de conexión REST de identidades administradas de recursos de Azure desde un cliente de Go
Obtención de un token mediante PowerShell Ejemplo del uso del punto de conexión REST de identidades administradas de recursos de Azure desde un cliente de PowerShell
Obtención de un token con CURL Ejemplo del uso del punto de conexión REST de identidades administradas de recursos de Azure desde un cliente de Bash o CURL
Control del almacenamiento en caché de tokens Instrucciones para controlar los tokens de acceso expirados
Control de errores Instrucciones para controlar los errores HTTP devueltos desde el punto de conexión del token de las identidades administradas de recursos de Azure
Identificadores de recurso de servicios de Azure Dónde obtener identificadores de recurso de los servicios de Azure admitidos

Obtención de un token con HTTP

La interfaz básica para obtener un token de acceso se basa en REST, de modo que podrá acceder a cualquier aplicación cliente que se ejecute en la máquina virtual que es capaz de realizar llamadas REST de HTTP. Este enfoque es similar al modelo de programación de Microsoft Entra, salvo que el cliente usa un punto de conexión en la máquina virtual (frente a un punto de conexión de Microsoft Entra).

Solicitud de ejemplo con el punto de conexión de Azure Instance Metadata Service (IMDS) (opción recomendada) :

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 Descripción
GET El verbo HTTP, indicando que se van a recuperar datos desde el punto de conexión. En este caso, el token de acceso de OAuth.
http://169.254.169.254/metadata/identity/oauth2/token Punto de conexión del token de las identidades administradas de recursos de Azure para Instance Metadata Service.
api-version Un parámetro de cadena de consulta, que indica la versión de API del punto de conexión de IMDS. Use la versión 2018-02-01 o superior de la API.
resource Un parámetro de cadena de consulta, que indica el URI del identificador de aplicación del recurso de destino. También aparece en la notificación aud (audiencia) del token emitido. En este ejemplo, se solicita un token para acceder a Azure Resource Manager, que tiene un URI de identificador de aplicación de https://management.azure.com/.
Metadata Campo de encabezado de solicitud HTTP requerido por las identidades administradas. Esta información se usa como mitigación frente a ataques de falsificación de solicitud del lado servidor (SSRF). Este valor debe establecerse en "true", todo en minúsculas.
object_id (Opcional) Un parámetro de cadena de consulta, que indica el valor de object_id de la identidad administrada para la que quiere que sea el token. Es obligatorio si la máquina virtual tiene varias identidades administradas asignadas por el usuario.
client_id (Opcional) Un parámetro de cadena de consulta, que indica el valor de client_id de la identidad administrada para la que quiere que sea el token. Es obligatorio si la máquina virtual tiene varias identidades administradas asignadas por el usuario.
msi_res_id (Opcional) Un parámetro de cadena de consulta, que indica el valor mi_res_id (Azure Resource AD) de la identidad administrada para la que quiere que sea el token. Es obligatorio si la máquina virtual tiene varias identidades administradas asignadas por el usuario.

Respuesta de ejemplo:

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 Descripción
access_token El token de acceso solicitado. Cuando se llama a una API REST protegida, el token se inserta en el campo de encabezado de solicitud Authorization como un token de "portador", lo que permite a la API autenticar al autor de la llamada.
refresh_token Las identidades administradas de recursos de Azure no lo usan.
expires_in El número de segundos que el token de acceso sigue siendo válido, antes de expirar, desde la hora de emisión. La hora de emisión puede encontrarse en la notificación iat del token.
expires_on La hora a la que expira el token de acceso. La fecha se representa como el número de segundos desde "1970-01-01T0:0:0Z UTC" (se corresponde con la notificación exp del token).
not_before El intervalo de tiempo cuando el token de acceso tiene efecto y se puede aceptar. La fecha se representa como el número de segundos desde "1970-01-01T0:0:0Z UTC" (se corresponde con la notificación nbf del token).
resource El recurso para el que se solicitó el token de acceso, que coincide con el parámetro de la cadena de consulta resource de la solicitud.
token_type El tipo de token, que es un token de acceso al "Portador", lo que significa que el recurso puede permitir el acceso al portador del token.

Obtención de un token mediante la biblioteca cliente de identidad de Azure

El uso de la biblioteca cliente de identidad de Azure es la manera recomendada de usar identidades administradas. Todos los SDK de Azure se integran con la biblioteca Azure.Identity que proporciona compatibilidad con DefaultAzureCredential. Esta clase facilita el uso de identidades administradas con los SDK de Azure. Más información

  1. Instale el paquete Azure.Identity y otros paquetes necesarios de la biblioteca del SDK de Azure, como Azure.Security.KeyVault.Secrets.

  2. Use el código de ejemplo siguiente. No es necesario preocuparse por la obtención de tokens. Puede usar directamente los clientes del SDK de Azure. El código es para mostrar cómo obtener el token, si es necesario.

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

Obtención de un token con la biblioteca Microsoft.Azure.Services.AppAuthentication para .NET

En el caso de las aplicaciones y las funciones de .NET, la manera más sencilla de trabajar con identidades administradas de recursos de Azure es a través del paquete Microsoft.Azure.Services.AppAuthentication. Esta biblioteca también le permitirá probar el código localmente en la máquina de desarrollo. Puede probar el código con su cuenta de usuario desde Visual Studio, la CLI de Azure o la autenticación integrada de Active Directory. Para obtener más información sobre las opciones de desarrollo local con esta biblioteca, consulte la referencia de Microsoft.Azure.Services.AppAuthentication. En esta sección se muestra cómo empezar a usar la biblioteca en su código.

  1. Agregue referencias a los paquetes de NuGet Microsoft.Azure.Services.AppAuthentication y Microsoft.Azure.KeyVault para la aplicación.

  2. Agregue el siguiente código a su aplicación:

    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 obtener más información sobre Microsoft.Azure.Services.AppAuthentication y las operaciones que expone, consulte la referencia de Microsoft.Azure.Services.AppAuthentication y el ejemplo de .NET sobre App Service y KeyVault con identidades administradas de recursos de Azure.

Obtención de un token con 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");
}

Obtención de un token con Java

Use esta biblioteca JSON para recuperar un token con 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;
                }
            }
        }
    }
}

Obtención de un token con 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)
}

Obtención de un token mediante PowerShell

En el ejemplo siguiente se muestra cómo utilizar el punto de conexión REST de identidades administradas de recursos de Azure desde un cliente de PowerShell para las siguientes tareas:

  1. Obtener un token de acceso.
  2. Usar el token de acceso para llamar a una API de REST de Azure Resource Manager y consultar información sobre la máquina virtual. No olvide sustituir el identificador de suscripción, el nombre del grupo de recursos y el nombre de máquina virtual en <SUBSCRIPTION-ID>, <RESOURCE-GROUP> y <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"}

Ejemplo de cómo analizar el token de acceso de la respuesta:

# 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

Obtención de un token con 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

Ejemplo de cómo analizar el token de acceso de la respuesta:

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

Almacenamiento en caché de tokens

El subsistema de identidades administradas almacena en caché los tokens, pero se recomienda implementar el almacenamiento en caché de tokens en el código. Debe prepararse para escenarios en los que el recurso indica que el token ha expirado.

Las llamadas por cable a Microsoft Entra ID solo se generan cuando:

  • el error de caché se produce debido a que no hay ningún token en la caché del subsistema de identidades administradas de recursos de Azure.
  • el token almacenado en caché ha expirado.

Control de errores

El punto de conexión de identidades administradas señala los errores a través del campo de código de estado del encabezado del mensaje de respuesta HTTP, como errores 4xx o 5xx:

Código de estado Motivo del error Realización del control
404 No encontrado. El punto de conexión de IMDS se está actualizando. Vuelva a intentarlo con retroceso exponencial. Consulte las instrucciones siguientes.
410 IMDS se está actualizando IMDS estará disponible en 70 segundos
429 Demasiadas solicitudes. Se ha alcanzado la limitación de IMDS. Vuelva a intentarlo con retroceso exponencial. Consulte las instrucciones siguientes.
Error 4xx en la solicitud. Uno o varios de los parámetros de solicitud eran incorrectos. No vuelva a intentarlo. Consulte los detalles del error para obtener más información. Los errores 4xx son de tiempo de diseño.
Error transitorio 5xx del servicio. El subsistema de identidades administradas para recursos de Azure o Microsoft Entra ID han devuelto un error transitorio. Es seguro volver a intentarlo después de esperar al menos 1 segundo. Si vuelve a intentarlo demasiado pronto o demasiadas veces, IMDS o Microsoft Entra ID pueden devolver un error de límite de frecuencia (429).
timeout El punto de conexión de IMDS se está actualizando. Vuelva a intentarlo con retroceso exponencial. Consulte las instrucciones siguientes.

Si se produce un error, el cuerpo de respuesta HTTP correspondiente contiene los detalles del error en formato JSON:

Elemento Descripción
error Identificador del error.
error_description Descripción detallada del error. Las descripciones de error pueden cambiar en cualquier momento. No escriba código que cree ramas en función de los valores de la descripción del error.

Referencia de la respuesta HTTP

En esta sección se documentan las posibles respuestas de error. Un estado de "200 OK" es una respuesta correcta y el token de acceso se encuentra en el cuerpo de respuesta JSON; en el elemento access_token.

status code Error Descripción del error Solución
400 - Solicitud incorrecta invalid_resource AADSTS50001: la aplicación denominada <URI> no se encontró en el inquilino denominado <ID-INQUILINO>. Este mensaje muestra si el administrador de inquilinos no ha instalado la aplicación o ningún usuario de inquilino ha dado su consentimiento. Es posible que haya enviado la solicitud de autenticación al inquilino incorrecto. (Solo Linux).
400 - Solicitud incorrecta bad_request_102 Encabezado de metadatos necesario no especificado. El campo Metadata del encabezado de la solicitud no está en la solicitud o tiene un formato incorrecto. El valor debe especificarse como true, todo en minúsculas. Consulte "Solicitud de ejemplo" en la sección REST anterior para obtener un ejemplo.
401 No autorizado unknown_source Origen desconocido <URI>. Compruebe que el identificador URI de la solicitud HTTP GET tiene el formato correcto. La parte scheme:host/resource-path debe especificarse como http://localhost:50342/oauth2/token. Consulte "Solicitud de ejemplo" en la sección REST anterior para obtener un ejemplo.
invalid_request En la solicitud falta un parámetro necesario, incluye un valor de parámetro no válido o un parámetro repetido, o bien no tiene el formato correcto.
unauthorized_client El cliente no está autorizado para solicitar un token de acceso mediante este método. Esto se debe a que una solicitud de una VM no tiene identidades administradas de recursos de Azure configuradas correctamente. Consulte Configure managed identities for Azure resources on a VM using the Azure portal (Configuración de identidades administradas de recursos de Azure en una VM mediante Azure Portal) si necesita ayuda con la configuración de la VM.
access_denied El propietario del recurso o el servidor de consentimiento rechazaron la solicitud.
unsupported_response_type El servidor de autorización no admite la obtención de un token de acceso mediante este método.
invalid_scope El ámbito solicitado no es válido, es desconocido o tiene un formato incorrecto.
500 Error interno del servidor unknown No se pudo recuperar el token de Active Directory. Para obtener información, consulte los registros en <ruta de acceso del archivo>. Compruebe que la máquina virtual tiene habilitadas las identidades administradas para los recursos de Azure. Consulte Configure managed identities for Azure resources on a VM using the Azure portal (Configuración de identidades administradas de recursos de Azure en una VM mediante Azure Portal) si necesita ayuda con la configuración de la VM.

Compruebe que el URI de la solicitud HTTP GET tiene el formato correcto, especialmente el del recurso especificado en la cadena de consulta. Consulte "Solicitud de ejemplo" en la sección REST anterior para obtener un ejemplo o Servicios de Azure que admiten la autenticación de Microsoft Entra para obtener una lista de servicios y sus respectivos identificadores de recurso.

Importante

Instrucciones de reintento

Se recomienda reintentar si recibe un código de error 404, 429 o 5xx (consulte Control de errores arriba). Si recibe un error 410, significa que IMDS se está actualizando y estará disponible en 70 segundos como máximo.

Se aplican límites al número de llamadas realizadas al punto de conexión de IMDS. Cuando se supera el umbral de limitación, el punto de conexión de IMDS limita las solicitudes sucesivas mientras la limitación está en vigor. Durante este período, el punto de conexión de IMDS devuelve el código de estado HTTP 429 ("Demasiadas solicitudes") y se producirá un error en las solicitudes.

Para volver a intentarlo, se recomienda la estrategia siguiente:

Estrategia de reintento Configuración Valores Funcionamiento
ExponentialBackoff Número de reintentos
Interrupción mínima
Interrupción máxima
Interrupción delta
Primer reintento rápido
5
0 segundos
60 segundos
2 segundos
false
Intento 1 - retraso de 0 segundos
Intento 2 - retraso de ~2 segundos
Intento 3 - retraso de ~6 segundos
Intento 4 - retraso de ~14 segundos
Intento 5 - retraso de ~30 segundos

Identificadores de recurso para los servicios de Azure

Consulte Servicios de Azure con compatibilidad con identidades administradas para obtener una lista de recursos que admiten identidades administradas para recursos de Azure.

Pasos siguientes