このページの見出し
tenant-pass は、-config で指定した 1 つの JSON ファイルを読み込みます。すべての項目を含む例は examples/config.example.json にあります。
設定ファイルの決まり
読み込みは厳格です。知らないキー、重複したキー、JSON の後ろに続く余分なデータは、どれもエラーになります。タイプミスした設定が黙って無視されることはありません。
確認は起動の時点でまとめて行います。サーバーが動き出す前にすべての設定を確かめ、エラーが 1 つでもあれば起動をやめて、見つかったエラーを一度に表示します。同じ確認は tenant-pass check-config -config FILE でもでき、-connect を付けるとディレクトリとすべてのノードへの接続も試します。
期間は Go の書き方の文字列で書きます("30s"、"15m"、"1h")。
シークレットはファイルで渡す
パスワードや鍵は設定ファイルに書かず、そのファイルのパス(*_file)を指定します。シークレットのファイルは、次の条件をすべて満たしていなければなりません。
- 通常のファイルである
- グループやほかのユーザーが書き込めない
- 所有者が、tenant-pass を動かしているユーザーか root である
所有者まで確かめるのは、ほかのユーザーが持つファイルなら、権限の設定がどうであれ、そのユーザーが書き換えられるからです。グループやほかのユーザーが読めるファイルには、ログに警告を出します。ファイルの末尾の改行は 1 つだけ取り除きます。
公開鍵、CA 証明書のバンドル、証明書、JWKS のファイル、そして設定ファイルそのものも、何を信頼するかを決めるファイルです。そのため、シークレットと同じように書き込み権限と所有者を確かめます。こちらは、ほかのユーザーが読めても警告は出しません。設定ファイルも、グループやほかのユーザーが書き込めないようにしておいてください。
暗号化しない接続には 2 つの設定が要る
暗号化しない HTTP や、暗号化しないストアへの接続は、テストのためだけにあります。使うには、その項目の insecure_plaintext* と、最上位の allow_insecure_plaintext: true の両方を書く必要があります。片方だけでは起動しません。
最上位のキー
| キー | 既定値 | 説明 |
|---|---|---|
listen | ":8443" | 待ち受けるアドレスです。 |
tls | 必須 | サーバーの TLS の設定です。後で説明します。 |
insecure_plaintext_http | false | API を暗号化しない HTTP で待ち受けます。allow_insecure_plaintext が必要で、tls と一緒には使えません。 |
allow_insecure_plaintext | false | 暗号化しない設定を全体として許可します。本番では決して使わないでください。 |
gateway_keys | 必須 | 信頼するゲートウェイの公開鍵です。 |
pass | パスの検証の設定です。 | |
apps | 必須 | API を呼んでよいアプリケーションです。 |
directory | 必須 | テナントのディレクトリです。static と sql のどちらか一方を指定します。 |
rotation | 必須 | ローテーションキーと、ローテーションの時間の設定です。 |
kms | 鍵管理システムへの接続です(鍵管理(Vault / OpenBao Transit))。 | |
job_tickets | ジョブチケットの設定です(バックグラウンドジョブ(ジョブチケット))。 | |
nodes | 必須 | tenant-pass が管理するストアです。 |
limits | リクエストの制限です。 | |
shutdown | 停止するときの待ち時間です。 | |
log_level | "info" | debug、info、warn、error のどれかです。 |
tls
| キー | 説明 |
|---|---|
cert_file | サーバー証明書のチェーン(PEM)です。 |
key_file | サーバーの秘密鍵(PEM)です。シークレットのファイルの決まりが当てはまります。 |
client_ca_file | 任意です。クライアント証明書を検証する CA 証明書のバンドルで、指定すると apps[].client_cert_uri が使えます。クライアントが証明書を出せば検証しますが、証明書を必須にするかどうかはアプリケーションごとの設定で決まります。 |
TLS は 1.2 以上です。暗号スイートは Go の既定のままで、弱いと知られているものは入っていません。
gateway_keys[]
| キー | 説明 |
|---|---|
id | 鍵 ID です。パスのフッターの kid と照らし合わせます。^[a-z][a-z0-9_-]{0,62}$ に一致させます。 |
public_key_file | Ed25519 の公開鍵です。PEM の PUBLIC KEY(PKIX)の形式で、tenant-pass gen-gateway-key で作れます。 |
鍵はいくつでも並べられます。ゲートウェイが複数あるときや、鍵を入れ替えている途中で使います。
pass
| キー | 既定値 | 範囲 | 説明 |
|---|---|---|---|
max_ttl | "60s" | 1s〜5m | パスの exp − iat の上限です。 |
leeway | "5s" | 0〜30s | iat について許す時計のずれです。exp には決して使いません。"0s" を指定すると、ずれを許しません。 |
apps[]
| キー | 説明 |
|---|---|
name | アプリケーションの名前です。ゲートウェイがこのアプリケーション向けに署名するパスの aud と一致させます。^[a-z][a-z0-9_-]{0,62}$ に一致させます。 |
token_sha256 | アプリトークンの SHA-256 です。小文字の 16 進で 64 文字です。tenant-pass gen-app-token で作れます。 |
client_cert_uri | アプリケーションのクライアント証明書が持っていなければならない URI 形式の SAN(たとえば SPIFFE ID)です。tls.client_ca_file が必要です。 |
jobs | 任意です。このアプリケーションでジョブチケットを使えるようにします。中身は下の表をご覧ください。jobs がないアプリケーションは、チケットを手に入れることも、認証情報と交換することもできません。 |
apps[].jobs のキーは次のとおりです。
| キー | 説明 |
|---|---|
issue | bool です。true にすると、POST /v1/job-tickets を呼べるようになります。 |
max_ttl | 発行するチケットの有効期間の上限です(既定は 1h、1m〜24h)。有効期間がこれを超えるチケットは、交換するときにも拒否します。 |
max_tenants_per_minute | チケットを交換するときに、1 分間に扱えるテナントの数です(既定は 60、レプリカごと)。limits.max_tenants_per_minute とは別に数えます。 |
trusted_issuers | このアプリケーションが交換してよいチケットの発行者です。job_tickets.trusted_issuers の ID を並べます。 |
token_sha256 と client_cert_uri の少なくとも一方が必要です。両方を設定すると、すべてのリクエストで両方が必要になります。トークンのハッシュと証明書の URI は、アプリケーションごとに違う値にしてください。
directory
directory.static
設定ファイルにテナントの一覧を直接書きます。
"directory": {"static": {"tenants": [
{"id": "acme", "hosts": ["acme.example.com"], "node": "pg1", "account": "t_acme", "enabled": true, "apps": ["billing"]}
]}}
| キー | 説明 |
|---|---|
id | テナント ID です。^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$ に一致させ、ほかのテナントと重ならないようにします。 |
hosts | このテナントのサイトの正規化済みのホスト名です。1 つのホスト名は 1 つのテナントにしか属せません。 |
node | nodes[].name のどれかです。 |
account | そのノードでのアカウントの名前です。 |
enabled | false にすると、認証情報の発行を拒否します(403 denied)。 |
apps | このテナントの認証情報を取得してよいアプリケーションです。必須で、空にはできません。 |
directory.sql
テナントの情報をすでに持っている PostgreSQL か MySQL のデータベースで、利用者が用意したクエリを実行して調べます。
"directory": {"sql": {
"driver": "postgres",
"endpoint": {"address": "central-db.internal:5432", "user": "tenant_pass_reader", "password_file": "/run/secrets/directory_pw", "database": "control"},
"by_host": "SELECT t.id AS tenant_id, t.node, t.role AS account, t.status = 'active' AS enabled FROM tenant_domains d JOIN tenants t ON t.id = d.tenant_id WHERE d.domain = $1 AND d.verified AND t.app = $2",
"by_tenant": "SELECT id AS tenant_id, node, role AS account, status = 'active' AS enabled FROM tenants WHERE id = $1 AND app = $2"
}}
| キー | 説明 |
|---|---|
driver | postgres か mysql です。 |
endpoint | 接続先です。接続先の設定 をご覧ください。必要な列への SELECT 権限だけを持つ、読み取り専用のアカウントを使ってください。 |
by_host | host を持つパスに使うクエリです。パラメーターは、1 つ目($1 / ?)がホスト名、2 つ目($2 / ?)がアプリケーションの名前です。 |
by_tenant | tenant を持つパスに使うクエリです。パラメーターは、テナント ID とアプリケーションの名前です。 |
1 つのアカウントを 2 つ以上のテナントに対応させてはいけません。2 つの行が、あるいは同じサーバーを指す 2 つのノード名が同じアカウントを指していても、tenant-pass にはそれを見抜く手段がないからです。
どちらのクエリも、tenant_id、node、account、enabled の 4 列だけを、この順番とこの名前で返してください(名前は AS で付けます)。返してよいのは 0 行か 1 行で、2 行以上返ったときはエラーとして発行を拒否します。クエリは読み取り専用のトランザクションの中で実行されます。起動するときには、両方のクエリをダミーの値で 1 回ずつ実行して、構文が通ることと正しい列が返ることを確かめます。
どのアプリケーションにどのテナントを扱わせるかは、2 つ目のパラメーターを使ってクエリの中で絞り込みます。すべてのアプリケーションがすべてのテナントを扱ってよいなら、AND $2::text IS NOT NULL のように、そのつもりであることをクエリに書いておいてください。
rotation
| キー | 既定値 | 説明 |
|---|---|---|
window | "15m" | ウィンドウの長さです。秒単位(小数なし)で、1m〜24h です。 |
renew_before | "5m" | ウィンドウの残り時間がこの値以下になったら、次のウィンドウのパスワードを返します。0 < renew_before ≤ window/2 です。 |
sweep_interval | "30s" | MySQL と Redis のノードで、期限切れのパスワードを削除(スイープ)する間隔です。5s ≤ sweep_interval ≤ renew_before です。 |
max_clock_skew | "10s" | レプリカの時計とストアのサーバーの時計のずれとして許す上限です。これを超えると書き込みを拒否します(clock_skew)。1s ≤ max_clock_skew ≤ renew_before/4 です。 |
keys | 必須 | ローテーションキーです。 |
rotation.keys[] のキーは次のとおりです。
| キー | 説明 |
|---|---|
id | 鍵 ID(^[a-z][a-z0-9_-]{0,62}$)です。パスワードを導出する入力の一部なので、ID を変えると、その鍵のパスワードがすべて変わります。 |
secret_file | 32 バイト以上のランダムなバイト列を Base64 にしたものを入れたファイルです。tenant-pass gen-rotation-key で作れます。同じ並びの繰り返しのような、明らかに仮の値は拒否します。 |
transit | secret_file の代わりに、Vault / OpenBao にある鍵を {"key": "<Transit hmac key>", "version": N} で指定します(kms.vault が必要です)。バージョンは固定されます。 |
not_before | RFC 3339 の形式の時刻です。ウィンドウ n では、not_before ≤ Start(n) を満たす鍵のうち、not_before がいちばん新しい鍵を使います。起動する時点で、いちばん古い鍵の not_before が少なくとも 1 ウィンドウ分過去になっている必要があります。 |
rotation の設定とノード名は、すべてのレプリカでそろえてください。window を変えると、すべてのアカウントのウィンドウの区切りが変わります。変えるときの手順は 運用 にあります。
nodes[]
| キー | 使う種類 | 説明 |
|---|---|---|
name | すべて | ノードの名前です。ディレクトリから参照します。パスワードを導出する入力の一部です。 |
type | すべて | postgres、mysql、redis のどれかです。 |
endpoint | postgres、mysql | 管理者としての接続先です。 |
servers | redis | ACL ユーザーを持つすべてのサーバー(プライマリ、レプリカ、クラスターのすべてのノード)への、管理者としての接続先です。 |
account_pattern | すべて | 必須です。管理対象のアカウントの名前が一致しなければならない正規表現(Go の RE2 の書き方)です。^…$ の形で書きます。選択(いずれかに一致)の記号を使ってもパターンの外に抜けられないように、常に ^(?:…)$ として扱います。管理者のアカウントが使っていないプレフィックスを選んでください(たとえば ^t_[a-z0-9_]{1,40}$)。 |
managed_group | postgres | 必須です。管理対象のロールが、すべてメンバーになっていなければならないロールです。 |
managed_role | mysql | 必須です。管理対象のアカウントに、すべて与えられていなければならないロールです。 |
managed_role_host | mysql | managed_role のホストの部分です。既定は % です。 |
account_host | mysql | 管理対象のアカウントのホストの部分です。既定は % です。 |
acl_save | redis | 変更の後に ACL SAVE を実行します(aclfile を使うサーバー向けです)。 |
managed_marker | redis | ユーザーが管理対象であることを示すチャネルのパターンです(ユーザーは &<marker> のルールを持っている必要があります)。既定は tenant-pass:managed です。 |
max_conns | postgres、mysql | 管理者の接続プールの大きさです。既定は 4 です。 |
connect | すべて | クライアントに返す接続先で、host、port、database(Redis にはありません)を指定します。ふつうは PgBouncer などのコネクションプーラーやプロキシを指定します。 |
管理者のアカウントに必要な権限は、各ストアのページをご覧ください(PostgreSQL、MySQL、Redis)。
接続先の設定
directory.sql.endpoint、nodes[].endpoint、nodes[].servers[] の書き方です。ドライバーの接続文字列(DSN)は受け付けません。DSN の安全でない既定値や、環境変数からの読み込みが紛れ込まないようにするためです。
| キー | 説明 |
|---|---|
address | host:port です。 |
user | ログインする名前です。 |
password_file | パスワードを入れたファイルです。 |
database | データベースの名前です。PostgreSQL のノードでは必須です。 tenant-pass 専用のデータベースで、PUBLIC もどの管理対象のロールも接続できないようにしておく必要があります(PostgreSQL をご覧ください)。PostgreSQL や MySQL のディレクトリでも使います。 |
tls.ca_file | サーバーを検証するための CA 証明書のバンドルです。既定ではシステムのルート証明書を使います。 |
tls.server_name | サーバー証明書と照らし合わせる名前です。既定は address のホストの部分です。 |
tls.cert_file、tls.key_file | 接続に使うクライアント証明書です(任意)。 |
insecure_plaintext | TLS を使いません。最上位の allow_insecure_plaintext が必要です。テスト専用です。 |
TLS の証明書のチェーンとホスト名は必ず検証します。検証を省く設定はありません。
kms
"kms": {"vault": {"address": "https://vault.internal:8200", "token_file": "/run/vault/token", "mount": "transit", "tls": {"ca_file": "/etc/tenant-pass/vault-ca.pem"}}}
| キー | 説明 |
|---|---|
vault.address | Vault の URL です。https にします。insecure_plaintext を使う場合だけ例外です(最上位の allow_insecure_plaintext も必要で、テスト専用です)。 |
vault.token_file | Vault のトークンを入れたファイルです。リクエストのたびに読み直します。 |
vault.namespace | 任意です。X-Vault-Namespace ヘッダーとして送ります。 |
vault.mount | Transit をマウントしたパスです。既定は transit です。 |
vault.tls | 接続先の設定の tls と同じです。 |
job_tickets
| キー | 既定値 | 説明 |
|---|---|---|
signing_key | tenant-pass 自身がチケットに署名する鍵です。id と、private_key_file(PEM。tenant-pass gen-signing-key で作れます)か transit(key、version)のどちらかを指定します。POST /v1/job-tickets を使うには必要です。 | |
trusted_issuers | 外部の発行者(スケジューラーなど)です。[{"id", "public_key_file"}] の形で指定します。 | |
max_ttl | "1h" | 受け付けるチケットの有効期間の上限です(1m〜24h)。 |
signing_key と trusted_issuers の少なくとも一方が必要です。鍵 ID も鍵そのものも、互いに重ならず、gateway_keys のものとも違っていなければなりません。Transit の署名鍵については、起動するときにこれを確かめます。
limits
| キー | 既定値 | 説明 |
|---|---|---|
max_tenants_per_minute | 60 | アプリケーションごとに、1 分間に扱えるテナントの数です(レプリカごと)。 |
issue_timeout | "5s" | ディレクトリで調べる時間と、ストアを更新する時間を合わせた上限です(100ms〜1m)。 |
max_concurrent_requests | 256 | レプリカごとに、同時に処理する認証情報のリクエストの数です。超えた分には 503 busy を返します。 |
shutdown
| キー | 既定値 | 説明 |
|---|---|---|
drain | "5s" | SIGTERM を受けてから待ち受けを閉じるまで、この時間だけ /readyz が 503 を返します。その間に、ロードバランサーがリクエストを振り分けるのをやめます。 |
timeout | "10s" | その後、処理中のリクエストが終わるのを、最大でこの時間だけ待ちます。 |
コンテナの実行基盤(オーケストレーター)が停止を待つ時間は、drain + timeout より長くしてください。既定値のままなら 20 秒が目安です。Docker の既定の 10 秒では足りません。
この文書は、リポジトリにある docs/ja/configuration.md をもとにしています(英語版は docs/en/configuration.md)。