はじめに
前回の記事で気になっていた Vault のauto-unseal
とauto-join
について、実際に試してみた記録です。今回試してみたリポジトリはこちら
https://github.com/tunamaguro/try-vault-heal-join
この例ではすぐに環境を壊しているので機密情報を含むデータを掲載していますが、実際に行われる場合は慎重に扱ってください。
また、掲載するデータには注意をしているつもりですが、もし載せてはいけない情報が書いてあった場合、Twitter の DM などでこっそり教えていただけると助かります。
auto-unseal を有効化する
とりあえず公式ドキュメントを読みます。
https://developer.hashicorp.com/vault/docs/configuration/seal
ざっくり読んだ感じ AWS や GCP,Azure の暗号化キー管理サービスを暗号化に用いることで、面倒だったunseal
を省いてくれるらしいです。
なので、事前に各サービスで鍵を生成しておく必要があります。今回は安いという理由で GCP を利用しました。
適当なプロジェクトを作成した後、GCP での unsealチュートリアルを参考に
サービスアカウントを作成します。今回は次の権限を与えて作成しました。
このサービスアカウントを利用するための鍵をcredentials.json
という名前でダウンロードしておきます
次にキーリングを作成します。GCP を全然触ったことがないのでよくわかっていませんが、暗号化に利用する鍵をまとめて管理するための何かだと思っています。 リージョンについてもここを変えると何が変わるのか分かっていませんが、チュートリアル見た感じ global で作られている風だったので揃えました
その後鍵を作成します
ここまでで GCP での作業は終了して、kubernetes での作業に移ります。先ほどダウンロードしたcredentials.json
を Secret として作成します
kubectl create ns vaultkubectl create secret generic gcp-kms-sa --from-file=credentials.json -n vault
こんな感じのシークレットができるはずです
apiVersion: v1data: credentials.json: keykind: Secretmetadata: creationTimestamp: null name: gcp-kms-sa namespace: vault
その後この認証ファイルを vault がマウントして利用できるように設定ファイルを書き換えます。 ドキュメントを読む限りすべての設定値は環境変数に設定すれば良さそうなので、セキュリティを考えるなら Secret から利用したほうがよいと思います
https://developer.hashicorp.com/vault/docs/configuration/seal/gcpckms#gcpckms-parameters
injector: enabled: falseserver: enabled: true affinity: "" standalone: enabled: true config: | ui = true listener "tcp" { tls_disable = 1 address = "[::]:8200" cluster_address = "[::]:8201" # Enable unauthenticated metrics access (necessary for Prometheus Operator) #telemetry { # unauthenticated_metrics_access = "true" #} } storage "file" { path = "/vault/data" } seal "gcpckms" { credentials = "/vault/userconfig/credentials.json" project = "test-vault-auto-unseal" region = "global" key_ring = "vault-auto-unseal" crypto_key = "unseal-key" } # https://github.com/hashicorp/vault-helm/blob/main/values.yaml#L592-L605 volumes: - name: gcp-creds secret: secretName: gcp-kms-sa volumeMounts: - name: gcp-creds readOnly: true mountPath: /vault/userconfig
これをargocd sync
するとポッドが作成はされますが Ready にはまだなりません。チュートリアルにも記載がありましたが、はじめのoperator init
だけは手動で行う必要があるようです
kubectl get pod -n vaultNAME READY STATUS RESTARTS AGEvault-0 0/1 Running 0 20s
初期化を行います
kubectl -n vault exec -it vault-0 -- vault operator initRecovery Key 1: fV8mxmHf3BqcAA/xhxRaX+WfkKChTY1Fqi9ECymPISweRecovery Key 2: T8Ilnd28apSs7teRfVlaUJwBQLrKp/Cii67tI5V5B41/Recovery Key 3: stQAoWyK0bsZWDShSMzmO8ioSw7ZDLthLKHMLFytdDHSRecovery Key 4: uHonbQLQY4hhS1K3vxtA7pxzwKE/lsmf7IReX5V0j/zERecovery Key 5: hIYKIAjTmxD7RxhPwoAXq/QGWJNMF2lgGsQ05srC6Dsd
Initial Root Token: hvs.cZIXK5JkorY2X3Bua2hFu4SU
Success! Vault is initialized
Recovery key initialized with 5 key shares and a key threshold of 3. Pleasesecurely distribute the key shares printed above.
状態を確認するとvault operator unseal
しないと True のままだった Sealed が、何もしなくても False になっています
kubectl -n vault exec -it vault-0 -- vault statusKey Value--- -----Recovery Seal Type shamirInitialized trueSealed falseTotal Recovery Shares 5Threshold 3Version 1.15.2Build Date 2023-11-06T11:33:28ZStorage Type fileCluster Name vault-cluster-07b4349eCluster ID 2d16b1bd-6586-68f3-8a0d-70d78b32db1fHA Enabled false
auto-join を有効にする
https://developer.hashicorp.com/vault/tutorials/raft/raft-storage#retry-join
HA 化した際のストレージとして Raft を用いる場合、各ポッドでvault operator raft join
を実行しないといけませんでした。ポッドが落ちるたびにこんなことをやりたくないので、自動で Raft クラスターに接続してもらうように設定します。
ドキュメントによると、retry_join
に接続先サーバのアドレスを書けば良さそうなので設定を追加します
server: ha: enabled: true replicas: 3 raft: enabled: true config: | ui = true
listener "tcp" { tls_disable = 1 address = "[::]:8200" cluster_address = "[::]:8201" # Enable unauthenticated metrics access (necessary for Prometheus Operator) #telemetry { # unauthenticated_metrics_access = "true" #} }
storage "raft" { path = "/vault/data" retry_join { leader_api_addr = "http://vault-0.vault-internal:8200" } retry_join { leader_api_addr = "http://vault-1.vault-internal:8200" } retry_join { leader_api_addr = "http://vault-2.vault-internal:8200" } }
seal "gcpckms" { credentials = "/vault/userconfig/credentials.json" project = "test-vault-auto-unseal" region = "global" key_ring = "vault-auto-unseal" crypto_key = "unseal-key" }
service_registration "kubernetes" {}
raft.enabled を true にしないとうまく動かなかったので注意。config も raft の下のものに書く必要がありました。ここでしばらく沼にはまり 30 分程度ムダにしました。皆さんは Helm の説明をよく読みましょう
これをデプロイすると下のようになります。意図通り 3 個ポッドがあり HA 用の設定になっているようです
例によって初期化はまだされていないので、vault operator init
します
kubectl -n vault exec -it vault-0 -- vault operator initRecovery Key 1: mOOF7BS2/8RQkT46padw9+Rpm28BzS1f0fH3fsLWCagdRecovery Key 2: VsIULAhtLJ5lVd7RiuiaHUWetXzBnBVm0uBuJwuYZsaPRecovery Key 3: umJeEcI+9uvsCakwns21KSOW3bkoo2zYoa+ZMca85hapRecovery Key 4: 00UezpLDHNmstgTkrge8RmCEDae3N6fsTPBjy5GNMjWgRecovery Key 5: micAIuoSedL/gkDo3gZX9pediYm6nxF9x87wX/LRCd1r
Initial Root Token: hvs.KIi1gwnfMWYdOhuMrOpSbA2M
Success! Vault is initialized
Recovery key initialized with 5 key shares and a key threshold of 3. Pleasesecurely distribute the key shares printed above.
kubectl -n vault exec -it vault-0 -- vault statusKey Value--- -----Recovery Seal Type shamirInitialized trueSealed falseTotal Recovery Shares 5Threshold 3Version 1.15.2Build Date 2023-11-06T11:33:28ZStorage Type raftCluster Name vault-cluster-69bba5eaCluster ID 7bc17321-5c56-6dbc-c906-ab5937bfe5e1HA Enabled trueHA Cluster https://vault-0.vault-internal:8201HA Mode activeActive Since 2024-01-12T14:44:42.866364051ZRaft Committed Index 61Raft Applied Index 61
vault-0
の初期化は無事完了し、auto-unseal まで行われたことが確認できます。ほかのポッドも同じようになっているか確認します
kubectl -n vault exec -it vault-1 -- vault statusKey Value--- -----Recovery Seal Type shamirInitialized trueSealed falseTotal Recovery Shares 5Threshold 3Version 1.15.2Build Date 2023-11-06T11:33:28ZStorage Type raftCluster Name vault-cluster-69bba5eaCluster ID 7bc17321-5c56-6dbc-c906-ab5937bfe5e1HA Enabled trueHA Cluster https://vault-0.vault-internal:8201HA Mode standbyActive Node Address http://10.244.3.11:8200Raft Committed Index 63Raft Applied Index 63
kubectl -n vault exec -it vault-2 -- vault statusKey Value--- -----Recovery Seal Type shamirInitialized trueSealed falseTotal Recovery Shares 5Threshold 3Version 1.15.2Build Date 2023-11-06T11:33:28ZStorage Type raftCluster Name vault-cluster-69bba5eaCluster ID 7bc17321-5c56-6dbc-c906-ab5937bfe5e1HA Enabled trueHA Cluster https://vault-0.vault-internal:8201HA Mode standbyActive Node Address http://10.244.3.11:8200Raft Committed Index 64Raft Applied Index 64
どのポッドも初期化が完了し vault クラスターが動き始めました
一応 CLI 上でも確認しておきます
vault loginvault operator raft list-peersNode Address State Voter---- ------- ----- -----01b0c5aa-a16f-8bbf-9e02-082e1fa55432 vault-0.vault-internal:8201 leader trueb4292c3d-7127-7272-38bd-8a3e682d61dc vault-2.vault-internal:8201 follower truec6ea822c-1d43-3c0b-9932-dac4465574a6 vault-1.vault-internal:8201 follower true
後片付け
作製した kubernetes クラスターと GCP 上のリソースは忘れないうちに消しておきましょう
kind delete clusters vault-testDeleted nodes: ["vault-test-control-plane" "vault-test-worker" "vault-test-worker3" "vault-test-worker2"]Deleted clusters: ["vault-test"]
後書き
auto-unseal
とauto-join
を設定しておけば、簡単に秘密鍵を管理する基盤をお家 kubernetes 上に構築できそうでした。
とくに今回で一番面倒だったのは、GCP プロジェクト作成~キーリング作成あたりなので、ここら辺を Terraform を使って自動化できれば、
お家 kubernetes に簡単に導入することも夢じゃなさそうだと思います。今度はそれをやりながらお家 kubernetes の設定ファイルを公開する作業を進めたいです