注目のOpen Policy Agent、その概要とKubernetesでの活用事例

2020年5月19日(火)
吉田 龍馬(よしだ・りゅうま)

はじめに

Kubernetesコミュニティにおいて、ここ数年で国内外の企業がOpen Policy Agentを導入しているという話を耳にすることが多くなってきました。今回は、KubernetesをはじめとしたCloud Native技術には触れているが、Open Policy Agentにはまだ触れたことがない方向けに、その概要や仕組み、Kubernetesでの活用事例などを紹介します。

なお、ここで扱うOpen Policy Agentの情報は執筆時点(2020年4月26日現在)での最新バージョンv0.19.1に基づいたものとなります。

Open Policy Agentとは

Open Policy Agent(以下、OPA)はオープンソースの軽量かつ汎用的なポリシーエンジンです。ポリシーをコードとして管理する(Policy as Code)ためのポリシー言語Regoと、アプリケーションからの問い合わせに対してポリシーの評価を行うAPIが提供されています。OPAは"oh-pa"、Regoは"ray-go"と発音します。

OPAをサイドカー、デーモン、ライブラリなどでアプリケーションに統合し、アプリケーション内のリクエスト制御をAPIを介してOPAに問い合わせた評価結果から判定するアーキテクチャにすることで、アプリケーションからポリシー制御の機能を切り離すことが可能になります。

OPAによりポリシー制御を分離することで、アプリケーションのソースコード変更、再デプロイを必要としないポリシー管理や、様々なアプリケーションにおけるポリシー制御を統一された仕組みで実現できます。

OPAの公式ページでは、マイクロサービスにおけるサービス間の認可、問い合わせ元の権限に基づいたデータフィルタリング、KubernetesのAdmission Controlを使ったリソースのバリデーション、SSHとsudoでのアクセス制御、Terraformの設定ファイルのバリデーションなど、様々なユースケースが紹介されています。

OPAの仕組み

ハイレベルアーキテクチャ

OPAはDocumentの集合であるData、Ruleの集合であるPolicyと、それらを操作するAPIで構成され、APIを介して受け取った問い合わせを元にDataをPolicyで評価した結果を返すアーキテクチャとなっています。

DataとPoilicyについて

DataはJSON形式のデータで、アプリケーションまたはユーザーがData APIを介して外部からロードする静的データのBase Documentと、RuleによるData(Base Document、Virtual Document)の評価結果であるVirtual Documentの2種類で構成されています。問い合わせ時の入力データもBase Documentに分類されますが、文脈によってInput DocumentやQuery Inputと表現されます。

PolicyはRegoを使用して定義されたRuleから構成されています。単一または複数のRuleを定義したRegoファイルをPolicy Moduleとして、Policy APIを介してOPAに追加できます。

チュートリアル

OPAでHTTP APIを認可することを想定したチュートリアルを紹介します。

仕様

HTTP APIに給与を参照するエンドポイント”GET /finance/salary/{user}”が実装されていると仮定して、以下のポリシーに基づいた認可処理をOPAで行っていきます。

  • 社員は自身の給与を参照できる
  • マネージャーは部下の給与も参照できる

また、OPAへの問い合わせ時には、入力データとして以下の情報を渡すこととします。

  • HTTPメソッド
  • エンドポイント
  • リクエスト元のユーザー

チュートリアルの実施

OPAをServerモードで起動します。今回はAPIも操作したいので、ローカルにDockerで起動したOPAを利用していきますが、公式から提供されているRego Playgroundを使ってWeb上で試すことも可能です。

$ docker run --rm -d --name opa -p 8181:8181 openpolicyagent/opa:0.19.1 run --server

起動時点でまだData, Policyは存在しないため、まずはData API経由で社員情報をBase DocumentとしてOPAに追加します。今回はaliceの部下がbob、charlieの部下がdavidと定義しています。

$ cat subordinates.json
{
  "alice": ["bob"],
  "bob": [],
  "charlie": ["david"],
  "david": []
}

$ curl -X PUT -H 'Content-Type:application/json' --data-binary @subordinates.json \
    localhost:8181/v1/data/subordinates

追加したBase DocumentはData APIを介して参照できます。Data APIを実行してみるとレスポンスのresultに先程追加した社員情報が格納されていることがわかります。

$ curl -s localhost:8181/v1/data/subordinates | jq .
{
  "result": {
    "alice": [
      "bob"
    ],
    "bob": [],
    "charlie": [
      "david"
    ],
    "david": []
  }
}

次に、Policy Moduleを作成します。このPolicy Module内ではallowという給与が参照可能か真偽値を返すRuleを定義しています。allowでは社員情報と入力データを元に評価が行われます。

また、パッケージ名とRule名から評価結果であるVirtual Documentの参照先が決定されます。今回はhttpapi.authzというパッケージ名でallowというRule名なので、Data APIから参照する場合は/v1/data/httpapi/authz/allow、他のRuleから参照する場合はdata.httpapi.authz.allowから評価結果を得ることができます。

$ cat httpapi_authz.rego
package httpapi.authz

# 社員情報をインポート
import data.subordinates as subord

default allow = false

# 社員は自身の給与を参照できる
allow {
  some username
  input.method == "GET"
  input.path = ["finance", "salary", username]
  input.user == username
}

# マネージャーは部下の給与も参照できる
allow {
  some username
  input.method == "GET"
  input.path = ["finance", "salary", username]
  subord[input.user][_] == username
}

