Envoy プロキシのデプロイ設定

サポートは、Envoy プロキシ に対して、sigsci-agent で実装された組み込みの Envoy gRPC API を介して利用可能です。これは gRPC サーバーとして実行されます。Envoy v1.11.0 以降が推奨されますが、Envoy v1.8.0 以降は、以下のドキュメントに記載されているように機能が制限されています。

Envoy (v1.11 以降) は、トラフィックを検査するための双方向 gRPC API をサポートしていません。代わりに、トラフィックを検査するために利用可能な 2つの独立した gRPC API があります。外部認証 HTTP フィルター (envoy.filters.http.ext_authz) gRPC API は、インバウンドリクエストの検査を待っている間、リクエストを保留状態にできるため、必要に応じてリクエストをブロックすることができます。その後、追加の gRPC AccessLog サービス gRPC API を使用して、送信リクエストデータを検査することができます。これら2つの API を、gRPC サーバーとして動作する sigsci-agent と組み合わせて使用することで、Envoy の組み込み API のみを用いて双方向の検査が可能になります。これにより、それぞれのアップストリームアプリケーションにモジュールをインストールすることなく、Web アプリケーションの検査が可能になります。この場合、sigsci-agent がモジュールとして機能します。

リクエスト許可 (通常) 処理

以下に説明する Envoy および Next-Gen WAF で許可されているリクエストを示す図。 

これは、sigsci-agent が Envoy を通じて許可している通常のリクエストの流れです。

  1. クライアントからのリクエストは Envoy によって受信され、Envoy の External Authorization (ext_authz) HTTP フィルターにルーティングされます。そこでリクエストのメタデータが抽出され、sigsci-agent を介して処理されます。

  2. リクエストメタデータは gRPC ext_authz API を介して sigsci-agent に送信されます。

  3. sigsci-agent は、「許可リクエスト」レスポンスを返し、リクエストが ext_authz HTTP フィルターを通過して通常の Envoy リクエスト処理を続行することを許可します。

  4. リクエストは追加の HTTP フィルターを通過し、ハンドラーに到達します。ハンドラーはリクエストを処理し、レスポンスを生成します。

  5. リクエスト/レスポンスのメタデータは、Envoy gRPC AccessLog Service (als) 経由で非同期に抽出され、sigsci-agent で処理が行われます。

  6. 並行して、レスポンスヘッダーや HTTP ステータスコードなどの追加のメタデータは gRPC als API 経由で sigsci-agent に送信され、さらに処理されます。一方、レスポンスデータは元のクライアントに送り返されます。

リクエストのブロック処理

以下に説明する Envoy を通過するリクエストが Next-Gen WAF によってブロックされる様子を示す図。 

これは、sigsci-agent が Envoy を通じたリクエストの処理をブロックした場合の流れです。

  1. クライアントからのリクエストは Envoy によって受信され、Envoy の External Authorization (ext_authz) HTTP フィルターにルーティングされます。そこでリクエストのメタデータが抽出され、sigsci-agent を介して処理されます。

  2. リクエストメタデータは gRPC ext_authz API を介して sigsci-agent に送信されます。

  3. sigsci-agent は「ブロックリクエスト」レスポンスを返し、HTTP フィルターチェーンによるリクエストの処理を継続することを許可しません。

  4. これにより ext_authz フィルターがトリガーされて HTTP 406 レスポンスが生成され、リクエストのそれ以降の処理がブロックされます。

Next-Gen WAF エージェントの設定

sigsci-agent は通常、Kubernetes を介してサイドカーとしてインストールされますが、通常のインストールとは設定が若干異なります。

sigsci-agent は、通常の RPC リスナーではなく、Envoy gRPC リスナーで実行されるように設定する必要があります。これを行うには、envoy-grpc-address エージェント設定オプションで Envoy gRPC リスナーを設定します。これにより、デフォルトの RPC リスナーの代わりにこのリスナーが起動します。

sigsci-agent 設定ファイルの設定値を次のように設定します。

envoy-grpc-address = "0.0.0.0:8000"

もしくは sigsci-agent 環境内で設定値を次のように設定します。

SIGSCI_ENVOY_GRPC_ADDRESS=0.0.0.0:8000

オプションとして、sigsci-agent は TLS を有効にして設定することも可能です。これを行うには、sigsci-agent 設定で証明書とキーファイルを設定します。

envoy-grpc-cert = "/path/to/cert.pem"
envoy-grpc-key = "/path/to/key.pem"

