Carpe Diem

備忘録

HashiCorp VaultのPolicyでハマったこと

概要

christina04.hatenablog.com

で説明したようにHashiCorp Vaultでは柔軟な権限設定ができますが、触っていて「え、こういう挙動・設定なの?」とハマった事がいくつかあったのでまとめます。

環境

  • vault v0.11.5

ハマったところ

pathは前方一致

例えば

path "secret/foo*" {
  capabilities = ["create"]
}

と権限を付与すれば、

  • secret/foo
  • secret/foobar
  • secret/foo/bar

のそれぞれでcreate権限が付与されます。

Policies - Vault by HashiCorp

KVのv2でpathが変わった

v1ではsecretというパスでkvを使いたい時

path "secret/*" {
  capabilities = ["create"]
}
path "secret/foo" {
  capabilities = ["read"]
}

というようにpolicy設定していましたが、v2では

path "secret/data/*" {
  capabilities = ["create"]
}
path "secret/data/foo" {
  capabilities = ["read"]
}

このように/data/というpathが挟まります。

Policies - Getting Started - Vault by HashiCorp

ただ次で説明するようにコマンドによって/data/だったり/metadata/だったりとpathが異なるため、全て対象にしたい場合はこれまで通りsecret/*という指定にしてください。

KV v2のpolicyが細かくなった

v2からコマンドによってpolicyのpathが変わりました。
特にlist, delete系が大きく変わりました。

v1では

path "secret/data/dev/team-1/*" {
  capabilities = ["create", "update", "read", "list", "delete"]
}

で全権限が設定できましたが、v2ではそうはいきません。

KV - Secrets Engines - Vault by HashiCorp

以下

$ vault kv コマンド secret/dev/team-1/xxx

というpathsecret/dev/team-1/xxxに対する権限設定です。

create, update, read系

この辺はこれまで通りです。

path "secret/data/dev/team-1/*" {
  capabilities = ["create", "update", "read"]
}

delete系

最新バージョンのキーのdelete

v2ではバージョン管理ができますが、最新版だけ消す権限は以下です。

path "secret/data/dev/team-1/*" {
  capabilities = ["delete"]
}

これで

$ vault kv delete secret/dev/team-1/foo

が使えます。

バージョン指定のdelete

バージョンを指定して消す権限は別になります。

$ vault kv delete -versions=1 secret/dev/team-1/foo

こういう使い方の場合は、

path "secret/delete/dev/team-1/*" {
  capabilities = ["update"]
}

という権限が必要です。
こちらだけでもバージョン指定すれば全バージョン消せますが、手間なので先程のdelete権限も一緒に設定した方が良いです。

undelete

deleteしたものを戻す権限です。

path "secret/undelete/dev/team-1/*" {
  capabilities = ["update"]
}

destroy

完全に削除するdestroyの権限です。

path "secret/destroy/dev/team-1/*" {
  capabilities = ["update"]
}

list

list権限です。

path "secret/metadata/dev/team-1/*" {
  capabilities = ["list"]
}

Policyは継承されない

vaultのpolicyはwhitelist形式です。
なので例えば

path "secret/data/*" {
  capabilities = ["create"]
}
path "secret/data/foo" {
  capabilities = ["read"]
}

というpolicyがあったとして、期待する挙動は

  • secret/*ではcreate権限あり
  • secret/foo ではcreateとreadの両方の権限がある

でしたが、実際は

  • secret/foo ではcreate権限が失われ、read権限のみになる

という挙動でした。

# 全体的な書き込み権限はある
$ vault kv put secret/piyo hoge=foo
Key              Value
---              -----
created_time     2018-12-20T06:03:19.38677Z
deletion_time    n/a
destroyed        false
version          1

# secret/fooへの書き込み権限が剥奪
$ vault kv put secret/foo hoge=foo
Error writing data to secret/data/foo: Error making API request.

URL: PUT http://127.0.0.1:8200/v1/secret/data/foo
Code: 403. Errors:

* 1 error occurred:
    * permission denied

ただこれは逆に言えば親子関係を意識せず権限設定できるので、「知らないところで許可されてしまっていた!」みたいなオペミスが減ると思います。

KV v2ではallowed_parameterといった設定で変な挙動になる

github.com

でも挙がっているように、v2ではデータ構造が変わったためallowしたはずがdenyになっていたりします。
なのでv2では使わない方が良さそうです。

ソース