0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AKS シークレットストアCSIドライバでworkload identityを使用する

Last updated at Posted at 2023-09-17

この記事について

AKS上のシークレットをAzure Key Vaultに保存するシークレットストアCSIドライバを設定した。Key Vaultへの認証にworkload identityを使用しようとしたところ、なかなか苦戦したのでメモ。

環境

  • Kunbernetes
    • Kubernetes Version: 1.26.6
    • Agentpoolのノードサイズと数: Standard_B2ms x 1
  • Azure CLI
    • version: 2.52.0

手順

基本的に以下のMSの公式の手順を踏んでいるが、一部そのままでは動かなかったため他の手順とマージしている。

AKSクラスタの設定

AKSクラスタを作成する。ポイントは以下。

  • KeyVault シークレットドライバを有効にするために azure-keyvault-secrets-providerアドオンを有効化する。
  • Workload identityを有効にするために、--enable-oidc-issuer--enable-workload-identityを指定する。
export AKS_CLUSTER_NAME="myAKSCluster"
export AKS_RG_NAME="myResourceGroup"
export LOCATION="japaneast"

az group create -n ${AKS_RG_NAME} -l ${LOCATION}
az aks create -n ${AKS_CLUSTER_NAME} -g ${AKS_RG_NAME} -l ${LOCATION} \
  --enable-addons azure-keyvault-secrets-provider \
  --enable-oidc-issuer \
  --enable-workload-identity \
  --enable-secret-rotation \
  --node-vm-size Standard_B2ms \
  --node-count 1

Azure KeyVaultの設定

Key Vaultを新しく作成する。

export KEYVAULT_NAME="your keyvault name"
export KEYVAULT_RG_NAME="myResourceGroup"

az keyvault create -n ${KEYVAULT_NAME} -g ${KEYVAULT_RG_NAME} -l ${LOCATION}

サンプルのシークレットを登録する

export KV_SECRET_USERNAME_KEY="username"
export KV_SECRET_USERNAME_VALUE="Obi-Wan"
export KV_SECRET_PASSWORD_KEY="password"
export KV_SECRET_PASSWORD_VALUE="MayThe4thBWU"

az keyvault secret set --vault-name ${KEYVAULT_NAME} \
  -n ${KV_SECRET_USERNAME_KEY} --value ${KV_SECRET_USERNAME_VALUE}
az keyvault secret set --vault-name ${KEYVAULT_NAME} \
  -n ${KV_SECRET_PASSWORD_KEY} --value ${KV_SECRET_PASSWORD_VALUE}

workload idの設定

OIDC IssuerのURLを取得し環境変数に格納する

export AKS_OIDC_ISSUER="$(az aks show -n "${AKS_CLUSTER_NAME}" -g "${AKS_RG_NAME}" --query "oidcIssuerProfile.issuerUrl" -otsv)"

Managed IDを作成し、クライアントIDとテナントIDを環境変数に格納する

export USER_ASSIGNED_ID_NAME="myIdentity"
export USER_ASSIGNED_ID_RG="myResourceGroup"
export SUBSCRIPTION="$(az account show --query id --output tsv)"

az identity create --name "${USER_ASSIGNED_ID_NAME}" \
  --resource-group "${USER_ASSIGNED_ID_RG}" \
  --location "${LOCATION}" \
  --subscription "${SUBSCRIPTION}"

export USER_ASSIGNED_CLIENT_ID="$(az identity show --resource-group "${USER_ASSIGNED_ID_RG}" --name "${USER_ASSIGNED_ID_NAME}" --query 'clientId' -otsv)"
export IDENTITY_TENANT=$(az aks show --name ${AKS_CLUSTER_NAME} --resource-group ${AKS_RG_NAME} --query identity.tenantId -o tsv)

https://learn.microsoft.com/ja-jp/azure/aks/csi-secrets-store-identity-access#configure-workload-identity
上記のサイトには、Managed IDに対しKey Vault AdministratorのRoleを付与せよとあるが、これではうまく動かなかった。

https://learn.microsoft.com/ja-jp/azure/aks/workload-identity-deploy-cluster#optional---grant-permissions-to-access-azure-key-vault
上記のサイトには、Key Vaultのset-policyの方を設定せよと書いてあり、こっちが正解。

Managed IDからKey Vaultへのアクセスを許可する。

az keyvault set-policy --name "${KEYVAULT_NAME}" \
  --secret-permissions get --spn "${USER_ASSIGNED_CLIENT_ID}"

Kubernetesのサービスアカウントの作成

kubeconfigを取得する

az aks get-credentials -n ${AKS_CLUSTER_NAME} -g "${AKS_RG_NAME}"

ネームスペースを作成する。サービスアカウントはネームスペース毎に独立なので、このあとの手順で作成する各種Kubernetesリソースはすべて同じネームスペースを指定すること。

export MY_NAMESPACE="csidrivertest"

kubectl create namespace ${MY_NAMESPACE}

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

  • azure.workload.identity/client-idのannotationで、先程作成したManaged IDと紐付ける
export SERVICE_ACCOUNT_NAME="workload-identity-sa"

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: "${MY_NAMESPACE}"
EOF

フェデレーションID資格情報を確立する。やっていることは、Managed ID側へのサービスアカウントの情報の登録。

export FEDERATED_IDENTITY_CREDENTIAL_NAME="myFedIdentity"

az identity federated-credential create \
  --name ${FEDERATED_IDENTITY_CREDENTIAL_NAME} \
  --identity-name "${USER_ASSIGNED_ID_NAME}" \
  --resource-group "${USER_ASSIGNED_ID_RG}" \
  --issuer "${AKS_OIDC_ISSUER}" \
  --subject system:serviceaccount:"${MY_NAMESPACE}":"${SERVICE_ACCOUNT_NAME}" --audience api://AzureADTokenExchange