または

SIGSCI_ENVOY_GRPC_CERT=/path/to/cert.pem
SIGSCI_ENVOY_GRPC_KEY=/path/to/key.pem

さらに、レスポンスデータ処理を有効にすることを推奨します。これを行うには、sigsci-agent を設定し、envoy-expect-response-data エージェント設定オプションを設定することで、Envoy からのレスポンスデータを取得できるようにする必要があります。デフォルトでは、sigsci-agent 内のレスポンスデータは無視されます。これは、古いバージョンの Envoy をより適切にサポートするための Envoy 設定オプションであるためです。Envoy v1.10 以降をお使いの場合は、このオプションを有効にする必要があります。

sigsci-agent 設定ファイルの設定値を次のように設定します。

envoy-expect-response-data = 1

もしくは sigsci-agent 環境内で設定値を次のように設定します。

SIGSCI_ENVOY_EXPECT_RESPONSE_DATA=1

sigsci-agent における検査の一部は設定可能ですが、一般的にはデフォルトとして残しておくべきです。詳細は inspection-* エージェント設定を確認してください。

Envoy 設定

Envoy はリクエストデータを処理するためにメインハンドラーフィルターの前に外部認証 HTTP フィルター (envoy.filters.http.ext_authz) で設定する必要があります。また、gRPC AccessLog サービス をセットアップしてレスポンスデータを処理する必要があります (オプションですが推奨)。これを行うには、Envoy の設定に以下の複数の設定項目を追加する必要があります。sigsci-agent を介した gRPC 呼び出しを処理するクラスター、メインハンドラーの前の envoy.filters.http.ext_authz HTTP フィルター、およびレスポンスデータを有効にする場合は、HTTP リスナーフィルターの access_log セクションに追加された envoy.http_grpc_access_log サービス。

Next-Gen WAF エージェントクラスターの追加

sigsci-agent 設定で使用される Envoy gRPC アドレスで構成されたクラスターを追加する必要があります。現在、レスポンスデータが有効になっている場合、Envoy で gRPC サービスの一貫性のあるハッシュを有効化する方法が (まだ) ないため、ロードバランシングは正しく動作しません。したがって、レスポンスデータ検査なしで envoy.filters.http.ext_authz API のみをで使用する場合を除き、現時点ではロードバランシングを設定しないことを推奨します。

clusters:
- name: sigsci-agent-grpc
connect_timeout: 0.2s
type: strict_dns
#lb_policy: LEAST_REQUEST
http2_protocol_options: {}
#tls_context: {}
### You can also use 'hosts' below, but this is deprecated
load_assignment:
cluster_name: sigsci-agent-grpc
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: sigsci-agent
port_value: 8000

addresssigsci-agent に対して解決可能なホスト名もしくは IP であり、port_valueenvoy-grpc-address オプションの sigsci-agent 設定で設定されたものと一致する必要があります。

ヒント : connect_timeoutsigsci-agent への接続のタイムアウト (データ処理のタイムアウトではありません) であり、必要に応じて調整できます。TLS を使用する場合は tls_context オプションを定義する必要があります。TLS は sigsci-agent 設定で envoy-grpc-certenvoy-grpc-keyを使って設定できます。sigsci-agentで TLS が設定されている場合、空の tls_context のみ (例 : tls_context: {}) を設定して、Envoy が TLS 経由で接続を認識できるようにする必要があります。証明書の検証が必要な場合は、validation_contexttls_context で設定し、検証に使用する trusted_ca ファイル名を指定する必要があります。gRPC サービスは HTTP/2 ベースであるため、http2_protocol_options: {} オプションが必要です。これにより、トラフィックが HTTP/2 として sigsci-agent クラスターに送られます。

Envoy 外部認可 HTTP フィルターを追加する

リスナーには、sigsci-agent クラスターを指すメインハンドラーの前に外部認証 HTTP フィルター (envoy.filters.http.ext_authz) を追加する必要があります。

http_filters:
- name: envoy.filters.http.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
transport_api_version: V3
grpc_service:
envoy_grpc:
cluster_name: sigsci-agent-grpc
timeout: 0.2s
failure_mode_allow: true
with_request_body:
# Maximum request body bytes buffered and sent to the sigsci-agent
max_request_bytes: 8192
# NOTE: If allow_partial_message is set false, then any request over
# the above max bytes will fail with an HTTP "413 Payload Too Large"
# so it is recommended to set this to true.
allow_partial_message: true
# NOTE: By default, envoy carries the HTTP request body as a UTF-8 string
# and it fills the body @ # field. To pack the request body as raw bytes,
# set pack_as_bytes to true.
pack_as_bytes: true
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

