Key Vaultに保存した情報をAKS上のPodから取得するような要件は良くあると思います。でもKey Vaultへの認証をどうしたものかと思っていました。Service Principal使えば良いのですが、AKSでもMSIを使えたら良いなと思い調べていたところ、以下の情報がドキュメントにありました。実際に試したので書いておきます。
(2020/04/10追記)英語で読むにしてもプレビューだったので勘違いしてましたが、 ja-jp
ページでなく en-us
ページを確認したらちょうどプレビュー外れてたので書き直しました。
Release Release 2020-03-16 · Azure/AKS · GitHub
前準備
バージョン 2.2.0
以上のAzure CLIで以下のコマンドで構築可能です。必要に応じてAzure CLIをアップデートします。
$ az version { "azure-cli": "2.3.1", "azure-cli-command-modules-nspkg": "2.0.3", "azure-cli-core": "2.3.1", "azure-cli-nspkg": "3.0.4", "azure-cli-telemetry": "1.0.4", "extensions": { "azure-devops": "0.17.0" } }
MSIが有効化されたAKSクラスタ作成
AKSでMSIを有効化するには、クラスタを作成する際に --enable-managed-identity
のオプションを有効化します。
$ az aks create -g rg-my-resource-group -n my-aks-cluster --node-count 1 --enable-managed-identity
上記のコマンドで作成したクラスタでは、以下のように servicePrincipalProfile.clientId
を見るとGUIDでなく、msi
という文字列になっていることがわかります。
$ az aks show -g rg-my-resource-group -n my-aks-cluster --query servicePrincipalProfile { "clientId": "msi" }
実体はAzure AD側ではなく、自動生成されるMCから始まる方のリソースグループにマネージドIDという種類のリソースで入っています。
AKSのnodeにSSHでログインして /etc/kubernetes/azure.json
を確認してみると my-aks-cluster-agentpool
のAPP IDが割り当てられていることがわかります。(nodeにSSHする方法はこちら)
認証情報取得できるか確認してみます。
# コンテナ立ち上げログイン local$ kubectl run --generator=run-pod/v1 -it --rm aks-ssh --image=debian # curlをインストール root@aks-ssh:/# apt update && apt install -y curl # MetadataからAccess Tokenを取得できることを確認 root@aks-ssh:/# curl 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' -H Metadata:true -s {"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSIsImtpZCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSJ9.eyJhdWQiOiJodHRwczovL21hbmFnZW1lbnQuYXp1cmUuY29tLyIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzA4NTAyZDk1LTQ0NjQtNDU3YS1iZjhlLTA3YTU0ODM0OTczMC8iLCJpYXQiOjE1ODY1NzcyODAsIm5iZiI6MTU4NjU3NzI4MCwiZXhwIjoxNTg2NjYzOTgwLCJhaW8iOiI0MmRnWURoU1l6cm54VzdXZVdVT3Y5aHZjRDJmQmdBPSIsImFwcGlkIjoiNGQzN2RjZDEtNDgzNC00YjkzLTkzMWUtYzIzMDkyMzJkYmI3IiwiYXBwaWRhY3IiOiIyIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvMDg1MDJkOTUtNDQ2NC00NTdhLWJmOGUtMDdhNTQ4MzQ5NzMwLyIsIm9pZCI6ImQ0MGU2ODNlLWQ5OWYtNDNkZS1iOWQ0LWE4OTg2MjM4NTNkZCIsInN1YiI6ImQ0MGU2ODNlLWQ5OWYtNDNkZS1iOWQ0LWE4OTg2MjM4NTNkZCIsInRpZCI6IjA4NTAyZDk1LTQ0NjQtNDU3YS1iZjhlLTA3YTU0ODM0OTczMCIsInV0aSI6IklXaGFyZW5zZDB5NlJtTlhudzhEQUEiLCJ2ZXIiOiIxLjAiLCJ4bXNfbWlyaWQiOiIvc3Vic2NyaXB0aW9ucy9iNmEwOWU5NS04Nzc2LTRhNzAtOWE5Yy00NjY4ZmVkZmQ0ZDQvcmVzb3VyY2Vncm91cHMvTUNfTXlSZXNvdXJjZUdyb3VwX015TWFuYWdlZENsdXN0ZXJfamFwYW5lYXN0L3Byb3ZpZGVycy9NaWNyb3NvZnQuTWFuYWdlZElkZW50aXR5L3VzZXJBc3NpZ25lZElkZW50aXRpZXMvTXlNYW5hZ2VkQ2x1c3Rlci1hZ2VudHBvb2wifQ.dINhbysiuKZxO-DX_O40AAb9HXk1IBZuzTWM-p33axRcJzTY9y_vSZWjz6vKiptlFbZSOgJ7Mv_J-bc6HX4uHNcA3ayWMBwngno4-Tr92TvXtGrvqDj3OE6GyRfvRXv18FWDnIdMftpzEFUCCUpsO-ISXwRsFd9LEpjyqocn_OcITU0wCXvmiHC2P-lwpahuTZvq3edkMckp2pPmOmO_kltJagrOhty7N9qLV_chKg8-W0UOxF3LGNZX4kXI2djRC-Ly0uic-3Ci_tjnniZREZEto6aLAtRHvoUTCWZFVvDd_HZkdSlcFcIjJdXgRo9vWisnTcIGh5uBTNyGnOQa3w","client_id":"4d37dcd1-4834-4b93-931e-c2309232dbb7","expires_in":"86399","expires_on":"1586663980","ext_expires_in":"86399","not_before":"1586577280","resource":"https://management.azure.com/","token_type":"Bearer"}
MSIへの権限割り当て
最低限の権限をMSIに割り当ててみます。まず、ACRからPullできないと始まらないので、ACRのPull権限を割り当てます。
ACR_RG_NAME=rg-my-resource-group ACR_NAME=myacr SP_DISPLAY_NAME=my-aks-cluster-agentpool acr_id=$(az acr show -g ${ACR_RG_NAME} --name ${ACR_NAME} --query 'id' --output tsv) sp_id=$(az ad sp list --query "[?displayName==\`${SP_DISPLAY_NAME}\`].objectId" --output tsv) az role assignment create --role "AcrPull" --assignee ${sp_id} --scope ${acr_id}
次にKey VaultのSecretもGetできるようにポリシーをセットしておきます。
$ az keyvault set-policy --name kv-my-vault --object-id $sp_id --secret-permissions get
Pythonの実行するPodの準備
やっとタイトルの話になります。MSIで認証してKey Vaultの情報を取得してみます。
以下のファイルを準備します。
my_app/ ├── Dockerfile ├── app.py └── requirements.txt manifests/ └── job-msi.yaml
コンテナのビルド
アプリはKey Vaultの値を取得して表示するだけのシンプルなものです。 ManagedIdentityCredential()
でシームレスにMSI使った認証ができるはずです。
KeyVaultの名前と、Secretの名前は環境変数で引き渡すようにしてます。
from azure.identity import ManagedIdentityCredential from azure.keyvault.secrets import SecretClient import os secret_name = os.environ.get("SECRET_NAME") vault_name = os.environ.get("VAULT_URL") vault_url = f"https://{vault_name}.vault.azure.net/" # MSIで認証 credential = ManagedIdentityCredential() # MSIの認証を使ってKey VaultからSecretをGet kv_client = SecretClient(vault_url=vault_url, credential=credential) secret_bundle = kv_client.get_secret(secret_name) print(secret_bundle.name) print(secret_bundle.value)
requirements.txtの内容です。
azure-identity azure-keyvault-secrets
Dockerfileもシンプルなものです。
FROM python:3.7.7-slim-buster WORKDIR /usr/src/app COPY requirements.txt ./ RUN pip install -r requirements.txt COPY ./app.py ./ CMD ["python","app.py"]
ACR上にビルドします。
$ az acr build --registry myacr --image msi-test ./my_app
k8sのPod定義を準備
ジョブとして実行するためのk8sのManifestとして、job-msi.yaml を準備します。こちらもかなりシンプルなものです。
環境変数でKey Vaultの名前と、Secretの名前を設定しています。
apiVersion: batch/v1 kind: Job metadata: name: msi-test spec: backoffLimit: 0 completions: 1 parallelism: 1 template: spec: containers: - name: msi-test image: myacr.azurecr.io/msi-test env: - name: VAULT_URL value: kv-my-vault - name: SECRET_NAME value: my-secret-text restartPolicy: Never
実行してみる
Key VaultにSecretを設定する
Key VaultにSecretを設定します。この値が出力されるはずです。
$ az keyvault secret set --vault-name kv-my-vault --name my-secret-text --value yomon8
先程作ったManifestファイル使ってJobを実行してみます。
$ kubectl apply -f manifests/job-msi.yaml
Completeしています。どうやら認証通ってそう。
$ kubectl get po NAME READY STATUS RESTARTS AGE msi-test-dsdlp 0/1 Completed 0 5s
ちゃんとKey Vaultに設定したSecretの値が出力されていることが確認できました。
$ kubectl logs msi-test-dsdlp my-secret-text yomon8