Come usare le identità gestite per risorse di Azure in una macchina virtuale di Azure per acquisire un token di accesso

Le identità gestite per le risorse di Azure sono una funzionalità di Microsoft Entra ID. Tutti i servizi di Azure che supportano le identità gestite per le risorse di Azure sono soggetti alla sequenza temporale di tali entità. Prima di iniziare, assicurarsi di esaminare lo stato di disponibilità delle identità gestite per la risorsa e i problemi noti.

Le identità gestite per le risorse di Azure offrono servizi di Azure con un'identità gestita automaticamente in Microsoft Entra ID. È possibile usare questa identità per eseguire l'autenticazione a qualsiasi servizio che supporti l'autenticazione di Microsoft Entra, senza avere credenziali nel codice.

Questo articolo fornisce vari esempi di codice e script per l'acquisizione di token. Contiene anche indicazioni sulla gestione della scadenza dei token e degli errori HTTP.

Prerequisiti

Se si prevede di usare gli esempi di Azure PowerShell presenti in questo articolo, assicurarsi di installare la versione più recente di Azure PowerShell.

Importante

  • Tutto il codice e gli script di esempio in questo articolo presuppongono che il client sia in esecuzione su una macchina virtuale con identità gestite per risorse di Azure. Usare la funzionalità di connessione alla macchina virtuale nel portale di Azure per eseguire la connessione in remoto alla macchina virtuale. Per informazioni dettagliate sull'abilitazione delle identità gestite per risorse di Azure in una macchina virtuale, vedere Configurare le identità gestite per le risorse di Azure in una macchina virtuale tramite il portale di Azure o una delle varianti dell'articolo riguardanti PowerShell, l'interfaccia della riga di comando, un modello o un Azure SDK.

Importante

  • Il limite di sicurezza delle identità gestite per le risorse di Azure è la risorsa in cui viene usata l'identità. Tutti i codici e gli script in esecuzione in una macchina virtuale possono richiedere e recuperare token per qualsiasi identità gestita disponibile nella macchina stessa.

Panoramica

Un'applicazione client può richiedere un token di accesso solo app per l'identità gestita per accedere a una determinata risorsa. Il token è basato sulle identità gestite per l'entità servizio delle risorse di Azure. Di conseguenza, non è necessario che il client ottenga un token di accesso con la propria entità servizio. Il token è adatto per l'uso come token di connessione nelle chiamate da servizio a servizio che richiedono le credenziali client.

Collegamento Descrizione
Ottenere un token tramite HTTP Dettagli sul protocollo per l'endpoint del token delle identità gestite per risorse di Azure
Ottenere un token con Azure.Identity Ottenere un token usando la libreria Azure.Identity
Ottenere un token usando la libreria Microsoft.Azure.Services.AppAuthentication per .NET Esempio di utilizzo della libreria Microsoft.Azure.Services.AppAuthentication da un client .NET
Ottenere un token tramite C# Esempio di utilizzo dell'endpoint REST delle identità gestite per risorse di Azure da un client C#
Ottenere un token tramite Java Esempio di utilizzo dell'endpoint REST delle identità gestite per risorse di Azure da un client Java
Ottenere un token tramite Go Esempio di utilizzo dell'endpoint REST delle identità gestite per risorse di Azure da un client Go
Ottenere un token con PowerShell Esempio di utilizzo dell'endpoint REST delle identità gestite per risorse di Azure da un client PowerShell
Ottenere un token tramite CURL Esempio di utilizzo dell'endpoint REST delle identità gestite per risorse di Azure da un client Bash/CURL
Gestione della memorizzazione nella cache dei token Indicazioni per la gestione di token di accesso scaduti
Gestione errori Materiale sussidiario per la gestione degli errori HTTP restituiti dall'endpoint del token delle identità gestite per risorse di Azure
ID di risorsa per servizi di Azure Come ottenere ID di risorsa per i servizi di Azure supportati

Ottenere un token tramite HTTP

L'interfaccia di base per l'acquisizione di un token di accesso si basa su REST. È pertanto accessibile a qualsiasi applicazione client in esecuzione nella macchina virtuale in grado di effettuare chiamate REST HTTP. Questo approccio è simile al modello di programmazione Microsoft Entra, ad eccezione del client che usa un endpoint nella macchina virtuale (rispetto a un endpoint Microsoft Entra).

