Identityに権限を与える方法(AKSからACRを利用する状況を例に)

初めに

ACR(Azure Container Registry)に格納済みのコンテナイメージを用いて、AKS(Azure Kubernetes Service)にPodをデプロイしようとした際に、権限周りの設定方法が色々あり、頭が混乱してきたので、まとめてみました。

まず前提の話を少しだけすると、
AzureにはRBAC(role-based access control)という概念が存在し、Azureリソースから他のAzureリソースにアクセスするためには、アクセス側のIdentityに対して、必要な権限を与える必要があります。

Identityには、
①service principal
②system-assigned managed identity 
③user-assigned managed identity

の三種類が存在し、それぞれ権限付与手順が異なるので、順番に見ていきたいと思います。

上記三つの違いはこちらを参照ください
Demystifying Service Principals - Managed Identities | Azure DevOps Blog

1.ACRの用意

#ResourceGroupの作成
$ RG="test"
$ az group create -g $RG -l japaneast

#ACRを作成
#注:ACR名は全世界でユニークである必要性がある
$ ACR_NAME="testACRXXX"
$ az acr create -g $RG -n $ACR_NAME --sku Basic


2.ACRにDocker Imageをpushする

#acrにログインしてdocker pushできるように
$ az acr login -n $ACR_NAME

#acrのサーバ名を確認
#注:ACR名の一部に大文字が含まれていても、小文字に変換されてしまう
$ az acr show -n $ACR_NAME --query loginServer -o table
Result
------------------------------
testacrXXX.azurecr.io

#変数ACR_NAMEを大文字から小文字へ変更
$ ACR_NAME=`echo $ACR_NAME | tr '[:upper:]' '[:lower:]'`

#ACRにpushする用のImageをpull
#今回は実験用なのでサイズが小さいalpineイメージを使用
$ docker pull alpine

#Imageにタグ付けする
#注:"testACR"ではなく"testacr"である
$ docker tag alpine $ACR_NAME.azurecr.io/alpine:v1

#ACRにイメージをpush
$ docker push $ACR_NAME.azurecr.io/alpine:v1

#ACRにちゃんとpushできたか確認
#ACRに存在するrepositoryを全表示
$ az acr repository list -n $ACR_NAME -otable
Result
--------
alpine

#ACRのalpineリポジトリに存在するタグを全表示
$ az acr repository show-tags -n $ACR_NAME --repository alpine -otable
Result
--------
v1

