Azure Kubernetes Service (AKS) クラスターにMicrosoft Entra ワークロード ID をデプロイして構成する

この記事では、Microsoft Entra ワークロード ID を使用してAzure Kubernetes Service (AKS) クラスターをデプロイおよび構成する方法について説明します。 この記事の手順は次のとおりです。

  • OpenID Connect (OIDC) 発行者と Microsoft Entra ワークロード ID を有効にして、Azure CLI または Terraform を使用し、新しい AKS クラスターを作成するか、既存の AKS クラスターを更新します。
  • ワークロード ID と Kubernetes サービス アカウントを作成します。
  • トークンのフェデレーション用にマネージド ID を構成する。
  • ワークロードをデプロイし、ワークロード ID を使用して認証を確認します。
  • 必要に応じて、クラスター内のポッドに、Azure キー コンテナー内のシークレットへのアクセス権を付与します。

前提条件

  • Azure アカウントがない場合は、開始する前に free アカウントを作成します。
  • この記事では、バージョン 2.47.0 以降のAzure CLIが必要です。 Azure Cloud Shellを使用している場合は、最新バージョンが既にインストールされています。 バージョンを確認するには、az --version を実行します。 インストールまたはアップグレードする必要がある場合は、「Install Azure CLIを参照してください。
  • クラスターの作成に使用している ID に、適切な最小限のアクセス許可が与えられていることを確認します。 詳細については、「Access と id オプションのAzure Kubernetes Service (AKS)を参照してください。
  • 複数のAzure サブスクリプションがある場合は、az account set コマンドを使用してリソースを課金する適切なサブスクリプション ID を選択します。
  • Terraform がローカルにインストールされている。 インストール手順については、「 Terraform のインストール」を参照してください。

一部の手順を自動的に構成するのに役立てるために、Service Connector を使用できます。 詳細については、「Tutorial: Microsoft Entra ワークロード ID を参照してください。

Terraform 構成ファイルを作成する

Terraform 構成ファイルは、Terraform が作成および管理するインフラストラクチャを定義します。

  1. main.tf という名前のファイルを作成し、次のコードを追加して Terraform バージョンを定義し、Azure プロバイダーを指定します。

    terraform {
     required_version = ">= 1.5.0"
     required_providers {
       azurerm = {
         source  = "hashicorp/azurerm"
         version = "~> 4.0"
       }
       kubernetes = {
         source  = "hashicorp/kubernetes"
         version = "~> 2.30"
       }
       random = {
         source  = "hashicorp/random"
         version = "~> 3.6"
       }
     }
    }
    provider "azurerm" {
     features {}
     subscription_id = var.subscription_id
    }
    data "azurerm_client_config" "current" {}
    
  2. 再利用可能な変数を定義し、すべてのリソースの一意の名前を生成するために、次のコードを main.tf に追加します。

    resource "random_string" "suffix" {
     length  = 6
     upper   = false
     special = false
     numeric = true
    }
    locals {
     suffix = random_string.suffix.result
     resource_group_name       = "rg-aks-wi-${local.suffix}"
     cluster_name              = "akswi${local.suffix}"
     managed_identity_name     = "uami-wi-${local.suffix}"
     federated_credential_name = "fic-wi-${local.suffix}"
     key_vault_name            = lower(substr("kvwi${local.suffix}", 0, 24))
     secret_name               = "secret-${local.suffix}"
     service_account_name      = "workload-sa-${local.suffix}"
     service_account_namespace = "default"
     workload_identity_subject = "system:serviceaccount:${local.service_account_namespace}:${local.service_account_name}"
    }
    

リソース グループを作成する

az group create コマンドを使用してリソース グループを作成します。

export RANDOM_ID="$(openssl rand -hex 3)"
export RESOURCE_GROUP="myResourceGroup$RANDOM_ID"
export LOCATION="<your-preferred-region>"
az group create --name "${RESOURCE_GROUP}" --location "${LOCATION}"

次のコードを main.tf に追加して、Azure リソース グループを作成します。 location の値を、お好みのAzureリージョンと一致するように更新します。

resource "azurerm_resource_group" "this" {
 name     = local.resource_group_name
 location = "eastus"
}

AKS クラスターで OIDC 発行者とMicrosoft Entra ワークロード ID を有効にする

新規または既存の AKS クラスターで OIDC 発行者とMicrosoft Entra ワークロード ID を有効にすることができます。