作成したPolicy ModuleをPolicy APIを介してOPAに追加します。

$ curl -X PUT -H 'Content-Type: text/plain' --data-binary @httpapi_authz.rego \
    localhost:8181/v1/policies/httpapi_authz

これでData, Policyの準備が完了したので、OPAに問い合わせのテストを行っていきます。以下はaliceがalice(自分)の給与を参照できるか問い合わせた例です。自分の給与は参照できるポリシーなのでtrueという評価結果が得られました。

$ cat alice_to_alice.json
{
  "input": {
    "method": "GET",
    "path": ["finance", "salary", "alice"],
    "user": "alice"
  }
}

$ curl -s -X POST -H 'Content-Type:application/json' --data-binary @alice_to_alice.json \
    localhost:8181/v1/data/httpapi/authz/allow | jq .
{
  "result": true
}

次は、aliceがbobの給与を参照できるか問い合わせた例です。マネージャーは部下の給与も参照できるポリシーなのでtrueという評価結果が得られました。

$ cat alice_to_bob.json
{
  "input": {
    "method": "GET",
    "path": ["finance", "salary", "bob"],
    "user": "alice"
  }
}

$ curl -s -X POST -H 'Content-Type:application/json' --data-binary @alice_to_bob.json \
    localhost:8181/v1/data/httpapi/authz/allow | jq .
{
  "result": true
}

最後は、aliceがdavidの給与を参照できるか問い合わせた例です。マネージャーは部下の給与も参照できるポリシーですが、davidはcharlieの部下でaliceの部下ではないのでfalseという評価結果が得られました。

$ cat alice_to_david.json
{
  "input": {
    "method": "GET",
    "path": ["finance", "salary", "david"],
    "user": "alice"
  }
}

$ curl -s -X POST -H 'Content-Type:application/json' --data-binary @alice_to_david.json \
    localhost:8181/v1/data/httpapi/authz/allow | jq .
{
  "result": false
}

今回は手動で入力データを作成してOPAに問い合わせを行いましたが、HTTP APIの内部でリクエスト情報から入力データを自動生成してOPAに問い合わせを行い、得られた評価結果からリクエスト制御を行うことでHTTP APIの認可をOPAに切り出すことができます。

また、このチュートリアルではHTTP APIの認可として簡単なポリシーを例にしましたが、RegoにはBuild-inされている関数が多数あるので、JWTを検証してClaimsの値を使用したり、TLSクライアント証明書の情報を使用したりなど、要件に応じてポリシーを作り込んでいくことも可能です。

KubernetesでのOPA活用事例

ここでは、KubernetesにおけるOPAの活用事例を紹介します。

Kubernetesリソースのバリデーション

Kubernetesクラスタに意図しないリソースが適用されることを避けるために、GatekeeperをAdmission Controller Webhookとして導入することで、kube-apiserverでOPAによるCRDベースのポリシーに基づいたリソースのバリデーションを行うことができます。これはPodSecurityPolicyの代替にもなります。

ほかにもkube-apiserverでのバリデーションではなく、マニフェストをバージョン管理しているリポジトリにCIでconftestを導入することで、マニフェストに対してOPAによるポリシーに基づいたユニットテストを実行することもできます。

RBACの拡張

Kubernetes Authorization via Open Policy Agentで紹介されていた事例です。社内にKubernetesクラスタを提供しているチームでは利用者の拡大によりRBACによる認可の管理に課題を抱えており、RBACのようなホワイトリスト形式での認可に加えOPAによるブラックリスト形式の認可を採用したという話です。アーキテクチャとしてはWebhook ModuleとAdmission Controller WebhookにGatekeeperを採用しているようです。

ワークロードから実行された悪意ある処理の検知

Secure Kubernetes using eBPF & Open Policy Agentで紹介されていた事例です。Kubernetesクラスタにデプロイされているワークロードから実行された悪意のある処理を検知するためにeBPFを使用してシステムコールを解析し、ポリシー違反がないかをOPAに問い合わせるアーキテクチャを採用しているようです。

Service Meshにおけるサービス間の認可

Data PlaneとしてEnvoyを採用しているService Meshであれば、EnvoyのExternal Authorization(認可の処理を別システムに任せるための機能)としてOPAを統合することで、リクエスト情報を元にサービス間の認可をOPAで行うことができます。また、Istioを使用しているケースでは公式で提供されているプラグインが利用できます。

おわりに

今回はOPAに触れたことがない方向けに、その概要や仕組み、Kubernetesでの活用事例などを紹介しました。OPAはCNCFのIncubatingプロジェクト(2020年4月26日現在)としてホストされており、開発も活発でコミュニティも拡大していて、国内外で採用事例が増えてきています。現在抱えている課題をOPAで解決できそうであれば、導入を検討してみるのも良いでしょう。

【参考資料】
https://www.openpolicyagent.org
https://github.com/open-policy-agent/opa

著者
吉田 龍馬(よしだ・りゅうま)
ゼットラボ株式会社/ヤフー株式会社
2015年にDMM.comに新卒として入社。Hadoop Ecosystemを利用したデータ分析基盤の開発と運用に従事。2018年12月よりゼットラボ株式会社でKubernetesをベースとしたインフラ基盤の研究開発を行っており、現在はCloud Nativeなアクセス制御システム(認証、認可)の研究開発を担当している。SPIFFE/SPIREプロジェクトのコントリビューター。CKA-1900-001691-0100保有。Twitter: @ryysud、GitHub: @ryysud

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています