アーキテクチャ
全体像
OpenFGA は gRPC API と HTTP ゲートウェイを公開する単一の Go バイナリである。リクエストはトランスポートハンドラに到達し、ミドルウェア (検証、認証、API 認可) を通り、サーバハンドラに渡り、トランスポート非依存のコマンドに委譲され、それがグラフ解決エンジンを駆動し、エンジンが差し替え可能なデータストアから関係タプルを読む。cmd/ の CLI がこれらを配線してサーバを起動する。
コンポーネント
CLI とサーバ起動 (cmd/)
cmd/openfga/main.go:14-26 は Cobra のルートコマンドを構築し、run、migrate、validate-models、version サブコマンドを取り付ける。サーバ本体は cmd/run/run.go で起動し、設定の読み込み、データストアのオープン、graceful shutdown を扱う。migrate は DB スキーマのマイグレーションを適用する。
トランスポートハンドラ (pkg/server/)
pkg/server/ は gRPC/HTTP ハンドラを持ち、API 面ごとに 1 ファイル (check.go、batch_check.go、list_objects.go、list_users.go、expand.go、write.go、read.go) になっている。AuthZEN 互換エンドポイントは pkg/server/authzen.go にある。ハンドラはリクエスト検証と API 認可を行い、コマンドに引き渡す。
コマンド (pkg/server/commands/)
pkg/server/commands/ はトランスポートから切り離したビジネスロジック層である。CheckQuery.Execute (check_command.go:102) が内部の解決リクエストを組み立て、resolver を呼ぶ。
グラフエンジン (internal/graph/)
internal/graph/ が中核である。LocalChecker がモデルの rewrite ルールを辿りタプルを読んでチェックを解決する。resolver はチェーン (キャッシュ、dispatch スロットリング、shadow 評価) に合成され、builder.go で構築される。
型システム (pkg/typesystem/)
pkg/typesystem/ は認可モデルをパース・検証し、クエリ経路最適化のためにモデルの重み付きグラフを構築する。TypeSystem は authzWeightedGraph フィールドを持つ (typesystem.go:184)。
ストレージ (pkg/storage/)
pkg/storage/ は OpenFGADatastore と RelationshipTupleReader インターフェースを定義し (storage.go:152)、インメモリ、PostgreSQL、MySQL、SQLite の実装を持つ。
リクエストの流れ
Check 呼び出しを端から端まで追う。
pkg/server/check.go:37(*Server).Checkがトレース span を開始し、リクエストを検証し、checkAuthzで API 認可を行う (check.go:63)。- ストアで
ExperimentalWeightedGraphCheckフラグが有効なら v2 パスs.v2Checkを試し、非タイムアウト系エラーでは v1 にフォールバックする (check.go:69-152)。 - v1 パスは
getCheckResolverBuilder(storeID).Build()で resolver チェーンを構築し (check.go:156)、モデルを解決し (check.go:162)、NewCheckCommandを構築し (check.go:168)、checkQuery.Executeを呼ぶ (check.go:182)。 (*CheckQuery).Execute(check_command.go:102) がResolveCheckRequestを組み立て、データストアをリクエスト単位のタプルキャッシュでラップし、c.checkResolver.ResolveCheckを呼ぶ (check_command.go:150)。(*LocalChecker).ResolveCheck(internal/graph/check.go:395) が解決深度を確認し、サイクルを検出し、self-defining タプルを短絡し、PathExistsで到達不能経路を枝刈りし、関係の rewrite ルールをCheckRewriteで評価する (check.go:465)。
各分岐は 内部実装 で詳しく追う。
主要な設計判断
- ステートレスエンジンと差し替え可能なストレージ。 認可状態はすべて
RelationshipTupleReaderインターフェースの背後にある (storage.go:152) ため、インスタンスは水平スケールでき、ストレージは差し替え可能。 - resolver チェーンは循環リンクリスト。 resolver は負荷の軽い順に並べられ、最後が先頭に委譲し直す (
builder.go:66-104)。CheckResolver契約はDelegate.ResolveCheckが無限再帰を起こさないことを要求する (interface.go:13-40)。 - 整合性はリクエスト単位で調整可能。
HIGHER_CONSISTENCYを要求しない限り、エンジンはキャッシュ無効化時刻を参照しキャッシュから応答しうる (check_command.go:110-112)。強整合性はオプトイン。 - 戦略選択はオンライン学習。 どの解決戦略を使うかを固定ルールではなく、
internal/planner/のプランナが Thompson Sampling でクエリ経路ごとに学習する。
拡張ポイント
- データストアドライバ は
OpenFGADatastore/RelationshipTupleReaderを実装する (pkg/storage/storage.go:152)。SQLite と MySQL のアダプタはコミュニティの貢献だった。 - 認証 は none、pre-shared key、OIDC をサポートする (
internal/authn/)。 - AuthZEN エンドポイント (
pkg/server/authzen.go) はCheckの上に OpenID AuthZEN 互換 API を公開する。