zaki work log

作業ログやら生活ログやらなんやら

[HashiCorp Vault] KVシークレットエンジンのデータの読み書きメモ (CLI/REST)

HashiCorp VaultのKVシークレットエンジンを使ったkey/value形式のデータの読み書きを試した。
触り始めて間もないので解釈や表現がおかしいところはあるかも。(あったら教えてください)

developer.hashicorp.com

HashiCorp VaultにおいてシークレットエンジンにはAWSAzureSSHなど様々なデータ構造の定義があり、本エントリではその中の一つであるkey/value形式のデータを扱うKVシークレットエンジンを使ったデータの読み書きについての簡単にまとめ。

ほんとはイケてないんだけど、作業はすべてrootで実施(root tokenでログイン済み状態)
RESTについては、使用するトークン(例では環境変数 VAULT_TOKEN にセットしてる)は、同様にroot tokenで、X-Vault-Tokenヘッダで指定する。X-Vault-Tokenでなく、一般的な"Authorization: Bearer $VAULT_TOKEN"でも認証可能。

KVシークレットエンジンの有効化

「KVシークレットエンジンの有効化」というと始めはピンとこなかったけど、「KV形式のデータを扱うための箱を作る」が近いイメージだと思う。
C言語風にいうとKV構造体変数を保持する領域を確保する、みたいな。

my-kv-secretという名前(パス)のKVシークレットエンジンを有効にするには以下のコマンド。

/ $ vault secrets enable -path=my-kv-secret -version=2 kv
Success! Enabled the kv secrets engine at: my-kv-secret/

-pathオプションを省略すると、kvというパスのKVシークレットエンジンが作成される。
-versionオプションを省略するとKVシークレットエンジンversion1で作成される。version2で作成する場合は-version=2を付加。
普通のLinuxコマンドと違って、オプションを末尾に付与できないので注意。

バージョンの違いについてはドキュメント参照

developer.hashicorp.com

KVシークレットエンジンの無効化

有効化の逆なので、要は削除。

/ $ vault secrets disable my-kv-secret
Success! Disabled the secrets engine (if it existed) at: my-kv-secret/

KVシークレットエンジンの一覧

/ $ vault secrets list
Path             Type         Accessor              Description
----             ----         --------              -----------
cubbyhole/       cubbyhole    cubbyhole_fa65f299    per-token private secret storage
identity/        identity     identity_0917a11b     identity store
my-kv-secret/    kv           kv_838b2e62           n/a
sys/             system       system_8a5e2f0e       system endpoints used for control, policy and debugging

-detailedを付与すると詳細が表示される。

読み書きと一覧

最初わかりづらかったんだけど、「一つのKVシークレットエンジンにkey/value形式のデータを保存」ではなく「一つのKVシークレットエンジン内にあるキー毎にkey/value形式のデータを保存」というデータ構造になってる。

という表現もやっぱりわかりづらいんで、百聞は一見に如かずで実行例。

write

CLI

my-kv-secretシークレットエンジンに、server1server2いうキーで、ユーザー名・パスワード・IPアドレスを保存。

/ $ vault kv put my-kv-secret/server1 username=zaki password=curry_tabetai host=192.168.10.89
Success! Data written to: my-kv-secret/server1
/ $ vault kv put my-kv-secret/server2 username=zaki password=curry_tabeta host=192.168.10.13
Success! Data written to: my-kv-secret/server2

ちなみにこの書式はKVシークレットエンジンversion1のもので、version2では非推奨。
version2では-mountオプションでシークレットエンジン名を指定する書式が推奨される。

/ $ vault kv put -mount=my-kv-secret server3 username=zaki password=asuha_curry host=192.168.10.10
Success! Data written to: my-kv-secret/server3

JSONファイル

JSON形式のファイルを使ったwriteも可能。

/ $ cat /var/tmp/sample.json 
{
  "username": "zaki",
  "password": "json-data",
  "host": "192.168.18.6"
}
/ $ vault kv put -mount=my-kv-secret server4 @/var/tmp/sample.json
Success! Data written to: my-kv-secret/server4

REST

developer.hashicorp.com

POSTするデータはdata以下に作成するのがポイント (ここ見落として30分くらい溶かした笑)

$ curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
  -X POST \
  -d '{ "data": { "username":"zaki", "password":"curl-post", "host":"192.168.18.21" } }' \
  http://192.168.0.75:8200/v1/my-kv-secret/data/server5
{"request_id":"45c406a2-9d38-b46c-fd48-32c887366fd8","lease_id":"","renewable":false,"lease_duration":0,"data":{"created_time":"2024-02-20T13:42:48.263373535Z","custom_metadata":null,"deletion_time":"","destroyed":false,"version":1},"wrap_info":null,"warnings":null,"auth":null}