az aks create コマンドと --enable-oidc-issuer パラメーターを使用して AKS クラスターを作成し、OIDC 発行者と --enable-workload-identity パラメーターでMicrosoft Entra ワークロード ID を有効にします。 次の例では、1 つのノードを含むクラスターを作成します:

export CLUSTER_NAME="myAKSCluster$RANDOM_ID"
az aks create \
    --resource-group "${RESOURCE_GROUP}" \
    --name "${CLUSTER_NAME}" \
    --enable-oidc-issuer \
    --enable-workload-identity \
    --generate-ssh-keys

数分後、コマンドが完了し、クラスターに関する情報が JSON 形式で返されます。

次のコードを main.tf に追加して、OIDC 発行者を使用して AKS クラスターを作成し、Microsoft Entra ワークロード ID 有効にします。

resource "azurerm_kubernetes_cluster" "this" {
 name                              = local.cluster_name
 location                          = azurerm_resource_group.this.location
 resource_group_name               = azurerm_resource_group.this.name
 dns_prefix                        = local.cluster_name
 oidc_issuer_enabled               = true
 workload_identity_enabled         = true
 role_based_access_control_enabled = true
 default_node_pool {
   name       = "system"
   node_count = 1
   vm_size    = "Standard_B4ms"
 }
 identity {
   type = "SystemAssigned"
 }
}

OIDC 発行者 URL を取得する

az aks show コマンドを使用して OIDC 発行者 URL を取得し、環境変数に保存します。

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

環境変数には、次の例のような発行者 URL が含まれている必要があります:

https://eastus.oic.prod-aks.azure.com/00000000-0000-0000-0000-000000000000/11111111-1111-1111-1111-111111111111/

既定では、発行者はベース URL https://{region}.oic.prod-aks.azure.com/{tenant_id}/{uuid} を使用するように設定されています。ここで {region} の値は、AKS クラスターがデプロイされている場所と一致します。 {uuid}値は OIDC キーを表します。これは、クラスターごとにランダムに生成され、変更できない GUID です。

OIDC 発行者 URL を取得する main.tf に次のコードを追加します。

output "oidc_issuer_url" {
 value = azurerm_kubernetes_cluster.this.oidc_issuer_url
}

マネージド ID の作成

  1. az account show コマンドを使用して、サブスクリプション ID を取得し、環境変数に保存します。

    export SUBSCRIPTION="$(az account show --query id --output tsv)"
    
  2. az identity create コマンドを使用して、ユーザー割り当てマネージド ID を作成します。

    export USER_ASSIGNED_IDENTITY_NAME="myIdentity$RANDOM_ID"
    az identity create \
        --name "${USER_ASSIGNED_IDENTITY_NAME}" \
        --resource-group "${RESOURCE_GROUP}" \
        --location "${LOCATION}" \
        --subscription "${SUBSCRIPTION}"
    

    次の出力例は、マネージド ID の正常な作成を示しています:

    {
      "clientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourcegroups/myResourceGroupxxxxxx/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentityxxxxxx",
      "location": "eastus",
      "name": "myIdentityxxxxxx",
      "principalId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "resourceGroup": "myResourceGroupxxxxxx",
      "systemData": null,
      "tags": {},
      "tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "type": "Microsoft.ManagedIdentity/userAssignedIdentities"
    }
    
  3. マネージド ID のクライアント ID を取得し、 az identity show コマンドを使用して環境変数に保存します。

    export USER_ASSIGNED_CLIENT_ID="$(az identity show \
        --resource-group "${RESOURCE_GROUP}" \
        --name "${USER_ASSIGNED_IDENTITY_NAME}" \
        --query 'clientId' \
        --output tsv)"
    

マネージド ID を作成するために、次のコードを main.tf に追加します。

resource "azurerm_user_assigned_identity" "this" {
 name                = local.managed_identity_name
 location            = azurerm_resource_group.this.location
 resource_group_name = azurerm_resource_group.this.name
}

