HashiCorpの日本語Vaultハンズオンを実施した!

業務でHashiCorpのVaultを使うかもしれないのでハンズオンをやってみた.GitHubに日本語のハンズオン資料が公開されているのでそれをもとに進めた.

github.com

ハンズオンアジェンダ

GitHubで公開されている日本語のハンズオンアジェンダを以下に示す.この中にはハンズオンとしての内容がまだ公開されていないものも含まれている.

  • 初めてのVault
  • Secret Engine 1: Key Value
  • Secret Engine 2: Databases
  • 認証とポリシー
  • Auth Method 1: LDAP
  • Auth Method 2: AppRole
  • Auth Method 3: OIDC
  • Auth Method 4: GitHub
  • Response Rapping
  • Secret Engine 3: Public Cloud (AWS, Azure, GCP)
  • Secret Engine 4: PKI Engine
  • Secret Engine 5: Transit (Encryption as a Service)
  • Secret Engine 6: SSH
  • 運用系機能色々
  • CIツール連携(Concourse, Jenkins)
  • Kubernetes連携
  • Cloud Foundry連携
  • Enterprise機能の紹介

今回は初めてVaultに触るので初めてのVaultSecret Engine 1: Key ValueSecret Engine 2: Databases認証とポリシーの4つをやってみる.具体的な手順はハンズオンに任せるとして,この記事ではそれぞれのハンズオンで学んだことと,自分が思う重要な概念や押さえるべきポイントについてまとめてみようと思う.

1. 初めてのVault

ここではVaultをインストールしてVaultを立ち上げ,あとのハンズオンの準備をしていく.

このハンズオンで学んだこと

  • Vaultのインストール
  • Vaultサーバの立ち上げ(開発モード)
  • シークレットエンジン
    • シークレットの保存・取得
  • Vaultサーバの立ち上げ(本番モード)
    • Vaultの初期化処理

シークレットエンジン

シークレットエンジンとはkey=valueでデータを格納・生成・暗号化するVaultのコンポーネントである. AWSのIAMのキーやDatabaseへアクセスするシークレットなどさまざまな用途で使えるように,Vaultで専用のコンポーネントが用意されている.例えばkvシークレットエンジンを新規で使う時はvault secrets enable -path=kv kvのようにシークレットエンジンを有効にする.さらに,パスを指定してエンドポイントにみたてて,以後そのエンドポイントに操作を実行するのが特徴である.用途にあったシークレットエンジンを使うことでシークレットを適切に扱うことが可能となる.

Vaultの初期化処理

本番モードのVaultではセキュアな設計がされているので,起動直後はsealedという状態になっておりVaultへログインできない.ログインするにはinitunsealという初期化処理が必要になる.まずinit処理をする.

$ vault operator init
Unseal Key 1: JLYUBHrdwWu2dxwjCazqsCQ4OJPJtiMFsIZeO1osyJ1t
Unseal Key 2: nEjGt+rYSOomqmyTsuF7PnKPS+NE3yPEfuo6WDXm/QDR
Unseal Key 3: d5nTCzEGKIBPFGCC3ANzKf8gGgwoV8APr6V9KdDcNjOW
Unseal Key 4: sd7vzV1FQk/96xQmIuKRKhydy9tGEmORbFyozAKxFc4n
Unseal Key 5: JqLGxcvA3gLrwQHIliWvl1ytkMbuDGu/6p2KzGpvnCa9

Initial Root Token: s.Wi5WjPfPHqbFAcXjwsDCHQLd
~~~

initの処理をすると,VaultをunsealするためのUnseal KeyInitial Root Tokenが生成される.試しにこの状態でRoot Tokenを使ってログインしてみる.

$ vault login
Token (will be hidden):
Error authenticating: error looking up token: Error making API request.

URL: GET http://127.0.0.1:8200/v1/auth/token/lookup-self
Code: 503. Errors:

* error performing token check: Vault is sealed

エラーになる.Vaultではsealed状態になっているといかに強力な権限のあるトークンを使ったとしても操作は受け付けない.unsealの処理はUnseal Keyを使う.デフォルトだと5つのキーが生成され,そのうち3つのキーが集まるとunsealされる.このアルゴリズムシャミアの秘密鍵分散法と呼ばれる.3つのUnseal Keyを入れてみる.

$ vault operator unseal
Unseal Key (will be hidden):
Key                Value
---                -----
Seal Type          shamir
Initialized        true
Sealed             true
Total Shares       5
Threshold          3
Unseal Progress    1/3
Unseal Nonce       32d20912-88dd-16e2-28d3-87344abec5fc
Version            1.2.3
HA Enabled         false
$ vault operator unseal
Unseal Key (will be hidden):
Key                Value
---                -----
Seal Type          shamir
Initialized        true
Sealed             true
Total Shares       5
Threshold          3
Unseal Progress    2/3
Unseal Nonce       32d20912-88dd-16e2-28d3-87344abec5fc
Version            1.2.3
HA Enabled         false
$ vault operator unseal
Unseal Key (will be hidden):
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    5
Threshold       3
Version         1.2.3
Cluster Name    vault-cluster-7815e4aa
Cluster ID      12747d60-78d3-8fad-6082-102052ac8c74
HA Enabled      false

これでログインができる.

$ vault login
s.Wi5WjPfPHqbFAcXjwsDCHQLdToken (will be hidden):
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.Wi5WjPfPHqbFAcXjwsDCHQLd
token_accessor       NX8h0laChNLO5oObu2nDtovT
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]

やや面倒なこの仕組みの何が嬉しいのかということについては以下のブログが参考になった.

christina04.hatenablog.com

2. Secret Engine 1: Key Value

ここではシンプルなKeyValueStore型のシークレットエンジンを使ってデータのCRUDをするハンズオンを行う.

