この記事はKubernetes Advent Calendar 2019の12日目の記事です。
こんにちは、普段はWebの会社でインフラエンジニアとして働いてます、gotoken(@kennygt51)です。今回は、Vault × Kubernetesというテーマで、以下の3点についてまとめました。
・HashiCorp社のVaultとはなにか
・Vault on Kubernetesを構築するチュートリアルのまとめ
・Production-ready Vault on Kubernetesに向けての考慮ポイント
HashiCorp社のVaultとはなにか
Vaultとは
そもそもVaultが何なのかよく知らないという人もいるかと思いますので、概要をおさらいしましょう。Vaultを使ったことがある人は読み飛ばして頂いて構いません。
Vaultとは、HashiCorp社が開発したOSSで、秘匿情報を管理・保護する為のソフトウェアです。 秘匿情報をセキュアに保存するとともに、秘匿情報へのアクセスコントロールを適切に制御する機能を提供します。
公式ドキュメントによると、以下の特徴があります。
Secrets Management
- アプリケーション・インフラ・システム全体で秘匿情報を集中管理する
- クラウドとDCをまたいでいても関係ない
- Dynamic Secrets
- 暗号化された秘匿情報を保存する
- 秘匿情報の保存先は拡張性が高い
- Secret Engineという仕組みで、様々な秘匿情報を管理できる
- 監査ログを細かく保存できる
- TokenのRevokeを時間ベースでおこなうなど、セキュアな設計
Data Encryption
- API-driven Encryption
- アプリケーションのデータを暗号化して保存する
- データを暗号化する為のキーを提供する
- 分散されたインフラ全体で、キーのアップデート・更新ができる
Identity-based Access
- IdentityにPolicyを割り当てることで柔軟な認可の制御ができる
- Multi-Factor Authentication
Vaultのユースケース
Kubernetes環境で秘匿情報を管理する方法としては、Vaultの他にも様々な手法があります。個人的な見解としては、以下のような秘匿情報管理の要件がある場合にVaultは技術選定の候補として挙がるかなと考えています。
- 管理すべき秘匿情報が大量にある場合
- 各アプリケーションやチーム毎に秘匿情報に対する適切なアクセスコントロールを実現したい場合
- 秘匿情報の管理をセントラルなインフラチームから開発チームに委譲していきたい場合
- Audit Logを適切に取得・管理したい場合(統制的な要件)
Architecture
VaultをKubernetes上に構築するにあたって、最低限知っておくべきVaultのアーキテクチャについて説明します。
基本
基本的にはクライアントサーバモデルです。Vault Servertに対して、クライアントからHTTP APIでアクセスします。curlなどを使って直接APIを叩く方法もありますが、APIをラップして簡単にVaultにアクセスできるVault CLIを使うのが便利です。Vault CLIは単一のバイナリで動くので、インストールも簡単です。公式ドキュメントからダウンロードできます。
Storage Backend
Storage Backendとは暗号化されたデータの恒久的な保存に責務を持つコンポーネントです。Vault Serverのconfigに設定するだけで、秘匿情報の保存先を柔軟に選択することができます。
設定可能なStorage Backendはこちらに一覧があります。MySQLやPostgreSQLなどのRDBに加えて、S3やDynamoDBなどのマネージドサービスを使うこともできます。
以下は、DynamoDBをStorage Backendに設定したconfigの例です。
storage "dynamodb" {
ha_enabled = "true"
region = "ap-northeast-1"
table = "vault-table"
}
Seal / Unseal
Vault Serverが起動すると、最初はsealed
というステータスで起動します。この状態では、保存されたSecretを取得することができません(Vaultは起動時にデータ復号用のMaste Keyを持っていない)
Vaultに対するあらゆるオペレーションを行う際にはUnseal
というプロセスを通してsealed
ステータスをunsealed
に変更する必要があります。
High Availability
Vaultは、Production運用時のダウンタイムを極小化する為に、HAをサポートしています。ただし選択するStorage BackendによってはHAをサポートしていないケースがあるので、注意が必要です。
例えば、S3はHAをサポートしていないので、Storage BackendにS3を選択すると、HAモードでVaultを起動することができません。
Policy
Policyによって、保存した秘匿情報に対するアクセス制御をおこないます。
より詳しくVaultのアーキテクチャについて知りたい場合は、公式ドキュメントを参照ください。 また以前に僕が書いた公式ドキュメントをざっくりと訳してまとめた記事も参考になるかと思います。
Vault on Kubernetesを構築するチュートリアルのまとめ
さっそく、Vault on Kubernetesをローカル環境で動かしてみましょう。大変有り難いことに、2019年に公式のVault Helm Chartが公開されました。
注意として、デフォルトではセキュアではない状態でinstallされる為、Production環境で動かすには各種設定を変更する必要があります。 ただ、ローカル環境でサンプルで動かす分にはこちらを利用すれば問題ないので、早速動かしてみましょう。
公式ドキュメントの手順を参考に進めていきます。
事前準備
- 「docker-for-desktop」なり「minikube」なりで、ローカルにKubernetes環境を構築しておく
- kubectl及びhelmを使えるようにしておく
作業
- 公式のVault Helm Chartから
git clone
します- 特定のタグがついているVersionをCheckoutすることを推奨しているので、それに従っておきます
git clone https://github.com/hashicorp/vault-helm.git
cd vault-helm
--dry-run
しますvalues.yaml
を書き換えることで、設定値を書き換えます。今回はサンプルなので特に変更はしません。
helm install --dry-run ./ --generate-name
- VaultをDeployします
helm install ./ --generate-name
vault operator init
というコマンドをVault Serverに対して実行し、Vaultをinitializeします- Vault ServerのPodからVault CLIを使えるようになっています(ローカル環境にVault CLIがインストールされていればそれでも可)
- なので、Vault ServerのPodに
kubectl exec
してVault CLIを実行します - 今回は検証のため
-key-shares=1 -key-threshold=1
というオプションを付与してUnseal Key
のシャードを1つにしています(デフォルトは5つ)
kubectl exec -it chart-XXXXX-vault-0 -- vault operator init -key-shares=1 -key-threshold=1
- 以下のように出力されます(<UNSEAL_KEY>と<INITIAL_ROOT_TOKEN>は、次移行の手順で使用します)
Unseal Key 1: <UNSEAL_KEY>
Initial Root Token: <INITIAL_ROOT_TOKEN>
・・・
vault operator unseal
というコマンドをVault Serverに対して実行し、Vault ServerをUnseal
します- 対話モードになるので、先程の
vault operator init
実行時に出力された<UNSEAL_KEY>を入力します
- 対話モードになるので、先程の
kubectl exec -it chart-XXXXX-vault-0 -- vault operator unseal
Sealed
KeyのValueがfalse
になればUnseal
に成功しています
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
ここまででVaultを利用する準備ができたので、試しに秘匿情報を登録してみましょう
まずはVaultにログインします
- 先程の
vault operator init
実行時に出力された<INITIAL_ROOT_TOKEN>を使ってroot権限でVaultにログインします
- 先程の
kubectl exec -it chart-XXXXX-vault-0 sh
vault login
# <INITIAL_ROOT_TOKEN>を入力
- Key-Value形式で秘匿情報を保存できるようにします
vault secrets enable -path=secret kv
- Vault CLIを使って秘匿情報を保存します
sample-key
というKeyに対してsample-value
というValueを持つ秘匿情報を登録します
vault kv put secret/my-secret sample-key=sample-value
- Vault CLIを使って、登録した秘匿情報を参照してみます
vault kv get secret/my-secret
======= Data =======
Key Value
--- -----
sample-key sample-value
- Vaultは非常に使いやすいWeb UIを持っています。登録した秘匿情報をWeb UIから参照してみましょう
kubectl port-forward
してブラウザからVaultにアクセスできるようにしておきます
kubectl port-forward chart-XXXXX-vault-0 8200:8200
http://localhost:8200/ui
にブラウザからアクセスしますToken
は先程の<INITIAL_ROOT_TOKEN>を入力します
- 無事にログインできました。
Secret Engines
という画面が表示されているかと思うので、secret/
というリンクをクリックすると、先程登録したmy-secret
を参照することができます
- 検証が終わったら
helm uninstall
しておきます
helm list
helm uninstall chart-XXXXX
Production-ready Vault on Kubernetesに向けての考慮ポイント
ここまで説明してきたとおり、公式のVault Helm Chartが用意されています。 ただし、デフォルトの設定値のままではProduction Readyな設定で動かないですし、マニフェストをHelmで管理していないケース(kustomizeを使っている場合など)もあり、まだ色々と考えることは多そうです。
そこで、公式ドキュメントを元に、KubernetesでProduction ReadyなVaultを構築する時にどうしていけばいいかを考えてみました。
Storage Backendの選定
データの永続化はStorage Backendが担うという点については説明したとおりです。Storage BackendはHAを有効化できるものと出来ないものがあります。例えば、S3はHAモードを有効化できず、DynamoDBやConsulはHAを有効化できます。これはStorage Backendを選定する際の大きな判断軸になるでしょう。例えばAWS EKS上に構築するのであればDynamoDBなどが有力な選択肢になります。
Storage Backendへのアクセス制御
秘匿情報そのものは全てStorage Backendに保存されます。データそのものはVaultによって暗号化されて保存されていますが、誤ってStorage Backendのデータを破損するオペレーションをすると、Vaultが利用できなくなります。人がアクセスする必要はないので、Storage Backendに対するアクセスはVault Severのみに制限するべきでしょう。
Auto-unsealの有効化
Vaultを(ライフサイクルの短い)コンテナで動かす以上、Vault Serverを起動する度に手動でUnseal
作業を行うのは、現実的ではありません。AWSの場合、KMSと連携することでコンテナ起動時のUnsealプロセスを自動化できます。
Vault ServerのUpgrade
Vault Serverをアップグレードを行う際には、Storage Backendのバックアップを取ることが強く推奨されています。 これは、Vaultはデータストアのbackward-compatibility(後方互換性)を保証しないからです。(Vaultのバージョンが上がると、それによりデータ構造が変更される可能性がある) つまりダウングレードする際には、Vault Serverのバイナリのバージョンを戻すだけではなく、データストアをバックアップからロールバックする必要があります。
Upgrade時に古いバージョンのActive系にフェイルオーバーすることは避けなければいけません。なので、公式のHelm Chartでは、Vault ServerをStatefulSetで構築したうえでOnDelete
update strategyを採用しています。Activeの前にStandbyを更新する必要があるので、Rolling Updateの代わりにOnDeleteを使用するのは非常に重要とのことです。
おわりに
実際にVaultを運用する際には、アクセスコントロール(Auth Methodを使った認証認可)やアプリケーション展開の仕組みなど、運用や利用の方が工夫・検討ポイントが多岐にわたります。今後何か機会があれば、運用面も含めてアウトプットしていきたいと思います。