あまりまだメジャーではないみたいですが、HashiCorpが機密情報管理用のツールとしてVaultを出しています。代替になるツールもあまり思い浮かばないし、物は試しと使ってみました。
Vaultでできること概要
- 機密情報等をKey,Value形式で書き込むと暗号化して保存してくれる。
-
Secret Backends
という機能で、MySQL、PostgreSQL、AWS、LDAP等と連携し、Vaultを通じてユーザー情報の追加、変更、削除等を行える。このときLease(期限)を設定し、一定期間後にアカウントを自動削除したり、パスワードをRevokeさせることができる。 - デフォルトの状態ではデータはすべて暗号化(Sealed)されており、Vault自身も復号する方法を知らない。復号には分散鍵による認証が必要になる。
- Vaultへのアクセス方法はCLIかREST API。
- Vaultへアクセスする際の認証はユーザーパスワード形式、GitHub連携、一時的なtokenの払い出しなどを扱える。
- Vaultに対して行われた操作はすべて保存され、監査に対応できる。
今回すること
- 試験的な運用のため、Secret Backendsはデフォルトのまま、シンプルに情報の保存と読み出しだけを試す。
(Secret BackendsはデフォルトだとGeneric
というものがマウントされており、これは単純に情報を保存すると、それを暗号化してファイルに書き込むのみ) - ユーザーパスワード形式で認証して使用することを想定する。
- 開発用途で起動できるdevモードが存在しているが、本番相当の設定を検証したいので今回は使わない。
初期設定
インストール
zipを落としてきてunzip
し、PATHの通っている場所に置いて完了。
設定
hclもしくはjsonで書いた設定ファイルを元として起動する。設定ファイルは Server Configuration - Vault by HashiCorp に記述方法が書かれているが、最低限2つの項目が必要とされる。
backend
Vaultのデータを保存するSecret Backendの設定。MySQLやPostgresqlといったRDBMS、S3やDynamoDB、プレーンのファイルなど様々選べる。Generic
を使う場合はfile
を設定することになる。
listener
APIリクエストを受け付けるリスナープロトコルの設定。現状はtcp
のみ対応。tls
を使う場合の証明書の設定等もできる。デフォルトではtls
が有効化されているため、使用しない場合は無効化の明示が必要となる。
tls無効化
- listenerで
tls_disable = 1
を指定する。 - vaultへの接続はデフォルトで
https
が使われるので、VAULT_ADDR
環境変数でhttp
のアドレスを指定する。
backend "file" {
path = "/home/ec2-user/vault"
}
listener "tcp" {
address = "127.0.0.1:8200"
tls_disable = 1
}
起動
先のhclファイルを指定して起動する。起動後にvault init
で初期化する。
注意点
- フロントで立ち上がり、ログを標準出力に流してくるため、リダイレクトとバックグラウンドでの起動が必要。
- vaultは
mlock
システムコールを使用するため、管理者権限で実行しなければエラーになる。configの中でmlock
の無効化もできるが、非推奨。 -
vault init
した際に表示されるUnseal Key
、Initial Root Token
はいずれも必要なので記録する。
$ sudo vault server -config /etc/vault.hcl &>/var/log/vault &
$ vault init
Unseal Key 1 (hex) : XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Unseal Key 1 (base64): XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
...
Initial Root Token: XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Vault initialized with 5 keys and a key threshold of 3. Please
securely distribute the above keys. When the Vault is re-sealed,
restarted, or stopped, you must provide at least 3 of these keys
to unseal it again.
Vault does not store the master key. Without at least 3 keys,
your Vault will remain permanently sealed.
Unseal
VaultはデフォルトだとSealed
(暗号化された状態)となっているため、先程出力されたUnseal Key
を使ってunseal
を行う必要がある。まずステータスを確認してみる。
$ vault status
Sealed: true
Key Shares: 5
Key Threshold: 3
Unseal Progress: 0
Version: Vault v0.6.1
Sealed: true
となっている。Key Shares
はUnseal
のために共有しているキーの数であり、このうちKey Threashold
に表示された閾値の数だけキーを入力するとUnseal
される。
キーは複数人で分散管理し、全員が持ち寄ることで初めて復号化できる、というのがこの機構の目的。技術的には「シャミアの秘密分散法」と呼ばれるものらしい。逆にSeal
するときはvault seal
コマンドを使えば一人で暗号化できるので、キーが漏れてしまった場合などはSeal
することで対処できる。
復号化する。vault unseal
コマンドを実行し、vault init
の際に表示されたキーから3つを順に入れていく。出力のUnseal Progress
が徐々に進んでいき、Threshold
に達するとunseal
される。
$ vault unseal
Key (will be hidden):
Sealed: true
Key Shares: 5
Key Threshold: 3
Unseal Progress: 1
Auth
認証機構。デフォルトで使用できるユーザーはrootのみなので、まずはrootで認証する。vault init
のときに出力されたrootのトークンを使う。
$ vault auth XXXXXXXXXXXXXXXXXXX
Successfully authenticated! You are now logged in.
token: XXXXXXXXXXXXXXXXXXXX
token_duration: 0
使用するAuth Backendを有効化する。今回はuserpass
。有効化後に、ユーザーを作成して認証までしてみる。
$ vault auth-enable userpass
Successfully enabled 'userpass' at 'userpass'!
$ vault write auth/userpass/users/chroju password=******
Success! Data written to: auth/userpass/users/chroju
$ vault auth -method=userpass username=chroju
Password (will be hidden):
Successfully authenticated! You are now logged in.
The token below is already saved in the session. You do not
need to "vault auth" again with the token.
token: XXXXXXXXXXXXXXXXXXXXX
token_duration: 2592000
token_policies: [default]
認証が成功するとtokenが発行されるが、APIを使うときはこのtokenで認証することができる。CLIではこの状態でもう操作が可能。なおtokenはカレントディレクトリの.vault-token
ファイルに書き込まれており、CLI使用時はこれでセッションを維持しているっぽい。
ACL
単にユーザーを作っただけでは、すべてのリソースに対する操作権限はDeny
に設定されているため、ユーザーがどのリソースに対してアクセス可能かはACLで定義する。Vaultにおける機密情報の保存場所は、いわゆるファイルパスのようなスラッシュで区切った形式で指定する。従って適切にフォルダを分けて、アクセス権を分散させることができる。
- ACLはHCLもしくはjsonにより記述する。
- フォルダ配下へのアクセスは自動で付与されない。例えば
path "secret"
に対する許可を書くと、secret
にはアクセスできてもsecret/foo
にはアクセスできない。 - ACLを付与しない限り、デフォルトで全アクセスは
Deny
される。 - userpassバックエンドでの認証は
auth/token/lookup-self
へのread
権限がなければ通らなかった。少し謎。
path "auth/token/lookup-self" {
policy = "read"
}
path "secret/*" {
policy = "write"
}
- ACLファイルを作成したら、Vaultに登録してからユーザーへ結びつける。
- ユーザーに対する
write
は全属性書き換えになるらしいので、常にパスワードも含めた全属性を設定してwrite
する必要がある。
$ vault policy-write allow-secret /etc/vault_acl.hcl
$ vault write auth/userpass/users/chroju password=****** policies=allow-secret
利用
データの読み書き。
$ vault write secret/foo value=bar
Success! Data written to: secret/foo
$ vault read secret/foo
普通に入力するとコマンドラインの履歴に残って気持ち悪いので、標準入力やファイルからの入力を駆使する。
# 標準入力を使う
$ echo -n '{ "username":"foo", "password":"bar" }' | vault write secret/server01
Success! Data written to: secret/server01
# jsonファイルを使う
$ cat server02.json
{
"username" : "foo",
"password" : "bar"
}
$ vault write secret/server02 @server02.json
Success! Data written to: secret/server02
APIからアクセスする。tokenをX-Vault-Token
ヘッダーに入力することで認証する。
$ curl http://localhost:8200/v1/secret/foo -H "X-Vault-Token: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
{"request_id":"b745ef53-ff32-9ffe-b8b2-a7dc03072f7e","lease_id":"","renewable":false,"lease_duration":2592000,"data":{"value":"bar"},"wrap_info":null,"warnings":null,"auth":null}
tokenはtoken-create
コマンドを使って、一時的な払い出しができる。オプション-ttl
で時間制約を持たせることができ、-use-limit
で使用回数を制限できる。
$ vault token-create -policy=allow-secret -ttl=1h
Key Value
--- -----
token bcae0b31-55af-8349-dd9a-f0200fbe6b53
token_accessor 39be2d81-4860-d271-365d-42db4db41f0e
token_duration 1h0m0s
token_renewable true
token_policies [allow-secret default]
その他留意点など
パスワードの変更
userpass
backendを使う場合、当然各ユーザーがパスワードの変更をしたくなるが、これもまたvault write
コマンドによる書き込みになる。パスワード情報はauth/userpass/users/${username}/password
というパスに保存されているため、このパスに対してACLで許可を与えなくては、パスワード変更はできない。
$ vault write auth/userpass/users/chroju/password username=chroju password=hogefuga
Success! Data written to: auth/userpass/users/chroju/password
しかし、そうなると各ユーザーに個別にACLを設定して、自分のパスワードパスだけに対するアクセス権を与えてやることになるので、ACLの種類がユーザーの数だけ増えて管理が大変になりそう。この点、もう少しいいソリューションはないのかなと思う。
雑感
- APIアクセスが主であり、また認証(Auth Backends)も
userpass
ではなくGitHub等の他サービスと連携させることが基本なのかなと思う。先に書いたパスワード変更の件など、userpass
でCLIを介して常時使うような設計にはなっていない気がした。 - とはいえHashiCorpのツールらしく、各機能がシンプルに独立していて、プラガブルに使える点はとてもいい。「こうしなければ使用できない」となってしまうような変な制限がなく、使い方に幅がある。それだけに運用方法は練る必要がある。
- スクリプト等でパスワードをハードコーディングするバッドプラクティスへの対策として、Vaultからパスワードを引っ張ってきたりできると思うので試したい。が、基本的にtokenにTTLがある状態で、どう設計すればいいのかよくわからない。軽くググってもいまいち事例が出てこないし、出てきたと思ったら唯一TTLの存在しないrootアカウントのtokenを使ってたりしてセキュリティ的によろしくない感じであった。