Kubernetes サービス アカウントを作成する

  1. az aks get-credentials コマンドを使用して AKS クラスターに接続します。

    az aks get-credentials --name "${CLUSTER_NAME}" --resource-group "${RESOURCE_GROUP}"
    
  2. kubernetes サービス アカウントを作成し、 kubectl apply コマンドを使用して次のマニフェストを適用して、マネージド ID のクライアント ID で注釈を付けます。

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

    ワークロード IDが正常に作成された場合の出力の例は、次のとおりです:

    serviceaccount/workload-identity-sa created
    
  1. Kubernetes リソースの作成を許可するように Kubernetes アクセスを構成する main.tf に次のコードを追加します。

    data "azurerm_kubernetes_cluster" "this" {
     name                = azurerm_kubernetes_cluster.this.name
     resource_group_name = azurerm_resource_group.this.name
    }
    provider "kubernetes" {
     host                   = data.azurerm_kubernetes_cluster.this.kube_config[0].host
     client_certificate     = base64decode(data.azurerm_kubernetes_cluster.this.kube_config[0].client_certificate)
     client_key             = base64decode(data.azurerm_kubernetes_cluster.this.kube_config[0].client_key)
     cluster_ca_certificate = base64decode(data.azurerm_kubernetes_cluster.this.kube_config[0].cluster_ca_certificate)
    }
    
  2. Kubernetes サービス アカウントを作成し、マネージド ID のクライアント ID で注釈を付けるために、次のコードを main.tf に追加します。

    resource "kubernetes_service_account" "this" {
     metadata {
       name      = local.service_account_name
       namespace = local.service_account_namespace
       annotations = {
         "azure.workload.identity/client-id" = azurerm_user_assigned_identity.this.client_id
       }
     }
    }
    

フェデレーション ID 資格情報を作成する

az identity federated-credential create コマンドを使用して、マネージド ID、サービス アカウント発行者、サブジェクトの間にフェデレーション ID 資格情報を作成します。

export FEDERATED_IDENTITY_CREDENTIAL_NAME="myFedIdentity$RANDOM_ID"
az identity federated-credential create \
    --name ${FEDERATED_IDENTITY_CREDENTIAL_NAME} \
    --identity-name "${USER_ASSIGNED_IDENTITY_NAME}" \
    --resource-group "${RESOURCE_GROUP}" \
    --issuer "${AKS_OIDC_ISSUER}" \
    --subject system:serviceaccount:"${SERVICE_ACCOUNT_NAMESPACE}":"${SERVICE_ACCOUNT_NAME}" \
    --audience api://AzureADTokenExchange

フェデレーション ID 資格情報が追加された後に反映されるまでに数秒かかります。 フェデレーション ID 資格情報を追加した直後にトークン要求が行われると、キャッシュが更新されるまでの間、要求が失敗する可能性があります。 このイシューを回避するには、フェデレーション ID 資格情報を追加した後に若干の遅延を追加できます。

マネージド ID、サービス アカウント発行者、サブジェクトの間にフェデレーション ID 資格情報を作成する main.tf に次のコードを追加します。

resource "azurerm_federated_identity_credential" "this" {
 name                = local.federated_credential_name
 resource_group_name = azurerm_resource_group.this.name
 parent_id           = azurerm_user_assigned_identity.this.id
 issuer              = azurerm_kubernetes_cluster.this.oidc_issuer_url
 subject             = local.workload_identity_subject
 audience            = ["api://AzureADTokenExchange"]
}

Microsoft Entraのフェデレーション ID 資格情報の詳細については、「 Microsoft Entra IDを参照してください。

Azure RBAC 承認を使用してキー コンテナーを作成する

次の例は、Azure ロールベースのアクセス制御 (Azure RBAC) 権限モデルを使用して、ポッドにキー ボールトへのアクセス権を付与する方法を紹介しています。 Azure Key Vault の Azure RBAC 権限モデルの詳細については、「Azure RBAC を使用して Azure Key Vault にアクセスするためのアプリケーションへの権限を付与する」を参照してください。

  1. az keyvault create コマンドを使用して、消去保護とAzure RBAC 承認が有効になっているキー コンテナーを作成します。 消去保護とAzure RBAC 承認の両方で構成されている場合は、既存のキー コンテナーを使用することもできます。

    export KEYVAULT_NAME="keyvault-workload-id$RANDOM_ID" # Ensure the key vault name is between 3-24 characters
    az keyvault create \
        --name "${KEYVAULT_NAME}" \
        --resource-group "${RESOURCE_GROUP}" \
        --location "${LOCATION}" \
        --enable-purge-protection \
        --enable-rbac-authorization
    
  2. az keyvault show コマンドを使用して、キー コンテナーのリソース ID を取得し、環境変数に保存します。

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

次のコードを main.tf に追加して、Azure RBAC 承認を使用してキー コンテナーを作成します。

