💭

[Azure][AKS][ME-ID][Terraform] Microsoft Entra ワークロード ID を AKS で試してみた

2023/10/30に公開

はじめに

本記事では、Microsoft Entra ワークロード ID を Azure Kubernetes Service (AKS) で試してみるにあたり思ったことや、個人の理解をまとめています。

また、下記記事を参考により簡単に ワークロード ID を AKS を試せるようにするべく、環境を構築するための Terraform コードを載せております。

参考情報

https://learn.microsoft.com/ja-jp/azure/aks/workload-identity-deploy-cluster

対象読者

AKS ワークロード ID をお手元の Azure 環境で試してみたい方

コード

https://github.com/hebo4096/aks-workload-identity-inspection

こちらのリポジトリの README に記載している手順を実施していただくことにより、Azure CLI がインストールされた Pod にてワークロード ID が検証できます。

マネージド ID

ワークロード ID を構成するにあたり、マネージド ID (ユーザー割り当て) が必要となるため、マネージド ID の概要についても整理します。

マネージド ID のメリット

Azure には、マネージド ID と呼ばれる概念があります。
マネージド ID を使うと、Azure Key Vault などを用いてアプリケーションへのアクセスに必要となるシークレットを管理することなく、Azure によって管理された ID により、Azure 内のリソースへアクセスすることが可能になります。

VM のシステム割り当てマネージド ID

マネージド ID の一例として、Azure VM ではシステム割り当てマネージド ID があります。
VM にてシステム割り当てマネージド ID を有効化することにより、当該マネージド ID に割り当てた Azure RBAC ロールをもとに他の Azure リソースに対して、設定したロールのアクセス許可に基づきアクセスすることができます。