ヒント : failure_mode_allow: true はフェイルオープンになるようにするためであり、推奨される設定です。そして timeout は、指定された時間経過後に定義されたフェイルモード (フェイルオープンの場合は true、フェイルクローズの場合は false) で失敗することを許可します。これが完了すると、すべての HTTP リクエストは最初に envoy.filters.http.ext_authz フィルターに送信され、sigsci-agent クラスターによって処理されます。次に、sigsci-agent はリクエストを処理し、リクエストがブロック対象の場合は 406 HTTP ステータスコードで認証を拒否し、許可される場合はリクエストを次の HTTP フィルターへ通過させます。他のモジュールと同様に、追加の HTTP リクエストヘッダーもリクエストに追加されます。

Envoy gRPC AccessLog サービスを追加する

これは推奨されるステップですが、任意です。Envoy で設定されている場合、 必要 があります。 Next-Genenvoy-expect-response-data WAF エージェント設定 セクションで記載されているように、 エージェント設定 オプションを設定し、エージェントも応答データを期待するように設定する。Envoy 外部認証 (envoy.filters.http.ext_authz) HTTP フィルターはリクエストデータのみを処理できます。sigsci-agent が完全な機能を発揮するためには gRPC AccessLog サービス を設定し、レスポンスデータを sigsci-agent に送信する必要があります。これを行うには、Envoy 設定のリスナーフィルター (通常は envoy.filters.network.http_connection_manager フィルターの下) にaccess_log セクションを追加する必要があります (セクションが存在しない場合)。存在する場合は、それに追加する必要があります。

詳細については、HTTP 設定マネージャーaccess_log 設定オプションを参照してください。こちらに (既存のアクセスログエントリーに加えて) envoy.http_grpc_access_log エントリーを追加する必要があります。

推奨設定は以下の通りです (制限事項を最小限に抑えるためのさらなるカスタマイズについては制約と考慮事項を参照)。

access_log:
- name: envoy.http_grpc_access_log
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.HttpGrpcAccessLogConfig
common_config:
log_name: "sigsci-agent-grpc"
transport_api_version: V3
grpc_service:
envoy_grpc:
cluster_name: sigsci-agent-grpc
timeout: 0.2s
additional_request_headers_to_log:
# These sigsci-agent headers are required for correct processing:
- "x-sigsci-request-id"
- "x-sigsci-waf-response"
# Optionally, additional headers can be added that should be recorded:
- "accept"
- "content-type"
- "content-length"
additional_response_headers_to_log:
- "date"
- "server"
- "content-type"
- "content-length"

制約と考慮事項

Envoy プロキシで sigsci-agent を使用する際の現在の制限事項は以下の通りです。Envoy プロキシのサポートが将来改善されるにつれて、これらの制限事項は解消され、軽減される見込みです。

デフォルトではリクエストボディは処理されません

Envoy v1.10.0 以前では、Envoy の外部認証はリクエストボディを送信しませんでした。Envoy のすべてのバージョンにおいて、リクエストボディはデフォルトでは ext_authz 呼び出しに含まれず、設定されない限り sigsci-agent によって検査されません。

Envoy v1.10.0 以降では、リクエストボディを含めるサポートが envoy.filters.http.ext_authz 設定に組み込まれており、前述の通り Envoy 設定のこのセクションで with_request_body を設定することが可能にになりました。

Envoy v1.11.0 以降では、部分的なボディをより正確に検出できるようサポートが拡張されました。

HTTP/2 (およびgRPC) をサポートするには、Envoy は v1.12.1 以降のバージョンを実行している必要があります。 Envoy v1.10.0 から v1.12.1 では、 with_request_body を使用してリクエストボディを正しく送信できません。

しかし、Envoy のアップグレードが可能になるまでは、Lua を使ってこの Envoy の制限を回避することができます。以下は、gRPC ベースのボディを検査のために sigsci-agent に渡すために使用できる Lua フィルターの例です。

これを実現するには、Lua HTTPフィルター (envoy.lua)envoy.ext_authz フィルターの前に設定し、このデータを含む内部 x-sigsci-encoded-body ヘッダーを追加します。ボディを抽出してリクエストに追加するには、以下のような短い Lua コードのスニペットを追加する必要があります。