resource "azurerm_key_vault" "this" {
 name                          = local.key_vault_name
 location                      = azurerm_resource_group.this.location
 resource_group_name           = azurerm_resource_group.this.name
 tenant_id                     = data.azurerm_client_config.current.tenant_id
 sku_name                      = "standard"
 rbac_authorization_enabled    = true
}

キー コンテナー管理のために RBAC 権限を割り当てる

  1. 呼び出し元オブジェクト ID を取得し、 az ad signed-in-user show コマンドを使用して環境変数に保存します。

    export CALLER_OBJECT_ID=$(az ad signed-in-user show --query id -o tsv)
    
  2. Azure RBAC キー コンテナー シークレット責任者 ロールを割り当てて、az role assignment create コマンドを使用して新しいキー コンテナーにシークレットを作成できるようにします。

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

次のコードを main.tf に追加して、Azure RBAC Key Vault Secrets Officer ロールを割り当てます。これにより、新しいkey vaultでシークレットを作成し、Key Vault Secrets User ロールをユーザー割り当てマネージド ID に割り当てることができます。

resource "azurerm_role_assignment" "user" {
 scope                = azurerm_key_vault.this.id
 role_definition_name = "Key Vault Secrets Officer"
 principal_id         = data.azurerm_client_config.current.object_id
}
resource "azurerm_role_assignment" "identity" {
 scope                = azurerm_key_vault.this.id
 role_definition_name = "Key Vault Secrets User"
 principal_id         = azurerm_user_assigned_identity.this.principal_id
}

シークレット アクセスの作成と構成

  1. az keyvault secret set コマンドを使用して、Key Vault でシークレットを作成します。

    export KEYVAULT_SECRET_NAME="my-secret$RANDOM_ID"
    az keyvault secret set \
        --vault-name "${KEYVAULT_NAME}" \
        --name "${KEYVAULT_SECRET_NAME}" \
        --value "Hello\!"
    
  2. ユーザー割り当てマネージド ID のプリンシパル ID を取得し、 az identity show コマンドを使用して環境変数に保存します。

    export IDENTITY_PRINCIPAL_ID=$(az identity show \
        --name "${USER_ASSIGNED_IDENTITY_NAME}" \
        --resource-group "${RESOURCE_GROUP}" \
        --query principalId \
        --output tsv)
    
  3. コマンドを使用して、az role assignment create ロールをユーザー割り当てマネージド ID に割り当てます。 この手順では、キー コンテナーからシークレットを読み取るアクセス許可をマネージド ID に付与します。

    az role assignment create \
        --assignee-object-id "${IDENTITY_PRINCIPAL_ID}" \
        --role "Key Vault Secrets User" \
        --scope "${KEYVAULT_RESOURCE_ID}" \
        --assignee-principal-type ServicePrincipal
    
  4. az keyvault show コマンドを使用して、キー コンテナー URL の環境変数を作成します。

    export KEYVAULT_URL="$(az keyvault show \
        --resource-group "${RESOURCE_GROUP}" \
        --name ${KEYVAULT_NAME} \
        --query properties.vaultUri \
        --output tsv)"
    

次のコードを追加して main.tf キー コンテナーにシークレットを作成します。

resource "azurerm_key_vault_secret" "this" {
 name         = local.secret_name
 value        = "Hello from Key Vault"
 key_vault_id = azurerm_key_vault.this.id
}

検証ポッドをデプロイしてアクセスをテストする

  1. ポッドをデプロイして、ワークロード ID がキー コンテナー内のシークレットにアクセスできることを確認します。 次の例では、ghcr.io/azure/azure-workload-identity/msal-go イメージを使用します。このイメージには、Microsoft Entra ワークロード ID を使用してAzure Key Vaultからシークレットを取得するサンプル アプリケーションが含まれています。

    kubectl apply -f - <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
        name: sample-workload-identity-key-vault
        namespace: ${SERVICE_ACCOUNT_NAMESPACE}
        labels:
            azure.workload.identity/use: "true"
    spec:
        serviceAccountName: ${SERVICE_ACCOUNT_NAME}
        containers:
          - image: ghcr.io/azure/azure-workload-identity/msal-go
            name: oidc
            env:
              - name: KEYVAULT_URL
                value: ${KEYVAULT_URL}
              - name: SECRET_NAME
                value: ${KEYVAULT_SECRET_NAME}
        nodeSelector:
            kubernetes.io/os: linux
    EOF
    
  2. Ready コマンドを使用して、ポッドがkubectl wait状態になるまで待ちます。

    kubectl wait --namespace ${SERVICE_ACCOUNT_NAMESPACE} --for=condition=Ready pod/sample-workload-identity-key-vault --timeout=120s
    
  3. SECRET_NAME コマンドを使用して、kubectl describe環境変数がポッドに設定されていることを確認します。

    kubectl describe pod sample-workload-identity-key-vault | grep "SECRET_NAME:"
    

    成功した場合、出力は次の例のようになります。

    SECRET_NAME: ${KEYVAULT_SECRET_NAME}
    
  4. kubectl logs コマンドを使用して、ポッドがトークンを取得してリソースにアクセスできることを確認します。

    kubectl logs sample-workload-identity-key-vault
    

    成功した場合、出力は次の例のようになります。

    I0114 10:35:09.795900       1 main.go:63] "successfully got secret" secret="Hello\\!"
    

    重要

    Azure RBAC ロールの割り当てが反映されるまでに最大 10 分かかることがあります。 ポッドがシークレットにアクセスできない場合は、ロールの割り当てが反映されるまで待つ必要があります。 詳細については、Azure RBAC のトラブルシューティング を参照してください。

