mcpField
K
keyvault-csi-driver

keyvault-csi-driver

github.com/julianobarbosaクラウド・DevOps14101 回インストール2 日前に更新
リポジトリ

keyvault-csi-driver について

keyvault-csi-driverは、Secrets Store CSI Driverを通じてAzure Key VaultをKubernetesに統合するためのガイダンススキルです。クラスターのシークレットを扱うチーム向けに、設定パターンとトラブルシューティングをまとめています。

主な機能

  1. 01SecretProviderClassリソースの設定
  2. 02CSIボリュームによるPodへのシークレットマウント
  3. 03Key Vaultの値をKubernetes Secretへ同期
  4. 04APIトークン、複数シークレット、TLSへの対応
  5. 05権限やマウント障害の診断

活用シーン

  1. 01Kubernetesワークロード用のKey Vaultシークレット設定
  2. 02403やシークレット不在の問題の調査
  3. 03TLS証明書マウントの設定
  4. 04CSI DriverとSecretProviderClassの状態確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/julianobarbosa/claude-code-skills --skill keyvault-csi-driver

インストール後、Claude Code で/keyvault-csi-driverを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
architecture.md
examples.md
troubleshooting.md
scripts/
create-keyvault-secret.sh
diagnose-csi.sh
grant-keyvault-access.sh

詳細

Azure Key Vault CSI ドライバーのスキル

概要

このスキルでは、Secrets Store CSI Driver を使用して Azure Key Vault を Kubernetes に統合する方法を説明します。組織のクラスター内にあるすべての機密データは Azure Key Vault に保存され、CSI ドライバー経由でアクセスします。

クイックリファレンス

環境設定
クラスターKey Vaultマネージド ID(クライアント ID)テナント ID
example-app-devkv-example-dev-hlg<WORKLOAD_IDENTITY_CLIENT_ID><TENANT_ID>
example-app-hubkv-example-default<WORKLOAD_IDENTITY_CLIENT_ID><TENANT_ID>
example-app-prdkv-example-prd<WORKLOAD_IDENTITY_CLIENT_ID><TENANT_ID>
example-app2-devkv-example2-devクラスター ID を確認<TENANT_ID>
example-app2-prdkv-example2-prdクラスター ID を確認<TENANT_ID>

SecretProviderClass のテンプレート

apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: <app>-secrets
  namespace: <namespace>
  labels:
    app.kubernetes.io/name: <app>
    app.kubernetes.io/component: secrets
spec:
  provider: azure
  parameters:
    usePodIdentity: "false"
    useVMManagedIdentity: "true"
    userAssignedIdentityID: "<managed-identity-client-id>"
    keyvaultName: "<keyvault-name>"
    cloudName: "AzurePublicCloud"
    tenantId: "<tenant-id>"
    objects: |
      array:
        - |
          objectName: "<secret-name-in-keyvault>"
          objectType: "secret"
          objectAlias: "<ALIAS_FOR_MOUNT>"
  # Optional: Sync to Kubernetes Secret
  secretObjects:
    - secretName: <k8s-secret-name>
      type: Opaque
      data:
        - objectName: "<ALIAS_FOR_MOUNT>"
          key: "<key-in-k8s-secret>"

Pod のボリュームマウント

spec:
  containers:
    - name: app
      volumeMounts:
        - name: secrets-store
          mountPath: "/mnt/secrets-store"
          readOnly: true
  volumes:
    - name: secrets-store
      csi:
        driver: secrets-store.csi.k8s.io
        readOnly: true
        volumeAttributes:
          secretProviderClass: "<secretproviderclass-name>"

よくあるパターン

パターン 1:シンプルな API トークン(例:Cloudflare)
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: cloudflare-api-token-kv
  namespace: external-dns
spec:
  provider: azure
  secretObjects:
    - data:
        - key: cloudflare_api_token
          objectName: cloudflare-api-token
      secretName: cloudflare-api-token
      type: Opaque
  parameters:
    usePodIdentity: "false"
    useVMManagedIdentity: "true"
    userAssignedIdentityID: "<WORKLOAD_IDENTITY_CLIENT_ID>"
    keyvaultName: "kv-example-dev-hlg"
    objects: |
      array:
        - |
          objectName: cloudflare-api-token
          objectType: secret
    tenantId: "<TENANT_ID>"
パターン 2:複数のシークレットを複数の K8s シークレットに同期
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: app-secrets
spec:
  provider: azure
  parameters:
    usePodIdentity: "false"
    useVMManagedIdentity: "true"
    userAssignedIdentityID: "<identity>"
    keyvaultName: "<keyvault>"
    tenantId: "<tenant>"
    objects: |
      array:
        - |
          objectName: "app-db-password"
          objectType: "secret"
          objectAlias: "DB_PASSWORD"
        - |
          objectName: "app-redis-password"
          objectType: "secret"
          objectAlias: "REDIS_PASSWORD"
  secretObjects:
    - secretName: app-db-secret
      type: Opaque
      data:
        - objectName: "DB_PASSWORD"
          key: "password"
    - secretName: app-redis-secret
      type: Opaque
      data:
        - objectName: "REDIS_PASSWORD"
          key: "password"
パターン 3:TLS 証明書
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: tls-cert-provider
spec:
  provider: azure
  secretObjects:
    - secretName: tls-secret
      type: kubernetes.io/tls
      data:
        - objectName: tls-cert
          key: tls.crt
        - objectName: tls-key
          key: tls.key
  parameters:
    usePodIdentity: "false"
    useVMManagedIdentity: "true"
    userAssignedIdentityID: "<identity>"
    keyvaultName: "<keyvault>"
    tenantId: "<tenant>"
    objects: |
      array:
        - |
          objectName: my-certificate
          objectType: cert
          objectAlias: tls-cert
        - |
          objectName: my-certificate
          objectType: secret
          objectAlias: tls-key