http_filters:
- name: envoy.lua
config:
inline_code: |
-- Add a special header to pass the encoded body
function envoy_on_request(req)
local len = 0
local reqbody
-- Determine the body length
local cl = req:headers():get("content-length")
if cl ~= nil then
len = tonumber(cl)
end
-- gRPC does not have a content-length header to limit the body before buffering
if len == 0 and req:headers():get("content-type") == "application/grpc" then
-- Triggers buffering
len = req:body():length()
end
-- Limit body length sent to the agent (adjust as needed)
if len > 0 and len <= 8192 then
-- Triggers buffering
reqbody = req:body():getBytes(0, len)
-- Encode the body for use in a header value
local enc, t = string.gsub(reqbody, "[^%w]", function(chr)
return string.format("%%%02X",string.byte(chr))
end)
req:headers():add("x-sigsci-encoded-body", enc)
end
end
- name: envoy.ext_authz
config:
grpc_service:
envoy_grpc:
cluster_name: sigsci-agent-grpc
timeout: 0.2s
failure_mode_allow: true
# with_request_body:
# max_request_bytes: 8192
# allow_partial_message: true
- name: envoy.router
config: {}

TLS ハンドシェイクのメタデータは抽出されません

現在、Envoy では送信元のリクエストで使用された TLS ハンドシェイクメタデータ (暗号やプロトコルバージョンなど) を sigsci-agent が参照する手段は (まだ) 提供されていません。このサイト (ワークスペース) では、TLS ハンドシェイクのメタデータに基づくシグナルはプロダクトでは表示されません。

この制限により、次のシステム信号は現在サポートされていません。

  • WEAKTLS

レスポンスベースのシグナルのみの場合、デフォルトで最小限のリクエストヘッダーのみが記録されます

リクエストが envoy.filters.http.ext_authz フィルターによって検査され、シグナルが発行されなかった場合、レスポンスは envoy.http_grpc_access_log サービスによって処理されます。レスポンスデータにシグナルが検出された場合、API がデフォルトですべてのリクエストヘッダーを送信しないため、シグナルと共に最小限のリクエストヘッダーのみが記録されます。ただし、追加のリクエストヘッダーを記録したい場合は、Envoy の additional_request_headers_to_log 設定の access_log オプションを介して追加する必要があります。

現在、以下のヘッダーが自動的に追加されます。

  • Host

  • User-Agent

  • Referer

  • X-Forwarded-For

2つの sigsci-agent 特有のヘッダーを追加する必要があります。さらに、追加のリクエストヘッダーは additional_request_headers_to_log を通じて明示的に追加できます。

additional_request_headers_to_log:
# These sigsci-agent headers are required for correct processing:
- "x-sigsci-request-id"
- "x-sigsci-waf-response"
# Optionally, additional headers can be added that should be recorded:
- "accept"
- "content-type"
- "content-length"
- "x-real-ip"

デフォルトではレスポンスヘッダーは処理されません

上記と同様に、最小限のリクエストヘッダーが envoy.http_grpc_access_log サービスによって処理されないため、デフォルトではこの API にはレスポンスヘッダーが送信されません。記録したいヘッダーは、現在ワイルドカードを指定する手段がないため、Envoy の access_log 設定の additional_response_headers_to_log オプションに明示的にリストする必要があります。以下の項目が推奨されます。

additional_response_headers_to_log:
- "date"
- "server"
- "content-type"
- "content-length"

サンプルデプロイ

サンプルデプロイ設定セクションには、完全な Envoy プロキシデプロイ設定が含まれています。これはご自身のデプロイの出発点として利用できます。サンプル設定を動作させるためには、次の手順を完了します。

  1. サイト (ワークスペース) のエージェントキーを更新するには、次のコマンドを実行してください。

    $ kubectl create secret generic sigsci.<site-name> \
    --from-literal=accesskeyid=<access-key-id> \
    --from-literal=secretaccesskey=<secret-access-key>

    必ず <site-name> をサイト (ワークスペース) の名前に、<access-key-id><secret-access-key> をエージェントキーに置き換えてください。

  2. サンプルデプロイ設定envoy-deployment.yamlとして保存してください。

  3. 次のコマンドを実行して envoy-deployment.yaml をデプロイします。

    $ kubectl apply -f envoy-deployment.yaml
  4. (任意) ポートフォワーディングを設定し、次のコマンドを実行してローカルでデプロイをテストします。

    $ kubectl port-forward svc/envoy 10000:10000

サンプルデプロイ設定

