tenant-pass

鍵管理(Vault / OpenBao Transit)

ローテーションキーと署名鍵を HashiCorp Vault / OpenBao の Transit に置き、鍵をホストからコピーできないようにする方法を説明します。得られる効果、計算結果が変わらない理由、準備の手順、ポリシー、鍵の入れ替え、可用性を扱います。

このページの見出し
  1. Transit に置くと何が変わるか
  2. 計算結果が変わらない理由
  3. 準備
  4. 設定
  5. Transit の鍵の入れ替え
  6. 公開鍵
  7. 可用性

tenant-pass と tenant-pass-gateway の鍵は、ファイルの代わりに鍵管理システムに置くこともできます。対応しているのは HashiCorp Vault と OpenBao で、どちらも Transit シークレットエンジン(鍵を外に出さずに暗号の計算だけを引き受ける機能)を使います。

鍵使う部品Transit の鍵の種類呼び出す操作
ローテーションキー(パスワードの導出)tenant-passhmactransit/hmac/<key>/sha2-256
ジョブチケットの署名鍵tenant-passed25519transit/sign/<key>
ゲートウェイの署名鍵tenant-pass-gatewayed25519transit/sign/<key>

Transit に置くと何が変わるか

鍵がファイルにあると、tenant-pass のホストに侵入した攻撃者はローテーションキーをコピーできます。そうなると、攻撃者を追い出した後も、その鍵が有効な間はずっと、ホストに触れることなくすべてのテナントのパスワードを導出できてしまいます。

Transit に置けば、鍵は Vault の外に出ません。攻撃者が鍵を使えるのは、ホストとその Vault のトークンを握っている間に限られ、トークンを無効にした時点で何も導出できなくなります。鍵を使った記録も、すべて Vault の監査ログに残ります。

逆に、いままさにホストを握っている攻撃者は止められません。そこは変わらないので注意してください。

計算結果が変わらない理由

ファイルの鍵から Transit に移しても、導出されるパスワードは変わりません。Transit の hmac/…/sha2-256 は、鍵の値を使ったごく普通の HMAC-SHA256 だからです。導出の仕様 もテストベクターもそのまま当てはまります。テスト用に書き出した鍵で、Transit の出力と手元で計算した HMAC が一致することも確かめています。

Transit の鍵はバージョンが上がっていくので、ローテーションキーごとに鍵の名前とバージョンの両方を指定します。パスワードはローテーションキーが有効な間ずっと同じでなければならないため、tenant-pass は常にそのバージョンを指定して計算を頼み、別のバージョンで返ってきた応答は拒否します。

署名は、Transit が返した後に tenant-pass が手元で検証します。使うのは起動時に読み込んだ公開鍵です。Transit の鍵の設定を間違えていても、検証に通らないトークンが外に出ることはありません。

Transit を呼ぶ回数は多くありません。導出した値はアカウントとウィンドウごとにメモリにキャッシュする(件数と期間には上限があります)ので、呼ぶのはリクエストごとではなく、アカウントとウィンドウごとに 2 回ほどです。

準備

Transit を有効にして、鍵を 3 つ作ります。

vault secrets enable transit
vault write -f transit/keys/tenant-pass-rotation type=hmac key_size=32
vault write -f transit/keys/tenant-pass-jobs type=ed25519
vault write -f transit/keys/tenant-pass-gateway type=ed25519

鍵を書き出せる設定(エクスポート可能)にはしないでください。それでは Transit に置く意味がなくなります。

ポリシーは部品ごとに 1 つ作り、必要な権限だけを付けます。

# tenant-pass
path "transit/hmac/tenant-pass-rotation/*" { capabilities = ["update"] }
path "transit/sign/tenant-pass-jobs"       { capabilities = ["update"] }
path "transit/keys/tenant-pass-jobs"       { capabilities = ["read"] }
# tenant-pass-gateway
path "transit/sign/tenant-pass-gateway" { capabilities = ["update"] }
path "transit/keys/tenant-pass-gateway" { capabilities = ["read"] }

