Service Mesh (ASM) は、WebAssembly for Proxies 仕様をサポートしており、これにより、ポータブルなプラグインを WebAssembly(Wasm)にコンパイルすることで Envoy プロキシの動作を拡張できます。これらのプラグインは、さまざまなプロキシサーバー上で実行可能です。Wasm プラグインは、メモリ安全なサンドボックス内でネイティブに近い速度で実行され、プロキシの再起動なしに更新できます。
本トピックでは、ヘッダーに基づく権限付与を強制する Go 言語ベースの Wasm プラグインの作成、Open Container Initiative(OCI)イメージへのパッケージング、および ASM イングレスゲートウェイへのデプロイ手順について説明します。
Envoy における Wasm プラグインの仕組み
Wasm プラグインは、ホストプロキシと通信するための明確に定義された API を備えたサンドボックス化された環境内で実行されます。このアーキテクチャには、以下の利点があります:
| 利点 | 説明 |
|---|---|
| ホットリロード可能 | Envoy プロキシを再起動せずにプラグインを更新できるため、トラフィックの継続的な処理が保証されます |
| 障害分離 | プラグインのクラッシュが Envoy プロキシ全体の停止を引き起こしません |
| セキュア | サンドボックスにより、プラグインの機能が明確に定義された API サーフェスに制限されます |
| マルチ言語対応 | C++、Go、Rust のいずれかでプラグインを作成できます |
詳細については、「Envoy における WebAssemblyおよびproxy-wasm-go-sdk の概要をご参照ください。
エンドツーエンドのワークフロー
本チュートリアルで作成するプラグインは、着信リクエストに allow: true ヘッダーが含まれているかどうかをチェックします。このヘッダーが存在しないリクエストには 403 Forbidden 応答が返されます。ヘッダーが存在するリクエストはバックエンドサービスへ透過的に転送されます。
proxy-wasm-go-sdk を使用して Go 言語でプラグインのロジックを記述します。
TinyGo を使用して Go コードを Wasm バイナリにコンパイルします。
バイナリを OCI イメージとしてパッケージ化し、Container Registry Enterprise Edition にプッシュします。
ASM で
WasmPluginリソースを作成し、Envoy プロキシにプラグインを適用します。
前提条件
開始する前に、以下の条件を満たしていることを確認してください。
クラスターが追加済みの ASM インスタンス(v1.18 以降)。詳細については、「ASM インスタンスへのクラスターの追加」をご参照ください。
自動サイドカープロキシ注入が有効化されていること。詳細については、「サイドカープロキシ注入ポリシーの設定」をご参照ください。
イングレスゲートウェイがデプロイ済みであること。詳細については、「イングレスゲートウェイの作成」をご参照ください。
HTTPBin アプリケーションがデプロイ済みで、アクセス可能であること。詳細については、「HTTPBin アプリケーションのデプロイ」をご参照ください。
OCI イメージ対応のために Container Registry Enterprise Edition インスタンスが作成済みであること。詳細については、「Container Registry Enterprise Edition インスタンスの作成」をご参照ください。
ステップ 1:開発環境のセットアップ
ローカルマシンに以下のツールをインストールします。
| ツール | 目的 | 参考情報 |
|---|---|---|
| Go | Go コンパイラおよびツールチェーン | go.dev |
| Docker | OCI イメージのビルドおよびプッシュ | docker.com |
| TinyGo | Go を Wasm にコンパイル(標準 Go コンパイラは Wasm 出力をサポートしていません) | TinyGo インストールガイド |
本プラグインは、proxy-wasm-go-sdk に依存しており、これは完全な Go SDK API および追加のサンプルを含んでいます。
ステップ 2:プラグインコードの記述
プロジェクトディレクトリを作成し、以下の内容で
main.goファイルを追加します。Go モジュールを初期化し、依存関係をダウンロードします。
go mod init go mod tidyコードを Wasm バイナリにコンパイルします。この操作により、現在のディレクトリに
plugin.wasmファイルが生成されます。tinygo build -o plugin.wasm -scheduler=none -target=wasi main.go
ステップ 3:OCI イメージのパッケージ化およびプッシュ
同じプロジェクトディレクトリで、
Dockerfileを作成します。FROM scratch ADD ./plugin.wasm ./plugin.wasmイメージをビルドします。
docker build -t header-authorization:v0.0.1 .Container Registry Enterprise Edition にイメージリポジトリを作成します。詳細な手順については、「Coraza Wasm プラグインを使用した ASM ゲートウェイ上での WAF 機能の実装」のステップ 1 のサブステップ 2.a および 2.b をご参照ください。本例では、名前空間は
test-oci、リポジトリ名はheader-authorizationです。
イメージにタグを付けて Container Registry Enterprise Edition インスタンスにプッシュします。リポジトリの詳細ページに表示される「レジストリへのイメージのプッシュ」の手順に従ってください。
ステップ 4:Wasm プラグインのイングレスゲートウェイへの適用
イメージのプル用のシークレットを作成します。背景情報については、「ステップ 2:イメージプルの権限の設定」をご参照ください。以下のプレースホルダーを実際の値に置き換えてください。
プレースホルダー 説明 <your-registry-domain>Container Registry Enterprise Edition インスタンスのドメイン名 <your-username>レジストリのユーザー名 <your-password>レジストリのパスワード kubectl create secret docker-registry -n istio-system wasm-secret \ --docker-server=<your-registry-domain> \ --docker-username=<your-username> \ --docker-password=<your-password>asm-plugin.yamlというファイルを作成し、以下の内容を記述します。<your-registry-domain>を、ご利用の Container Registry Enterprise Edition インスタンスのドメイン名に置き換えてください。apiVersion: extensions.istio.io/v1alpha1 kind: WasmPlugin metadata: name: header-authorization namespace: istio-system spec: imagePullPolicy: IfNotPresent imagePullSecret: wasm-secret selector: matchLabels: istio: ingressgateway url: oci://<your-registry-domain>/test-oci/header-authorization:v0.0.1 phase: AUTHNASM インスタンスの kubeconfig ファイルを使用して接続し、リソースを適用します。
kubectl apply -f asm-plugin.yaml
ステップ 5:プラグインの検証
イングレスゲートウェイ上で Wasm プラグインのデバッグログを有効化します。イングレスゲートウェイが実行されているデータプレーンクラスターの kubeconfig ファイルを使用します。
<ingress-gateway-pod>を、イングレスゲートウェイを実行している Pod の名前に置き換えてください。kubectl -n istio-system exec <ingress-gateway-pod> -c istio-proxy -- \ curl -XPOST "localhost:15000/logging?wasm=debug"allowヘッダーを**含まない**リクエストを送信します。期待される出力は以下のとおりです。curl <ingress-gateway-ip>/status/418Forbidden by ASM Wasm Pluginイングレスゲートウェイの Pod ログを確認します。ログエントリにより、プラグインがリクエストをブロックしたことが確認できます。
2024-03-08T08:16:46.747394Z debug envoy wasm external/envoy/source/extensions/common/wasm/context.cc:1168 wasm log istio-system.header-authorization: request header: 'allow' is , only true can passthrough thread=24 {"bytes_received":"0","bytes_sent":"28","downstream_local_address":"xxxxxxx","downstream_remote_address":"xxxxxxxx","duration":"0","istio_policy_status":"-","method":"GET","path":"/status/418","protocol":"HTTP/1.1","request_id":"780c8493-13e4-4f97-9771-486efe30347c","requested_server_name":"-","response_code":"403","response_flags":"-","route_name":"httpbin","start_time":"2024-03-08T08:16:46.747Z","trace_id":"-","upstream_cluster":"outbound|8000||httpbin.default.svc.cluster.local","upstream_host":"-","upstream_local_address":"-","upstream_service_time":"-","upstream_response_time":"-","upstream_transport_failure_reason":"-","user_agent":"curl/8.4.0","x_forwarded_for":"xxxxxx","authority_for":"xxxxxx"}allow: trueヘッダーを**含む**リクエストを送信します。期待される出力は以下のとおりです。ティーポット応答により、HTTPBin アプリケーションへのアクセスが可能であり、プラグインが正しく動作していることが確認できます。curl <ingress-gateway-ip>/status/418 -H "allow: true"-=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
TinyGo のメモリリークを nottinygc で修正
TinyGo でコンパイルされた Wasm プラグインは、メモリリークを示す場合があります。proxy-wasm-go-sdk コミュニティでは、この問題を解決するために、nottinygc をカスタムガーベジコレクターとして使用することを推奨しています。
main.goの先頭に、以下の import 文を追加します。この依存関係がまだ利用できない場合は、go mod tidyを実行してダウンロードしてください。import _ "github.com/wasilibs/nottinygc"カスタム GC フラグを指定して Wasm バイナリを再構築します。
-gc=customフラグにより、TinyGo のデフォルトガーベジコレクターが nottinygc に置き換えられ、-tags='custommalloc nottinygc_envoy'により、Envoy 向けに最適化されたアロケーターが有効化されます。tinygo build -o plugin.wasm -gc=custom -tags='custommalloc nottinygc_envoy' \ -target=wasi -scheduler=none main.goOCI イメージを再構築し、更新版を Container Registry Enterprise Edition にプッシュした後、
WasmPluginリソースを再適用して修正を展開します。