Flex Gateway新着情報
Governance新着情報
Monitoring API ManagerWebAssembly (WASM) 拡張機能を使用して、Envoy 上でカスタム検索条件として機能するカスタムポリシーを実装できます。これらのポリシーは、 WebAssembly for Proxies (Rust SDK) を使用して実装します。以下の例では、Rust と関連ツールに関する知識があることを前提としています。
カスタムポリシーは、Envoy に依存しないイベント駆動型の L4/L7 プロキシ用ローレベルインターフェースである proxy-wasm ABI に基づいています。このインターフェースは、WASM 拡張機能とホストがやり取りする方法を指定し、リスン可能なライフサイクルイベントである HTTP 要求ライフサイクルイベントに加えて WASM 検索条件ライフサイクルイベントも使用します。
SDK は、各ライフサイクルイベントに関連した情報を取得するためのメソッドを提供します。たとえば、on_http_request_headers イベントから取得されるデータを使用して、関連するカスタムポリシーロジックを実行でき、その結果によって、要求を処理する必要があるかどうかをランタイムに通知できます。
on_http_request_headers
エンドポイントが完全な HTTP リクエストヘッダーのセットを受け取るとトリガーされます。
on_http_request_body
エンドポイントが HTTP 要求の最初の数バイトを受け取るとトリガーされます。
on_http_response_headers
エンドポイントが完全な HTTP レスポンスヘッダーのセットを受け取るとトリガーされます。
on_http_response_body
エンドポイントが HTTP 応答本文の最初の数バイトを受け取るとトリガーされます。
on_configure
WASM 検索条件が使用可能な設定で開始されるとトリガーされます。
Flex Gateway は、ポリシー設定を JSON にシリアル化し、シリアル化された設定は Envoy WASM 検索条件の設定に使用されます。この JSON をカスタムポリシーで使用されるデータに非シリアル化して解析できます。
次の Envoy 検索条件テンプレートは、ライフサイクルイベントの実装方法を示しています。
use proxy_wasm::traits::*;
use proxy_wasm::types::*;
proxy_wasm::main! {{
    proxy_wasm::set_log_level(LogLevel::Trace);
    proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> {
        Box::new(HttpConfigHeaderRoot {
            header_content: String::new(),
        })
    });
}}
struct HttpConfigHeader {
    header_content: String,
}
impl Context for HttpConfigHeader {}
impl HttpContext for HttpConfigHeader {
    fn on_http_request_headers(&mut self, _num_headers: usize, _end_of_stream: bool) -> Action {
        Action::Continue
    }
    fn on_http_request_body(&mut self, _body_size: usize, _end_of_stream: bool) -> Action {
        Action::Continue
    }
    fn on_http_response_headers(&mut self, _num_headers: usize, _end_of_stream: bool) -> Action {
        Action::Continue
    }
    fn on_http_response_body(&mut self, _body_size: usize, _end_of_stream: bool) -> Action {
        Action::Continue
    }
}
struct HttpConfigHeaderRoot {
    header_content: String,
}
impl Context for HttpConfigHeaderRoot {}
impl RootContext for HttpConfigHeaderRoot {
    fn on_configure(&mut self, _: usize) -> bool {
        if let Some(config_bytes) = self.get_plugin_configuration() {
            self.header_content = String::from_utf8(config_bytes).unwrap()
        }
        true
    }
    fn create_http_context(&self, _: u32) -> Option<Box<dyn HttpContext>> {
        Some(Box::new(HttpConfigHeader {
            header_content: self.header_content.clone(),
        }))
    }
    fn get_type(&self) -> Option<ContextType> {
        Some(ContextType::HttpContext)
    }
}
次のチュートリアルでは、すでに Exchange にパブリッシュされているポリシー定義のポリシー実装の例を作成する方法を示しています。
このポリシー例では、x-custom-auth ヘッダーがユーザー設定の値と一致しない要求をブロックしています。
ポリシー開発プロセスは、以下のステップで行います。
ポリシー定義 JSON ファイルを作成する。
プロジェクトをセットアップする。
カスタムポリシーを開発する。
ポリシー実装例では、ポリシー定義 JSON ファイルが必要です。Flex Gateway は、ポリシー設定をポリシー定義構造と一緒に JSON として Envoy WASM 検索条件に渡します。
認証ヘッダーポリシーの例には、ヘッダーで渡す必要のある値のパラメーターのみを使用しています。ポリシー定義 JSON ファイルは次の内容と一致している必要があります。
{
  "title": "Custom Auth Header",
  "type": "object",
  "description": "Enforces HTTP authentication matching x-custom-auth value to what is configured in the policy.",
  "properties": {
    "secret-value": {
      "title": "Custom Auth Header Password",
      "type": "string",
      "@context": {
        "@characteristics": [
          "security:sensitive"
        ]
      }
    }
  },
  "required": [
    "secret-value"
  ],
  "unevaluatedProperties": false,
  "@context": {
    "@vocab": "anypoint://vocabulary/policy.yaml#",
    "security": "anypoint://vocabulary/policy.yaml#"
  },
  "$id": "custom-auth-header-simple",
  "$schema": "https://json-schema.org/draft/2019-09/schema"
}
次のコマンドで Rust プロジェクトを作成します。
cargo new flex_custom_policy_example --lib
これにより flex_custom_policy_example ディレクトリが作成されます。
次のコンテンツを flex_custom_policy_example ディレクトリの Cargo.toml にコピーします。
[package]
name = "flex_custom_policy_example"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["cdylib"]
name="flex_custom_policy_example"
path="src/lib.rs"
[dependencies]
proxy-wasm = { git = "https://github.com/proxy-wasm/proxy-wasm-rust-sdk.git", tag = "v0.2.0" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
[profile.release]
opt-level = "z"
lto = "fat"
次のポリシーブートストラップコードを新しい Rust ソースファイルに追加します。
use proxy_wasm::traits::*;
use proxy_wasm::types::*;
use serde::Deserialize;
proxy_wasm::main! {{
    proxy_wasm::set_log_level(LogLevel::Trace);
    proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> {
        Box::new(CustomAuthRootContext {
            config: CustomAuthConfig::default(),
        })
    });
}}
このコードは、WASM 検索条件を Envoy にデプロイするために必要です。main ブロックは、ルートコンテキストを設定します。このルートコンテキストは、受け取った各 HTTP 要求に対して子コンテキストを生成するために使用する Envoy エンティティです。
次のルートコンテキスト実装コードを追加します。
struct CustomAuthRootContext {
    config: CustomAuthConfig,
}
impl Context for CustomAuthRootContext {}
impl RootContext for CustomAuthRootContext {
    fn create_http_context(&self, _: u32) -> Option<Box<dyn HttpContext>> {
        Some(Box::new(CustomAuthHttpContext {
            config: self.config.clone(),
        }))
    }
    fn get_type(&self) -> Option<ContextType> {
        Some(ContextType::HttpContext)
    }
}
各 Envoy 検索条件は、ルートコンテキスト実装を提供するために必要です。RootContext trait には、実装可能な便利なメソッドが含まれています。この例では、Envoy が子コンテキストを生成できるように、HTTP 検索条件は create_http_context と get_type を実装しています。
次の Struct を追加して、この JSON の解析を有効にします。
#[derive(Default, Clone, Deserialize)]
struct CustomAuthConfig {
    #[serde(alias = "secret-value")]
    secret_value: String,
}
Flex Gateway は、ポリシー定義で指定されている JSON を使用してポリシーを設定します。解析が必要な JSON には secret-value という項目が 1 つあります。
設定を非シリアル化します。
基本的なポリシー設定構造を作成したら、逆シリアル化するために RootContext on_configure メソッドを実装する必要があります。
CustomAuthRootContext の RootContext の実装内で、次のスニペットのように on_configure メソッドを追加します。
impl RootContext for CustomAuthRootContext {
    fn on_configure(&mut self, _: usize) -> bool {
        if let Some(config_bytes) = self.get_plugin_configuration() {
            self.config = serde_json::from_slice(config_bytes.as_slice()).unwrap();
        }
        true
    }
    // Other implemented methods
    // ...
}
次の HTTP コンテキストコードを追加します。
struct CustomAuthHttpContext {
    pub config: CustomAuthConfig,
}
impl Context for CustomAuthHttpContext {}
impl HttpContext for CustomAuthHttpContext {}
受け取った各要求によって新しい CustomAuthHttpContext が作成されます。この CustomAuthHttpContext は、HTTP 要求が有効である間は有効です。これにより (要求間の状態データではなく) 要求に関連した状態データを格納できます。
次のコアポリシー機能ロジックを追加します。
impl HttpContext for CustomAuthHttpContext {
    fn on_http_request_headers(&mut self, _num_headers: usize, _end_of_stream: bool) -> Action {
        if let Some(value) = self.get_http_request_header("x-custom-auth") {
            if self.config.secret_value == value {
                return Action::Continue;
            }
        }
        self.send_http_response(401, Vec::new(), None);
        Action::Pause
    }
}
proxy-wasm ABI は、受け取ったリクエストヘッダー値を取得して、値を secret-value と比較します。secret-value がヘッダーと一致すると、実装は Action::Continue を返します。そうでない場合は Action::Pause を返し、検索条件自身が send_http_response を使用して呼び出し側のクライアントに応答を返します。
注意: Rust SDK には、get_http_request_header を使用した非 UTF-8 値の読み込みの問題があります。この問題を回避するには、get_http_request_headers_bytes メソッドを使用し、from_utf8  メソッドを使用してバイトを読み取ります。次に例を示します。
let header = self.get_http_request_header_bytes("x-custom-auth").map(String::from_utf8).and_then(Result::ok);
wasm32 をターゲットとして追加して、コンパイルを有効にします。
rustup target add wasm32-wasi
ポリシーに含まれるすべてのサードパーティライブラリは、wasm32-wasi Rust コンパイルターゲットと互換性がある必要があります。
| 
 一部のライブラリは wasm32-wasi ターゲットと適切に互換性があっても、Flex Gateway にデプロイすると適切に動作しないことがあります。この状況が発生した場合のデプロイメントエラーの例は次のとおりです。 
 これらの問題を解決するには、サードパーティライブラリのオーナーに問い合わせるか、別のライブラリを使用してください。  | 
次のコマンドでカスタムポリシーをコンパイルします。
cargo build --target wasm32-wasi --release
コンパイルにより、バイナリ .wasm ファイルが ./target/wasm32-wasi/release ディレクトリに出力されます。
Exchange へのカスタムポリシーのパブリッシュついての詳細は、「Flex Gateway または Mule 4 カスタムポリシーのパブリッシュ」を参照してください。