Vault への認証方式は問いません(Kubernetes、AppRole、クラウドの IAM など)。取得したトークンは、Vault Agent かサイドカーにファイルとして書き出させてください。tenant-pass はリクエストのたびにこのファイルを読み直すので、トークンが更新されても再起動は要りません。

設定

"kms": {
  "vault": {
    "address": "https://vault.internal:8200",
    "token_file": "/run/vault/token",
    "namespace": "",
    "mount": "transit",
    "tls": {"ca_file": "/etc/tenant-pass/vault-ca.pem"}
  }
},
"rotation": {
  "keys": [
    {"id": "r-2026-11", "transit": {"key": "tenant-pass-rotation", "version": 1}, "not_before": "2026-11-01T00:00:00Z"}
  ]
},
"job_tickets": {
  "signing_key": {"id": "tp-jobs-1", "transit": {"key": "tenant-pass-jobs", "version": 1}}
}
キー説明
addressVault の URL です。https が必須です。暗号化しない接続を使えるのは、insecure_plaintext(と最上位の allow_insecure_plaintext)を設定した場合だけです(テスト専用)。
token_fileVault のトークンを入れたファイルです。シークレットのファイルの決まり(所有者と書き込み権限)が当てはまります。リクエストのたびに読み直します。
namespaceX-Vault-Namespace ヘッダーとして送ります(Vault Enterprise / HCP 用)。
mountTransit をマウントしたパスです。既定は transit です。
tlsca_file、server_name、cert_file / key_file(クライアント証明書で認証する場合)を指定します。証明書の検証は常に行います。

Vault がリダイレクトを返しても、tenant-pass は従いません。従えば、トークンを別の場所に送ってしまうおそれがあるからです。環境変数で指定した HTTP プロキシも使いません。そのため address には、アクティブなノード(またはアクティブなノードにだけ振り分けるロードバランサー)を指定してください。待機中のノードにつながってリダイレクトが返ってきたら、エラーになります。エラーに含まれるのは HTTP のステータスだけで、レスポンスボディやトークンは含まれません。

ゲートウェイの設定も同じ形で、kms.vault と signing_key.transit を書きます。

Transit の鍵の入れ替え

ローテーションキー

vault write -f transit/keys/tenant-pass-rotation/rotate を実行すると、バージョン 2 ができます。これを、ファイルの鍵のときと同じように、未来の not_before を付けた新しいローテーションキーとして設定に追加します(手順は 運用)。

{"id": "r-2026-12", "transit": {"key": "tenant-pass-rotation", "version": 2}, "not_before": "2026-12-01T03:00:00Z"}

古いローテーションキーを設定から消すまでは、Transit でバージョン 1 を使える状態(min_available_version)にしておいてください。

署名鍵

Transit で鍵を入れ替えたら、新しいバージョンを新しい id で設定し、新しい公開鍵を署名を検証する側に渡します。ゲートウェイの鍵なら、tenant-pass の gateway_keys に追加します。tenant-pass 自身のジョブ用の鍵は、ジョブチケットの検証にそのまま使われるので、何もしなくてかまいません。古い鍵 ID は、その鍵で署名したパスやチケットがすべて期限切れになるまで、信頼したままにしておきます。

公開鍵

Transit に置いたゲートウェイの鍵を tenant-pass の gateway_keys に設定するには、公開鍵を PEM の形式に変換します。

vault read -field=keys -format=json transit/keys/tenant-pass-gateway \
  | jq -r '."1".public_key' | base64 -d > gw.raw
# Ed25519 の SubjectPublicKeyInfo の先頭部分(8 進のエスケープは POSIX のどの printf でも使える)
( printf '\060\052\060\005\006\003\053\145\160\003\041\000'; cat gw.raw ) \
  | openssl pkey -pubin -inform DER -outform PEM > gateway-2026-11.pub

可用性

Transit の鍵を使うと、キャッシュにないパスワードを導出するたびに Vault が要ります。Vault に接続できなければ、キャッシュにないウィンドウへのリクエストは 503 unavailable で失敗します。監査ログでは store_error になり、エラーに kms が含まれます。Vault は高可用性の構成で動かし、このエラーにアラートを設定してください。

この文書は、リポジトリにある docs/ja/kms.md をもとにしています(英語版は docs/en/kms.md)。