OPA(Open Policy Agent)は Rego 言語で記述されたポリシーを用いて、入力(input)や外部データ(data)に基づいて評価を行い、許可/拒否などの判定を行うエンジンである。
実装例については、AWS Prescriptive Guidance のマルチテナント API 認可制御ガイドが参考になる。OPA を活用した SaaS におけるマルチテナント認可の実装戦略が紹介されており、本稿の背景理解にも役立つ。
sequenceDiagram
participant Client as クライアント
participant API as アプリケーション
participant OPA as OPA
participant Policy as Regoポリシー
participant Data as 外部データ
Client->>API: リクエスト送信
API->>OPA: input を含む評価要求
OPA->>Data: ポリシー評価用データ取得
Data-->>OPA: リソースデータ
OPA->>Policy: Rego ポリシーで評価
Policy-->>OPA: 結果(allow/deny)
OPA-->>API: 判定結果
API-->>Client: 応答
ページネーションにおいて OPA をナイーブに適用した場合、以下のような問題が発生する可能性がある。
このように、OPAを適用した際のページネーションには、単なるSQLベースの設計には存在しない実装上・体験上の課題が内在している。
ナイーブな実装においては、OPA は全件の評価結果を返すため、SQL のような OFFSET/LIMIT
による制御が難しく、結果数が動的に変動する。このため、リスト取得時の許可リソース件数が不定であるという問題が発生する。
以下では、ポリシー適用なしの「通常の SQL」におけるページネーション(OFFSET/LIMIT やキーセット方式)の基本挙動を、具体例や図を交えて説明する。これと、OPA適用後の挙動との対比で理解が深まる。
項目 | SQL のフィルタリング | OPA の評価処理 |
---|---|---|
件数確定 | WHERE 句で件数を事前制御 | ポリシー評価後に件数が決定 |
ページネーション | OFFSET/LIMIT が安定動作 | 再評価と取得の繰り返しが必要 |
処理負荷 | DB が効率的に処理 | アプリケーション/OPA 側で高負荷 |
sequenceDiagram
participant Client
participant API
participant DB
participant OPA
Client->>API: GET /resources?page=N
API->>DB: OFFSET/LIMIT でN件取得
DB-->>API: N件返却
loop リソースごと
API->>OPA: evaluate(resource)
OPA-->>API: allow/deny
end
alt 許可数 < N
API->>DB: 追加取得 & 評価繰り返し
end
API-->>Client: 許可されたN件を返却
sequenceDiagram
participant Client as クライアント
participant App as アプリケーション
participant DB as データベース
Client->>App: GET /items?page=P&size=N
Note over App: page, size から OFFSET, LIMIT 計算
App->>DB: SELECT * FROM items WHERE <条件> ORDER BY ... LIMIT N OFFSET (P-1)*N
DB-->>App: N件(または残り分だけ)
App-->>Client: 結果返却
flowchart TB
subgraph 通常SQL
A1[Client: GET /items?page=P&size=N] --> B1[App: WHERE句組立 + ORDER BY + OFFSET/LIMIT 計算]
B1 --> C1[DB: 絞り込み後に OFFSET/LIMIT 適用]
C1 --> D1[App: 結果 N 件(または残り分)取得]
D1 --> E1[Client: 結果返却]
end
subgraph OPAナイーブ評価
A2[Client: GET /items?page=P&size=N] --> B2[App: OFFSET/LIMIT でまず取得]
B2 --> C2[DB: N 件取得]
C2 --> D2[App: 各リソースを OPA 評価]
D2 --> F2{許可数 >= N?}
F2 -- yes --> G2[App: N 件返却] --> H2[Client: 結果返却]
F2 -- no --> I2[App: 不足分補うため次チャンク取得] --> B2
end
全件取得+逐次評価を避けるため、OPAのポリシー内容をアプリ側で理解し、事前に SQL へ条件を反映。
OPA の Compile API を利用し、Rego ポリシーの一部を SQL WHERE 句に変換可能なロジックに変換。
sequenceDiagram
participant App
participant OPA
participant DB
App->>OPA: Compile API(入力: user_id, unknowns: data.resources)
OPA-->>App: 残余ロジック AST
App-->>DB: SQL WHERE 句に変換してクエリ実行
DB-->>App: フィルタ済データ取得
バックエンドは全許可リソースを返し、フロント側でページネーションを行う方式。
DB で大まかに絞り込んだ上で、OPA をフィルタ処理に組み込む方式。
OPA をナイーブに適用したリスト取得においては、ページネーションとポリシー評価の非整合によって、返却件数の不定・処理負荷の増大・ページ境界の曖昧化・ユーザー体験の低下といった複合的な問題が発生する。
これらを解消するためには、以下のような方針が有効であると考えられる:
これらの対策を通じて、OPA を導入しつつも、スケーラビリティと一貫したページネーション体験を両立できるアーキテクチャを実現できる。