# ConfigMap: Contains the Envoy configuration with ext_authz integration.
apiVersion: v1
kind: ConfigMap
metadata:
name: envoy-config
data:
envoy.yaml: |
node:
id: proxy-node
cluster: proxy-cluster
static_resources:
listeners:
- name: listener_0
address:
socket_address:
address: 0.0.0.0
port_value: 10000
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: edge_cluster
host_rewrite_literal: "http.edgecompute.app"
cors:
allow_origin_string_match:
- prefix: "*"
allow_methods: GET, PUT, DELETE, POST, OPTIONS
allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
max_age: "1728000"
expose_headers: custom-header-1,grpc-status,grpc-message
access_log:
- name: envoy.access_loggers.stdout
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
- name: envoy.http_grpc_access_log
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.HttpGrpcAccessLogConfig
common_config:
log_name: "sigsci-agent-grpc"
transport_api_version: V3
grpc_service:
envoy_grpc:
cluster_name: sigsci-agent-grpc
timeout: 0.2s
additional_request_headers_to_log:
# These sigsci-agent headers are required for correct processing:
- "x-sigsci-request-id"
- "x-sigsci-waf-response"
# Optionally, additional headers can be added that should be recorded:
- "accept"
- "content-type"
- "content-length"
additional_response_headers_to_log:
- "date"
- "server"
- "content-type"
- "content-length"
http_filters:
# ext_authz filter calls the NGWAF agent via gRPC.
- name: envoy.filters.http.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
transport_api_version: V3
grpc_service:
envoy_grpc:
cluster_name: sigsci-agent-grpc
failure_mode_allow: false
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
# Cluster for forwarding requests to https://http.edgecompute.app.
- name: edge_cluster
connect_timeout: 0.25s
type: LOGICAL_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: edge_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: http.edgecompute.app
port_value: 443
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
sni: "http.edgecompute.app"
# Cluster used by the ext_authz filter to contact the NGWAF agent.
- name: sigsci-agent-grpc
connect_timeout: 0.25s
type: STATIC
lb_policy: ROUND_ROBIN
http2_protocol_options: {} # <--- This tells Envoy to use HTTP/2 for gRPC
load_assignment:
cluster_name: sigsci-agent-grpc
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
# Both containers share the same network namespace.
address: 127.0.0.1
port_value: 9999
---
# Deployment: Combines the Envoy proxy and the Next‑Gen WAF Agent sidecar.
apiVersion: apps/v1
kind: Deployment
metadata:
name: envoy-waf-deployment
spec:
replicas: 1
selector:
matchLabels:
app: envoy-waf
template:
metadata:
labels:
app: envoy-waf
spec:
containers:
# Envoy container – set to use debug logging for detailed output.
- name: envoy
image: envoyproxy/envoy:v1.22-latest
args:
- "-c"
- "/etc/envoy/envoy.yaml"
- "-l"
- "debug" # Change to "trace" for even more verbosity.
ports:
- containerPort: 10000
volumeMounts:
- name: envoy-config
mountPath: /etc/envoy
# Next‑Gen WAF Agent container (sigsci-agent) configured for ext_authz (gRPC mode).
- name: sigsci-agent
image: signalsciences/sigsci-agent:latest
imagePullPolicy: IfNotPresent
env:
- name: SIGSCI_ACCESSKEYID
valueFrom:
secretKeyRef:
name: sigsci.my-site-name-here
key: accesskeyid
- name: SIGSCI_SECRETACCESSKEY
valueFrom:
secretKeyRef:
name: sigsci.my-site-name-here
key: secretaccesskey
# Instruct the agent to expect response data and configure its gRPC address.
- name: SIGSCI_ENVOY_EXPECT_RESPONSE_DATA
value: "1"
- name: SIGSCI_ENVOY_GRPC_ADDRESS
value: "localhost:9999"
- name: SIGSCI_DEBUG_ALL_THE_THINGS
value: "true"
- name: SIGSCI_WAF_DATA_LOG
value: "/dev/stdout"
ports:
- containerPort: 9999
securityContext:
readOnlyRootFilesystem: true
volumes:
- name: envoy-config
configMap:
name: envoy-config
---
# Service: Exposes the Envoy listener on port 10000.
apiVersion: v1
kind: Service
metadata:
name: envoy
spec:
selector:
app: envoy-waf
ports:
- protocol: TCP
port: 10000
targetPort: 10000

次の手順

エージェントとモジュールのインストールを確認し、モジュールオプションを調査する