Azure VM 上で Azure リソースのマネージド ID を使用してアクセス トークンを取得する方法

Azure リソース用マネージド ID は、Microsoft Entra ID の機能です。 Azure リソースのマネージド ID をサポートする各 Azure サービスは、それぞれ固有のタイムラインの下で提供されます。 ご利用のリソースに対するマネージド ID の提供状態と既知の問題をあらかじめ確認しておいてください。

Azure リソースのマネージド ID は、Microsoft Entra ID で自動的に管理される ID を Azure サービスに提供します。 この ID を使用すると、コード内に資格情報を記述することなく、Microsoft Entra の認証をサポートする任意のサービスに対して認証を行うことができます。

この記事では、トークンの取得に使用する各種コードとスクリプトの例を提供します。 また、トークンの有効期限や HTTP エラーの処理についてのガイダンスも提供します。

前提条件

  • Azure リソースのマネージド ID 機能に慣れていない場合は、こちらの概要を参照してください。 Azure アカウントをお持ちでない場合は、無料のアカウントにサインアップしてから先に進んでください。

この記事の Azure PowerShell の例を使用する場合は、Azure PowerShell の最新バージョンをインストールする必要があります。

重要

  • この記事のすべてのサンプル コード/スクリプトは、Azure リソースのマネージド ID を使用する仮想マシン上でクライアントが実行されていることを前提としています。 お使いの VM にリモート接続するには、Azure portal で仮想マシンへの "接続" 機能を使用します。 VM で Azure リソースのマネージド ID を有効にする方法の詳細については、「Azure Portal を使用して VM 上に Azure リソースのマネージド ID を構成する」、または関連する記事 (PowerShell、CLI、テンプレート、または Azure SDK の使用) のいずれかを参照してください。

重要

  • Azure リソース用マネージド ID のセキュリティ境界は、ID が使われているリソースです。 仮想マシン上で実行されるすべてのコード/スクリプトは、そこで使用できる任意のマネージド ID のトークンを要求して取得できます。

概要

クライアント アプリケーションは、特定のリソースにアクセスするために、マネージド ID のアプリ専用アクセス トークンを要求できます。 トークンは、Azure リソース サービス プリンシパルのマネージド ID に基づいています。 そのため、クライアントが、独自のサービス プリンシパルでアクセス トークンを取得する必要はありません。 トークンは、クライアント資格情報を必要とするサービス間の呼び出しのベアラー トークンとしての使用に適しています。

Link 説明
HTTP を使用してトークンを取得する Azure リソース トークン エンドポイントのマネージド ID に関するプロトコルの詳細
Azure.Identity を使用してトークンを取得する Azure.Identity ライブラリを使用してトークンを取得する
.NET 用の Microsoft.Azure.Services.AppAuthentication ライブラリを使用してトークンを取得する .NET クライアントからの Microsoft.Azure.Services.AppAuthentication ライブラリの使用例
C# を使用してトークンを取得する C# クライアントから Azure リソース REST エンドポイントのマネージド ID を使用する例
Java を使用してトークンを取得する Java クライアントから Azure リソース REST エンドポイントのマネージド ID を使用する例
Go を使用してトークンを取得する Go クライアントから Azure リソース REST エンドポイントのマネージド ID を使用する例
PowerShell を使用してトークンを取得する PowerShell クライアントから Azure リソース REST エンドポイントのマネージド ID を使用する例
CURL を使用してトークンを取得する Bash/CURL クライアントから Azure リソース REST エンドポイントのマネージド ID を使用する例
トークンのキャッシュの処理 有効期限が切れたアクセス トークンの処理に関するガイダンス
エラー処理 Azure リソース トークン エンドポイントのマネージド ID から返される HTTP エラーを処理するためのガイダンス
Azure サービスのリソース ID サポートされている Azure サービスのリソース ID を取得する場所

HTTP を使用してトークンを取得する

