Web ブラウザ上で Wasmを使ってOpen Policy Agent (OPA) を実行


はじめに

汎用ポリシーエンジンである Open Policy Agent では、WebAssembly 形式でポリシーを配布可能です。本記事では、WebAssembly 形式で出力された Open Policy Agent のポリシーを Web ブラウザで評価することを試してみた内容を紹介します。

Open Policy Agent とは

Open Policy Agent (OPA) は OSS の軽量で汎用的なポリシーエンジンです。開発時や運用時におけるルール(ポリシー)を事前に定義することで、ポリシーに反する情報を検出できます。OPA はポリシーを定義するための宣言型言語 Rego と、ポリシー評価のためのシンプルな API を提供しています。

WebAssembly とは

WebAssembly とは、 Web ブラウザ上で実行可能なバイナリコードの仕様です。C/C++, Rust などの言語で記述されたプログラムをコンパイルし、Web ブラウザ上で実行します。実行時のパース等が不要で高速に動作させることができるため、ブラウザの機能では実現できなかった処理が可能になります。

また、WebAssembly はプラットフォームに依存せず、高いポータビリティを有していることから、Web ブラウザ以外での活用という点でも注目されています。

WebAssembly と OPA

OPA には、ポリシーを WebAssembly 形式で出力する機能があります。通常ポリシー評価のためには、OPA を Daemon として動作させて API を利用するか、ライブラリとして組み込む(Go 言語に限る)必要があります。ポリシーを Wasm 形式で出力することで、Web ブラウザをはじめ、さまざまなプラットフォーム上で OPA のポリシーを評価できるようになります。

Web ブラウザ上で OPA を動作させる手順

ここからは、OPA のポリシーを WebAssembly (Wasm) 形式で出力し、Web ブラウザ上で実行させる手順を説明していきます。

なお、Node.js 上での実行に関しては、opa-wasm のサンプル等を参考にしてください。

Wasm ファイルの作成

まずは Rego で記述したポリシーから、Wasm ファイルを作成します。 Wasm ファイルの作成には、バンドルファイルを作成するための opa build コマンドを利用します。

$ opa build -t wasm -e 'example/allow' policy/wasm/policy.rego

Wasm 形式でポリシーを出力するには最低 1 つ、エントリーポイントとなるルールを指定する必要があります(-e で指定)。上記の例では、example パッケージの allow というルールがエントリーポイントとなります。

opa build コマンドが成功すると、bundle.tar.gz というバンドルファイルが生成されます。Wasm ファイルはこのバンドルファイルの中に出力されます。

# bundle.tar.gz の中身を確認
$ tar tvf bundle.tar.gz
-rw------- 0/0             128 1970-01-01 09:00 /policy/wasm/policy.rego
-rw------- 0/0          116734 1970-01-01 09:00 /policy.wasm
-rw------- 0/0              87 1970-01-01 09:00 /.manifest
# policy.wasm ファイルのみを解凍
$ tar -xzf bundle.tar.gz /policy.wasm

Wasm 形式の注意点としては、JSON で記述される Data ドキュメントが含まれないという点が挙げられます。Daemon として OPA を実行する場合、ポリシーと一緒に Data ドキュメントが読み込まれ、ポリシーの評価時に Data ドキュメントの情報が参照されます。しかし、Wasm で利用する際には後述するように外部から Data の情報をセットする必要があります。

Wasm ファイルの読み込み (@open-policy-agent/opa-wasm の利用)

作成した Wasm 形式のポリシーを JavaScript で利用するには、@open-policy-agent/opa-wasm パッケージを利用します。

$ npm install @open-policy-agent/opa-wasm

@open-policy-agent/opa-wasm には loadPolicy という関数が用意されており、これを利用して OPA の wasm ファイルを読み込むことができます。

import { loadPolicy } from "@open-policy-agent/opa-wasm";

...
// wasm ファイルを ArrayBufferとして読み込む
const policyWasm = await fetch("/path/to/wasm").then(res => res.arrayBuffer());
// webpack の arraybuffer-loader を利用すればバンドル時に組み込むことも可能
// const policyWasm = require("./path/to/policy.wasm");

const policy = await loadPolicy(policyWasm);

ポリシー評価の実行

loadPolicy によって作成されたオブジェクトには、setData()evaluate() メソッドが提供されています。

setData() はポリシーに Data ドキュメントをセットします。前述の通り、Wasm 形式のポリシーには Data ドキュメントが含まれないため、(API などを利用して) 外部から取得してポリシーに Data ドキュメントをセットします。

const data = { hello: "world" };
policy.setData(data);

evaluate() は Data ドキュメントと入力を基にポリシーを評価し、評価結果が object として返却されます。

input には JSON serializable なオブジェクトを指定します。

const input = { world: "world" };
const result = policy.evaluate(input);
console.log(result);
// {result: true}

おわりに

OPA のポリシーを Wasm 形式で作成し、Web ブラウザ上でポリシー評価をしてみました。Wasm 形式でポリシーを配布できるため、1 つのコードベースから複数のプラットフォームで同じポリシーを適用できる点はかなり有用だと感じました。例えば Web アプリケーションとバックエンドサーバで、同一のポリシーを利用して Payload の Validation を行うといったユースケースも考えられます。

引き続き OPA, WebAsembly の動向に注目していきたいと思います。