Secret Provider Classの設定

Secret Provider Classを作成する。

  • Podから環境変数としてクレデンシャルを参照する場合には、secretObjectsの設定が必要。
export SECRET_PROVIDER_CLASS_NAME="azure-kv-spc"
export SECRET_NAME="azure-kv-secret"

export SECRET_USERNAME_KEY="username"
export SECRET_PASSWORD_KEY="password"

cat <<EOF | kubectl apply -f -
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: ${SECRET_PROVIDER_CLASS_NAME}
  namespace: ${MY_NAMESPACE}
spec:
  provider: azure
  parameters:
    usePodIdentity: "false"
    useVMManagedIdentity: "false"
    clientID: "${USER_ASSIGNED_CLIENT_ID}"
    keyvaultName: ${KEYVAULT_NAME}
    cloudName: ""
    objects:  |
      array:
        - |
          objectName: ${KV_SECRET_USERNAME_KEY}
          objectType: secret
          objectVersion: ""
        - |
          objectName: ${KV_SECRET_PASSWORD_KEY}
          objectType: secret
          objectVersion: ""
    tenantId: "${IDENTITY_TENANT}"
  secretObjects:
  - data:
    - key: ${SECRET_USERNAME_KEY}
      objectName: ${KV_SECRET_USERNAME_KEY}
    - key: ${SECRET_PASSWORD_KEY}
      objectName: ${KV_SECRET_PASSWORD_KEY}
    secretName: ${SECRET_NAME}
    type: Opaque 
EOF

シークレットを参照するPodをデプロイする

以下、ポイント。

  • シークレットを取得するためには、ボリュームとしてマウントする方法と、環境変数として参照する方法がある。
  • 環境変数として参照する場合にも、ボリュームのマウントは必要。
export MY_POD_NAME="busybox-secrets-store-inline-wi"

cat <<EOF | kubectl apply -f -
kind: Pod
apiVersion: v1
metadata:
  name: ${MY_POD_NAME}
  namespace: ${MY_NAMESPACE}
spec:
  serviceAccountName: ${SERVICE_ACCOUNT_NAME}
  containers:
    - name: busybox
      image: registry.k8s.io/e2e-test-images/busybox:1.29-4
      command:
        - "/bin/sleep"
        - "10000"
      volumeMounts:
      - name: secrets-store01-inline
        mountPath: "/mnt/secrets-store"
        readOnly: true
      env:
      - name: SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: ${SECRET_NAME}
            key: ${SECRET_USERNAME_KEY}
      - name: SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: ${SECRET_NAME}
            key: ${SECRET_PASSWORD_KEY}
  volumes:
    - name: secrets-store01-inline
      csi:
        driver: secrets-store.csi.k8s.io
        readOnly: true
        volumeAttributes:
          secretProviderClass: ${SECRET_PROVIDER_CLASS_NAME}
EOF

https://learn.microsoft.com/ja-jp/azure/aks/csi-secrets-store-identity-access#configure-workload-identity
上記のサイトにはmetadata.labelsにazure.workload.identity/use=trueを指定せよと記載されているが、今回は記載しなくても問題なく動作した
(通常、workload identityを有効にするためには、Podのmetadata.labelsにazure.workload.identity/use=trueが必要。)
今回azure.workload.identity/use=trueを省略しても動作した理由は不明だが、SecretProviderClassがシークレットを取得してくれている(Podは認証通す必要がない?)からかもしれない。

動作確認

シークレットを取得。

k get secret -n ${MY_NAMESPACE} 

以下のように、自動的にシークレットが作成されていることを確認。

NAME              TYPE     DATA   AGE
azure-kv-secret   Opaque   2      2s

次に、PodをDescribeしてみる。

k describe po -n ${MY_NAMESPACE} ${MY_POD_NAME}

以下、表示の抜粋。

  • /mnt/secrets-storeにシークレットがマウントされている
  • 環境変数としてSECRET_USERNAMESECRET_PASSWORDが登録されている。
Name:             busybox-secrets-store-inline-wi
Namespace:        csidrivertest
Service Account:  workload-identity-sa
Labels:           <none>
Annotations:      <none>
Status:           Running
Containers:
  busybox:
--- 中略 ---
    Ready:          True
    Environment:
      SECRET_USERNAME:             <set to the key 'username' in secret 'azure-kv-secret'>  Optional: false
      SECRET_PASSWORD:             <set to the key 'password' in secret 'azure-kv-secret'>  Optional: false
    Mounts:
      /mnt/secrets-store from secrets-store01-inline (ro)
      /var/run/secrets/azure/tokens from azure-identity-token (ro)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-wt9hp (ro)
--- 中略 ---
Volumes:
  secrets-store01-inline:
    Type:              CSI (a Container Storage Interface (CSI) volume source)
    Driver:            secrets-store.csi.k8s.io
    FSType:            
    ReadOnly:          true
    VolumeAttributes:      secretProviderClass=azure-kv-spc

シークレットがマウントされているパスをlsしてみる。

k exec -n ${MY_NAMESPACE} ${MY_POD_NAME} -- ls -l /mnt/secrets-store

以下の様に、ファイルとしてシークレットが格納されている。

lrwxrwxrwx  1 root   root       15 Sep 17 13:36 password -> ..data/password
lrwxrwxrwx  1 root   root       15 Sep 17 13:36 username -> ..data/username

まとめ

AKSのシークレットをAzure Key Vaultに保存し、認証をworkload identityで行うことができた。シークレットの管理を外部に任せつつ、namespace単位でアクセス権限を分けられるので、シークレットを安全に運用できそう。

参考にしたサイト

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?