Open Policy Agent 概要 メモ


Open Policy Agentについて、個人用にメモする。

## 特徴

* Open Policy Agent（OPA）は、オープンソースの汎用的なポリシーエンジン
  * ポリシーエンジン：ポリシーに違反した情報を発見し、事前に定義されたアクションを実行する機構

* 与えられた構造化データがRegoと呼ばれるポリシー言語で記述されたポリシーを満たしているか判定する。
* メリット
  * Policy(ルール)を明文管理できる。
  * Policyをコードベースで運用管理できる。
  * ...

![opa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/98609fe7-09fc-187b-a8a2-3297fd9a0fed.png)


## 動作確認

* [公式](https://www.openpolicyagent.org/docs/v0.16.2/http-api-authorization/)の手順に従い、dockerを利用した動作確認を行ってみる

* 環境構築

  * 下記のdocker-compose.ymlを用意する。

  ```yaml
  version: '2'
  services:
    opa:
      image: openpolicyagent/opa:0.16.2
      ports:
        - 8181:8181
      # WARNING: OPA is NOT running with an authorization policy configured. This
      # means that clients can read and write policies in OPA. If you are
      # deploying OPA in an insecure environment, be sure to configure
      # authentication and authorization on the daemon. See the Security page for
      # details: https://www.openpolicyagent.org/docs/security.html.
      command:
        - "run"
        - "--server"
        - "--log-format=json-pretty"
        - "--set=decision_logs.console=true"
    api_server:
      image: openpolicyagent/demo-restful-api:0.2
      ports:
        - 5000:5000
      environment:
        - OPA_ADDR=http://opa:8181
        - POLICY_PATH=/v1/data/httpapi/authz
  ```

  * 次のコマンドを実行する。

    ```shell
    docker-compose -f docker-compose.yml up
    ```

* ポリシー設定

  * テスト用ポリシーファイル`example.rego`を用意する。

    ```rego
    package httpapi.authz
    
    # bob is alice's manager, and betty is charlie's.
    subordinates = {"alice": [], "charlie": [], "bob": ["alice"], "betty": ["charlie"]}
    
    # HTTP API request
    import input
    
    default allow = false
    
    # Allow users to get their own salaries.
    allow {
      some username
      input.method == "GET"
      input.path = ["finance", "salary", username]
      input.user == username
    }
    
    # Allow managers to get their subordinates' salaries.
    allow {
      some username
      input.method == "GET"
      input.path = ["finance", "salary", username]
      subordinates[input.user][_] == username
    }
    ```

  * 下記のAPIリクエストを行い、ポリシーファイルを読み込ませる。

    ```curl
    curl -X PUT --data-binary @example.rego \
      localhost:8181/v1/policies/example
    {}
    ```

  * ポリシー動作確認

    正常系：aliceによる自身のsalary情報参照権限確認

    ```curl
    curl --user alice:password localhost:5000/finance/salary/alice
    Success: user alice is authorized
    ```

    正常系：bobによるaliceのsalary情報参照権限確認

    ```
    curl --user bob:password localhost:5000/finance/salary/alice
    Success: user bob is authorized
    ```

    

    異常系

    ```curl
    curl --user alice:password localhost:5000/finance/salary/hoge
    Error: user alice is not authorized to GET url /finance/salary/hoge
    ```

* ポリシー更新

  * テスト用ポリシーファイル`example-hr.rego`を用意する。

    ```rego
    package httpapi.authz
    
    import input
    
    # Allow HR members to get anyone's salary.
    allow {
      input.method == "GET"
      input.path = ["finance", "salary", _]
      input.user == hr[_]
    }
    
    # David is the only member of HR.
    hr = [
      "david",
    ]
    ```

  * 下記APIリクエストを行い、ポリシーを更新する。

    ```curl
    curl -X PUT --data-binary @example-hr.rego \
      http://localhost:8181/v1/policies/example-hr
    {}
    ```

  * ポリシー動作確認

    下記リクエストを行い、全ユーザーがdavidのsalary情報参照権限があることを確認できる。

    ```
    curl --user david:password localhost:5000/finance/salary/alice
    Success: user david is authorized
    curl --user david:password localhost:5000/finance/salary/bob
    Success: user david is authorized
    curl --user david:password localhost:5000/finance/salary/charlie
    Success: user david is authorized
    curl --user david:password localhost:5000/finance/salary/david
    Success: user david is authorized
    ```

    



## 参考情報

* [Policy-based control for cloud native environments](https://www.openpolicyagent.org/)
* [Open Policy Agent](https://www.openpolicyagent.org/docs/latest/)