ファイルの場所

SecretProviderClass ファイルは次の場所に保存されています。

argo-cd-helm-values/kube-addons/<application>/<cluster>/secretproviderclass.yaml

例:

  • argo-cd-helm-values/kube-addons/defectdojo/example-app-dev/secretproviderclass.yaml
  • argo-cd-helm-values/kube-addons/external-dns/example-app-dev/secretproviderclass.yaml
  • argo-cd-helm-values/kube-addons/cert-manager/example-app-dev/csi-cloudflare-api-key.yaml

トラブルシューティング

エラー:403 Forbidden

原因: マネージド ID に Key Vault のアクセス許可がありません。

解決方法:

# Get identity info from error message, then:
az keyvault set-policy \
  --name "<keyvault-name>" \
  --object-id "<object-id-from-error>" \
  --secret-permissions get list

# Or for RBAC-enabled Key Vaults:
az role assignment create \
  --role "Key Vault Secrets User" \
  --assignee-object-id "<object-id>" \
  --assignee-principal-type ServicePrincipal \
  --scope "/subscriptions/.../Microsoft.KeyVault/vaults/<kv-name>"
エラー:シークレットが見つからない

原因: シークレット名が存在しないか、大文字と小文字が一致していません。

解決方法:

# List secrets (names are case-sensitive)
az keyvault secret list --vault-name "<kv-name>" --query "[].name" -o tsv
エラー:K8s シークレットが作成されない

原因: CSI ボリュームをマウントした Pod がまだありません。

解決方法: ボリュームをマウントする Pod をデプロイします。K8s シークレットは、少なくとも 1 つの Pod が SecretProviderClass を使用した場合にのみ作成されます。

エラー:Pod が ContainerCreating で停止する

診断:

kubectl describe pod <pod-name> -n <namespace>
kubectl get pods -n kube-system | grep secrets-store
kubectl logs -n kube-system -l app=secrets-store-provider-azure

スクリプト

Key Vault のアクセス許可を付与する
# Use the helper script
./scripts/grant-keyvault-permissions.sh

# Or quick manual command
az keyvault set-policy \
  --name "kv-example-dev-hlg" \
  --object-id "<object-id>" \
  --secret-permissions get list
Key Vault にシークレットを作成する
az keyvault secret set \
  --vault-name "kv-example-dev-hlg" \
  --name "my-app-secret" \
  --value "secret-value"
すべての SecretProviderClass を一覧表示する
kubectl get secretproviderclass -A
CSI ドライバーの状態を確認する
kubectl get pods -n kube-system | grep secrets-store

重要な注意事項

  1. CSI ボリュームが必須: secretObjects を使用して K8s シークレットに同期する場合でも、Pod は必ず CSI ボリュームをマウントする必要があります。

  2. シークレット名: Key Vault のシークレット名では大文字と小文字が区別されます。完全に一致する名前を使用してください。

  3. オブジェクトのエイリアス: マウント時にファイルシステムで使用できる名前にするには、objectAlias を使用してください。

  4. 名前空間のスコープ: SecretProviderClass は名前空間単位です。必要とする名前空間ごとに作成してください。

  5. RBAC とアクセス ポリシー: Key Vault の認可モデルを確認してください。

    az keyvault show --name "<kv>" --query "properties.enableRbacAuthorization"
    

詳細なリファレンス

実装例とアーキテクチャの詳細については、以下を参照してください。


注意点

  • K8s Secret は、Pod が CSI ボリュームをマウントするまで作成されません: secretObjects: の同期は遅延実行されるため、Pod がなければ Secret もありません。CSI ボリュームを自分ではマウントせず、Secret を直接利用するアプリは、先に同じワークロード内の別の Pod がマウントするまで、初回デプロイ時に失敗します。
  • Workload Identity と VM Managed Identity は異なるコードパスです: useVMManagedIdentity: "true" は IMDS から読み取ります。Workload Identity には usePodIdentity: "false" と useVMManagedIdentity: "false" に加え、serviceAccount のアノテーションが必要です。フラグを混在させると、誤った ID に暗黙的にフォールバックします。
  • Key Vault の名前は objects: 内では大文字と小文字が区別されますが、K8s のキーでは区別されません: KV 内の Secret 名が MyToken の場合、SPC に mytoken と記述すると見つかりません。CSI のログには「secret not found」とだけ表示され、大文字と小文字の違いについてのヒントはありません。
  • RBAC と Access Policy の設定はテナント単位ではなく、Vault 単位です: アクセスポリシー(az keyvault set-policy)を使用する Vault もあれば、Azure RBAC(Key Vault Secrets User ロール)を使用する Vault もあります。まず properties.enableRbacAuthorization を確認してください。誤った種類の権限を付与すると、同じエラーメッセージで 403 が返されます。
  • TLS 証明書には 2 つの objectType エントリーが必要です: 証明書を tls.crt と tls.key としてマウントするには、objectType: cert(公開部分)と objectType: secret(秘密鍵を含む完全な PEM)の両方が必要で、どちらも同じ KV 証明書名を指定します。いずれかが欠けていると、Ingress TLS が警告なしに機能しなくなります。
  • CSI のローテーションはデフォルトではオプトインであり、デプロイ時のみです: ドライバーで --enable-secret-rotation=true を設定し、Pod を再起動しない限り、KV の値が変わっても Pod にマウントされた Secret は更新されません。長時間稼働する Pod は古い Secret を使い続けます。

コメント