🏗️

AKSでWorkload Identityの設定と動作確認をする方法 (KeyVault編)

2025/01/13に公開

はじめに

Azure Kubernetes ServiceのPodに対して、Azureリソースへのアクセスに使用するマネージドIDを割り当てる方法は、現在はWorkload Identity(ワークロードID)が推奨されています。

Workload Identityを使用するAKSクラスターを構築した時、アプリケーションをデプロイする前にPodからSQL DatabaseやKeyVaultなどのAzure PaaSへの接続経路やマネージドIDによる認証が正しく構成できているかの確認を行いたいケースがあります。
今回はAKSでWorkload Identotyを設定しながら、正しく構成できているかの動作確認を行う方法をまとめてみました。

PoC環境の構成

こちらの手順をベースにAKSクラスターを展開します。
PodからWorkload IdentityでアクセスするAzure PaaSとしてKeyVaultも展開していきます。

PoC環境の準備

手元にクラスターがあるよという方はスキップして読み替えてください。

Azure CLIで使用する環境変数の設定

Azure CLIでAKSクラスターやWorkload Identityの設定を行なっていきます。
作成するリソース名などを環境変数に設定するので、必要に応じて書き換えてください。

export LOCATION="westus"
export RESOURCE_GROUP_NAME="azpoc-aks-usw-rg"
export AKS_CLUSTER_NAME="azpoc-aks-usw-aks"
export MANAGED_IDENTITY_NAME="azpoc-aks-usw-mi-wi"
export SERVICE_ACCOUNT_NAMESPACE="default"
export SERVICE_ACCOUNT_NAME="azpoc-aks-usw-mi-wi"
export KEYVAULT_NAME="azpoc-aks-usw-vault"
export KEYVAULT_SECRET_NAME="secret01"

AKSクラスターの準備

リソースグループの作成

今回の構成一式を格納するリソースグループを作ります。
不要になったらリソースグループごと削除すればOKです。

az group create \
    --name "${RESOURCE_GROUP_NAME}" \
    --location "${LOCATION}"

AKSクラスターの展開

--enable-oidc-issuer--enable-workload-identityオプションを指定し、OIDC IssuerとWorkload Identityを有効化したAKSクラスターを展開します。

az aks create \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --name "${AKS_CLUSTER_NAME}" \
    --enable-oidc-issuer \
    --enable-workload-identity \
    --generate-ssh-keys

AKSクラスターへログイン

kubectlコマンドでAKSクラスターに接続するための認証情報を取得します。

az aks get-credentials \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --name "${AKS_CLUSTER_NAME}"

kubectlは以下コマンドでインストールできます。

az aks install-cli

kubectlでクラスター情報が表示できることを確認しておきます。

kubectl cluster-info

Workload Identityの設定

PodがAzureリソースへのアクセスに使用するマネージドIDを作成し、サービスアカウントの登録とフェデレーションID資格情報の設定を行います。

マネージドIDの作成

Workload Identityで使用するマネージドIDを作成します。
このマネージドIDを使ってKeyVaultにアクセスします。

az identity create \
    --name "${MANAGED_IDENTITY_NAME}" \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --location "${LOCATION}"

ServiceAccountの作成

先ほど作成したマネージドIDのクライアントIDを取得しおきます。

export APPLICATION_CLIENT_ID=$(az identity show \
    --name "${MANAGED_IDENTITY_NAME}" \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --query "clientId" --output tsv)

サービスアカウントのマニュフェストをデプロイします。
作成したマネージドIDのクライアントIDをannotationsで指定しています。

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    azure.workload.identity/client-id: ${APPLICATION_CLIENT_ID}
  name: "${SERVICE_ACCOUNT_NAME}"
  namespace: "${SERVICE_ACCOUNT_NAMESPACE}"
EOF

フェデレーションID資格情報の設定

AKSクラスターのOIDC Issuer Endpoint URLを取得しておきます。

export AKS_OIDC_ISSUER="$(az aks show \
    --name "${AKS_CLUSTER_NAME}" \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --query "oidcIssuerProfile.issuerUrl" \
    --output tsv)"