マネージド ID によるアクセス制御を実現するにあたり、VM 内の Instance Metadata Service (IMDS)※ のトークン エンドポイント (https://169.254.169.254/metadata/identity/oauth2/token) が使用されます。Azure リソースへアクセスするまでのフローは下記画像のとおりです。

※ IMDS は ローカル ネットワーク内に専用エンドポイント (169.254.169.254) を設け、VM の構成情報などを提供する仕組みです。もちろん、VM 内からのみアクセスできるエンドポイントとなります。

画像の引用元の参考情報

https://learn.microsoft.com/ja-jp/entra/identity/managed-identities-azure-resources/how-managed-identities-work-vm

VM のシステム割り当てマネージド ID では IMDS のトークン エンドポイントからアクセス トークンを取得し、そのアクセス トークンを用いて Azure リソースへアクセスします。
後述いたしますワークロード ID にて Azure リソースへアクセスするまでのフローとは異なる点に注意が必要となります。

AKS におけるワークロード ID の仕組みについて

ワークロード ID では、こちら にも記載がある通り、Pod が Azure リソースへアクセスする際に、以下のフローによりアクセス トークンを取得します。

① Microsoft Entra ID が AKS クラスタ専用に発行される OIDC Issuer URL にメタデータ (OpenID Discovery Document) を要求する
② Microsoft Entra ID が OIDC Issuer URL から Issuer のメタデータ (OpenID Discovery Document) を取得し、JWKS エンドポイントを抽出する
③ Microsoft Entra ID が OIDC Issuer の JWKS エンドポイントから公開署名キー (OpenID JWKS Document) を取得し、サービス アカウント トークンを検証する
③ サービス アカウント トークンの検証が成功したら、Pod に対してアクセス トークンを払い出す

上記のフローにてアクセス トークンが Pod に対して払い出されます。

VM のシステム割り当てマネージド ID との違い

VM のシステム割り当てマネージド ID ではローカルなエンドポイントにアクセスすることにより取得できましたが、ワークロード ID では公開された AKS 専用のエンドポイントから取得した公開署名キーによってサービス アカウント トークンの検証を行うことによりアクセス トークンが払い出されます。

https://learn.microsoft.com/ja-jp/azure/aks/workload-identity-overview?tabs=dotnet

Azure AD Pod Identity (Deprecated) と ワークロード ID の違いは?

従来までは Azure AD Pod Identity により Pod に対して Identity を付与していましたが、こちらは 2022 年に非推奨となっているようです。

https://learn.microsoft.com/ja-jp/azure/aks/use-azure-ad-pod-identity

Azure AD Pod Identity では専用の CRD (AzureIdentity/AzureIdentityBinding) をクラスタにインストールする必要がありましたが、ワークロード ID では、Kubernetes リソース (Pod/ServiceAccount) に特定の label や annotation を付与するだけで良いようです。

専用の CRD を廃止し、[ワークロード ID の仕組みについて] の節で説明した、ServiceAccount によるアクセス制御に合わせにいくためにワークロード ID に変わったのでしょうか。

Pod に設定される環境変数について

Pod に対してワークロード ID を付与するにあたり、下記の環境変数が Pod に対して設定されます。

AZURE_CLIENT_ID

ワークロード ID を付与する Pod 用に作成したユーザー割り当てマネージド ID の クライアント ID を環境変数として設定します。

AZURE_TENANT_ID

Pod が保持する サービス アカウント トークンの検証を行う Azure AD のテナント ID を環境変数として設定します。

AZURE_FEDERATED_TOKEN_FILE

volumeMount により、コンテナ内でマウントされるファイルパスが設定されます。
これがワークロード ID で用いられるサービス アカウント トークンの実体となります。

Azure VM では Instance MetaData Service (IMDS) のトークン エンドポイントよりアクセス トークンを取得しますが、ワークロード ID on AKS では、サービス アカウント トークンがファイルとしてマウントされており、さらにはトークンの検証が必要となるのが一つの特徴になるかと思います。

サインインの動作について

Azure VM のシステム割り当てマネージド ID では az login --identity にてマネージド ID の資格情報でサインインが可能ですが、ワークロード ID に対応したサインインオプションはまだ機能として用意されていないようです。(2023 年 10 月 27 日時点)

下記 Issue にて Feature Request があがっている模様...
https://github.com/Azure/azure-cli/issues/26858

上記の Feature Request にも記載がある通り、現在は下記コマンドにてサインインするのがよさそうです。

az login --federated-token { AZURE_FEDERATED_TOKEN_FILE のファイルパス内のトークン } --service-principal -u { AZURE_CLIENT_ID } -t { AZURE_TENANT_ID }

終わりに

ワークロード ID の仕組みについて個人的なメモをまとめてきました。
他のクラウドプロバイダに構築しているリソースとの ID フェデレーションについても調査してみたいなぁ...

おまけ:ワークロード ID のサービス アカウント トークンと ServiceAccount (Kubernetes リソース) によって払い出されるサービス アカウント トークンとの違い

サービス アカウント トークンは volumeMount により、ファイルとして Pod にマウントされます。
ServiceAccount (Kubernetes リソース) のサービス アカウント トークンはクラスタ内のリソースへアクセスするために用いられるトークンである一方、ワークロード ID では Kubernetes における独自のサービス アカウント トークンをファイルとして Pod にマウントします。
マウントしたファイルに記載されているサービス アカウント トークンを用いて Azure リソースへアクセスすることができます。

それぞれのトークンのマウント先は以下の通りです。

# ワークロード ID のサービス アカウント トークン
# refs -> https://azure.github.io/azure-workload-identity/docs/installation.html#azure-ad-workload-identity-components
/var/run/secrets/azure/tokens/azure-identity-token

# ServiceAccount (Kubernetes リソース) のサービス アカウント トークン
# refs -> https://kubernetes.io/docs/tasks/run-application/access-api-from-pod/
/run/secrets/kubernetes.io/serviceaccount/token

いずれのサービス アカウント トークンも JWT 形式なので、https://jwt.ms にてデコード可能です。

  • ワークロード ID のサービス アカウント トークンのデコード結果
{
  "aud": [
    "api://AzureADTokenExchange"
  ],
  "exp": 1698514527,
  "iat": 1698510927,
  "iss": "<AKS の公開 OIDC Issuer URL>",
  "kubernetes.io": {
    "namespace": "<リソースがデプロイされている namespace>",
    "pod": {
      "name": "<クラスタにデプロイされている Pod の名前>",
      "uid": "<クラスタにデプロイされている Pod の uid>"
    },
    "serviceaccount": {
      "name": "<クラスタにデプロイされている ServiceAccount の名前>",
      "uid": "<クラスタにデプロイされている ServiceAccount の uid>"
    }
  },
  "nbf": 1698510927,
  "sub": "system:serviceaccount:<リソースがデプロイされている namespace>:<クラスタにデプロイされている ServiceAccount の名前>"
}
  • ServiceAccount (Kubernetes リソース) のサービス アカウント トークンのデコード結果
{
  "aud": [
    "<AKS の公開 OIDC Issuer URL>",
    "https://<Kubernetes の API Server>",
    "\"<Kubernetes の API Server>\""
  ],
  "exp": 1730046927,
  "iat": 1698510927,
  "iss": "<AKS の公開 OIDC Issuer URL>",
  "kubernetes.io": {
    "namespace": "<リソースがデプロイされている namespace>",
    "pod": {
      "name": "<クラスタにデプロイされている Pod の名前>",
      "uid": "<クラスタにデプロイされている Pod の uid>"
    },
    "serviceaccount": {
      "name": "<クラスタにデプロイされている ServiceAccount の名前>",
      "uid": "<クラスタにデプロイされている ServiceAccount の uid>"
    },
    "warnafter": 1698514534
  },
  "nbf": 1698510927,
  "sub": "system:serviceaccount:<リソースがデプロイされている namespace>:<クラスタにデプロイされている ServiceAccount の名前>"
}

違いが aud クレームの値にしかないことが分かりました。

Discussion