概要
HashiCorp VaultにはCubbyhole Response Wrappingという仕組みが用意されています。
これによってトークンや秘密情報の受け渡し時の漏洩リスクを最小限にします。
課題・背景
人やマシンにトークンを渡す場合、
などの問題点を考慮する必要があります。
また仮に漏洩した場合に
- 漏洩したトークンが不正に利用された
ということを検知する仕組みが必要になります。
Cubbyhole Response Wrappingはそれらを解決する手段です。
環境
- Vault 1.2.2
Cubbyhole Response Wrapping
Cubbyholeは一時的なロッカーです。
渡したいトークンや秘密情報をそのロッカーに詰め込み、鍵をかけます。
そしてその鍵を開けるための一時トークンを発行します。
その一時トークンを使ってのみ、ロッカー内の情報にアクセスできます。
この一時トークンは一度使うと二度と使えなくなります。
またロッカーの中身はrootユーザでさえ見ることはできません。
メリットは?
メリットは以下の3つです。
実トークンを受け渡ししない(漏洩リスク・トークン使い回しの低減)
- 生成した人からの漏洩
- 盗聴による漏洩
があったとしてものその一時トークン自体が何かしらの効力を持つわけではないのでリスクが低減します。
トークンの漏洩検知
Response Wrappingで生成した一時トークンは一度使うと二度と使えなくなります。
これは逆に言うと、生成して本来使いたい人やマシンがその一時トークンでロッカーを開けようとしたときにエラーが発生したならば、他の誰かが一時トークンを使用したということ(=漏洩検知)になります。
公開期限がある
Cubbyholeというロッカーには使用期限があるため、一定期間が過ぎた場合、一時トークンとその中身は破棄されます。
これによって誰の記憶にも残っていないほど昔に発行したトークンが生きてて不正利用された、というような負債がなくなります。
使ってみる
Response Wrappingはトークン生成や秘密情報の取得など、様々なケースで利用できる汎用的な仕組みです。
具体的な使用例を以下に示します。
vault tokenを生成する際に
保管&一時トークン生成
通常の生成方法に-wrap-ttl
オプションを付けるだけで済みます。
$ vault token create -wrap-ttl=10m Key Value --- ----- wrapping_token: s.xZErNVt6BwAWMV99Td1AcDsH wrapping_accessor: mguresS2VWq8mWCPVyZSTZB2 wrapping_token_ttl: 10m wrapping_token_creation_time: 2019-08-20 04:46:00.065733 +0900 JST wrapping_token_creation_path: auth/token/create wrapped_accessor: 3b4lzXZDHozAoyBvaIZGlgTN
発行されたトークンがCubbyholeに保管され、それを開けるための一時トークンs.xZErNVt6BwAWMV99Td1AcDsH
が発行されました。
Unwrapして取得
一時トークンs.xZErNVt6BwAWMV99Td1AcDsH
を使ってCubbyholeから取り出します。
$ vault unwrap s.xZErNVt6BwAWMV99Td1AcDsH Key Value --- ----- token s.UVgQf13X0xtBeFyurqjtVkWn token_accessor 3b4lzXZDHozAoyBvaIZGlgTN token_duration ∞ token_renewable false token_policies ["root"] identity_policies [] policies ["root"]
2回目はエラー
もう一度一時トークンを使って取り出せるか試してみます。
$ vault unwrap s.xZErNVt6BwAWMV99Td1AcDsH Error unwrapping: Error making API request. URL: PUT http://127.0.0.1:8200/v1/sys/wrapping/unwrap Code: 400. Errors: * wrapping token is not valid or does not exist
エラーが発生しました。
一度取り出すと二度と取り出せないことが確認できます。
KVの値を取得する際に
通常であれば
で行ったようにKVにアクセスできるポリシーを管理し、それを使えるユーザやトークンを発行して〜という流れを踏みますが、1度きりの取得で良い場合はResponse Wrappingが有用です。
kvを有効化します。
$ vault secrets enable -version=2 kv
何かしらデータを保存します。
$ vault kv put kv/mysql password=hogehoge Key Value --- ----- created_time 2019-08-19T20:16:52.548115Z deletion_time n/a destroyed false version 1
保管&一時トークン生成
kvの値をCubbyholeに保管し、一時トークンを発行します。
$ vault kv get -wrap-ttl=10m kv/mysql Key Value --- ----- wrapping_token: s.otcshQXo8jp2TEqg9isld0go wrapping_accessor: 2n5Chj0pWEY3eTOlu64Nu02c wrapping_token_ttl: 10m wrapping_token_creation_time: 2019-08-20 05:17:35.374926 +0900 JST wrapping_token_creation_path: kv/data/mysql
s.otcshQXo8jp2TEqg9isld0go
が一時トークンです。
Unwrapして取得
unwrapします。
$ vault unwrap s.otcshQXo8jp2TEqg9isld0go Key Value --- ----- data map[password:hogehoge] metadata map[created_time:2019-08-19T20:16:52.548115Z deletion_time: destroyed:false version:1]
データが取得できました。
値はCubbyholeに保管されたものなので元のKVを更新しても変わらない
Cubbyholeに保管されたものは元のKVを更新しても変わりません。実際に検証してみます。
一時トークンを取得します。
$ vault kv get -wrap-ttl=10m kv/mysql Key Value --- ----- wrapping_token: s.wpv58UFOsBINSXxMaXPLwfWl wrapping_accessor: ZpN5Kl43LJ4XBDGZCmpnhX9m wrapping_token_ttl: 10m wrapping_token_creation_time: 2019-08-20 06:19:24.887369 +0900 JST wrapping_token_creation_path: kv/data/mysql
元のKVを更新します。
$ vault kv put kv/mysql password=fugafuga Key Value --- ----- created_time 2019-08-19T21:19:31.942267Z deletion_time n/a destroyed false version 2
unwrapしてみます。
$ vault unwrap s.wpv58UFOsBINSXxMaXPLwfWl Key Value --- ----- data map[password:hogehoge] metadata map[created_time:2019-08-19T20:16:52.548115Z deletion_time: destroyed:false version:1]
以前の値のままです。