Richiesta di esempio che usa l'endpoint del servizio metadati dell'istanza (IMDS) (consigliato):

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 Descrizione
GET Verbo HTTP che indica la volontà di recuperare dati dall'endpoint. In questo caso, un token di accesso OAuth.
http://169.254.169.254/metadata/identity/oauth2/token Endpoint delle identità gestite per le risorse di Azure per il servizio metadati dell'istanza.
api-version Parametro della stringa di query che indica la versione dell'API per l'endpoint IMDS. Usare la versione 2018-02-01 dell'API o versione successiva.
resource Parametro della stringa di query che indica l'URI dell'ID app della risorsa di destinazione. Viene visualizzato anche nell'attestazione aud (audience, destinatari) del token emesso. In questo esempio viene richiesto un token per accedere ad Azure Resource Manager, con l'URI di ID app https://management.azure.com/.
Metadata Campo di intestazione della richiesta HTTP richiesto dalle identità gestite. Queste informazioni vengono usate come mitigazione contro gli attacchi di richiesta lato server falsi (SSRF). Questo valore deve essere impostato su "true", usando tutte lettere minuscole.
object_id (Facoltativo) Un parametro di stringa di query che indichi il valore object_id dell'identità gestita per cui si desidera il token. Obbligatorio, se la macchina virtuale dispone di più identità gestite assegnate dall'utente.
client_id (Facoltativo) Un parametro di stringa di query che indichi il valore client_id dell'identità gestita per cui si desidera il token. Obbligatorio, se la macchina virtuale dispone di più identità gestite assegnate dall'utente.
msi_res_id (Facoltativo) Parametro della stringa di query che indica il msi_res_id (ID risorsa di Azure) dell'identità gestita per cui si vuole il token. Obbligatorio, se la macchina virtuale dispone di più identità gestite assegnate dall'utente.

Risposta di esempio:

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 Descrizione
access_token Token di accesso richiesto. Quando si chiama un'API REST protetta, il token viene incorporato nel campo dell'intestazione della Authorization richiesta come token di connessione, consentendo all'API di autenticare il chiamante.
refresh_token Non usata dalle identità gestite per risorse di Azure.
expires_in Numero di secondi per cui il token di accesso continua a essere valido, prima della scadenza, dal momento del rilascio. L'ora del rilascio è indicata nell'attestazione iat del token.
expires_on Intervallo di tempo in cui il token di accesso scade. La data è rappresentata come numero di secondi da "1970-01-01T0:0:0Z UTC" (corrisponde all'attestazione exp del token).
not_before Intervallo di tempo in cui il token di accesso è valido e può essere accettato. La data è rappresentata come numero di secondi da "1970-01-01T0:0:0Z UTC" (corrisponde all'attestazione nbf del token).
resource Risorsa per cui è stato richiesto il token di accesso, che corrisponde al parametro della stringa di query resource della richiesta.
token_type Tipo di token, ovvero un token di accesso di connessione, che indica che la risorsa può concedere l'accesso al titolare del token.

Ottenere un token usando la libreria client di identità di Azure

L'uso della libreria client di identità di Azure è il modo consigliato per usare le identità gestite. Tutti gli SDK di Azure sono integrati con la Azure.Identity libreria che fornisce supporto per DefaultAzureCredential. Questa classe semplifica l'uso di identità gestite con Gli SDK di Azure.Ulteriori informazioni

  1. Installare il pacchetto Azure.Identity e altri pacchetti di libreria di Azure SDK necessari, ad esempio Azure.Security.KeyVault.Secrets.

  2. Usare il codice di esempio seguente. Non è necessario preoccuparsi di ottenere i token. È possibile usare direttamente i client Azure SDK. Il codice è per illustrare come ottenere il token, se necessario.

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

Ottenere un token usando la libreria Microsoft.Azure.Services.AppAuthentication per .NET

Per le funzioni e le applicazioni .NET, il modo più semplice per usare le identità gestite per risorse di Azure è tramite il pacchetto Microsoft.Azure.Services.AppAuthentication. Questa libreria consentirà anche di testare il codice in locale nel computer di sviluppo. È possibile testare il codice usando l'account utente di Visual Studio, l'interfaccia della riga di comando di Azure o l'autenticazione integrata di Active Directory. Per altre informazioni sulle opzioni di sviluppo locale con questa libreria, vedere la documentazione di riferimento della libreria Microsoft.Azure.Services.AppAuthentication. In questa sezione viene illustrato come muovere i primi passi con la libreria nel codice.

  1. Aggiungere un riferimento ai pacchetti NuGet Microsoft.Azure.Services.AppAuthentication e Microsoft.Azure.KeyVault all'applicazione.

  2. Aggiungere il codice seguente all'applicazione:

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

Per altre informazioni su Microsoft.Azure.Services.AppAuthentication e sulle relative operazioni esposte, vedere la documentazione di riferimento su Microsoft.Azure.Services.AppAuthentication e l'esempio .NET del Servizio app di Azure e dell'insieme di credenziali delle chiavi con le identità gestite per risorse di Azure.

Ottenere un token tramite 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");
}

Ottenere un token tramite Java

Usare questa libreria JSON per recuperare un 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;
                }
            }
        }
    }
}

