Sealed Secretsを試してみた

Sealed Secrets は Secretリソースを暗号化してくれるものです。
今いる現場でも手動デプロイしているので、Gitで管理すべく試してみました。

今回はRancherで構築したラズパイクラスタ で試します。

ubuntu@k8s1:~$ kubectl get node -o wide
NAME   STATUS   ROLES               AGE   VERSION    INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME
k8s1   Ready    controlplane,etcd   15d   v1.24.13   192.168.0.51   <none>        Ubuntu 20.04.6 LTS   5.4.0-1089-raspi   docker://20.10.24
k8s2   Ready    worker              15d   v1.24.13   192.168.0.52   <none>        Ubuntu 20.04.6 LTS   5.4.0-1069-raspi   docker://20.10.24
k8s3   Ready    worker              15d   v1.24.13   192.168.0.53   <none>        Ubuntu 20.04.6 LTS   5.4.0-1089-raspi   docker://20.10.24

ラズパイにkubesealインストール

手順はこちら
今回はコントロールプレーンにkubesealをインストールします。
arm64版があるので、ラズパイでも使えます。

ubuntu@k8s1:~$ wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.23.0/kubeseal-0.23.0-linux-arm64.tar.gz
ubuntu@k8s1:~$ tar -xvzf kubeseal-0.23.0-linux-arm64.tar.gz kubeseal
kubeseal
ubuntu@k8s1:~$ sudo install -m 755 kubeseal /usr/local/bin/kubeseal
ubuntu@k8s1:~$ kubeseal --version
kubeseal version: 0.23.0

Controllerのインストール

手順はこちら
Rancherで構築したダウンストリームクラスターなのでRancher GUIを使います。

まずリポジトリを作成します。

sealed_secrets_01.png

Chartsに出てくると思います。

sealed_secrets_02.png

最新のv0.23.0がインストールできるようです。

sealed_secrets_03.png

Rancher名前空間ちゃんと作ってくれないので、あらかじめ作成してます。

sealed_secrets_04.png

サービス名を固定したいのでfullnameOverrideだけ指定しています。

sealed_secrets_05.png

以下のリソースが作られました。

ubuntu@k8s1:~$ kubectl get all -n sealed-secrets-system
NAME                                             READY   STATUS    RESTARTS   AGE
pod/sealed-secrets-controller-68b55774fd-lf7gw   1/1     Running   0          95s

NAME                                TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/sealed-secrets-controller   ClusterIP   10.43.227.84   <none>        8080/TCP   95s

NAME                                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/sealed-secrets-controller   1/1     1            1           95s

NAME                                                   DESIRED   CURRENT   READY   AGE
replicaset.apps/sealed-secrets-controller-68b55774fd   1         1         1       96s
ubuntu@k8s1:~$ kubectl get secret -n sealed-secrets-system
NAME                                                TYPE                 DATA   AGE
sealed-secrets-keygt242                             kubernetes.io/tls    2      2m59s
sh.helm.release.v1.sealed-secrets-2-1690010267.v1   helm.sh/release.v1   1      3m7s

使ってみる

こちら の手順で試してみます。

ubuntu@k8s1:~$ echo -n bar | kubectl create secret generic mysecret --dry-run=client --from-file=foo=/dev/stdin -o json >mysecret.json
ubuntu@k8s1:~$ cat mysecret.json 
{
    "kind": "Secret",
    "apiVersion": "v1",
    "metadata": {
        "name": "mysecret",
        "creationTimestamp": null
    },
    "data": {
        "foo": "YmFy"
    }
}

fooのbarがYmFyになってますね。

kubesealで暗号化したSealedSecret作ります。

ubuntu@k8s1:~$ kubeseal <mysecret.json >mysealedsecret.json
error: cannot get sealed secret service: services "sealed-secrets-controller" not found.
Please, use the flag --controller-name and --controller-namespace to set up the name and namespace of the sealed secrets controller

サービス名と名前空間を指定しないといけないようです。

