keyvault-csi-driver について
keyvault-csi-driverは、Secrets Store CSI Driverを通じてAzure Key VaultをKubernetesに統合するためのガイダンススキルです。クラスターのシークレットを扱うチーム向けに、設定パターンとトラブルシューティングをまとめています。
主な機能
- 01SecretProviderClassリソースの設定
- 02CSIボリュームによるPodへのシークレットマウント
- 03Key Vaultの値をKubernetes Secretへ同期
- 04APIトークン、複数シークレット、TLSへの対応
- 05権限やマウント障害の診断
活用シーン
- 01Kubernetesワークロード用のKey Vaultシークレット設定
- 02403やシークレット不在の問題の調査
- 03TLS証明書マウントの設定
- 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.mdexamples.mdtroubleshooting.mdscripts/create-keyvault-secret.shdiagnose-csi.shgrant-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-dev | kv-example-dev-hlg | <WORKLOAD_IDENTITY_CLIENT_ID> | <TENANT_ID> |
| example-app-hub | kv-example-default | <WORKLOAD_IDENTITY_CLIENT_ID> | <TENANT_ID> |
| example-app-prd | kv-example-prd | <WORKLOAD_IDENTITY_CLIENT_ID> | <TENANT_ID> |
| example-app2-dev | kv-example2-dev | クラスター ID を確認 | <TENANT_ID> |
| example-app2-prd | kv-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.yamlargo-cd-helm-values/kube-addons/external-dns/example-app-dev/secretproviderclass.yamlargo-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
重要な注意事項
-
CSI ボリュームが必須:
secretObjectsを使用して K8s シークレットに同期する場合でも、Pod は必ず CSI ボリュームをマウントする必要があります。 -
シークレット名: Key Vault のシークレット名では大文字と小文字が区別されます。完全に一致する名前を使用してください。
-
オブジェクトのエイリアス: マウント時にファイルシステムで使用できる名前にするには、
objectAliasを使用してください。 -
名前空間のスコープ: SecretProviderClass は名前空間単位です。必要とする名前空間ごとに作成してください。
-
RBAC とアクセス ポリシー: Key Vault の認可モデルを確認してください。
az keyvault show --name "<kv>" --query "properties.enableRbacAuthorization"
詳細なリファレンス
実装例とアーキテクチャの詳細については、以下を参照してください。
- references/architecture.md - CSI ドライバーのアーキテクチャ
- references/examples.md - 実際の使用例
- references/troubleshooting.md - 詳細なトラブルシューティング
注意点
- 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 を使い続けます。