アクセス トークンの取得に使用する基本的なインターフェイスは REST に基づいているため、HTTP REST の呼び出しを行える VM 上で実行されている、すべてのクライアント アプリケーションにアクセスできます。 この方法は、クライアントが仮想マシン上のエンドポイントを使用する点以外は、Microsoft Entra のプログラミング モデルと同じです (Microsoft Entra のプログラミング モデルでは、Microsoft Entra エンドポイントを使用)。

Azure Instance Metadata Service (IMDS) エンドポイントを使用するサンプル要求 (推奨) :

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
要素 説明
GET HTTP 動詞。エンドポイントからデータを取得する必要があることを示します。 この例では、OAuth アクセス トークンです。
http://169.254.169.254/metadata/identity/oauth2/token Instance Metadata Service 用の Azure リソース エンドポイントのマネージド ID。
api-version クエリ文字列パラメーター。IMDS エンドポイントの API バージョンです。 API バージョン 2018-02-01 以上を使用してください。
resource クエリ文字列パラメーター。ターゲット リソースのアプリ ID URI です。 発行されたトークンの aud (audience) 要求にも表示されます。 この例では、アプリ ID URI が https://management.azure.com/ の Azure Resource Manager にアクセスするためのトークンを要求しています。
Metadata マネージド ID に必要な HTTP 要求ヘッダー フィールド。 この情報は、サーバー側のリクエスト フォージェリ (SSRF) 攻撃に対する軽減策として使用されます。 この値は、"true" に設定し、すべて小文字にする必要があります。
object_id (省略可能) クエリの文字列パラメーター。トークン用の管理対象 ID の object_id を示します。 VM に複数のユーザーが割り当てたマネージド ID がある場合は必須です。
client_id (省略可能) クエリの文字列パラメーター。トークン用の管理対象 ID の client_id を示します。 VM に複数のユーザーが割り当てたマネージド ID がある場合は必須です。
msi_res_id (省略可能) クエリの文字列パラメーター。トークン用の管理対象 ID の msi_res_id (Azure リソース ID) を示します。 VM に複数のユーザーが割り当てたマネージド ID がある場合は必須です。

応答のサンプル:

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"
}
要素 説明
access_token 要求されたアクセス トークン。 セキュリティで保護された REST API を呼び出すとき、トークンは Authorization 要求ヘッダー フィールドに "ベアラー" トークンとして埋め込まれ、API が呼び出し元を認証できるようにします。
refresh_token Azure リソースのマネージド ID には使用されません。
expires_in アクセス トークンが発行されてから期限切れになるまでの有効継続時間 (秒単位)。 発行時刻はトークンの iat 要求で確認できます。
expires_on アクセス トークンが期限切れになるまでの期間。 日付は "1970-01-01T0:0:0Z UTC" からの秒数として表されます (トークンの exp 要求に対応)。
not_before アクセス トークンが有効になり、承認されるまでの期間。 日付は "1970-01-01T0:0:0Z UTC" からの秒数として表されます (トークンの nbf 要求に対応)。
resource アクセス トークンの要求対象リソース。要求の resource クエリ文字列パラメーターと一致します。
token_type トークンの種類。つまり "ベアラー" アクセス トークン。リソースが、このトークンのベアラーへのアクセスを提供できることを意味します。

Azure ID クライアント ライブラリを使用してトークンを取得する

マネージド ID を使用するには、Azure ID クライアント ライブラリを使用する方法をお勧めします。 すべての Azure SDK は、DefaultAzureCredential のサポートを提供する Azure.Identity ライブラリと統合されています。 このクラスを使用すると、Azure SDK でマネージド ID を簡単に使用できます。詳細については、こちらを参照してください。

  1. Azure.Identity パッケージと、Azure.Security.KeyVault.Secrets などの他の必要な Azure SDK ライブラリ パッケージをインストールします。

  2. 下のサンプル コードを使用します。 トークンの取得について心配する必要はありません。 Azure SDK クライアントを直接使用できます。 このコードは、必要に応じてトークンを取得する方法を示すものです。

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

.NET 用の Microsoft.Azure.Services.AppAuthentication ライブラリを使用してトークンを取得する