ubuntu@k8s1:~$ kubeseal --controller-name sealed-secrets-controller --controller-namespace sealed-secrets-system <mysecret.json >mysealedsecret.json
ubuntu@k8s1:~$ cat mysealedsecret.json 
{
  "kind": "SealedSecret",
  "apiVersion": "bitnami.com/v1alpha1",
  "metadata": {
    "name": "mysecret",
    "namespace": "default",
    "creationTimestamp": null
  },
  "spec": {
    "template": {
      "metadata": {
        "name": "mysecret",
        "namespace": "default",
        "creationTimestamp": null
      }
    },
    "encryptedData": {
      "foo": "AgAJ+P3zx55lVc8/6fyGLo6xjcrrBxElkD/2ZS4GZaK3bClojzam4JASH/0GBZyWqrh0pnoKbtKlBhDe9EIA0+dDz2L5Rizc0UjZdgttVmYTboLjvjbYUFPOdK5/Mk0GcYnIrhYskJQCKFc2Nehlx28Uckfex7UUYV2JZtXEc4niNacBPtFDdypUJQh7LEMcJ8m/Zs0jMgcfrs9y/A+f3JDdWIQicVr/9Uyo5lGrsJxCovIPlyxiBL3uy1V5yn9V5tbpm5l5H+yOdW3l6+/CU+QrUQUbHdJv0Y17IxXvUM4dpnrKUeVXUJ/e9cbmBHx9TzHyl0quBmQ9sC1+KOqf/AbfSz6TFexIww2ALkkxXFKKn8VwRhc3vvbUuyDZQ7mhn0xjaGetZsUjHcPKeupm9RHDrcKZ2fC/CELQQF5HT3YL1EZ9PuzMkvsbzX5rIar7d8EJA+9tIy5l45/fzLw1no5ABtozrXFDBXNl8gK9xzbUmNnGCR+U7lw2HNlxStwctFpT7P0cmToz90AKWBGToBWkChDgsDmUfFGVBXWwOo9dNzb6K+QLZBzJA8k44wM7EEjCpzU9AryreOwP6JzfD+QnCvHtGMu/ZtjPVEqAosWyJvRGznT6Nef6JVHuH7AUf1yeq/qFh7F9k9KD45o9Z3NoGQ3dbgSciTU4qOCI0noYHbkV+EM01tqonq36BTPiKFIsAlc="
    }
  }
}

無事barが暗号化されたSealedSecretが作成できたようです。

クラスタにデプロイしてみます。

ubuntu@k8s1:~$ kubectl create -f mysealedsecret.json
sealedsecret.bitnami.com/mysecret created
ubuntu@k8s1:~$ kubectl get secret mysecret
NAME       TYPE     DATA   AGE
mysecret   Opaque   1      12s
ubuntu@k8s1:~$ kubectl get secret mysecret -o yaml
apiVersion: v1
data:
  foo: YmFy
kind: Secret
metadata:
  creationTimestamp: "2023-07-22T07:26:44Z"
  name: mysecret
  namespace: default
  ownerReferences:
  - apiVersion: bitnami.com/v1alpha1
    controller: true
    kind: SealedSecret
    name: mysecret
    uid: b9aae13d-9c73-4858-ad62-e719b3aa78f8
  resourceVersion: "5350956"
  uid: 91fa0a2b-0a47-4777-a024-7ee72390808a
type: Opaque
ubuntu@k8s1:~$ kubectl get secret mysecret -o jsonpath="{.data.foo}" | base64 -d
bar

デプロイした後でデコードしたらbarが戻ってきた!
なるほど。

GitLabからデプロイ

こちら で作成したGitLabのKASを使ってGitLabからpodにデプロイしてみます。
まずkubesealでファイルからSealedSecretリソースを作成します。

