Carpe Diem

備忘録

VaultのCubbyhole Response Wrapping

概要

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の値を取得する際に

通常であれば

christina04.hatenablog.com

で行ったように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]

以前の値のままです。

ソース