このハンズオンで学んだこと

  • Key Value Store型のシークレットエンジン
    • データのCRUD
    • データのバージョニング管理
    • 2つのデータ更新パターン

3. Secret Engine2: Databases

ここではMySQLとVaultを使い,Vaultで発行したシークレットを用いてMySQLにアクセスするハンズオンを行う.

このハンズオンで学んだこと

  • Databaseのシークレットエンジン
  • Vaultが対応しているDatabaseシークレットエンジン一覧
  • VaultがMySQLの操作を制限するようなロールを作成し,そのロールの内容に基づいてVaultがアプリケーションへシークレットを生成する流れ
  • 動的シークレットの破棄
  • Rootユーザのパスワードローテーション

MySQLへのアクセスの流れ

以下の図のような流れでアプリケーションはMySQLへのアクセスを実現する.

f:id:a-mochan:20191117084705p:plain
MySQLへのアクセスの流れ

それぞれのステップをみていく.

① Vaultに特権ユーザのクレデンシャルとデータベースの接続先を登録する.MySQLrootユーザ(特権ユーザ)を指定してコネクションの設定をする.②で作成するロールもここで指定しておく必要がある.また,ロールは複数指定できる.

$ vault write database/config/mysql-handson-db \
  plugin_name=mysql-legacy-database-plugin \
  connection_url="{{username}}:{{password}}@tcp(127.0.0.1:3306)/" \
  allowed_roles="role-handson" \
  username="root" \
  password="rooooot"

MySQLへの権限やシークレットのTTLを記述したロールを定義する

$ vault write database/roles/role-handson \
  db_name=mysql-handson-db \
  creation_statements="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';GRANT SELECT ON *.* TO '{{name}}'@'%';" \
  default_ttl="1h" \
  max_ttl="24h"

③ クライアントからVaultに対してシークレットの発行を依頼する

$ vault read database/creds/role-handson
Key                Value
---                -----
lease_id           database/creds/role-handson/G3tJu3gN8nGoL8Z8MlVkvD2g
lease_duration     1h
lease_renewable    true
password           A1a-qIpUomJUoXOiHlQh
username           v-role-PaKXo1BO1

④ 取得したシークレットでMySQLにアクセス

$ mysql -u v-role-PaKXo1BO1 -p -h 127.0.0.1
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
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>

⑤ ロールによりSelectはできるがInsertはできないことを確認する.

$ mysql> select * from products;
+------+-------------+-------+
| id   | name        | price |
+------+-------------+-------+
|    1 | Nice hoodie | 1580  |
+------+-------------+-------+
1 row in set (0.00 sec)

$ mysql> insert into products (id, name, price) values (2, "hoge", 1600);
ERROR 1142 (42000): INSERT command denied to user 'v-role-PaKXo1BO1'@'127.0.0.1' for table 'products'

動的シークレットの破棄

ロールにシークレットのTTLを設定できる.TTLを過ぎれば当該シークレットではMySQLにログインできなくなる.またrevoke処理で発行したシークレットを明示的に無効にできる.再びMySQLにログインしたい場合は,再度シークレットを発行するか,シークレットのTTLが切れる前にrenew処理と呼ばれるTTLを延長する処理のどちらかを実行すればよい.

Rootユーザのパスワードローテーション

VaultにMySQLの特権を持たせているためそのパスワードの扱いが非常にセンシティブである.Vaultにはコンフィグレーションとして登録したデータベースのパスワードをローテーションさせるAPIがある.これを使ってこまめにRootのパスワードをリフレッシュできる.ただし,MySQLのRootユーザがVaultに登録してあるもの1つだけだと,Rootユーザのパスワードのローテーションを行った後はRootのパスワードはVaultしか扱うことができない.そのため通常別の特権ユーザをMySQLに準備してから行う

4. 認証とポリシー

ここではエンドポイントごとにポリシーを設定してトークンを発行し,アクセスコントロールを試してみるハンズオンを行う.

このハンズオンで学んだこと.

  • ポリシーの利用方法

ロールとポリシーの違い

ポリシーの作成方法や使い方はハンズオンで十分学ぶことができる.個人的に思うここでの重要なポイントは1つ前のSecret Engine2: Databasesで学んだロールと今回のポリシーの違いだと思う.利用するアプリケーションのアクセスをコントロールをしているという点においては同じだが,ロールとポリシーではコントロールする対象領域が異なる.1つ前のハンズオンを例にとると,ロールの場合コントロールする対象領域はMySQLだった.つまり,MySQLへアクセスするシークレットが発行された上で,そのシークレットでMySQLにログインするアプリケーションにどんな制限を持たせるかというのを定義するのがロールである.一方,ポリシーはVaultのエンドポイントを対象領域としている.例えば,「kvタイプのとあるエンドポイントにはread,writeを持たせるけど,databaseタイプのエンドポイントにはアクセスさせない」というようなポリシーを定義をする.もしこの例が適用されたトークンが発行されると,たとえロールの設定にすべてのテーブルへのアクセス許可を書いていたとしても,そもそもdatabaseタイプのエンドポイントにアクセスができないのでシークレットが発行されず,MySQLにログインすることすらできない.まとめると,ポリシーはエンドポイント単位でのアクセスコントロールを制御し,ロールはエンドポイントに対応しているSecret Engineの中でもっと細かいアクセスコントロールを制御するものだと思う.

まとめ

  • HashiCorpのVaultハンズオンを一部試してみた
  • Vaultの日本語ハンズオンはとても分かりやすかった.Vaultが何か分からない方におすすめ!
  • 認証を絡めたハンズオンもいくつかあるのでやっていこうと思う.また,この記事を書いている間にもハンズオンが変更されたり増えていたりしたのでまた試してみようと思う.