Open2

Managed Identity から取得したトークンでアプリケーションの認証をしてみる

Tsubasa NomuraTsubasa Nomura

トークンの取得方法と含まれるクレーム

Managed Identity を有効にした VM 上で以下のコマンドを実行するとトークンを取得できる。

curl "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=api%3A%2F%2Fbd239da0-3acf-424c-95f8-41518d3a3079" -H "Metadata:true"

上記の例のようにresource に指定できるリソースは、Azure のサービスだけでなく、ME-ID のアプリ登録したアプリの ID も指定できる。

つまり、エンタープライズ アプリケーションで登録されているアプリの識別子 URIをリソースとして指定できる。

ただし、リソースの種類によって、トークンに含まれるクレームが異なる。特に、Managed Identity が割り当てられたリソースの識別子であるxms_miridは、含まれるリソースの種類、含まれないリソースの種類がある。

以下は、resourceに、https://appservice.azure.com を指定した時のトークンをデコードした例。

{
  "aud": "https://appservice.azure.com",
  "iss": "https://sts.windows.net/<tenant id>/",
  "iat": 1699635590,
  "nbf": 1699635590,
  "exp": 1699722290,
  "aio": "E2VgYGh6ssKNcXFN/Pv5qdNuzRedCQA=",
  "appid": "d090b38d-59ff-4c47-b759-f70024c19814",
  "appidacr": "2",
  "idp": "https://sts.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47/",
  "oid": "c7c89e9a-a179-47b2-9273-f57c5dcaed96",
  "rh": "0.ARoAv4j5cvGGr0GRqy180BHbR3wK-qu2pjZHgxBYVVCHh80aAAA.",
  "sub": "c7c89e9a-a179-47b2-9273-f57c5dcaed96",
  "tid": "<tenant id>",
  "uti": "Bw88HDIcC0CsuhhwGMg4AA",
  "ver": "1.0",
  "xms_mirid": "/subscriptions/<subscription id>/resourcegroups/rg-mgidtest-1110/providers/Microsoft.Compute/virtualMachines/vmjumpbox"
}

一方で、以下はアプリケーション登録したリソースを指定した場合のデコード結果。xms_mirid が含まれていない。

{
  "aud": "api://bd239da0-3acf-424c-95f8-41518d3a3079",
  "iss": "https://sts.windows.net/<tenant id>",
  "iat": 1699633115,
  "nbf": 1699633115,
  "exp": 1699719815,
  "aio": "E2VgYDiXeaVQ7VSKj1V61bZphy7VAwA=",
  "appid": "d090b38d-59ff-4c47-b759-f70024c19814",
  "appidacr": "2",
  "idp": "https://sts.windows.net/<tenant id>/",
  "oid": "c7c89e9a-a179-47b2-9273-f57c5dcaed96",
  "rh": "0.ARoAv4j5cvGGr0GRqy180BHbR6CdI73POkxClfhBUY06MHkaAAA.",
  "sub": "c7c89e9a-a179-47b2-9273-f57c5dcaed96",
  "tid": "72f988bf-86f1-41af-91ab-2d7cd011db47",
  "uti": "Bw88HDIcC0CsuhhwfYs3AA",
  "ver": "1.0"
}

xms_mirid が含まれないとアクセス元を特定できないため、アプリケーションの検証が出来ない。

トークンを検証するコード

from jose import jwt
from jose.exceptions import JWTError
import requests

def get_azure_ad_public_keys(tenant_id):
    url = f"https://login.microsoftonline.com/{tenant_id}/discovery/v2.0/keys"
    response = requests.get(url)
    return response.json()['keys']

def validate_token(token, azure_ad_public_keys, audience, issuer):
    try:
        # トークンのデコードと検証
        decoded_token = jwt.decode(
            token,
            azure_ad_public_keys,
            algorithms=['RS256'],
            audience=audience,
            issuer=issuer,
            options={"verify_exp": True}
        )
        return decoded_token
    except JWTError as e:
        print(f"トークン検証エラー: {e}")
        return None

# Azure AD テナント ID とトークン
tenant_id = "<tenant id>"
token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6~~~~~~~~~~~~~~"

# Azure AD の公開鍵を取得
azure_ad_public_keys = get_azure_ad_public_keys(tenant_id)

# アプリケーションの Audience と Issuer
audience = "https://appservice.azure.com"
issuer = f"https://sts.windows.net/{tenant_id}/"

# トークンの検証
validated_token = validate_token(token, azure_ad_public_keys, audience, issuer)
print(validated_token)
if validated_token:
    print("トークンは有効です")
else:
    print("トークンは無効です")

実行結果:

tsunomur@vmjumpbox:~$ python3 validate.py
{'aud': 'https://appservice.azure.com', 'iss': 'https://sts.windows.net/<tenant id>/', 'iat': 1699635590, 'nbf': 1699635590, 'exp': 1699722290, 'aio': 'E2VgYGh6ssKNcXFN/Pv5qdNuzRedCQA=', 'appid': 'd090b38d-59ff-4c47-b759-f70024c19814', 'appidacr': '2', 'idp': 'https://sts.windows.net/<tenant id>/', 'oid': 'c7c89e9a-a179-47b2-9273-f57c5dcaed96', 'rh': '0.ARoAv4j5cvGGr0GRqy180BHbR3wK-qu2pjZHgxBYVVCHh80aAAA.', 'sub': 'c7c89e9a-a179-47b2-9273-f57c5dcaed96', 'tid': '<tenant id>', 'uti': 'Bw88HDIcC0CsuhhwGMg4AA', 'ver': '1.0', 'xms_mirid': '/subscriptions/<subscription id>/resourcegroups/rg-mgidtest-1110/providers/Microsoft.Compute/virtualMachines/vmjumpbox'}
トークンは有効です