ubuntu@k8s1:~$ echo -n 'P@ssw0rd' > ./password.txt
ubuntu@k8s1:~$ cat password.txt 
P@ssw0rd
ubuntu@k8s1:~$ kubectl create secret generic mypassword --from-file=./password.txt --dry-run=client -o yaml > mypassword.yaml
ubuntu@k8s1:~$ kubeseal --controller-name sealed-secrets-controller --controller-namespace sealed-secrets-system --secret-file mypassword.yaml --format yaml > mysealedpassword.yaml
ubuntu@k8s1:~$ cat mysealedpassword.yaml
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  creationTimestamp: null
  name: mypassword
  namespace: default
spec:
  encryptedData:
    password.txt: AgCjTiDrWVaBag5dXyiXX7LdPlfIR+QzLz92hlxOv7/InTt14d1+VlMxQHZx0F0lfG8H24/xA0jlTx91x3SB1cJQpkETZe+sLeo0kdibgFYdzWiJ4pwYW1iP3Qyu1KCrQY0XlZwnmE3uNDc9o8UZBdxhLPHdHJg7hPHWAMa96x4ZnyYP95ezC0rqKZn8Z0qz1kRuDkOIDuAfTtL+nVUTAD2kqrOw+QlD8Dx/zqGksh+fBEo6pq5kN+1+pLVRPhF3GeuaSB7fngLuCxceQslDFmwOk3d90aSUQEo+PaN+jJm9SqnzLPkbWCEd5EX3MGbt8NPqnG5tg2iCyABAaytV9L6EyxvRpNPIW/p4Z+uRRsmmRimDizP/IgFXpdglDQbll30a8LLbhcJ1StiJLRLPSJ3/I/docIaCMgMlQ8aLT8G63Fx57XaEJCVWrUP1oOT8nqJ9V0Awuz3A2T8a5dzSBinrRIG1cwFS6Aia057PQCWz7pHrMGtu+x+TRFTDkkFeLqA1zHoImsnasEyNWemkR5rpxmyFHJl9+GzsjtR/yvVh6E1aTiX+t6avc1P6ysbi6A80Hct5T8X/lRzn45FTGy22yAnVMkNxlmzMl+xuGtiRhbJgxMfSU77VYa8QECdnMMYGDd8BeWgnrKjb9qykQGGz4T1S5s754xj1Z6hiEgfbLmuHf9aUMTC4aKGxz0s8ZQjVGh66tM8Ctw==
  template:
    metadata:
      creationTimestamp: null
      name: mypassword
      namespace: default

これでgitで管理しても安心。

sealed_secrets_06.png

SealedSecretリソースをpodにマウントして試してみたいので以下のようなyamlを準備します。

ubuntu@k8s1:~/my-project$ cat nginx.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:latest
        name: nginx
        resources: {}
        volumeMounts:
        - name: secret
          mountPath: "/tmp"
      volumes:
      - name: secret
        secret:
          secretName: mypassword
          items:
          - key: password.txt
            path: secret
status: {}

デプロイするために.gitlab-ci.ymlは以下のようにします。

ubuntu@k8s1:~/my-project$ cat .gitlab-ci.yml
deploy:
  stage: deploy
  image:
    name: bitnami/kubectl:latest
    entrypoint: ['']
  script:
    - kubectl config get-contexts
    - kubectl config use-context root/my-project:my-agent
    - kubectl apply -f ./mysealedpassword.yaml
    - kubectl apply -f ./nginx.yaml

以下のようなファイル構成にします。

my-project/
├── .gitlab-ci.yml
├── README.md
├── mysealedpassword.yaml
└── nginx.yaml

GitLabにpushします。
うまくいけば以下のようにジョブが成功します。

sealed_secrets_07.png

マウントできているか確認します。

ubuntu@k8s1:~/my-project$ kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-7d86865557-29ncz   1/1     Running   0          9m32s
ubuntu@k8s1:~/my-project$ kubectl exec -it nginx-7d86865557-29ncz -- cat /tmp/secret
P@ssw0rd

平文でマウントされていますね!
まだバージョン1にもなっていないalpha版のようですが、良さそうですね。