※”unauthorized: authentication required”と表示されてimage pushできない人はおそらくタグ付けの段階でスペル間違えてます。(経験談

1章2章の参考資料:
Tutorial - Prepare container registry to deploy image - Azure Container Instances | Microsoft Docs

3.AKSがACRからimage pullできるようにする

3章の共通部分

#AKSの名前設定
$ AKS_NAME="testaks"


3-1.AKSのIdentityにservice principalを使用する場合

service principalを利用する場合は、AKSに紐づけられたservice principalに当該ACRのAcrPull権限が必要。

①service principalを自動作成する場合

(ⅰ)AKS作成時にACR設定する場合

#AKS作成時に、利用するACRを指定
$ az aks create -g $RG -n $AKS_NAME --attach-acr $ACR_NAME


(ⅱ)AKS作成後に設定を更新して、ACRを利用できるようにする場合

#AKS作成
$ az aks create -g $RG -n $AKS_NAME --node-count 1 --node-vm-size Standard_B2s

#ACRを利用できるように、設定を更新
$ az aks update -g $RG -n $AKS_NAME --attach-acr $ACR_NAME


②service principalを手動作成する場合

3-1-②の共通部分

#AKSと紐づけるservice principalを生成し、そのID及びPASSWORDを変数に格納
$ APP_ID=$(az ad sp create-for-rbac --skip-assignment -n test-aks-sp --query appId -otsv)
$ PASSWORD=$(az ad sp credential reset --name $APP_ID --query password -otsv)


(ⅰ)AKS作成時にACR設定する場合

#AKS作成時にserviceprincipal、password、利用するACRを指定
$ az aks create -g $RG -n $AKS_NAME --node-count 1 --node-vm-size Standard_B2s --service-principal $APP_ID --client-secret $PASSWORD --attach-acr $ACR_NAME


(ⅱ)AKS作成後に設定を更新して、ACRを利用できるようにする場合

#AKS作成時にservice principal、passwordを指定
$ az aks create -g $RG -n $AKS_NAME --node-count 1 --node-vm-size Standard_B2s --service-principal $APP_ID --client-secret $PASSWORD

#ACRを利用できるように、設定を更新
$ az aks update -g $RG -n $AKS_NAME --attach-acr $ACR_NAME


(ⅲ)AKSに紐づけられたservice principalに適切なRoleを割り当てる場合

#AKS作成時にservice principal、passwordを指定
$ az aks create -g $RG -n $AKS_NAME --node-count 1 --node-vm-size Standard_B2s --service-principal=$APP_ID --client-secret=$PASSWORD

#ACRのresource idを取得
$ ACR_ID=$(az acr show -g $RG -n $ACR_NAME --query id -otsv)

#AKSのServicePrincipalに”ACRからイメージをpullする権限”を付与
$ az role assignment create --assignee $APP_ID --scope $ACR_ID --role AcrPull

3-1の参考資料:
Service principals for Azure Kubernetes Services (AKS) - Azure Kubernetes Service | Microsoft Docs

3-2.AKSのIdentityにmanaged identityを使用する場合

AKSのmanaged identityにはContorolPlaneとKubeletの二つがある。 ACRのコンテナイメージを利用する場合は、AKSのkubeletのmanaged identityに当該ACRのAcrPull権限が必要。
Use managed identities in Azure Kubernetes Service - Azure Kubernetes Service | Microsoft Docs

①system-assigned managed identityを使用する場合

(ⅰ)AKS作成時にACR設定する場合

#AKS作成時に、managed identityを有効化、利用するACRを指定
$ az aks create -g $RG -n $AKS_NAME --node-count 1 --node-vm-size Standard_B2s --enable-managed-identity --attach-acr $ACR_NAME


(ⅱ)AKS作成後に設定を更新して、ACRを利用できるようにする場合

#AKS作成時に、managed identityを有効化
$ az aks create -g $RG -n $AKS_NAME --node-count 1 --node-vm-size Standard_B2s --enable-managed-identity

#ACRを利用できるように、設定を更新
$ az aks update -g $RG -n $AKS_NAME --attach-acr $ACR_NAME


(ⅲ)AKSのmanaged identity(kubelet)に適切なRoleを割り当てる場合

#AKS作成時に、managed identityを有効化
$ az aks create -g $RG -n $AKS_NAME --node-count 1 --node-vm-size Standard_B2s --enable-managed-identity

#kubeletのmanaged identityを取得
#kubeletのmanaged identityは"${AKSの名前}-agentpool"で表示されるので、下記のように検索 
$ MI=$(az ad sp list --all --filter "displayName eq 'test-aks-agentpool'" --query [].objectId -otsv)

#kubeletのmanaged identityに対して”ACRからイメージをpullする権限”を付与
$ ACR_ID=$(az acr show -g $RG -n $ACR_NAME --query id -otsv)
$ az role assignment create --assignee $MI --scope $ACR_ID --role AcrPull


②user-assigned managed identityを使用する場合

3-2-②の共通部分

#各managed identityを作成し、それぞれのIDを変数へ代入しておく
$ ID=$(az identity create -n test-identity -g $RG --query id -otsv)

$ KUBELET_ID=$(az identity create -n test-kubelet-identity -g $RG --query id -otsv)

$ SUBNET_ID=$(az network vnet create -g $RG -n test-vnet --address-prefixes 10.0.0.0/8 --subnet-name test-subnet --subnet-prefixes 10.0.0.0/16 --query 'newVNet.subnets[0].id' -otsv)


(ⅰ)AKS作成時にACR設定する場合

#AKS作成時、kubelet用のidentityを指定、利用するACRを指定
$ az aks create -g $RG -n $AKS_NAME --network-plugin azure --vnet-subnet-id $SUBNET_ID --docker-bridge-address 172.17.0.1/16 --dns-service-ip 10.2.0.10 --service-cidr 10.2.0.0/24 --enable-managed-identity --assign-identity $ID --assign-kubelet-identity $KUBELET_ID --attach-acr $ACR_NAME


(ⅱ)AKS作成後に設定を更新して、ACRを利用できるようにする場合

#AKS作成時、kubelet用のidentityを指定
$ az aks create -g $RG -n $AKS_NAME --network-plugin azure --vnet-subnet-id $SUBNET_ID --docker-bridge-address 172.17.0.1/16 --dns-service-ip 10.2.0.10 --service-cidr 10.2.0.0/24 --enable-managed-identity --assign-identity $ID --assign-kubelet-identity $KUBELET_ID

#ACRを利用できるように、設定を更新
$ az aks update -g $RG -n $AKS_NAME --attach-acr $ACR_NAME


(ⅲ)AKSに紐づけられたmanaged identity(kubelet)に適切なRoleを割り当てる場合

#AKS作成時、kubelet用のidentityを指定
$ az aks create -g $RG -n $AKS_NAME --network-plugin azure --vnet-subnet-id $SUBNET_ID --docker-bridge-address 172.17.0.1/16 --dns-service-ip 10.2.0.10 --service-cidr 10.2.0.0/24 --enable-managed-identity --assign-identity $ID --assign-kubelet-identity $KUBELET_ID

#kubeletのmanaged identityに対して”ACRからイメージをpullする権限”を付与
$ ACR_ID=$(az acr show -g $RG -n $ACR_NAME --query id -otsv)
$ az role assignment create --assignee $KUBELET_ID --scope $ACR_ID --role AcrPull

上記のことを行うためには、azure-cliのversion2.26.0以上が要求されるのですが、 現在、azure-cli 2.26.0のバグのため、実際には実行不可能な模様。
(自身の環境では、az ask create実行時に下記のようなエラーが発生してしまう)
az acr build results in "TypeError: 'NoneType' object is not callable" - githubmemory

3-2-②の参考資料:
Azure Kubernetes Service (AKS) with Bring-Your-Own Identity (BYOID) | by Jonathan | Jun, 2021 | Medium

4.AKSがACRからイメージをpullできるか試す

#AKSにアクセスするために認証する
$ az aks get-credentials -g $RG -n $AKS_NAME

#ACRに先ほどpushしたイメージを用いてPodを作成し、適当なコマンドを実行させる
$ k run test --image $ACR_NAME.azurecr.io/alpine:v1 --command sleep 3600
pod/test created

#無事、イメージのpullが成功し、Podがrunning状態であることを確認
$ k get po --watch
NAME   READY   STATUS    RESTARTS   AGE
test   1/1     Running   0          2m31s


5.クリーンアップ

#現在存在しているResourceGroupを全部表示する
az group list -otable

#test ResourceGroupを削除
#--no-waitを指定すると、削除中でもターミナルが使うことが可能
az group delete -g $RG --no-wait -y

#VNet作成時に自動で作成されたResourceGruopも削除
az group delete -g NetworkWatcherRG --no-wait -y

#全てのResourceGroupが削除中になっているか確認
az group list -otable

参考資料

Managed identities for Azure resources | Microsoft Docs

Assign Azure roles using Azure CLI - Azure RBAC | Microsoft Docs