アーキテクチャ
Authrimは、Cloudflare Workersエコシステム上に構築された統合アイデンティティ&アクセスプラットフォームです。このページでは、マルチワーカーシステム、データベース抽象化レイヤー、PIIパーティションルーティング、Durable Objectリージョンシャーディングについて解説します。
システム概要
Authrimは、Service Bindingsで接続された複数の専門Workerで構成されています。ar-router Workerが中央のエントリーポイントとして機能し、ドメイン固有のWorkerにリクエストを振り分けます。
flowchart LR
router["ar-router
(エントリーポイント)"]
subgraph endpoints["OIDC / Auth"]
discovery["ar-discovery
(OIDCメタ)"]
auth["ar-auth
(認可EP)"]
token["ar-token
(トークンEP)"]
userinfo["ar-userinfo
(UserInfo EP)"]
end
subgraph federation["フェデレーション"]
saml["ar-saml
(SAML IdP)"]
bridge["ar-bridge
(外部IdP)"]
end
subgraph ops["運用"]
mgmt["ar-management
(管理API)"]
async["ar-async
(バックグラウンド処理)"]
end
router --> discovery & auth & token & userinfo
router --> saml & bridge
router --> mgmt & async
| Worker | 役割 |
|---|---|
| ar-router | リクエストルーティング、レート制限、CORS |
| ar-discovery | /.well-known/openid-configuration、JWKS |
| ar-auth | 認可エンドポイント、同意、ログインフロー |
| ar-token | トークンエンドポイント(コード交換、リフレッシュ、デバイス) |
| ar-userinfo | UserInfoエンドポイント |
| ar-management | 管理API(ユーザー、クライアント、ロール、ポリシー) |
| ar-saml | SAML IdPおよびSP |
| ar-bridge | 外部IdP連携(ソーシャルログイン、エンタープライズSSO) |
| ar-async | バックグラウンドジョブ(鍵ローテーション、クリーンアップ、SCIMsync) |
すべてのWorkerは共通ライブラリ ar-lib-core を共有しており、データベース抽象化、リポジトリ、ユーティリティ、Durable Objectの定義を提供します。
データベース抽象化レイヤー
DatabaseAdapterインターフェース
すべてのデータベース操作は DatabaseAdapter インターフェースを通じて行われ、基盤となるストレージエンジンを抽象化します。
interface DatabaseAdapter { query<T>(sql: string, params?: unknown[]): Promise<T[]>; queryOne<T>(sql: string, params?: unknown[]): Promise<T | null>; execute(sql: string, params?: unknown[]): Promise<ExecuteResult>; transaction<T>(fn: (tx: TransactionContext) => Promise<T>): Promise<T>; batch(statements: PreparedStatement[]): Promise<ExecuteResult[]>; isHealthy(): Promise<HealthStatus>;}主要な実装はCloudflare D1(サーバーレスSQLite)向けの D1Adapter です。指数バックオフ付きリトライロジックとヘルスチェック監視を備えています。
トランザクションセマンティクス: D1は従来のSQLトランザクションをサポートしていません。代わりに、D1Adapterは transaction() 呼び出し内のすべてのステートメントを収集し、D1バッチとして実行します — all-or-nothing(すべて成功またはすべてロールバック)のセマンティクスを提供します。
BaseRepositoryパターン
すべてのエンティティリポジトリは BaseRepository<T> を継承し、以下を提供します。
- CRUD操作 —
findById、create、update、delete - ページネーション — カーソルベース、ソート設定可能
- フィルタリング — 型安全な条件とオペレータサポート(
eq、in、like等) - ソフトデリート —
is_activeフラグによる(デフォルト動作) - SQLインジェクション防止 — 許可リストに対するフィールド名の検証
3データベース分離
Authrimは、データの機密性に応じて3つの独立したD1データベースを使用します。
| データベース | 目的 | 内容 |
|---|---|---|
| DB_CORE | 認証コア | ユーザー(非PII)、クライアント、セッション、トークン、ロール |
| DB_PII | 個人データ | メール、氏名、住所 — 地理的にパーティション分割 |
| DB_ADMIN | プラットフォーム管理 | 管理者ユーザー、監査ログ、テナント設定 |
この分離により、PIIを管轄に適したデータベースに保存しつつ、認証操作はDB_COREのみにアクセスすることが保証されます。
PIIパーティションルーター
PIIPartitionRouter は、PIIデータアクセスを正しいデータベースパーティションにルーティングします。各パーティションは個別の DatabaseAdapter インスタンス(異なる地理的リージョンに配置可能)にマッピングされます。
信頼レベル階層
新しいユーザーのPIIをどのパーティションに保存するかを決定する際、ルーターは信頼階層(信頼度の高い順)で評価します。
| 優先度 | 方法 | 信頼レベル | 説明 |
|---|---|---|---|
| 1 | テナントポリシー | 高 | テナント固有のパーティション指定 |
| 2 | 居住地申告 | 高 | ユーザー自己申告の居住国 |
| 3 | カスタムルール | 中 | 属性ベースのルーティングルール(プラン、ロール等) |
| 4 | IPルーティング | 低 | Cloudflareジオヘッダー(フォールバックのみ) |
| 5 | デフォルトパーティション | — | 最終手段 |
パーティション設定
パーティション設定はKV(インメモリキャッシュ、10秒TTL付き)に保存され、管理APIを通じてテナントごとに設定可能です。
- 利用可能なパーティション — 登録済みデータベースアダプター(例:
eu、us、apac、default) - テナントオーバーライド — テナントのすべてのユーザーを特定パーティションに強制
- カスタムルール — 優先順位付きの属性ベース条件
- IPルーティングトグル — 地理的フォールバックの有効/無効
users_core.pii_partition カラムが各ユーザーのPIIがどのパーティションに格納されているかを追跡し、後続の読み取り時の正しいルーティングを可能にします。
Durable Objectリージョンシャーディング
Durable Objects(DO)は強い一貫性を持つステートフルストレージを提供し、Authrimではセッション、認可コード、チャレンジ、リフレッシュトークンなどに使用されます。リージョンシャーディングにより、これらのDOを複数のシャードと地理的リージョンに分散させます。
なぜリージョンシャーディングが必要か
単一のDurable Objectインスタンスは約50〜100リクエスト/秒を処理できます。数千の同時認証フローを処理するプラットフォームでは、リソースタイプごとに単一のDOではボトルネックになります。リージョンシャーディングは以下により解決します。
- 水平スケーリング — N個のシャードにわたる負荷分散
- 地理的局所性 —
locationHintによるユーザー近接配置 - 予測可能なルーティング — リソースIDにシャード情報を埋め込み、ルックアップなしでルーティング
シャード設定
シャードキーアルゴリズム
Authrimは**FNV-1a(32ビット)**ハッシュを使用してシャード割り当てを決定します。
shardIndex = fnv1a32(shardKey) % totalShardsshardKey はリソースタイプによって異なります。
- セッション: ランダムなセキュアID(均一分布)
- AuthCode / RefreshToken:
userId:clientId(ユーザー・クライアントペアで共置) - PAR / DeviceCode / CIBA / DPoP:
clientId - チャレンジ: ランダムID
リージョンIDフォーマット
すべてのリージョンシャーディングされたリソースIDには、ルーティング情報が埋め込まれます。
g{generation}:{region}:{shard}:{prefix}_{randomPart}例:
g1:apac:3:ses_X7g9kPq2Lm4R— APACリージョン、シャード3、世代1のセッションg1:enam:1:acd_9f8a2b1c— US Eastリージョン、シャード1の認可コード
対応するDOインスタンス名は以下の形式です。
{tenantId}:{region}:{typeAbbrev}:{shard}例: default:apac:ses:3
リージョン分布
シャードは、パーセンテージ分布に基づいて地理的リージョンに分割されます。デフォルト設定(合計4シャード):
| リージョン | 割合 | シャード数 | 範囲 |
|---|---|---|---|
| enam(US East) | 50% | 2 | 0–1 |
| weur(West Europe) | 25% | 1 | 2 |
| apac(Asia Pacific) | 25% | 1 | 3 |
calculateRegionRanges() 関数がパーセンテージを具体的なシャード範囲に変換し、すべてのシャードがカバーされることを保証します。
配置と共置
locationHintによる配置
DOスタブを作成する際、Authrimは locationHint をCloudflareに渡します。
namespace.get(id, { locationHint: 'apac' });このヒントは、指定されたDO IDに対する最初の get() 呼び出しでのみ有効です — CloudflareがDOを物理的にどこに配置するかを決定します。以降の呼び出しは、すでに配置されたインスタンスにルーティングされます。
共置グループ(Colocation Groups)
同じシャードキーを同じシャードにルーティングする必要があるDOは、同一のシャード数を持つ必要があります。Authrimはこれを強制するために共置グループを定義しています。
| グループ | シャード数 | メンバー | 理由 |
|---|---|---|---|
| user-client | 4 | AuthCode、RefreshToken | 同じ userId:clientId キー |
| random-high-rps | 4 | Revocation | 高スループット |
| random-medium-rps | 4 | Session、Challenge | 中スループット |
| client-based | 4 | PAR、DeviceCode、CIBA、DPoP | 同じ clientId キー |
| vc | 4 | CredOffer、VPRequest | Verifiable Credentials |
共置グループ内でシャード数が不一致の場合、間欠的な認証失敗が発生します — ユーザーのAuthCodeとRefreshTokenが異なるシャードに配置され、コード交換フローが破綻します。
マイグレーションとルーティング
世代ベースのマイグレーション
シャード設定が変更される場合(例: 4シャードから32シャードへのスケール)、Authrimは世代ベースのアプローチを使用します。
- 現在の世代設定が
previousGenerationsにアーカイブされる - 更新されたシャード数と分布で新しい世代が作成される
- 新しいリソースは新しい世代を使用する
- 既存のリソースは元の世代へのルーティングを継続する(情報がIDに埋め込まれているため)
これにより、データマイグレーションは不要です — 異なるシャード設定を持つ古いリソースと新しいリソースが共存します。最大5つの過去世代が保持されます。
リソース作成フロー
1. ランダムIDを生成 / シャードキーを計算2. KVからRegionShardConfigを取得(10秒キャッシュ)3. 計算: shardIndex = fnv1a32(shardKey) % totalShards4. シャード範囲からリージョンを解決5. リソースID作成: g{gen}:{region}:{shard}:{prefix}_{random}6. DOインスタンス名を構築: {tenant}:{region}:{type}:{shard}7. locationHint付きでDOスタブを取得8. DOにリクエストを送信既存リソースアクセスフロー
1. リソースIDを解析 → generation、region、shardを抽出2. 解析情報からDOインスタンス名を構築3. locationHint付きでDOスタブを取得(既存の配置先にルーティング)4. DOにリクエストを送信既存リソースへのアクセスには設定の参照は不要です — すべてのルーティング情報がID自体に埋め込まれています。
キャッシュ戦略
Authrimは、データベース読み取りを最小化するために3層キャッシュ戦略を使用します。
block-beta
columns 1
kv["KVキャッシュ(グローバル、~60秒)
JWKS、OIDCメタデータ、設定"]
do["DOインメモリ(シャード単位)
セッション、トークン、コード"]
d1["D1データベース(永続)
信頼できるソース"]
- KV: 結果整合性を持つグローバルKey-Valueストア。設定、公開鍵、読み取り頻度の高いデータに使用。
- DOインメモリ: 各Durable Objectがインメモリ状態を維持。シャード内で強い一貫性のある読み取りを提供。
- D1: 永続ストアであり信頼できるソース。すべての書き込みはD1へ、読み取りは可能な限りキャッシュから提供。
設定キャッシュ(リージョンシャード設定、パーティション設定)は、鮮度とパフォーマンスのバランスを取るために10秒のTTLを使用します。
次のステップ
- エッジコンピューティング — エッジネイティブアーキテクチャの意義
- アイデンティティハブ — 統合アイデンティティ連携のコンセプト
- PII分離 — データベースレベルのPII分離の詳細