Workload Identityで使用するマネージドIDにフェデレーションID資格情報を設定します。

az identity federated-credential create \
    --name fed-identity \
    --identity-name "${MANAGED_IDENTITY_NAME}" \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --issuer "${AKS_OIDC_ISSUER}" \
    --subject system:serviceaccount:"${SERVICE_ACCOUNT_NAMESPACE}":"${SERVICE_ACCOUNT_NAME}" \
    --audience api://AzureADTokenExchange

これでWorkload Identityを使うための事前設定が完了です。

KeyVaultの準備

KeyVaultの作成

PodからアクセスさせるKeyVaultを作成します。

az keyvault create \
    --name "${KEYVAULT_NAME}" \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --location "${LOCATION}" \
    --enable-rbac-authorization

KeyVaultのアクセス権設定

作成したKeyVaultのリソースIDを取得しておきます。

export KEYVAULT_RESOURCE_ID=$(az keyvault show \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --name "${KEYVAULT_NAME}" \
    --query id \
    --output tsv)

自分のEntraオブジェクトIDを取得しておきます。

export CURRENT_USER_OBJECT_ID=$(az ad signed-in-user show --query id --output tsv)

KeyVaultのシークレット作成ができるようにキー コンテナー シークレット責任者ロールを自分に割り当てておきます。

az role assignment create \
    --assignee "${CURRENT_USER_OBJECT_ID}" \
    --role "Key Vault Secrets Officer" \
    --scope "${KEYVAULT_RESOURCE_ID}"

Workload Identityで使用するマネージドIDのオブジェクトIDを取得しおきます。

export APPLICATION_OBJECT_ID=$(az identity show \
    --name "${MANAGED_IDENTITY_NAME}" \
    --resource-group "${RESOURCE_GROUP_NAME}" \
    --query "principalId" \
    --output tsv)

KeyVaultのシークレットをPodから参照できるようにマネージドIDへキー コンテナー シークレット ユーザーロールを割り当てておきます。

az role assignment create \
    --assignee-object-id "${APPLICATION_OBJECT_ID}" \
    --role "Key Vault Secrets User" \
    --scope "${KEYVAULT_RESOURCE_ID}" \
    --assignee-principal-type ServicePrincipal

KeyVaultのシークレット登録

Podが参照するシークレットををKeyVaultに登録しておきます。

az keyvault secret set \
    --vault-name "${KEYVAULT_NAME}" \
    --name "${KEYVAULT_SECRET_NAME}" \
    --value "Hello\!"

Workload Identityの動作確認

動作確認用Podの準備

Microsoft Container Registry (MCR)はAzure FirewallのFQDNタグに含まれているので、使い勝手の良いMCRのAzure PowerShellコンテナイメージで動作確認を行います。

Azure CLIで使用する環境変数の設定

PoC環境の準備の手順でAKSクラスターを立てた方はそのままコピペしてください。ご自身の環境をがある方は適宜打ち替えてください。

export SERVICE_ACCOUNT_NAMESPACE="default"
export SERVICE_ACCOUNT_NAME="azpoc-aks-usw-mi-wi"

Workload Identityを使用するPodをデプロイ

このPodでWorkload Identityを使用するので、azure.workload.identity/use: "true"ラベルを記述し、spec\serviceAccountNameでマネージドIDを紐づけたサービスアカウントを指定しておきます。

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: powershell
  namespace: ${SERVICE_ACCOUNT_NAMESPACE}
  labels:
    azure.workload.identity/use: "true"
spec:
  serviceAccountName: ${SERVICE_ACCOUNT_NAME}
  containers:
    - image: mcr.microsoft.com/azure-powershell:latest
      name: powershell
      command: ["sleep", "infinity"] 
EOF

Podに接続

ここから先はPodの内部でコマンドを実行するので、Podのシェルに接続します。
初回はコンテナイメージのPullが実行されるので、Podが起動するまで数分かかることがあります。

kubectl exec -it powershell -- /bin/bash

Podの環境変数確認

Workload Identityを使用するPodでは、以下の環境変数が展開されます。

環境変数 説明
AZURE_AUTHORITY_HOST Microsoft Entra IDエンドポイント
https://login.microsoftonline.com/
このエンドポイントに対してAzureリソースアクセス用のアクセストークンを要求する。
AZURE_FEDERATED_TOKEN_FILE サービスアカウントのトークンファイルのパス。
/var/run/secrets/azure/tokens/azure-identity-token
このサービスアカウントトークンを添えてMicrosoft Entra IDエンドポイントにAzureリソースアクセス用のアクセストークンを要求すると、Microsoft Entra IDはAKSのOIDC Issuerでサービスアカウントトークンを検証し、Azureリソースアクセスに使用するアクセストークンを発行する。
AZURE_TENANT_ID マネージドIDが登録されているEntraのテナントID
AZURE_CLIENT_ID マネージドIDのクライアントID

Podに展開されている環境変数も確認してみます。

env | grep AZURE_

KeyVaultへ接続してみる

アクセストークンを発行し、KeyVaultのシークレット値を参照してみます。
冒頭の構成図に記載している①〜④のフローでアクセストークンを発行し、Azureリソースにアクセスします。

①Azureリソースアクセス用のアクセストークンを要求
 サービスアカウントトークン(AZURE_FEDERATED_TOKEN_FILE)を添えて
 Microsoft Entra IDエンドポイント(AZURE_AUTHORITY_HOST)に
 Azureリソースアクセス用のアクセストークンを要求します。
②サービスアカウントのトークンを検証
 Microsoft Entra IDはAKSのOIDC Issuerでサービスアカウントトークンを検証します。
③Azureリソースアクセス用のアクセストークンを発行
 サービスアカウントトークンの検証に成功したら、
 Microsoft Entra IDはAzureリソースアクセスに使用するアクセストークンを発行します。
④アクセストークンでAzureリソースにアクセス
 Podのアプリケーションはアクセストークンを用いてAzureリソースにアクセスします。

PodでPowerShellを実行

アクセストークンの発行とKeyVaultのシークレット取得はREST APIで行います。
APIへのHTTPリクエストの送信には、今回はPowerShellのInvoke-webRequestコマンドを使用するので、pwshコマンドでPowerShellを実行します。

pwsh

アクセストークンを発行する

Microsoft Entra IDエンドポイントに対してAzureリソースアクセス用のアクセストークンを要求します。
scopeはhttps://vault.azure.net/.defaultを指定します。
発行されたアクセストークンを$AccessTokenに格納しておきます。

$scope="https://vault.azure.net/.default"
$jwt=$(cat ${Env:AZURE_FEDERATED_TOKEN_FILE})

$AccessToken=( `
    Invoke-webRequest `
    -Method "POST" `
    -Body "scope=$scope&grant_type=client_credentials&client_id=${Env:AZURE_CLIENT_ID}&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion=$jwt" `
    "https://login.microsoftonline.com/${Env:AZURE_TENANT_ID}/oauth2/v2.0/token" `
    | ConvertFrom-Json).access_token

アクセストークンを用いてKey Vaultへ接続する

PowerShellにもKeyVault名とシークレット名を環境変数で設定しておきます。

$Env:KEYVAULT_NAME="azpoc-aks-usw-vault"
$Env:KEYVAULT_SECRET_NAME="secret01"

発行されたアクセストークンを使用してKeyVaultのシークレット値を参照することができます。

(Invoke-webRequest `
    -Headers @{Authorization="Bearer $AccessToken"} `
    "https://${Env:KEYVAULT_NAME}.vault.azure.net/secrets/${Env:KEYVAULT_SECRET_NAME}?api-version=2016-10-01" `
    | ConvertFrom-Json).value

最後に

AKSクラスターでWorkload Identityを構成し、PowerShellのみでアクセストークンの発行と動作確認を試してみました。
REST APIをコールすればアクセストークンを発行でき、アプリケーションデプロイしなくてもAKSクラスター構築時のAzure PaaSへの接続確認・RBACの認証確認ができるので、構築作業時の動作確認に便利そうです。

参考

Discussion