JSONファイルを使う場合も同様

$ cat tmp/post.json 
{ "data": { "username":"zaki", "password":"curl-json-post", "host":"192.168.18.26" } }
$ curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
  -X POST \
  -d @tmp/post.json \
  http://192.168.0.75:8200/v1/my-kv-secret/data/server6
{"request_id":"3a52eeff-2be4-9b01-94cf-d6316d64f208","lease_id":"","renewable":false,"lease_duration":0,"data":{"created_time":"2024-02-20T13:45:11.476087387Z","custom_metadata":null,"deletion_time":"","destroyed":false,"version":1},"wrap_info":null,"warnings":null,"auth":null}

エンドポイントはシークレットエンジンのバージョンで異なるので注意。
前述の例はversion2の場合。
version1の場合は/v1/<secret-engine-name>/<key-name>となり、/dataが無くなる。
(先頭の/v1APIバージョンであってシークレットエンジンのバージョンではない)

developer.hashicorp.com

ここまで全部ユーザー名・パスワード・ホストと、データ構造をそろえているけど、これはたまたまそうしてるだけで、別にそろってる必要はなく柔軟に書き込み可能。

list

/ $ vault kv list my-kv-secret
Keys
----
server1
server2
server3
server4
server5
server6

writeで作った6件分のキーがリストされていることがわかる。

RESTの場合は以下の通り。

$ curl -s -H "X-Vault-Token: $VAULT_TOKEN" -X LIST http://192.168.0.75:8200/v1/my-kv-secret/metadata | python -m json.tool
{
    "request_id": "fb371bc4-b31b-7cb1-a870-e3fedc8411ef",
    "lease_id": "",
    "renewable": false,
    "lease_duration": 0,
    "data": {
        "keys": [
            "server1",
            "server2",
            "server3",
            "server4",
            "server5",
            "server6"
        ]
    },
    "wrap_info": null,
    "warnings": null,
    "auth": null
}

ちなみにAPIリファレンスにこれ乗って無さそうなんだけど。。(/metadataのあとのパス記載が全てrequiredになってる)

read

CLI

putで作成したデータは当然getで参照できる。

/ $ vault kv get my-kv-secret/server1
====== Secret Path ======
my-kv-secret/data/server1

======= Metadata =======
Key                Value
---                -----
created_time       2024-02-20T13:30:15.916047056Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

====== Data ======
Key         Value
---         -----
host        192.168.10.89
password    curry_tabetai
username    zaki

KVシークレットエンジンversion2を使っていると、この通りメタデータも含まれる。(version1の場合はデータのみ) 書式についてもputと同様、-mountの使用が推奨されている。

/ $ vault kv get -mount=my-kv-secret server2
====== Secret Path ======
my-kv-secret/data/server2

======= Metadata =======
Key                Value
---                -----
created_time       2024-02-20T13:30:15.990461672Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

====== Data ======
Key         Value
---         -----
host        192.168.10.13
password    curry_tabeta
username    zaki

また、-formatを使えばjsonyaml形式でも出力できる。

/ $ vault kv get -format=json -mount=my-kv-secret server3
{
  "request_id": "804b3606-ee34-7734-1ff3-efa9011ce5d2",
  "lease_id": "",
  "lease_duration": 0,
  "renewable": false,
  "data": {
    "data": {
      "host": "192.168.10.10",
      "password": "asuha_curry",
      "username": "zaki"
    },
    "metadata": {
      "created_time": "2024-02-20T13:30:16.03813777Z",
      "custom_metadata": null,
      "deletion_time": "",
      "destroyed": false,
      "version": 1
    }
  },
  "warnings": null
}

REST

$ curl -s -H "X-Vault-Token: $VAULT_TOKEN" http://192.168.0.75:8200/v1/my-kv-secret/data/server4 | python -m json.tool
{
    "request_id": "b6370992-2cc7-9e63-97ff-ea7daf9d0e9b",
    "lease_id": "",
    "renewable": false,
    "lease_duration": 0,
    "data": {
        "data": {
            "host": "192.168.18.6",
            "password": "json-data",
            "username": "zaki"
        },
        "metadata": {
            "created_time": "2024-02-20T13:30:16.101513188Z",
            "custom_metadata": null,
            "deletion_time": "",
            "destroyed": false,
            "version": 1
        }
    },
    "wrap_info": null,
    "warnings": null,
    "auth": null
}

環境

  • HashiCorp Vault on Kubernetes
    • CHART: vault-0.27.0
    • APP VERSION: 1.15.2

更新と削除はまた別途…

=> 書いたよ (2024.07.31)

zaki-hmkc.hatenablog.com


ところでSecrets EngineだったりSecrets EnginesだったりSecrets enginesだったり公式ドキュメントの表記揺れが結構あるように見える。。どれが正解なの。。