.NET アプリケーションと Functions の場合、Azure リソースのマネージド ID を使用する最も簡単な方法は、Microsoft.Azure.Services.AppAuthentication パッケージを利用することです。 このライブラリを使用すると、開発用コンピューターでコードをローカルでテストすることもできます。 Visual Studio、Azure CLI、または Active Directory 統合認証のユーザー アカウントを使って、自分のコードをテストすることができます。 このライブラリでのローカル開発オプションについて詳しくは、Microsoft.Azure.Services.AppAuthentication のリファレンスに関するページをご覧ください。 このセクションでは、コードでライブラリを使い始める方法を示します。

  1. Microsoft.Azure.Services.AppAuthentication および Microsoft.Azure.KeyVault NuGet パッケージに対する参照をアプリケーションに追加します。

  2. 次のコードをアプリケーションに追加します。

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

Microsoft.Azure.Services.AppAuthentication およびそれによって公開される操作の詳細については、Microsoft.Azure.Services.AppAuthentication リファレンスAzure リソースのマネージド ID を使用する App Service および KeyVault の .NET サンプルを参照してください。

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

Java を使用してトークンを取得する

Java を使用してトークンを取得するには、この JSON ライブラリを使用します。

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

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

PowerShell を使用してトークンを取得する

次の例では、PowerShell クライアントから Azure リソース REST エンドポイントのマネージド ID を使用して、以下を実行する方法を示します。

  1. アクセス トークンを取得します。
  2. アクセス トークンを使用して Azure Resource Manager の REST API を呼び出し、VM に関する情報を取得します。 <SUBSCRIPTION-ID><RESOURCE-GROUP>、および <VM-NAME> の代わりに、ご自分のサブスクリプション ID、リソース グループ名、および仮想マシン名をそれぞれ使用する必要があります。
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"}

応答からアクセス トークンを解析する方法の例を次に示します。

# 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

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

応答からアクセス トークンを解析する方法の例を次に示します。

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

トークンのキャッシュ

マネージド ID サブシステムによってトークンがキャッシュされますが、コードにトークン キャッシュを実装することをお勧めします。 リソースによってトークンの有効期限切れが示されるシナリオに備える必要があります。

ネットワークを介した Microsoft Entra ID の呼び出しは、次の場合にのみ行われます。

  • Azure リソース サブシステム キャッシュのマネージド ID にトークンがないためキャッシュ ミスが発生する。
  • キャッシュのトークンの有効期限が切れている。

エラー処理

マネージド ID エンドポイントは、HTTP 応答メッセージのヘッダーに含まれる状態コード フィールドを通じて、4xx エラーまたは 5xx エラーのいずれかとして、エラーを通知します。

状態コード エラーの理由 処理方法
404 見つかりません。 IMDS エンドポイントが更新されています。 指数バックオフを使用して再試行してください。 以下のガイダンスを参照してください。
410 IMDS は更新プログラムを実行しています IMDS は 70 秒以内に使用可能になります
429 要求が多すぎます。 IMDS スロットルの上限に達しました。 指数バックオフを使用して再試行してください。 以下のガイダンスを参照してください。
要求の 4xx エラーです。 1 つ以上の要求パラメーターが正しくありませんでした。 再試行しないでください。 詳しくは、エラーの詳細を確認します。 4xx エラーは、デザイン時のエラーです。
サービスからの 5xx の一時的なエラーです。 Azure リソース サブシステムまたは Microsoft Entra ID のマネージド ID から一時的なエラーが返されました。 少なくとも 1 秒間待機した後に、安全に再試行できます。 再試行が早すぎる場合や再試行の回数が多すぎる場合は、IMDS および Microsoft Entra ID からレート制限エラー (429) が返されることがあります。
タイムアウト IMDS エンドポイントが更新されています。 指数バックオフを使用して再試行してください。 以下のガイダンスを参照してください。

エラーが発生すると、対応する HTTP 応答本文に、JSON とエラーの詳細が含まれます。

要素 説明
error エラー識別子。
error_description エラーの詳細な説明。 エラーの説明は、予告なく変更になる場合があります。 エラーの説明に含まれる値に基づいて分岐するコードを作成しないでください。