Ottenere un token tramite 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)
}

Ottenere un token con PowerShell

L'esempio seguente illustra come usare l'endpoint REST delle identità gestite per risorse di Azure da un client PowerShell per:

  1. Acquisire un token di accesso.
  2. Usare il token di accesso per chiamare un'API REST di Azure Resource Manager e ottenere informazioni sulla macchina virtuale. Assicurarsi di sostituire l'ID di sottoscrizione, il nome del gruppo di risorse e il nome della macchina virtuale, rispettivamente, per <SUBSCRIPTION-ID>, <RESOURCE-GROUP>, e <VM-NAME>.
Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' -Headers @{Metadata="true"}

Esempio di come analizzare il token di accesso dalla risposta:

# 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

Ottenere un token tramite 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

Esempio di come analizzare il token di accesso dalla risposta:

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

Memorizzazione del token nella cache

Il sottosistema delle identità gestite memorizza nella cache i token, ma è comunque consigliabile implementare la memorizzazione nella cache dei token nel codice. È necessario prepararsi per gli scenari in cui la risorsa indica che il token è scaduto.

Le chiamate in transito a Microsoft Entra ID vengono restituite solo quando:

  • Si verifica il mancato riscontro nella cache a causa dell'assenza di token nella cache del sottosistema delle identità gestite per le risorse di Azure.
  • Il token memorizzato nella cache è scaduto.

Gestione degli errori

L'endpoint delle identità gestite segnala errori tramite il campo del codice di stato dell'intestazione del messaggio di risposta HTTP, come errori 4xx o 5xx:

Codice di stato Motivo dell'errore Come gestirlo
404 - Non trovato. L'endpoint IMDS è in fase di aggiornamento. Riprovare con il backoff esponenziale. Seguire le indicazioni riportate di seguito.
410 IMDS sta passando attraverso gli aggiornamenti IMDS sarà disponibile entro 70 secondi
429 - Numero eccessivo di richieste. È stato raggiunto il limite del servizio metadati dell'istanza. Riprovare con il backoff esponenziale. Seguire le indicazioni riportate di seguito.
Errore 4xx nella richiesta. Uno o più dei parametri della richiesta non sono corretti. Non riprovare. Esaminare i dettagli dell'errore per maggiori informazioni. Errori 4xx in fase di progettazione.
Errore temporaneo 5xx dal servizio. Le identità gestite per il sottosistema delle risorse di Azure o l'ID Microsoft Entra hanno restituito un errore temporaneo. È possibile riprovare dopo aver aspettato almeno 1 secondo. Se si ritenta troppo rapidamente o troppo spesso, IMDS e/o Microsoft Entra ID può restituire un errore di limite di frequenza (429).
timeout L'endpoint IMDS è in fase di aggiornamento. Riprovare con il backoff esponenziale. Seguire le indicazioni riportate di seguito.

Se si verifica un errore, il corpo della risposta HTTP corrispondente contiene dati JSON con i dettagli dell'errore:

Elemento Descrizione
error Identificatore dell'errore.
error_description Descrizione dettagliata dell'errore. Le descrizioni degli errori possono cambiare in qualsiasi momento: non scrivere codice che crei rami in base ai valori contenuti nella descrizione dell'errore.

Riferimenti per la risposta HTTP

Questa sezione illustra le possibili risposte di errore. Uno stato di tipo "200 OK" costituisce una risposta con esito positivo e il token di accesso è contenuto nei dati JSON del corpo della risposta, nell'elemento access_token.

