API ゲートウェイ
HTTP の入口:認証、署名、アクセス制御、オブザーバビリティ
プロジェクト背景
1つのゲートウェイがエンドユーザー向けアプリ、テナント/パートナー向け管理画面、そして後に外部向け管理 API を提供する。ルートごとに認証、テナント解決、アクセス制御、オブザーバビリティの組み合わせが異なり、すべての下流サービスは監査のために呼び出し元を知る必要がある。
アーキテクチャ
クライアント → Gin ミドルウェアチェーン(ログ/リカバリー → トレーシング → メトリクス → ドメイン/テナント解決 → トークン認証 → アカウント状態 → ブラックリスト/ホワイトリスト → IP ポリシー)→ 入力検証と権限チェックを行い gRPC サービスへファンアウトするハンドラー → クライアントごとに整形したレスポンス。認証ミドルウェアはオペレーター、IP、パス、テナント、トレース ID を送信側の gRPC メタデータに書き込む。
主な技術ポイント
初期ミドルウェア:ユーザーコンテキストを注入するトークン認証、リクエスト署名検証、多次元のブラックリスト/ホワイトリスト、ドメインからテナントへの解決、IP ポリシー、panic リカバリー付き構造化ログ、OpenTelemetry トレーシング、Prometheus メトリクス
後の追加:認証が必要な全ルートへのアカウント状態ガード、プラットフォーム別のドメインスイッチ、すべての下流 gRPC 呼び出しへのオペレーター/テナント/トレースのメタデータ付与
パートナーネットワーク向けの階層型・フィールド単位の認可:オペレーターは自分の配下にのみ操作でき、機微なフィールド(リスクレベル、紐付け IP、パスワード)には個別の権限を設定
管理画面レスポンスでの PII マスキング。複数サービスにまたがるアカウント作成の補償ロールバック
サービス横断のリストフィルターを ID 集合に解決し、並列に実行
コア実装
合成可能なミドルウェアチェーン
横断的関心事をそれぞれ独立した Gin ミドルウェアにし、ルートグループが必要なポリシーだけを選んで適用できるようにした。
Why: エンドユーザー、管理画面、連携の各ルートで必要なセキュリティは異なる。関心事を分離することでハンドラーを小さく保てる。
すべての下流呼び出しに呼び出し元の ID を付与
認証後、ミドルウェアがオペレーター ID、クライアント IP、HTTP パス、テナント、トレース ID を送信側 gRPC メタデータとして付与する。
Why: これにより、どの下流サービスも呼び出し元を再判定することなく、操作者を特定できる監査イベントやトレースを記録できる。
Result: これがプラットフォーム全体の監査証跡の基盤となった(監査ログサービスを参照)。
階層型認可
プラットフォーム管理者はどこでも操作でき、会員はアクセスできず、その他のオペレーターはパートナーツリー上で自分の配下にあるアカウントのみ操作できる権限チェック。マスターアカウントとサブアカウント、個々の機微なフィールドには別途ルールを設けた。
Why: 多階層パートナーネットワークでは「ユーザーを編集できるか」だけでは不十分で、問題は「誰のユーザーか」である。
技術的意思決定
| 技術的意思決定 | 選択 | 代替案 | 理由 |
|---|---|---|---|
| フレームワーク | Gin | go-zero REST | Gin のミドルウェアチェーンはルートグループ単位のきめ細かな制御が可能で、エッジではコード生成よりもそれが重要になる。 |
| 呼び出し元をどこで解決するか | ゲートウェイで1回解決し、gRPC メタデータとして伝播 | 各サービスがトークンを再検証 | 検証はリクエストごとに1回で済み、ログ・トレース・監査イベントで一貫した単一の ID を使える。 |