HTTP 応答リファレンス

このセクションでは、想定されるエラー応答について説明します。 "200 OK" の状態は成功応答であり、access_token 要素内の応答本文の JSON にアクセス トークンが含まれています。

status code エラー エラーの説明 解決策
400 Bad Request invalid_resource AADSTS50001: <URI> という名前のアプリケーションが <TENANT-ID> という名前のテナントに見つかりませんでした。 このメッセージは、テナント管理者がアプリケーションをインストールしていない場合、またはテナント ユーザーが同意していない場合に表示されます。 間違ったテナントに認証要求を送信した可能性があります。\ (Linux のみ)
400 Bad Request bad_request_102 必要なメタデータ ヘッダーが指定されていません 要求で Metadata 要求ヘッダー フィールドが見つからないか、形式が正しくありません。 値は true として指定し、すべて小文字にする必要があります。 例については、上記の「REST」セクションの「要求のサンプル」を参照してください。
401 権限がありません unknown_source 不明なソース <URI> HTTP GET 要求の URI の形式が正しいことを確認します。 scheme:host/resource-path 部分は、http://localhost:50342/oauth2/token として指定する必要があります。 例については、上記の「REST」セクションの「要求のサンプル」を参照してください。
invalid_request 要求に必要なパラメーターが含まれていないか、要求に無効なパラメーター値が含まれているか、要求に複数回パラメーターが含まれているか、要求の形式が正しくないかのいずれかです。
unauthorized_client クライアントには、このメソッドを使用してアクセス トークンを要求する権限がありません。 Azure リソースのマネージド ID が正しく構成されていない VM での要求が原因です。 VM の構成についてサポートが必要な場合は、「Azure portal を使用して VM 上に Azure リソースのマネージド ID を構成する」を参照してください。
access_denied リソース所有者または承認サーバーによって、要求が拒否されました。
unsupported_response_type このメソッドを使用したアクセス トークンの取得は、承認サーバーによってサポートされていません。
invalid_scope 要求されたスコープが無効、不明、または形式が正しくありません。
500 内部サーバー エラー unknown Active Directory からのトークンの取得に失敗しました。 詳細については、<file path> のログを参照してください VM で、Azure リソースのマネージド ID が有効になっていることを確認します。 VM の構成についてサポートが必要な場合は、「Azure portal を使用して VM 上に Azure リソースのマネージド ID を構成する」を参照してください。

また、HTTP GET 要求の URI、特にクエリ文字列で指定されたリソース URI の形式が正しいかどうかを確認します。 例については、上記の「REST」セクションの「要求のサンプル」を参照してください。または、「Microsoft Entra 認証をサポートする Azure サービス」で、サービスの一覧と、そのリソース ID を参照してください。

重要

再試行のガイダンス

404、429、または 5xx のエラー コードが表示される場合、再試行することをお勧めします (前の 「エラー処理」を参照)。 410 エラーが表示された場合は、IMDS が更新中であり、最大 70 秒で使用可能になることを示しています。

スロットル制限は、IMDS エンドポイントに対して行われる呼び出し回数に適用されます。 スロットルのしきい値を超えた場合、IMDS エンドポイントは、スロットルが有効な状態にあっても、それ以降の要求を制限します。 この期間中、IMDS エンドポイントは HTTP 状態コード 429 ("要求が多すぎます") を返し、要求は失敗します。

再試行については、次の方法をお勧めします。

再試行戦略 設定 動作のしくみ
ExponentialBackoff 再試行回数
最小バックオフ
最大バックオフ
差分バックオフ
最初の高速再試行
5
0 秒
60 秒
2 秒
false
試行 1 - 0 秒の遅延
試行 2 - 最大 2 秒の遅延
試行 3 - 最大 6 秒の遅延
試行 4 - 最大 14 秒の遅延
試行 5 - 最大 30 秒の遅延

Azure サービスのリソース ID

Azure リソースのマネージド ID をサポートするリソースの一覧については、マネージド ID がサポートされている Azure サービスに関するページを参照してください。

次のステップ