Codice di stato Errore Descrizione dell'errore Soluzione
400 Richiesta non valida invalid_resource AADSTS50001: l'applicazione denominata <URI> non è stata trovata nel tenant denominato <TENANT-ID.> Questo messaggio indica se l'amministratore del tenant non ha installato l'applicazione o nessun utente tenant ha acconsentito. È possibile che la richiesta di autenticazione sia stata inviata al tenant sbagliato.\ (Solo Linux)
400 Richiesta non valida bad_request_102 L'intestazione dei metadati richiesta non è stata specificata. Il campo di intestazione della richiesta Metadata non è presente nella richiesta oppure non è formattato correttamente. Il valore deve essere specificato come true, usando tutte lettere minuscole. Per un esempio, vedere "Richiesta di esempio" nella sezione REST precedente.
401 - Non autorizzato unknown_source Origine sconosciuta <URI> Verificare che l'URI della richiesta HTTP GET sia formattato correttamente. La parte scheme:host/resource-path deve essere specificata come http://localhost:50342/oauth2/token. Per un esempio, vedere "Richiesta di esempio" nella sezione REST precedente.
invalid_request Nella richiesta manca un parametro obbligatorio oppure la richiesta include un valore di parametro non valido, contiene uno stesso parametro più volte o non è formata in modo corretto.
unauthorized_client Il client non è autorizzato a richiedere un token di accesso usando questo metodo. Causato da una richiesta in una macchina virtuale che non dispone di identità gestite per le risorse di Azure configurate correttamente. Per informazioni sulla configurazione della macchina virtuale, vedere Configurare le identità gestite per le risorse di Azure in una macchina virtuale tramite il portale di Azure.
access_denied Il proprietario della risorsa o il server di autorizzazione ha rifiutato la richiesta.
unsupported_response_type Il server di autorizzazione non supporta l'acquisizione di un token di accesso tramite questo metodo.
invalid_scope L'ambito richiesto non è valido, è sconosciuto o ha un formato non valido.
500 - Errore interno del server Sconosciuto Impossibile recuperare il token da Active Directory. Per informazioni dettagliate, vedere i log in <percorso del file> Verificare che la macchina virtuale abbia identità gestite per le risorse di Azure abilitate. Per informazioni sulla configurazione della macchina virtuale, vedere Configurare le identità gestite per le risorse di Azure in una macchina virtuale tramite il portale di Azure.

Verificare anche che l'URI della richiesta HTTP GET sia formattato correttamente, in particolare l'URI della risorsa specificato nella stringa di query. Vedere la "richiesta di esempio" nella sezione REST precedente per un esempio o i servizi di Azure che supportano l'autenticazione di Microsoft Entra per un elenco di servizi e i rispettivi ID risorsa.

Importante

  • IMDS non è progettato per essere usato dietro un proxy e in questo modo non è supportato. Per esempi di come ignorare i proxy, vedere Esempi di metadati dell'istanza di Azure.

Indicazioni per nuovi tentativi

È consigliabile riprovare se si riceve un codice di errore 404, 429 o 5xx (vedere Gestione degli errori precedente). Se viene visualizzato un errore 410, indica che IMDS sta attraversando gli aggiornamenti e sarà disponibile in un massimo di 70 secondi.

I limiti di limitazione si applicano al numero di chiamate effettuate all'endpoint IMDS. Al superamento della soglia di limitazione delle richieste, l'endpoint IMDS limiterà eventuali altre richieste mentre la limitazione è attiva. Durante questo periodo, l'endpoint IMDS restituisce il codice di stato HTTP 429 ("Troppe richieste") e le richieste hanno esito negativo.

Per eseguire nuovi tentativi è consigliabile seguire la strategia seguente:

Strategia di ripetizione dei tentativi Impostazioni Valori Funzionamento
ExponentialBackoff Conteggio tentativi
Interruzione temporanea minima
Interruzione temporanea massima
Interruzione temporanea delta
Primo tentativo rapido
5
0 secondi
60 secondi
2 secondi
false
Tentativo di 1 - intervallo di 0 sec
Tentativo 2 - intervallo di ~2 sec
Tentativo 3 - intervallo di ~6 sec
Tentativo 4 - intervallo di ~14 sec
Tentativo 5 - intervallo di 30 sec

ID di risorsa per servizi di Azure

Vedere Servizi di Azure con supporto delle identità gestite per un elenco di risorse che supportano le identità gestite per le risorse di Azure.

Passaggi successivi