AKS クラスターでMicrosoft Entra ワークロード ID を無効にする

有効になっている AKS クラスターでMicrosoft Entra ワークロード ID を無効にし、az aks update コマンドを使用して --disable-workload-identity パラメーターを使用して AKS クラスターを更新します。

az aks update \
    --resource-group "${RESOURCE_GROUP}" \
    --name "${CLUSTER_NAME}" \
    --disable-workload-identity

検証ポッドをデプロイする

次のコードを main.tf 追加して、ワークロード ID を使用してキー コンテナー内のシークレットにアクセスする検証ポッドをデプロイします。

resource "kubernetes_pod" "test" {
 metadata {
   name      = "workload-identity-test"
   namespace = local.service_account_namespace
   labels = {
     "azure.workload.identity/use" = "true"
   }
 }
 spec {
   service_account_name = kubernetes_service_account.this.metadata[0].name
   container {
     name  = "test"
     image = "ghcr.io/azure/azure-workload-identity/msal-go"
     env {
       name  = "KEYVAULT_URL"
       value = azurerm_key_vault.this.vault_uri
     }
     env {
       name  = "SECRET_NAME"
       value = azurerm_key_vault_secret.this.name
     }
   }
 }
}

Terraform を初期化する

main.tf コマンドを使用して、terraform init ファイルを含むディレクトリで Terraform を初期化します。 このコマンドは、Terraform を使用してAzureリソースを管理するために必要なAzure プロバイダーをダウンロードします。

terraform init

Terraform実行計画を作成する

terraform plan コマンドを使用して Terraform 実行プランを作成します。 このコマンドは、Terraform が Azure サブスクリプションで作成または変更するリソースを示します。

terraform plan

Terraform 構成を適用する

実行プランを確認して確認した後、 terraform apply コマンドを使用して Terraform 構成を適用します。 このコマンドは、Azure サブスクリプションの main.tf ファイルで定義されているリソースを作成または変更します。

terraform apply

デプロイメントを確認する

  1. az aks get-credentials コマンドを使用して AKS クラスターに接続します。

    az aks get-credentials --name <cluster-name> --resource-group <resource-group>
    
  2. kubectl get pods コマンドを使用して、検証ポッドの状態を確認します。

  3. ポッドが Ready 状態になったら、 kubectl logs コマンドを使用してポッド ログを確認して、キー コンテナー シークレットにアクセスできることを確認します。

    kubectl logs workload-identity-test
    

この記事では、Kubernetes クラスターをデプロイし、その資格情報で認証するアプリケーション ワークロードの準備としてMicrosoft Entra ワークロード ID を使用するように構成しました。 これで、アプリケーションをデプロイし、最新バージョンの Azure Identity クライアント ライブラリでワークロード ID を使用するように構成する準備ができました。 最新のクライアント ライブラリ バージョンを使用するようにアプリケーションを書き換えることができない場合は、ワークロード ID を短期的な移行ソリューションとして使ってマネージド ID を使用して認証するように、アプリケーション ポッドを設定できます。

Service Connector 統合により、AKS ワークロードとAzure バッキング サービスの接続構成を簡略化できます。 認証とネットワーク構成を安全に処理し、Azure サービスに接続するためのベスト プラクティスに従います。 詳細については、Microsoft Entra Workload Identity を使用して AKS の Foundry Models で Azure OpenAI に接続する方法と、Service Connector の概要を参照してください。