Open Policy Agent (OPA) の認可アーキテクチャ適用

## この記事の目的

認可 (Authorization) に携わっていると [Open Polisy Agent (OPA)](https://www.openpolicyagent.org/) を目にするようになってきました。
筆者も利用が広がってきていることを感じて [公式ドキュメント](https://www.openpolicyagent.org/docs/latest/) を読みこみ触ってみましたが、なかなか奥深かったのでこちらの記事で共有します。

:::note info
こちらの記事は CNCJ: Cloud Native Security Japan LT祭り「アプリケーションレイヤ認可の動向とアーキテクチャ」の前半部分に相当します。
もしご興味あれば、動画も参考にしてみていただければと思います。
https://youtu.be/VyIFE17KXfg?si=hBCNd9zHgF49jpAi&t=5933
:::

## OPA の簡単な紹介

![opa-horizontal-color.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1997806/5a490b78-d2f0-b5ef-5332-c17721827f13.png)

以下の本でも詳細に解説が行われているので参考にしてみてください。

https://zenn.dev/mizutani/books/d2f1440cfbba94

公式ドキュメントを引用して簡単にご紹介します。

### Policy とは

[^OPA/DOC-PHILOSOPHY]: https://www.openpolicyagent.org/docs/latest/philosophy/

>A policy is a set of rules that governs the behavior of a software service. That policy could describe rate-limits, names of trusted servers, the clusters an application should be deployed to, permitted network routes, or accounts a user can withdraw money from.[^OPA/DOC-PHILOSOPHY]

ポリシーとはサービスの動作を制御するルールが記載されたものを指します。
あるユーザが操作できる機能一覧やアクセスしてもよいサーバ一覧など、サービスによってその中身は多種多様に及びます。

### OPA とは / OPA の導入について

[^OPA/DOC-WHAT-IS-OPA]: https://www.openpolicyagent.org/docs/latest/philosophy/#what-is-opa

>OPA is a lightweight general-purpose policy engine that can be co-located with your service.[^OPA/DOC-WHAT-IS-OPA]

統一的な規格 (汎用ポリシー記述言語 Rego) を用いてポリシーおよびポリシー判定処理をサービスから切り離すことを目的とした、Go 言語製の OSS 汎用ポリシーエンジンです。
2021年2月には Cloud Native Computing Foundation (CNCF) Graduated と認定されました[^CNCF/OPA-GRADUATED]。

[^CNCF/OPA-GRADUATED]: https://www.cncf.io/announcements/2021/02/04/cloud-native-computing-foundation-announces-open-policy-agent-graduation/

OPA はクエリを受けとることで、ポリシーと適合するかを判断して結果を返します。
Rego はスキーマ定義 (インタフェース設計) に自由度が高い特徴があり、サービスへの適用制限を緩和しています。

![opa-overview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1997806/979e6b78-dcb0-efe6-cd46-ecd574648e1a.png)
※ 公式ドキュメントの図[^OPA/DOC-OVERVIEW]に追記

[^OPA/DOC-OVERVIEW]: https://www.openpolicyagent.org/docs/latest/#overview

様々なサービスのポリシー管理を委譲できるサービスであり、ルールの管理効率化に利用されます。
すなわち、複数の異なるサービスのポリシーについて Git で中央集中的・横断的に違反や競合を管理・判別しやすくするために利用されます。
「判定処理を外部化して共通管理する」運用や体制が整ってくれば、ますます利用されていくのかなと感じます。

ただし、**サービス (または通信) なんでもかんでも「OPA を使って制御してやろう」と走り出してしまうとどこかで大きな壁に突き当たってしまう可能性が高いと思います。**
まず、制御しようとしているものがアプリケーション層におけるポリシー判定で制御するべきもので、ポリシーの切り離しに対応できるものであるかを考えないといけません。
実装に踏み切る場合、自前のアプリであれば処理の切り出し (HTTP 通信) に留まりますが、OSS や他社製サービスを利用する場合は OPA 連携に対応しているかを予め確認しておく必要があります。
また、その導入が「運用を楽にするため (主体は管理者)」なのか「規約に遵守した業務を強制させるため (主体は社員)」なのかによっても影響範囲が大きく変わってきます。
影響範囲が広ければ広いほど緻密な設計が求められる[^1]ため、よくわからないまま実装すると取り返しのつかないことになってしまうかもしれません。

[^1]: セキュリティ設計は、過度に厳しくすることで業務影響が出るような状況にしてはいけません。

「判定」機能の一点だけ見てしまうと、OPA を活用するべきポイントは見えてきません。

では、実際に OPA がどのような使われ方をしているか確認していきたいと思います。

### OPA のユースケース

OPA のユースケースを以下に並べてみました。

![opa-usecase-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1997806/153b4388-f118-0dfb-5a92-bcb612cb3049.png)

OPA 連携 (あるいは OPA 組み込み) は様々な判定処理の (外部) 実装として行われています。
上の図ではクライアントやアプリに関わる「認可」と開発者に関わる「検証」で分類をしています。
ポリシーを始めとするコードベースのファイルを必ず伴いますので、ここでは Git を中心としたライフサイクルについても図に表現しています。

併せて関連 OSS をマッピングしてみると以下のような感じになるかと思います。

![opa-usecase-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1997806/e9beae6e-9a04-1d7c-fead-5cb2a743fe3b.png)

現状は「検証」の領域[^0]で OPA の活用がかなり進んでいます。(Gatekeeper 等)

[^0]:「検証」はデプロイ前に IaC ファイルのチェックを行ったり、タグ付けを強制したりするケースを思い浮かべていただければ理解しやすいと思います。

一方で、最近では「認可」の領域で OPA の活用が盛り上がりを見せ始めています。

## 認証・認可の振り返り

![oauth-2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1997806/f42b36eb-bd17-c8bd-7858-cb9966d6de9a.png)

認証: **「あなたは誰？」**
認可: **「あなたは何に対して何ができる？」**

認可はしばしば認証を前提とします。現在標準となっている [OAuth 2.0](https://oauth.net/2/) ではトークンに含めた形で権限情報が渡されて認可を行っています。

![oauth-3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1997806/37cea355-648d-0bc9-4740-eacb81f37cb2.png)

すると

- 機械ユーザは逐一作らないといけないの...？
- トークンが有効な間にステータス更新されても自動反映できない...

といった悩み事が出てきます。OPA を利用した認可はココにアプローチします。

## OPA と認可

OPA が認可の世界でどのように使われようとしているのかを理解するためには、まずゼロトラストアーキテクチャのさわりを理解しておく必要があります。

![nist.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1997806/ea1c76ce-5268-b561-d43b-a5ca6c0c91f7.png)

上の図は [NIST SP 800-207](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-207.pdf) に記載されたゼロトラストアーキテクチャ図です。

System が Enterprise Resource に接続しようとするとき、(意識的あるいは無意識的に) System からの通信は Policy Enforcement Point (PEP) を経由するようにしておきます。

PEP (Proxy や API Gateway 等) は

- 通信が許可されるべきものかどうかを Policy Decision Point (PDP) に問い合わせる。
- PDP からの応答をもって通信を許可するか、拒否をする。

を行います。
この時 **PDP に相当する役割を果たすのが OPA** です。
先ほどの OSS マッピング図の「保護・制御」に記載された Proxy や API Gateway 製品群は特に PEP としての利用が想定されています。

PAP (Policy Administration Point) や PIP (Policy Information Point) という要素もあり、これらはポリシーやデータの最新化を担います。

もう少し書き下してみます。

![auth-layer.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1997806/144b438e-08b8-d5d1-6269-78c98470ce72.png)

OAuth 2.0 の世界では Identify Provider (IdP) が管理・発行するトークンに応じて認可処理を行っていました。これでは先ほど述べたように ID の発行や更新について取り扱いが難しく、結果として荒い認可しか実装できない[^2]傾向があります。

[^2]: 例えばロールを超細分化する、ユーザの属性を超細分化するなどして何とか細かい認可を行おうとすると、ロールや属性の管理が煩雑となり、現実的な運用をできなくなる恐れがあります。

一方で注目したいのが、図右半分のアプリケーションレイヤでの認可です。
アプリが行う判定の通信には必ずしもトークンを含める必要はありません。
通信する内容に必要最低限の情報だけあれば、PDP 側に保持するデータで十分に判定できます。
すなわち PDP 側に含めるデータとポリシーの書き方によっては如何様にもきめ細やかな認可[^3]を実装することができます。

[^3]: 例えばユーザによって画面要素の表示/非表示を切り替えるなどの実装も検討できます。

よって、OPA を活用した認可を実装すると以下のメリットが想定されます。

- **細かい制御ができる**
- **リアルタイム性がある**
- **ルールを外部化し明文化できる**

ではゼロトラストアーキテクチャだけあれば従来の認可は不要になるのか？

**それは違います。**

PDP に集約しすぎてしまうとポリシーが異様に膨大になったり、統合管理が機能しなくなってしまう可能性があります。
[OPA とは / OPA の導入について](#opa-とは--opa-の導入について) でも述べましたが、組織のどのレイヤでどれくらい細かい制御をしなければならないのか、それは OPA で実装するべきことなのかよく考えて使い分けていくことが求められます。

## OPA を活用した認可アーキテクチャ

OPA を活用した代表的な認可アーキテクチャは以下の2パターンあります。[^4]

[^4]: OPA SDK を利用した Go 言語製サーバでの組み込みや、WebAssembly 化を利用したフロントエンドエッジでの実行方法もありますが、現時点では特殊パターンなので割愛します。

- 中央集中型
- 分散型

![deploy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1997806/1a9800fd-e269-aa35-d829-7263592ea9de.png)

「中央集中型」はすべてのアプリ、PEP が同一の PDP に通信を行う構成です。

例えばアプリが冗長化されているとき、PDP は同一のものを参照するので常に同じ判定が返ってくることが保証されます。
一方で、単一の PDP が様々なアプリに対応できるようにならなければならないので、ルールの肥大化やパフォーマンスの低下が懸念されます。
よって、中央集中型の構成を取る場合は、テナントを適切なサイズで切るなどの対応をしていく必要があります。

「分散型」は各アプリの傍に専用の PDP を配置する構成です。

「中央集中型」と異なり通信が近傍で行われるため、セキュア (通信内容が露出しない) で迅速であることに強みがあります。
一方で各 PDP への同時ポリシー更新を可能な限り保証する必要があります。
近年のクラウドネイティブ台頭においては、ポリシー更新を行う OSS も現れてきており「分散型」に注目が集まっています。

## 最後に

Open Policy Agent (OPA) の基本情報と認可領域へのアプローチをまとめてみました。
難しい分野ですが、具に調べていくと仕組み自体は単純だったりします。

こちらのアーキテクチャについては現時点で既に広く利用されているわけではなく、標準化や仕様の策定が進められている段階です。
続きの記事では OPA を使うときの Tips と標準化動向について投稿が行われる予定です。

【2024/12/11 追記】
Tips 記事公開しました。

https://qiita.com/caunu-s/items/e5d29088bd391c47824f

併せて読んでみていただければと思います。