認可と職務分掌
Merlon は対話的ユーザーを JWT セッションで、非対話的クライアントを API キーで認証する。両方の経路に同一のロールモデルが適用される。導入組織は、これらのロールを自組織のアクセス制御・変更管理ポリシーにマッピングしなければならない。
最初の管理者
新規デプロイにはアカウントが1つもなく、ログインに使える認証情報も存在しない。ブラウザから /setup で到達する POST /api/v1/setup は、唯一の初期 Admin アカウントを作成し、それ以外は何もしない。
- 認証なしで到達できる。その時点では、誰かを認証しうる認証情報が存在しないためである。
- ちょうど1回だけ成功する。ユーザー行が1件でも存在すれば
409を返すため、後から2人目の管理者を発行する目的で再実行することはできない。 - パスワードは12文字以上を要求する。
- ログイン画面からリンクしている。そうしなければ初回運用者は URL を知っている必要がある。このリンクは条件なしで表示する。アカウントが存在するかどうかをサーバーに問い合わせると、ログイン画面へ到達できる者すべてにその事実を開示してしまうためである。
セットアップ後、Admin は「ユーザ管理」または /api/v1/admin/users API でローカルアカウントを管理する。
| 操作 | エンドポイント |
|---|---|
| アカウント一覧 | GET /api/v1/admin/users |
| アカウント作成 | POST /api/v1/admin/users |
| ロールまたは有効状態の変更 | PATCH /api/v1/admin/users/{id} |
| 代替パスワードの設定 | POST /api/v1/admin/users/{id}/reset-password |
| 全セッションの強制終了 | POST /api/v1/admin/users/{id}/revoke-sessions |
パスワードは12文字以上でなければならない。ロール、有効状態、パスワードの変更および明示的なセッション失効は、対象アカウントで有効だった全セッションを終了する。その後のログインは現在のロールで新しいセッションを開始する。無効なアカウントはログインできない。最後の有効Adminは無効化も降格もできない。
アカウント変更とその監査レコードは同一transactionでcommitされる。監査詳細には権限変更を含むが、パスワード、パスワードhash、token、refresh-session family識別子を含めない。
デプロイ上の帰結として、初回起動から最初の管理者作成までの区間が、未認証の呼び出し元が特権アカウントを作成しうる唯一の瞬間となる。セットアップを完了する前に、新規インスタンスを信頼できないネットワークへ公開しないこと。
MERLON_AUTH_ENABLED=false は認証を完全に無効化する。これはデモ構成とローカル開発のために存在する。本番で設定してはならない。設定リファレンスを参照。
セッションのライフサイクル
ログインに成功するたびに独立したリフレッシュトークンファミリーが開始され、アクセストークンにはトークン識別子とファミリー識別子の両方が付与される。リフレッシュは同じファミリー内でリフレッシュトークンをローテーションする。ローテーション済みトークンの再利用を検知した場合は、侵害の兆候としてファミリー全体を失効させる。
ログアウトは、現在のアクセストークンとリフレッシュトークンファミリーを失効させる。同じユーザーの他の並行セッションは有効なままであり、直後の再ログインは別のファミリーを開始するため、先のログアウトの影響を受けない。1ユーザーが保持できる有効なファミリーは最大5つであり、それを超えるセッションを開始すると最も古いファミリーが失効する。
PostgreSQL 構成では、認証済みリクエストごとに、永続化されたリフレッシュトークンファミリーが引き続き有効か確認する。このため、ログアウトと強制失効は API レプリカ間で共有され、API プロセスを再起動しても維持される。
旧ビルドが発行したセッションファミリー識別子のないアクセストークンは、更新後に拒否される。該当ユーザーは再度ログインする必要がある。
各リフレッシュトークンファミリーには、セッション開始時のロールも記録される。管理者がユーザーのロールまたは有効状態を変更すると、既存のアクセストークンとリフレッシュトークンは拒否される。ユーザーは変更後の権限で再度ログインする必要がある。
リフレッシュとログアウトは、Cookie 認証を使用する状態変更リクエストである。クライアントは csrf_token Cookie の値を X-CSRF-Token ヘッダーへ設定しなければならない。値がない場合や一致しない場合、サーバーはセッション状態を変更する前に 403 で拒否する。
永続化されたサーバー側の失効を確認できない場合は、ログアウト成功として扱わずエラーを返す。ブラウザの Cookie は消去し、失敗した試行を監査ログへ記録する。プロセス内の補助的な失効キャッシュへの書込み失敗は、PostgreSQL へcommit済みの失効を取り消さない。
Admin は POST /api/v1/admin/users/{id}/revoke-sessions を呼び出し、指定ユーザーの現在有効なファミリーをすべて失効できる。これは意図的な強制ログアウトに使用するユーザー単位の経路であり、その後の正常なログインは拒否しない。ログイン成功、リフレッシュ、ログアウト、現在セッションの失効、ユーザー単位の失効は、それぞれ異なる監査アクションとして記録される。トークン値とリフレッシュファミリー識別子は監査ログへ記録しない。
ロール
| 権限 | Admin | Analyst | Viewer |
|---|---|---|---|
ホワイトリスト登録を申請する(whitelist:request) | Yes | Yes | No |
ホワイトリスト登録を承認する(whitelist:approve) | Yes | No | No |
監査記録を読み取る(audit:read) | Yes | No | No |
ローカルユーザー管理(user:manage) | Yes | No | No |
ルールの作成・更新・インポート・有効化・無効化(rule:write) | Yes | No | No |
大規模な対象母集団に対する一括実行を確定する(batch:execute:large) | Yes | No | No |
顧客を再スコアリングする(cdd:score) | Yes | Yes | No |
リスク階層のオーバーライド提案を承認する(cdd:override:approve) | Yes | No | No |
この表が権限モデルの全体である。GET /api/v1/system/capabilities は別立ての権限表ではなくこの表から回答を導出するため、ここに権限を追加すれば追加の配線なしに運用画面へ反映される。
ケイパビリティの発見
GET /api/v1/system/capabilities は、管理機能および権限で保護された機能のそれぞれについて、available / not_configured / forbidden / unsupported / degraded / unavailable のいずれであるか、必要な権限、画面として提供されるのか API のみなのか、そしてドキュメントの所在を返す。GET /api/v1/auth/me は同一セッションの auth_mode・roles・permissions を返す。
UI はこれを用いて操作を隠すか、理由を表示する。これは認可ではない。ここに挙げられたケイパビリティは、実際に処理を行うルート側でも再度強制される。クライアントが隠した操作であっても、サーバーは同じように拒否する。
auth_mode は 3 種類のデプロイを区別する。
auth_mode | 意味 |
|---|---|
session | ユーザーがログインする。API キーも併用できる |
api_key_only | API キーによる認証は行われるが、JWT 署名鍵が未設定のためユーザーはログインできない |
disabled | MERLON_AUTH_ENABLED=false。いかなるリクエストにもロールが存在しない |
認証を無効にしたデプロイでは、依存関係が設定されているケイパビリティはすべて available を返す。拒否の根拠となるロールが存在しないためである。一方、そのデプロイが設定していない機能は not_configured のままとなる。権限がないことと機能がないことは別の事実である(ADR-0024)。
API のみで提供される機能
すべてのバックエンド機能に画面があるわけではない。意図的な非提供は、利用者が探し当てるのではなく明示的に記録する。
| ケイパビリティ | エンドポイント | 画面を用意していない理由 |
|---|---|---|
retention.manage | GET/PUT /api/v1/admin/retention-policies | 保持期間は管理者がデプロイごとに一度設定するもので、変更は監査される。保持とパージ を参照 |
accounts.manage | POST /api/v1/accounts、GET /api/v1/accounts/{id}、POST/GET /api/v1/accounts/{id}/customers | 口座の紐付けはアナリストではなくアダプター層が取り込み時に確立する。アダプターガイド を参照 |
ホワイトリストのワークフローでは、申請者が自身の申請を承認できないことが強制される。これにより、ホワイトリスト判断について、独立した一次申請と二次承認の統制が提供される。
ルールの有効化・無効化についても、同じ分離がアプリケーション内で強制される。事前チェックではなくリポジトリのトランザクション内で実施される(ADR-0014)。対象バージョンを正確にロックしたうえで、承認者と当該バージョンの作成者が同一の場合、またはいずれかの識別情報が欠けている場合は 403 で拒否する。推測による補完は行わず、フェイルクローズドで動作する。API 経由で作成されたルールおよびルールバージョンは常に無効状態であるため、有効化は必ず別個に帰属可能な二つ目の行為となる。
状態変更のたびに、同一トランザクション内で rule_activation_events 行が書き込まれ、対象バージョン・作成者・承認者・要求された状態・タイムスタンプが記録される。サービス実行ロールにはこの承認台帳に対する SELECT と INSERT のみが付与されるため、承認の証跡を事後に改変することはできない。
認証設計と認証情報の取り扱いについては、設定リファレンス を参照。