Open Policy Agentについて詳しく知りたかったので、公式ドキュメントを参照して調べてみた。
Open Policy Agent(OPA、「オーパ」と発音。)とは、ポリシー適用のためのOSSの汎用ポリシーエンジン。
宣言型言語(Rego、「レイゴ」と発音。)を用いてポリシーをコードとして記述することができる。
Styraによって開発されており、現在もStyraとOSSコミュニティが開発を継続している。
Cloud Native Computing Foundation(CNCF)のGraduatedプロジェクトとして認定されている。
OPAはポリシー決定とポリシー適用を分離する。
任意の構造化データを入力として受け取り、ポリシーを適用して結果を出力する。
構造化データはJSON、YAML、CSV、XMLなど任意の形式である。
+---------------------+
| Service |
+---------------------+
↑ ↑
Request, Event | | Decision (any JSON value)
| |
v |
+---------------------+
| OPA |
+---------------------+
↑ ↑
Query (any | |
JSON value) | |
| |
+----------+-----------+----------+
| |
+---------------+ +------------------+
| Policy | | Data |
| (Rego) | | (JSON) |
+---------------+ +------------------+
OPAは入力としてのクエリとポリシーとデータを照合することで、ポリシー決定を行う。
OPAとポリシー(Rego)は特定のドメインに依存しないため、汎用的なポリシーエンジンとして様々な条件をポリシーに記述できる。
OPAはサイドカー、ホストレベルのデーモン、ライブラリとして利用できる。
OPAはポリシーをポリシー決定とポリシー適用に分離することで、ポリシーの再利用性やテスト容易性、デプロイ独立性を向上させることができる。
その結果、ビジネス要件への適応性が向上したり、ポリシーの違反や競合の検出能力を高めることができる。
OPAではポリシーと認可を次のように定義している。
ポリシーという概念の中に認可が含まれている。認可をより一般化したものがポリシーという立ち位置になる。
OPAはポリシー評価のために3種類のデータを扱う:
data
とinput
で参照される。モデル | Regoでの参照 | ロード方法 |
---|---|---|
非同期プッシュ | data |
OPAのAPI(例: PUT /v1/data) |
非同期プル | data |
バンドル機能 |
同期プッシュ | input |
リクエスト時に直接渡す(例: POST) |
同期プル | ローカル変数 | http.send などの組み込み関数で取得 |
data.foo.bar
のようにベースドキュメントと同じように参照できる。data
以下にベースドキュメントと仮想ドキュメントが混在可能。input
はリクエスト固有の一時的なベースドキュメントと捉える。data
やポリシーはOPA内部でキャッシュされる。http.send
で取得した同期データもローカル変数として扱われ、必要に応じてキャッシュ可能。OPAではポリシーの記述にRegoという宣言型言語を使用する。
Regoはクエリの実行方法ではなく、クエリがどのような結果を返すかに集中してロジックを書くことができる。
ロールに応じたアクセス制御(RBAC)を行うポリシーを例に挙げる。
このポリシーでは次のようなことが実現できる。
以下はRego Playgroundで実行することができるサンプルコードになっている。
// Policy: ポリシーの定義
package example
default allow = false
allow if {
perms := data.role_permissions[input.user.role][input.resource]
perms[_] == input.action
}
// INPUT: ポリシー実行時に参照される入力データ
{
"user": {
"id": "u001",
"role": "editor"
},
"resource": "projects",
"action": "write"
}
// DATA: ポリシー実行時に参照されるデータ
{
"role_permissions": {
"viewer": {
"projects": ["read"]
},
"editor": {
"projects": ["read", "write"]
},
"admin": {
"projects": ["read", "write", "delete"]
}
}
}
// OUTPUT: ポリシー実行時の結果
{
"allow": true
}
OPAではテストのためのフレームワークも用意されており、ポリシー単体のでテストを行うことができる。
package example
test_allow_editor_write {
input := {
"user": {
"id": "u001",
"role": "editor"
},
"resource": "projects",
"action": "write"
}
data := {
"role_permissions": {
"viewer": {
"projects": ["read"]
},
"editor": {
"projects": ["read", "write"]
},
"admin": {
"projects": ["read", "write", "delete"]
}
}
}
allow with input as input with data as data
}
入力値と期待値を示すだけで簡単にテストを実装することができる。
パラメータ化テストやデータ駆動型テスト、モック、ベンチマーク、カバレッジなどにも対応している。
Regoの仕様については、Policy Languageを参照。
ポリシーで定義できることについては、 Policy Referenceを参照。
OPA/Rego入門はregoの基礎について分かりやすく書かれている。
OPAは内部的にはTrieを活用したルールのインデックスにより最適化が図られている。
cf. Optimizing OPA: Rule Indexing
Trieのデータ構造を意識してポリシーを記述することで、性能劣化の要因を防ぐことができる。(たぶん)
実際の注意点としては、Policy Performanceにいくつか記載されている。
OPAをライブラリとして利用するか、OPAサーバーを用意するかは並列化の対応が異なる。
If you are embedding OPA as a library, it is your responsibility to dispatch concurrent queries to different Goroutines/threads. If you are running the OPA server, it will parallelize concurrent requests and use as many cores as possible.
cf. policy-performance/#resource-utilization
ライブラリとして利用する場合は、並列化の対応が必要になる。OPAサーバーを利用する場合は、並列化の対応が自動で行われる。性能要件に応じて選択する必要がある。
--optimize
という最適化レベルを指定するオプションが用意されており、opa bundle
の最適化に費やす時間とリソースを調整することができる。ポリシーのサイズが最適化されることにより、ポリシーのロードや評価時のメモリ使用量を削減できる。大規模なポリシーやシビアな性能調整が必要な場合に活用できる。
外部データを扱う構成のパターンについてまとめる。
アプローチ | パフォーマンス/可用性 | 更新頻度※1 | サイズ制限※2 | 推奨されるデータ | セキュリティ | 備考 |
---|---|---|---|---|---|---|
JWTトークン | 高い | ユーザーの再ログイン時 | 制限あり | ユーザー属性 | トークン署名の検証、TTLの確認 | ユーザー認証時のみ更新。属性が頻繁に変わる場合には不向き。 |
input オーバーロード |
高い | 更新頻度に依存 | サイズの制限は少ない | ローカルで動的なデータ | サービスとOPA間の接続セキュリティ | 動的で頻繁に更新されるデータに適している。外部データの取り込みは開発者側の責任。 |
バンドルAPI | 高い | 低い | サイズ制限あり | 静的な中規模データ | APIのアクセス制御 | 外部データをバンドルとして一括で同期。データが静的であれば最適。 |
プッシュデータ | 高い | 高い | サイズ制限あり | 動的で中規模データ | APIのアクセス制御 | 外部データの更新頻度を細かく調整可能。データが頻繁に更新される場合に適切。 |
評価時のデータ取得 | ネットワーク依存 | 常に最新 | サイズ制限なし | 大規模または動的データ | 外部サービスへのアクセスセキュリティ | 外部データが非常に頻繁に更新される場合やデータ量が大きい場合に適している。ネットワークの可用性が鍵。 |
※1更新とは、外部データの変更がOPAに反映される頻度や容易さを指す。データが頻繁に変わる場合、リアルタイム性や反映の仕組みが重要になる。
※2サイズとは サイズは、OPAが扱う外部データの量を指し、メモリ上に保持できるか、リクエスト毎に持ち回す必要があるかなどが選定に影響する。大規模データではオンデマンド取得が現実的。
External Dataを参照。
Open TelemetryやPrometheusをサポートしている。
Monitoringを参照。
関連書籍