投稿

EKS Secrets Store CSI の同期問題:syncSecret.enabled を有効にして Secret が作成されない問題を解決

AWS Secrets Manager と Secrets Store CSI Driver の連携で、SecretProviderClass は存在するのに Kubernetes Secret が同期されない問題を、Helm の syncSecret.enabled 設定を更新して解決した記録です。

EKS Secrets Store CSI の同期問題:syncSecret.enabled を有効にして Secret が作成されない問題を解決

今回 EKS にサービスをデプロイする際、アプリケーションに必要な機密情報を AWS Secrets Manager に保存し、Secrets Store CSI Driver を通じて Pod に提供する構成にしました。SecretProviderClass は作成済みで、secretObjects も設定していましたが、アプリケーションの起動時に Secret が見つからないというエラーが発生しました。

設定を適用すれば、CSI が Kubernetes Secret も同期して作成してくれると思っていました。しかし調べてみると、同期を制御する syncSecret.enabled という設定が無効のままでした。この設定を更新すると、Secret が正常に同期され、問題は解決しました。

ファイルのマウントと Secret の同期は別の機能

Secrets Store CSI Driver と AWS provider を組み合わせると、AWS Secrets Manager のデータを Pod 内のファイルとしてマウントできます。アプリケーションが secretKeyRef を使って環境変数に値を読み込む場合は、さらに Kubernetes Secret への同期が必要です。

flowchart TD
    SM["AWS Secrets Manager"] --> Provider["AWS provider"]
    Provider --> CSI["Secrets Store CSI Driver"]
    SPC["SecretProviderClass"] -->|取得と同期の設定を定義| CSI
    CSI -->|Pod が CSI volume をマウント| Files["Pod 内の機密ファイル"]
    CSI -->|同期を有効にし secretObjects に従って作成| Secret["Kubernetes Secret"]
    Secret -->|secretKeyRef| Env["アプリケーションの環境変数"]

この 2 つの利用方法は同じデータソースを使いますが、必要な設定は異なります。SecretProviderClassparameters は AWS から取得するデータを定義し、secretObjects は同期先の Kubernetes Secret の名前、種類、キーを定義します。AWS provider 公式ドキュメント

また、同期を開始するには、Pod が対応する CSI volume をマウントする必要があります。SecretProviderClass を作成しただけでは、Kubernetes Secret はすぐには作成されません。CSI Secret 同期ドキュメント

SecretProviderClass は存在するのに Secret が作成されない

以下では、リソース名を例示用の名前に置き換えています。当時の SecretProviderClass には、すでに同期の設定が含まれていました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: app-database-secret
  namespace: app
spec:
  provider: aws
  secretObjects:
    - secretName: app-db-secret
      type: Opaque
      data:
        - objectName: db-user
          key: db-user
        - objectName: db-password
          key: db-password
  parameters:
    region: ap-northeast-1
    objects: |
      - objectName: "<SECRETS_MANAGER_SECRET_ARN>"
        objectType: secretsmanager
        jmesPath:
          - path: username
            objectAlias: db-user
          - path: password
            objectAlias: db-password

この設定では、Secrets Manager の JSON から usernamepassword を取得します。マウントする内容に db-userdb-password という別名を付け、app-db-secret 内の同名のキーに同期します。

ところが、リソースを確認すると結果が異なりました。

1
2
kubectl get secretproviderclass -n app
kubectl get secret app-db-secret -n app

SecretProviderClass は存在していましたが、Kubernetes Secret の取得は NotFound になりました。そこで、driver 自体の同期設定に注目しました。SPC で「何を同期するか」を定義していても、driver 側でその機能が有効になっている必要があります。

原因は syncSecret.enabled が無効だったこと

この環境の CSI driver は Helm で管理していたため、まず実際のリリース名を調べました。

1
helm list -n kube-system

secrets-store-csi-driver が見つかったので、デフォルト値を含む設定全体を取得しました。

1
2
3
helm get values secrets-store-csi-driver \
  -n kube-system \
  --all

原因となっていたのは、次の設定です。

1
2
syncSecret:
  enabled: false

SecretProviderClass に secretObjects を記述していても、Helm 設定の syncSecret.enabledfalse のままで、同期に必要な RBAC が有効になっていませんでした。

syncSecret.enabledSecrets Store CSI Driver の Helm values に属する設定なので、driver 側の設定を変更します。SecretProviderClass のフィールドでも、Pod の annotation でもありません。公式 chart では、この設定で Kubernetes Secret の同期に必要な roles と bindings を制御しています。CSI Helm chart の設定ドキュメント

そのため、driver コンテナの起動引数を見るだけでは、同期機能が有効かどうかは判断できません。この設定が主に変更するのは RBAC であり、対応する --sync-secret という引数がコンテナの args に追加されるわけではありません。

設定を更新すると Secret が正常に同期された

原因が分かったので、既存の Helm リリースを更新し、syncSecret.enabledtrue に変更しました。

まず、公式 chart リポジトリを追加します。

1
2
3
helm repo add secrets-store-csi-driver \
  https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts
helm repo update

続いて driver を更新します。以下は当時のリリース名、namespace、chart バージョン 1.6.0 を使用した例です。別の環境に適用する場合は、その環境の値に置き換えてください。

1
2
3
4
5
6
helm upgrade secrets-store-csi-driver \
  secrets-store-csi-driver/secrets-store-csi-driver \
  --version 1.6.0 \
  -n kube-system \
  --reuse-values \
  --set syncSecret.enabled=true

--reuse-values で既存のリリース設定を引き継ぎ、今回変更する設定を上書きします。更新後の値は次のとおりです。

1
2
syncSecret:
  enabled: true

公式のインストールドキュメントでも、Kubernetes Secret の同期を有効にする設定として syncSecret.enabled=true が案内されています。CSI インストールドキュメント

この設定を更新すると、Pod が対応する CSI volume をマウントした状態で、secretObjects に定義した Kubernetes Secret が正常に作成されました。これで今回の同期問題は解決しました。

今回見落としていたのは、driver 側の同期設定でした。SecretProviderClass が同期内容を定義し、Pod のマウントがデータ取得を開始し、syncSecret.enabled が Kubernetes Secret の同期に必要な権限を設定します。この 3 つがそろうことで、Kubernetes Secret を参照するアプリケーションに Secrets Manager のデータを提供できます。

この投稿は投稿者によって CC BY 4.0 の下でライセンスされています。

トレンドのタグ