--- title: Quarks SecretでKubernetesのSecretをサーバーサイドで自動生成させる tags: ["Kubernetes", "Quarks", "Quarks Secret"] categories: ["Dev", "CaaS", "Kubernetes", "Secret", "QuarksSecret"] date: 2020-09-19T14:55:56Z updated: 2020-09-19T15:22:18Z --- Kubernetesのmanifestをgitで管理するとき、`Secret`の扱いが課題になりがちです。 基本的にデプロイに必要なKubernetesリソースのyamlは全てGitに管理したいですが、 `Secret`リソースは機密情報がbase64エンコードまたは平文で保存されており、 Kubernetesの`Secret`をサポートするプロジェクトとして、 * [External Secrets](https://github.com/godaddy/kubernetes-external-secrets) * [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) が有名です。 External Secretsでは`Secret`の内容をHashicorp VaultやAWS Secrets Managerといった外部のSecret Managerに管理します。 `ExternalSecret`リソースに外部Secret Managerの参照を定義し、そこから`Secret`オブジェクトを生成します。 `ExternalSecret`リソースのYAMLはgit管理可能です。 Sealed Secretsでは`SealedSecret`リソースにクライアントサイドで暗号化した`Secret`の内容を設定し、サーバーサイドで復号して`Secret`オブジェクトを生成します。暗号化には`kubeseal` CLIを使用します。 `SealedSecret`リソースのYAMLはgit管理可能です。 どちらも汎用的に`Secret`を扱えますが、動機が"自動生成したパスワードを`Secret`に設定したい"だけであれば、 手間が大きく、やりたいことに対して複雑に感じます。 サーバーサイドでパスワードや証明書を自動生成したいだけであれば、[Quarks Secret](https://quarks.suse.dev/docs/quarks-secret/)がシンプルです。 Quarks Secretの簡単な使い方を紹介します。 > Note: [Quarks](https://quarks.suse.dev)はSuseが主に開発を進めている、Cloud FoundryのBOSHでデプロイしていたソフトウェアをKubernetesにデプロイするために変換するController群です。
その中でもQuarks SecretはBOSHで使われていた機密情報自動生成機能を移行したもので、この部分だけスタンドアローンで利用できます。 同様なツールとしては[secretgen-controller](https://github.com/k14s/secretgen-controller)があります。 ### Quarks Secretのインストール インストールはHelmで行います。 ``` helm repo add quarks https://cloudfoundry-incubator.github.io/quarks-helm/ helm install qsecret quarks/quarks-secret --namespace quarks --create-namespace --wait ``` インストールが完了したら、`quarkssecrets.quarks.cloudfoundry.org`というカスタムリソースが出来ます。 ``` $ kubectl get crd | grep quarks quarkssecrets.quarks.cloudfoundry.org 2020-09-19T13:27:52Z ``` この`QuarksSecret`オブジェクトを作成すると`Secret`オブジェクトを自動生成できます。自動生成できる`Secret`の種類は * `password` * `certificate` * `tls` * `ssh` * `rsa` * `basic-auth` * `dockerconfigjson` * `copy` * `templatedconfig` です。個々の使い方は[ドキュメント](https://quarks.suse.dev/docs/quarks-secret/)と[サンプル](https://github.com/cloudfoundry-incubator/quarks-secret/tree/master/docs/examples)で学べます。 デフォルトでは`staging` Namespaceのみ監視対象になります。 他のNamespaceも対象としたい場合は、`Namespace`リソースの`quarks.cloudfoundry.org/monitored`ラベルに`qsecret-quarks-secret`(Helmでインストールした場合のデフォルト値)を設定する必要があります。 この設定がないと`QuarksSecret`オブジェクトを作成しても`Secret`は生成されません。 ここでは`default` Namespaceにそのラベルを設定します。 ``` kubectl patch namespace default --type=json -p '[{"op": "add", "path": "/metadata/labels", "value": {"quarks.cloudfoundry.org/monitored": "qsecret-quarks-secret"}}]' ``` ### Passwordの自動生成 次の`demo.yml`を作成します。 ```yaml apiVersion: quarks.cloudfoundry.org/v1alpha1 kind: QuarksSecret metadata: name: demo spec: type: password secretName: demo ``` ``` $ kubectl apply -f demo.yml quarkssecret.quarks.cloudfoundry.org/demo created ``` `QuarksSecret`リソースを作成すると`demo`という名前の`Secret`ができていることがわかります。 ``` $ kubectl get secret,quarkssecret demo NAME TYPE DATA AGE secret/demo Opaque 1 5s NAME COPIED GENERATED quarkssecret.quarks.cloudfoundry.org/demo true true ``` 生成された`Secret`の値(`password`)を確認します。 ``` $ kubectl get secret demo -o go-template='{{index .data "password" | base64decode}}' niBhcLk5NKBOSDeA6cS1APeKcmIFppNGKcyCRuZCq8lnJf9PfMbhC15ezuAbeTfE ``` ### Passwordのローテート Passwordはローテート可能です。次のような`rotate.yml`を作成します。 ```yaml apiVersion: v1 kind: ConfigMap metadata: name: rotate labels: quarks.cloudfoundry.org/secret-rotation: "true" data: secrets: '["demo"]' ``` ``` $ kubectl apply -f rotate.yml quarkssecret.quarks.cloudfoundry.org/demo created ``` 生成された`password`の値を確認します。 ``` $ kubectl get secret demo -o go-template='{{index .data "password" | base64decode}}' 57BzENCpDmqFBVrnxOoMnlZzEvfA0iGY2S5cmV9cJVK2p4cwWbtgCY35wmKOcXGN ``` ### Basic Authの自動生成 ユーザー名、パスワードをまとめて生成できます。次の`auth.yml`を作成します。 ```yaml apiVersion: quarks.cloudfoundry.org/v1alpha1 kind: QuarksSecret metadata: name: auth spec: type: basic-auth secretName: auth ``` ``` $ kubectl apply -f auth.yml quarkssecret.quarks.cloudfoundry.org/auth created ``` `kubernetes.io/basic-auth` Typeの`Secret`が生成されます。 ``` $ kubectl get secret,quarkssecret auth NAME TYPE DATA AGE secret/auth kubernetes.io/basic-auth 2 33s NAME COPIED GENERATED quarkssecret.quarks.cloudfoundry.org/auth true true ``` 生成された`Secret`の値(`username`及び`password`)を確認します。 ``` $ kubectl get secret auth -o go-template='{{index .data "username" | base64decode}}' wfdfcank0141g7B6hCbl7953uzFWofYp8RKQAgsEyVbEeSPPCj2Q46wf5lGHfbWY $ kubectl get secret auth -o go-template='{{index .data "password" | base64decode}}' ZtsfXWGfqqDHlMjBJchLHDER3uN2m8nvmq2P6qon5zQvVkWoG5tYAtQQbrH9V0Iq ``` ### アプリケーションのサンプル 実用例として、gitで管理するアプリケーションのマニフェストサンプルを示します。 `hello.yml`を作成します。このファイルはgitで管理できますし、これ以外のファイルは管理する必要がありません。 ```yaml apiVersion: v1 kind: Namespace metadata: name: demo labels: quarks.cloudfoundry.org/monitored: qsecret-quarks-secret --- apiVersion: quarks.cloudfoundry.org/v1alpha1 kind: QuarksSecret metadata: name: hello-password namespace: demo spec: type: password secretName: hello-password --- apiVersion: apps/v1 kind: Deployment metadata: namespace: demo name: demo labels: app: demo spec: replicas: 1 selector: matchLabels: app: demo template: metadata: labels: app: demo spec: containers: - name: hello image: ghcr.io/making/hello env: - name: SPRING_SECURITY_USER_PASSWORD valueFrom: secretKeyRef: name: hello-password key: password --- apiVersion: v1 kind: Service metadata: namespace: demo name: demo labels: app: demo spec: ports: - name: http port: 80 protocol: TCP targetPort: 8080 selector: app: demo type: ClusterIP ``` ``` kubectl apply -f hello.yml ``` `Service`をPort Forwardします。 ``` kubectl port-forward -n demo service/demo 8080:80 ``` 生成されたパスワードを取得します。 ``` PASSWORD=$(kubectl get secret -n demo hello-password -o go-template='{{index .data "password" | base64decode}}') ``` パスワード有無でそれぞれアクセスします。 ``` $ curl localhost:8080 -v > GET / HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.64.1 > Accept: */* > < HTTP/1.1 401 < Set-Cookie: JSESSIONID=C88CB80B86495DBF086159105F93FBE2; Path=/; HttpOnly < WWW-Authenticate: Basic realm="Realm" < X-Content-Type-Options: nosniff < X-XSS-Protection: 1; mode=block < Cache-Control: no-cache, no-store, max-age=0, must-revalidate < Pragma: no-cache < Expires: 0 < X-Frame-Options: DENY < Content-Type: application/json < Transfer-Encoding: chunked < Date: Sat, 19 Sep 2020 14:40:55 GMT < {"timestamp":"2020-09-19T14:40:55.679+00:00","status":401,"error":"Unauthorized","message":"","path":"/"} $ curl localhost:8080 -u user:${PASSWORD} -v > GET / HTTP/1.1 > Host: localhost:8080 > Authorization: Basic dXNlcjpHY1hSall6c2J5MzRCaENGb3FUclk0Nm94VjhicFQ5UUNJRFBIUkY2U05ROXFBb0RHSm9lazRlUE1JblVsblZO > User-Agent: curl/7.64.1 > Accept: */* > < HTTP/1.1 200 < Set-Cookie: JSESSIONID=6AE2EF09AEFA5F44EA4C32F4A3A5A9D6; Path=/; HttpOnly < X-Content-Type-Options: nosniff < X-XSS-Protection: 1; mode=block < Cache-Control: no-cache, no-store, max-age=0, must-revalidate < Pragma: no-cache < Expires: 0 < X-Frame-Options: DENY < Content-Type: text/plain;charset=UTF-8 < Content-Length: 15 < Date: Sat, 19 Sep 2020 14:52:04 GMT < Hello World! ``` --- Quarks Secretで簡単にサーバーサイドでパスワードを自動生成できました。 シンプルな例であれば、`Secret`だけGitとは別に管理するという面倒くさいことをしなくても済みます。