HashiCorp Vault 入門
これは何?
HashiCorp Vaultに入門するためのまとめです。この資料を読むことで HashiCorp Vault is 何?
が(なんとなく)わかるようになります。
背景
エンジニアが障害対応などのためにDBに対してログインする必要があるが、DBのUser管理が大変なのでなんとかしたい(共有アカウントはセキュリティ的にアレだし、個々のエンジニア用に用意するのは手間がかかり過ぎる)!
そんな折、以下の情報を見て「HashiCorp Vault使えばいけるっぽいやん!」となったのでHashiCorp Vaultについて調べました。
HashCorp Vault is 何?
Vaultはみんな大好きHashiCorp社の提供するプロダクトのひとつであり、以下のような機密情報管理を提供しています。
- Secretの中央管理(Centralization)
- 暗号化(Encryption)
- 認証(Authentication)
- 認可(Authorization)
- 鍵交換(Rotation)
ユースケースとしては以下のようなものが挙げられます。
- シークレット管理
- 中央集権的な生成、保存、提供
- データプロテクション
- データ暗号化のためのAPIと暗号化のキー管理の機能を提供し、アプリケーションのデータをセキュアに保つ
- 動的シークレット
- すべてのクライアントで一意かつ一時的なシークレットを発行可能
また、HashiCorp Vault用のhelm chartも用意されておりkubernetesとの連携もできます。Helm Chartも用意されていますし、KubernetesをVaultの認証として利用する方法も提供されています。
Vaultのアーキテクチャ
Vaultのアーキテクチャは以下のようになっています(以下の公式より拝借)。
Secrets Engine
シークレットエンジンはデータの作成/保存/暗号化を提供しており、Vaultの中心機能とも言える部分です。シークレットエンジンを利用することで、認証されたクライアントがシークレット(何かにアクセスするために必要な「何か」)を使用する際の管理ワークフローが実装できます。例えば特定のRDSに対して一時的にread可能なUserをVaultが自動で作成するといったことができます。
Secrets Engineは各種クラウドインフラ/DBなどに対応しており、例えば一時的に利用可能なIAM UserやMySQL Userを生成できます。
Policy
Vaultではクライアントに対するアクセスコントロールのためにPolicyを提供しています。Policyは以下のようにPathベースのリソース(以下の場合ではdatabase/*
)に対して実行可能な権限を capabilities
として定義することが基本です。記法はTerraformと同じ感じです。
path "database/*" {
capabilities = ["read", "list"]
}
※この記事のハンズオンではRoot Tokenを利用して操作していますが、商用環境などでは必要最低限の権限を持つユーザーを作成したり、認証プロバイダー経由での認証などを行うことをおすすめします。
Auth Method
Vaultへの認証とPolicyの紐付けを管理しています。認証には各種クラウドインフラ/AzureAD/Kubernetesなどと連携できます。
Audit Devices
Vaultにおけるすべてのrequest/responseのログを管理している。殆どの操作に伴うrequest/responseに含まれる文字列はHMAC-SHA256によりhash化された状態で出力されます。出力先はFile/Syslog/Socketが提供されています。
軽いハンズオン
Vaultを使って一時的に利用可能なMySQL Userを自動生成してみます。ざっくりした流れは以下の感じです。
※このハンズオンは以下に沿って自分で動かしたときの記録なので、気になる方は以下の記事も見て下さい。
Vaultをインストールする
手元の環境にVaultをインストールします。
$ brew tap hashicorp/tap
$ brew install hashicorp/tap/vault
$ vault -version // バージョンが表示されればok
Vault v1.1.1+ent ('7a8b0b75453b40e25efdaf67871464d2dcf17a46')
# コマンド補完をインストール
$ vault -autocomplete-install
$ exec $SHELL
Vaultサーバーを起動する
Vaultのサーバーを起動します(便宜上developモードで起動しています)。起動した際に色々と必要な情報を表示するので手元に控えておきます。
$ export VAULT_ADDR="http://127.0.0.1:8200"
$ vault server -dev
==> Vault server configuration:
Api Address: http://127.0.0.1:8200
Cgo: disabled
Cluster Address: https://127.0.0.1:8201
Go Version: go1.15.13
Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
Log Level: info
Mlock: supported: false, enabled: false
Recovery Mode: false
Storage: inmem
Version: Vault v1.7.3
Version Sha: 5d517c864c8f10385bf65627891bc7ef55f5e827
==> Vault server started! Log data will stream in below:
....
WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory
and starts unsealed with a single unseal key. The root token is already
authenticated to the CLI, so you can immediately begin using Vault.
You may need to set the following environment variable:
$ export VAULT_ADDR='http://127.0.0.1:8200'
The unseal key and root token are displayed below in case you want to
seal/unseal the Vault or re-authenticate.
Unseal Key: cp1sStszUVUtZX+oE31CRxei3l4HQlV5iaip2PJ0TaU=
Root Token: s.1tIM6CCjPle33LQL4EBl6pC4
Vaultにloginする
Vaultサーバー起動時に返された Root Token
を使ってVaultにloginします。
$ export VAULT_ADDR='http://127.0.0.1:8200'
$ vault login
Token (will be hidden): // ここにRoot Tokenを入れる
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.
Key Value
--- -----
token s.1tIM6CCjPle33LQL4EBl6pC4
token_accessor fbWMZnjT81aGg148aroeTIhr
token_duration ∞
token_renewable false
token_policies ["root"]
identity_policies []
policies ["root"]
Secretの一覧を見てみましょう。
$ vault secrets list
Path Type Accessor Description
---- ---- -------- -----------
cubbyhole/ cubbyhole cubbyhole_c12b3b70 per-token private secret storage
identity/ identity identity_ceb10b15 identity store
secret/ kv kv_bb6fd737 key/value secret storage
sys/ system system_d3f8f769 system endpoints used for control, policy and debugging
Database Secretを利用可能にする
defaultではDatabaseのsecret engineを利用できないため、明示的にONにする必要があります。
$ vault secrets enable -path=database database
Success! Enabled the database secrets engine at: database/
# secretsに `database/`が追加されている
$ vault secrets list
Path Type Accessor Description
---- ---- -------- -----------
cubbyhole/ cubbyhole cubbyhole_c12b3b70 per-token private secret storage
database/ database database_8dec999e n/a
identity/ identity identity_ceb10b15 identity store
secret/ kv kv_bb6fd737 key/value secret storage
sys/ system system_d3f8f769 system endpoints used for control, policy and debugging
アクセス対象のDBを用意する
以下のようにMySQLを用意します。
$ docker run --name mysql -e MYSQL_ROOT_PASSWORD=rooooot -p 3306:3306 -d mysql:5.7.22
$ docker exec -it mysql bin/bash
$ mysql -u root -prooooot -h127.0.0.1
mysql> create database sample_vault;
Query OK, 1 row affected (0.01 sec)
mysql> use sample_vault;
mysql> create table products (id int, name varchar(50), price varchar(50));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into products (id, name, price) values (1, "Terraform", "1580");
Query OK, 1 row affected (0.00 sec)
VaultからMySQLに接続するための設定を行う
VaultからMySQLを操作するためにMySQLの設定情報を登録します。
※ DB関連の設定の詳細はこちらが参考になりそうです。
$ vault write database/config/vault-mysql-db \
plugin_name=mysql-database-plugin \
connection_url="{{username}}:{{password}}@tcp(127.0.0.1:3306)/" \
allowed_roles="role-vault-sample" \
username="root" \
password="rooooot"
MySQLに対する操作をVaultにを設定する
VaultからMySQLに対してUserを生成するために、VaultとSQLの紐付けを database/roles/
配下に設定します(pluginの仕様)。
今回は sample_vault.products
テーブルに対するSELECT権限のみ付与しています。またこの際にdefault_ttl
(生成時のTTL)や再接続できる期限(max_ttl
)などを設定することができます。
$ vault write database/roles/role-vault-sample \
db_name=vault-mysql-db \
creation_statements="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';GRANT SELECT ON sample_vault.products TO '{{name}}'@'%';" \
default_ttl="120s" \
max_ttl="180s"
Success! Data written to: database/roles/role-vault-sample
$ vault list database/roles
Keys
----
role-vault-sample
VaultからMySQL Userを作成する
VaultからMySQLのUserを作成してみます。database/creds/<先程作成したRole名>
に対してreadすることで新しいクレデンシャルが発行されます。
なおこのクレデンシャルはすべてのクライアントで一意のため、実行するたびに新しいクレデンシャルが発行されます。
$ vault read database/creds/role-vault-sample
Key Value
--- -----
lease_id database/creds/role-vault-sample/Ka3aJbZOs8oa3bjC8mc9YdZV
lease_duration 2m
lease_renewable true
password 064mL4-cCTTfDDUnyd6z
username v-root-role-vault-lxUKDka3w8xixU
MySQLにログインしてみる
上記のUser情報でMySQLにログインしてみましょう。
mysql -u v-root-role-vault-lxUKDka3w8xixU -p064mL4-cCTTfDDUnyd6z -h127.0.0.1
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 19
Server version: 5.7.22 MySQL Community Server (GPL)
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| sample_vault |
+--------------------+
2 rows in set (0.00 sec)
mysql> use sample_vault;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> select * from products;
+------+-----------+-------+
| id | name | price |
+------+-----------+-------+
| 1 | Terraform | 1580 |
+------+-----------+-------+
1 row in set (0.00 sec)
このユーザーにはproductsテーブルに対する参照権限のみ与えられているため、productsテーブルに対する書き込みや他テーブルの追加はできません。
mysql> insert into products (id, name, price) values (2,"Vault", "2000");
ERROR 1142 (42000): INSERT command denied to user 'v-root-role-vault-lxUKDka3w8xixU'@'127.0.0.1' for table 'products'
mysql> create table users;
ERROR 1142 (42000): CREATE command denied to user 'v-root-role-vault-lxUKDka3w8xixU'@'127.0.0.1' for table 'users'
また、max_ttl
を迎えた場合にはUserを利用できなくなります。
# 180秒後には再ログインできなくなっている
mysql -u v-root-role-vault-lxUKDka3w8xixU -p064mL4-cCTTfDDUnyd6z -h127.0.0.1
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'v-root-role-vault-lxUKDka3w8xixU'@'127.0.0.1' (using password: YES)
というわけで、いい感じにVaultから一時的なMySQL Userを作成することができました!
※業務で利用するには色々と変更/工夫する必要がありそうですが、それらの設定も公式Docsを辿るとだいたい記載されていそうなので、気になる方はのぞいてみてください。
雑感
- Vaultすごい!(コナミカン)
- 商用環境で使うには色々調査と工夫が必要そう..
- VaultからアクセスするDBのuser/passwordの管理
- Vaultに任せてもいいけど、既存のリソースへの影響ががが
- Vaultへの認証
- 認証プロバイダー経由での認証がしたい(対応している)
- 適切なPolicy管理
- Vault自体の管理
- 落ちると...
- etc.
- VaultからアクセスするDBのuser/passwordの管理
参考
Vaultについていい感じにまとまっています。
HashiCorpの中の人がまとめた資料
HashiCorpの中の人が書いたValueハンズオン(日本語)
メジャー機能を一通り触ってみたい人におすすめです。
公式のDocs
実装で困った時にまずは見てみるのが良さそうです。
Discussion