OPA 事始め

7 min読了の目安(約7000字TECH技術記事

Open Policy Agent (OPA) 事始め

Copyright: Hiro Osaki 2021

はじめに

このドキュメントは、Open Policy Agent (OPA) を一度触ってみたいという方向けです.

最短経路は8分で済みます.

(本記事は, OPA up and runningのZenn転載版になります.)

1. 初めてのRego: Rego Playground

OPAとそこで使われるRego言語がどんなものなのかを掴むのに, OPAをインストールす必要はありません. 最速の方法は, Styraが開発した"Rego Playground" というWebサービスを使うことです.

1.1. Rego言語のプログラムを動かしてみる (所要: 5分)

  • https://play.openpolicyagent.org/ にアクセス.

  • Evaluate ボタンをクリック.

  • 初の Rego 言語 プログラミングにチャレンジしましょう. 左のウィンドウの一番下に, 以下の3行を足します.

    newdata = msg {
      msg := concat("", ["Received the message: ", input.message])
    }
    

    この3行は、新しいデータ newdata を追加するコードです.

  • 再度 Evaluate をクリック.

    OUTPUT ウィンドウに新しいデータ newdata が追加されます.

    その結果はこのようになります.

    {
      "hello": true,
      "newdata": "Received the message: world"
    }
    

    2行目の "newdata": ... が、新しいデータです. それ以外の "hello" は, もともとのソースコード hello {...} の結果です.

  • inputを変える

    • 右の INPUT ウィンドウに "message":... と書かれてあります.

    • この中身を "message": "distopia" に変えてみます.

    • Evaluate を再度クリック. このような結果が出るでしょう.

      {
          "hello": false,
          "newdata": "Received the message: distopia"
      }
      

    • hello の結果を見ます. 先ほどの true から false に結果が変わっています. 理由は,

      hello の中身に m == "world" と書かれているためです.

      この文は, もし message"world" なら, 返り値は true になることを意味します.

      そうでなければ, 返り値は false です.

  • data を使ってみる

    • data ウィンドウに以下を書き込みます.

      {
        "rule": "be good"
      }
      
    • 左のウィンドウの最後の行に以下を追記します.

      importdata = msg {
        msg := concat("", ["Received the static data: ", data.rule])
      }
      
    • Evaluate を再度クリック.

    • 新たなコードの結果が表示されます.

      "importdata": "Received the static data: be good",
      

1.2. まとめ: OPA が何をするのか (所要: 3分)

  • Rego Playground を使ってみて分かること.

    1. OPA はポリシーファイルを読み込む.
      ポリシーファイルは Rego 言語で newdata = msg {...} のように記述されます. (Playgroundの左ウィンドウ)
    2. OPA は input のデータを受け取る.
      input のデータはJSONフォーマットでなければなりません. (Playgroundの右上ウィンドウ)
    3. OPA は data のデータも受け取る.
      data のデータもJSONフォーマットでなければなりません. (Playgroundの右中央のウィンドウ. data は初期値で {}になっています)
    4. OPA はポリシーの処理により output を生成する.
      生成される output もJSONフォーマットです. (Playgroundの右下ウィンドウ)
  • まとめ: OPA はRegoファイルを読み込み, JSON データを処理します. そして, OPA は 出力のJSONデータを生成します.

  • 詳細は, 公式ドキュメントのintroduction https://www.openpolicyagent.org/docs/latest/ に記載されています.

2. 自分の環境でOPAを起動する

2.1. OPA をインストールする(所要: ~ 5分)

2.2. OPAの起動を確認する (所要: 5分))

  • opa run を実行してみます.

    $ opa run
    

    その実行中に, a = 3exit を実行できます.

    $ opa run
    OPA 0.26.0 (commit , built at )
    
    Run 'help' to see a list of commands and check for updates.
    
    > a = 3
    Rule 'a' defined in package repl. Type 'show' to see rules.
    > x = 3
    Rule 'x' defined in package repl. Type 'show' to see rules.
    > show
    package repl
    
    a = 3
    
    x = 3
    > exit
    

2.3. OPAをサーバとして起動する (所要: 5分)

  • example.regoというファイルを作成します.

    mkdir example/
    cd example/
    # create example.rego
    

    以下をexample.regoとして保存します. 1章と中身は同じですね.

    package play
    
    default hello = false
    
    hello {
        m := input.message
        m == "world"
    }
    
    newdata = msg {
        msg := concat("", ["Received the message: ", input.message])
    }
    
    importdata = msg {
        msg := concat("", ["Received the static data: ", data.rule])
    }
    

    input.json も以下の内容で作成します. これも1章と同じです.

    # create input.json
    
    {
      "input": {
        "message": "world"
      }
    }
    
  • 以下コマンドを実行します.

    opa run -s ./example.rego
    
  • 別のコマンドラインから OPA サーバにリクエストを出します。

    • まずは /v1/data/play にアクセスします.
    $ curl localhost:8181/v1/data/play -i -d @input.json -H 'Content-Type: application/json'
    
    {"result":{"hello":true,"newdata":"Received the message: world"}}
    
    
    • 次に, /v1/data/play/hello にアクセスします.
    $ curl localhost:8181/v1/data/play/hello -i -d @input.json -H 'Content-Type: application/json'
    
    {"result":true}
    # Same as the value of "hello" in section 1.1
    
    • /v1/data/play/newdata
    $ curl localhost:8181/v1/data/play/newdata -i -d @input.json -H 'Content-Type: application/json'
    
    {"result":"Received the message: world"}
    # Same as the value of "newdata" in section 1.1
    
    • /v1/data/play/importdata
    $ curl localhost:8181/v1/data/play/importdata -i -d @input.json -H 'Content-Type: application/json'
    
    {}
    # This is undefined because no data is imported.
    

2.4. OPA にデータを読み込ませる (5 min)

# create data.json
{
  "rule": "be good"
}

サーバの起動コマンドを以下のように変えて, OPAサーバを再度起動します.

# add ./data.json to command arguments
opa run -s ./example.rego ./data.json
  • OPAサーバにリクエストを送信します.

    • /v1/data/play
    $ curl localhost:8181/v1/data/play -i -d @input.json -H 'Content-Type: application/json'
    
    {"result":{"hello":true,"importdata":"Received the static data: be good","newdata":"Received the message: world"}}
    # Field "importdata" was added.
    

    このように、読み込んだデータに応じてOPAが処理を変えます.

    • /v1/data/play/importdata
    $ curl localhost:8181/v1/data/play/importdata -i -d @input.json -H 'Content-Type: application/json'
    
    {"result":"Received the static data: be good"}
    # Data was added. Same as the value of "importdata" in section 1.1
    

2.5. まとめ: OPAができること (所要: 3分)

  • OPA サーバが自分の環境で起動でき, HTTPリクエストに応じて処理を実行しました.
    • HTTP リクエストで JSONデータを送信します.
    • さらにボディは {"input": ***}の形式である必要があります.
  • OPA サーバは <server>/v1/api/data/<package name>[/<object name>] のようなエンドポイントを持ちます.
    • Regoファイルの最初の行 package play により, <package name>play であることを定義しています.
    • Regoファイルの中のルールの定義 hello {...} により, <object name>hello であることを定義しています.
  • OPAの返り値は, {"result": ***}の形式のJSONデータです.
    • 返り値の中身は, アクセスするエンドポイントによって変わります.
      • もし <package name> がリクエストされると, 返り値は "result" フィールドに全部の値を含みます.
      • もし <package name>/<object name> がリクエストされると, 返り値は "result" フィールドに指定されたオブジェクト = ルールの結果が含まれます.

3. 参考資料