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?

Vaultでk8s secret作るCSI Driver試したけど全然思った動きじゃなかった話

Last updated at Posted at 2024-08-29

諦めた記事です

Vaultでk8s secret作るCSI Driver試したけど全然思った動きじゃなかった。残念ながら導入を見送った話。

GUI と k8s secret(できればselaedsecret) を連動させたいです。GUIは高機能なのがいいです。何かいい方法があれば教えて〜

残念なところ

vaultで新しいパスワードに更新してもSecretProviderClassが k8s secretを更新してくれない。
pod/deploymentを "削除" しないと更新しない。downtime必須。そういうものとしてissueもcloseされてた😭

https://github.com/kubernetes-sigs/secrets-store-csi-driver/issues/389

悲しいけどテストした結果をメモっておく

ref

rancher-desktop でこの通り試しました

https://developer.hashicorp.com/vault/tutorials/kubernetes/kubernetes-secret-store-driver

install vault with vault-csi-provider

helm install vault hashicorp/vault \
   --set "server.dev.enabled=true" \
   --set "injector.enabled=false" \
   --set "csi.enabled=true" \
   -n default

できた

$ k get pods
NAME                       READY   STATUS    RESTARTS   AGE
vault-csi-provider-k7rh8   2/2     Running   0          3m1s
vault-0                    1/1     Running   0          3m1s

vaultのroot tokenを探しておく。 root でした。GUIで確認しながら作業するため。

$ k logs  vault-0  | grep "Root Token"
Root Token: root

port forwardして http://localhost:8200 でGUIにアクセスできるようになる。loginはtoken選んで root といれる.

 k port-forward  vault-0 8200:8200 &

Screenshot 2024-08-29 at 22.00.14.png

vaultのsetupをしていく。まずvault podに入る

kubectl exec -it vault-0 -- /bin/sh

試すkey value secretを作る(vaultでは KV secret engineと呼ぶ)

vault kv put secret/db-pass password="db-secret-password"
vault kv get secret/db-pass

GUIでも作成されたのが確認できた
Screenshot 2024-08-29 at 22.00.24.png
Screenshot 2024-08-29 at 22.00.30.png

k8sとの認証?をセットアップする。ここがよくわからない。vault podの中からk8s apiを叩いて情報を取れるようにするためのrole, policyを作ってるみたい。これは webapp-sa という service accountに紐づくみたいだけど、ものすごーくあとで作るserviceaccountなのでずっと意味わからなかった

まず、最初はauthentication methodはこう
Screenshot 2024-08-29 at 22.01.55.png

vault auth enable kubernetes
vault write auth/kubernetes/config \
    kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443"

結果、こうなる 2行目のコマンドはGUIに何の変化も見えなかった
Screenshot 2024-08-29 at 22.02.03.png
Screenshot 2024-08-29 at 22.02.51.png

policy作る

vault policy write internal-app - <<EOF
path "secret/data/db-pass" {
  capabilities = ["read"]
}
EOF

Screenshot 2024-08-29 at 22.03.20.png

vault write auth/kubernetes/role/database \
    bound_service_account_names=webapp-sa \
    bound_service_account_namespaces=default \
    policies=internal-app \
    ttl=20m

Screenshot 2024-08-29 at 22.03.42.png

secretを作ってくれるやつをinstallする準備

helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts

install. 時間かかる.
helm install csi secrets-store-csi-driver/secrets-store-csi-driver \
    --set syncSecret.enabled=true

できた

kubectl  get pods -l "app=secrets-store-csi-driver"
NAME                                 READY   STATUS              RESTARTS   AGE
csi-secrets-store-csi-driver-fng9n   0/3     ContainerCreating   0          19s

こいつはいろんなものをinstallしていく。clusterrole, clusterrolebinding, csidriver etc

k get clusterrolebinding | grep secretp
secretprovidersyncing-rolebinding                      ClusterRole/secretprovidersyncing-role                             27s
secretproviderclasses-rolebinding                      ClusterRole/secretproviderclasses-role                             27s

k get clusterrolebinding | grep secret
secretprovidersyncing-rolebinding                      ClusterRole/secretprovidersyncing-role                             35s
secretproviderclasses-rolebinding                      ClusterRole/secretproviderclasses-role                             35s

k get clusterrole | grep secret
secretproviderclasses-admin-role                                       2024-08-29T13:24:24Z
secretproviderclasses-viewer-role                                      2024-08-29T13:24:24Z
secretproviderclasses-role                                             2024-08-29T13:24:24Z
secretprovidersyncing-role                                             2024-08-29T13:24:24Z
secretproviderclasspodstatuses-viewer-role                             2024-08-29T13:24:24Z

k get csidriver
NAME                       ATTACHREQUIRED   PODINFOONMOUNT   STORAGECAPACITY   TOKENREQUESTS   REQUIRESREPUBLISH   MODES       AGE
secrets-store.csi.k8s.io   false            true             false             <unset>         false               Ephemeral   54s

podもできた

$ kubectl get pods
NAME                                 READY   STATUS    RESTARTS   AGE
vault-csi-provider-w6kqk             2/2     Running   0          4m56s
vault-0                              1/1     Running   0          4m56s
csi-secrets-store-csi-driver-hsjtg   3/3     Running   0          101s

SecretProviderClassを作る。これはsecretをマウントさせるためのもの。あとでk8s secretにするやつに書き換えら得るが、ここではとりあえずマウントだけするためのやつ

cat > spc-vault-database.yaml <<EOF
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: vault-database
spec:
  provider: vault
  parameters:
    vaultAddress: "http://vault.default:8200"
    roleName: "database"
    objects: |
      - objectName: "db-password"
        secretPath: "secret/data/db-pass"
        secretKey: "password"
EOF
kubectl apply --filename spc-vault-database.yaml
$ kubectl get secretproviderclass
NAME             AGE
vault-database   39s
kubectl describe SecretProviderClass vault-database
Name:         vault-database
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  secrets-store.csi.x-k8s.io/v1
Kind:         SecretProviderClass
Metadata:
  Creation Timestamp:  2024-08-29T13:26:23Z
  Generation:          1
  Managed Fields:
    API Version:  secrets-store.csi.x-k8s.io/v1
    Fields Type:  FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .:
          f:kubectl.kubernetes.io/last-applied-configuration:
      f:spec:
        .:
        f:parameters:
          .:
          f:objects:
          f:roleName:
          f:vaultAddress:
        f:provider:
    Manager:         kubectl-client-side-apply
    Operation:       Update
    Time:            2024-08-29T13:26:23Z
  Resource Version:  978604
  UID:               f652fd46-4a2f-4ab8-8669-f9eb94f77e99
Spec:
  Parameters:
    Objects:  - objectName: "db-password"
  secretPath: "secret/data/db-pass"
  secretKey: "password"

    Role Name:      database
    Vault Address:  http://vault.default:8200
  Provider:         vault
Events:             <none>

ここでやっとserviceaccountを作る。vaultのk8s authで作ったやつ。

kubectl create serviceaccount webapp-sa
$ k get sa
NAME                       SECRETS   AGE
default                    0         16m
vault-csi-provider         0         13m
vault                      0         13m
secrets-store-csi-driver   0         5m17s
webapp-sa                  0         39s     <---------------

pod を作る。

cat > webapp-pod.yaml <<EOF
kind: Pod
apiVersion: v1
metadata:
  name: webapp
spec:
  serviceAccountName: webapp-sa
  containers:
  - image: jweissig/app:0.0.1
    name: webapp
    volumeMounts:
    - name: secrets-store-inline
      mountPath: "/mnt/secrets-store"
      readOnly: true
  volumes:
    - name: secrets-store-inline
      csi:
        driver: secrets-store.csi.k8s.io
        readOnly: true
        volumeAttributes:
          secretProviderClass: "vault-database"
EOF
kubectl apply --filename webapp-pod.yaml

secretが/mntにマウントされてるのがわかる

$ k describe pod webapp
Name:         webapp
Namespace:    default
Priority:     0
Node:         lima-rancher-desktop/192.168.5.15
Start Time:   Thu, 29 Aug 2024 22:27:07 +0900
Labels:       <none>
Annotations:  <none>
Status:       Pending
IP:
IPs:          <none>
Containers:
  webapp:
    Container ID:
    Image:          jweissig/app:0.0.1
    Image ID:
    Port:           <none>
    Host Port:      <none>
    State:          Waiting
      Reason:       ContainerCreating
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /mnt/secrets-store from secrets-store-inline (ro)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-8bzml (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             False
  ContainersReady   False
  PodScheduled      True
Volumes:
  secrets-store-inline:
    Type:              CSI (a Container Storage Interface (CSI) volume source)
    Driver:            secrets-store.csi.k8s.io
    FSType:
    ReadOnly:          true
    VolumeAttributes:      secretProviderClass=vault-database
  kube-api-access-8bzml:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  3s    default-scheduler  Successfully assigned default/webapp to lima-rancher-desktop
  Normal  Pulling    3s    kubelet            Pulling image "jweissig/app:0.0.1"

確かこれでsecretの中身が見れたはず。

kubectl exec webapp -- cat /mnt/secrets-store/db-password

次に SecretProviderClassを k8s secretにするやつに書き換える。

$ cat > spc-vault-database.yaml <<EOF
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: vault-database
spec:
  provider: vault
  secretObjects:
  - data:
    - key: password
      objectName: db-password
    secretName: dbpass
    type: Opaque
  parameters:
    vaultAddress: "http://vault.default:8200"
    roleName: "database"
    objects: |
      - objectName: "db-password"
        secretPath: "secret/data/db-pass"
        secretKey: "password"
EOF
 kubectl apply --filename spc-vault-database.yaml

pod側もk8s secretを使うようにする。

cat > webapp-pod.yaml <<EOF
kind: Pod
apiVersion: v1
metadata:
  name: webapp
spec:
  serviceAccountName: webapp-sa
  containers:
  - image: jweissig/app:0.0.1
    name: webapp
    env:
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: dbpass
          key: password
    volumeMounts:
    - name: secrets-store-inline
      mountPath: "/mnt/secrets-store"
      readOnly: true
  volumes:
    - name: secrets-store-inline
      csi:
        driver: secrets-store.csi.k8s.io
        readOnly: true
        volumeAttributes:
          secretProviderClass: "vault-database"
EOF

podを 削除 して作り直すと動く

$ kubectl delete pod webapp && kubectl apply --filename webapp-pod.yaml
pod "webapp" deleted
pod/webapp created

secretが作られていて

kubectl get secret dbpass
NAME     TYPE     DATA   AGE
dbpass   Opaque   1      8s

pod から envとして取れる

kubectl exec webapp -- env | grep DB_PASSWORD
DB_PASSWORD=db-secret-password

k8s secretを直接みると、ちゃんと入ってるね

$ kubectl get secret dbpass -o jsonpath='{.data.password}' | base64 -d
db-secret-password

ここから残念さに気づく

Vault GUI で KV のpasswordを更新した。

Screenshot 2024-08-29 at 22.31.51.png

しかし、全然k8s secretが更新されない。やっとわかったのは、それを利用しているpodが削除 -> 生成されると更新されるということだ。

podを削除して作り直す

$ kubectl delete pod webapp && kubectl apply --filename webapp-pod.yaml
pod "webapp" deleted
pod/webapp created

更新された!

kubectl get secret dbpass -o jsonpath='{.data.password}' | base64 -d
new-password

しかし、これじゃdowntimeが発生するじゃんか。deploymentでやってみよう。
一回podは消しておく

kubectl delete pod webapp

Deploymentを作る

$ cat deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
spec:
  replicas: 1 # Number of webapp pods to run
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      serviceAccountName: webapp-sa
      containers:
      - image: jweissig/app:0.0.1
        name: webapp
        env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: dbpass
              key: password
        volumeMounts:
        - name: secrets-store-inline
          mountPath: "/mnt/secrets-store"
          readOnly: true
      volumes:
      - name: secrets-store-inline
        csi:
          driver: secrets-store.csi.k8s.io
          readOnly: true
          volumeAttributes:
            secretProviderClass: "vault-database"

このあといろいろ試したんですけどダメでした。

  • k delete deployment して apply すると、secret は更新される
  • k rollout restart しても secret は古いまま
  • k delete pod しても、secret は古いまま。
    • あくまで SecretProviderClass を使っているのは deployment だから、 deployment が削除されないと secret を更新する契機にならない様子

ここでissueを見に行って絶望しました

切ない意見

Not having each pod contain a consistent view of the external secret in a way that can be updated declaratively is a dealbreaker for this driver.
各ポッドに、宣言的に更新できる方法で外部シークレットの一貫したビューが含まれていないことは、このドライバーにとって致命的です。
https://github.com/kubernetes-sigs/secrets-store-csi-driver/issues/389

諦め!残念!

何かいい方法があれば教えて〜

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?