配置 Envoy Gateway 扩展
概述
Envoy Gateway 支持通过 EnvoyExtensionPolicy 进行流量扩展。你可以将扩展策略附加到 Gateway 或 HTTPRoute,在不修改应用代码的情况下,在 Envoy 数据平面中运行自定义逻辑。
本文档介绍三种扩展机制:
先决条件
在配置扩展之前,请确保你已完成以下任务:
- 安装或升级 Envoy Gateway 到支持所需扩展字段的版本。本文档中的 Dynamic Module 示例需要 Envoy Gateway 1.8 或更高版本。
- 配置 EnvoyGatewayCtl
- 配置 Gateway
- 配置 Route
- 准备一个后端 Service 和一个将流量转发到该 Service 的
HTTPRoute。
本文档中的示例使用以下资源名称。请将其替换为你环境中的名称。
NOTE
扩展制品必须可被 Envoy 数据平面访问。对于 Wasm 模块,请使用 Envoy pods 可以访问的 HTTP 或 OCI 源。对于 Dynamic Modules,请确保在 Envoy 启动之前已将共享对象文件挂载到 Envoy 容器中。
配置 LuaFilter 扩展
使用 LuaFilter 进行轻量级请求或响应处理。以下示例将一个 Lua 脚本附加到 example-route,并添加 x-gwext-lua: enabled 响应头。
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
name: lua-header-policy
namespace: gateway-demo
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: example-route
lua:
- type: Inline
inline: |
function envoy_on_response(response_handle)
response_handle:headers():add("x-gwext-lua", "enabled")
end
应用该策略:
kubectl apply -f lua-header-policy.yaml
验证该路由是否返回响应头:
curl -i -H "Host: www.example.com" http://<GATEWAY_ADDRESS>/<PATH>
预期响应头:
有关更多 Lua 配置选项,请参见上游
Envoy Gateway Lua task。
配置 Wasm 扩展
当扩展逻辑打包为 WebAssembly 模块时,请使用 Wasm。以下示例从 HTTP 端点加载上游 Envoy Gateway Wasm task 中使用的示例 Wasm 模块,并将其附加到 example-route。
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
name: wasm-header-policy
namespace: gateway-demo
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: example-route
wasm:
- name: wasm-filter
rootID: my_root_id
code:
type: HTTP
http:
url: https://raw.githubusercontent.com/envoyproxy/examples/main/wasm-cc/lib/envoy_filter_http_wasm_example.wasm
sha256: 79c9f85128bb0177b6511afa85d587224efded376ac0ef76df56595f1e6315c0
应用该策略:
kubectl apply -f wasm-header-policy.yaml
验证 Wasm 过滤器是否运行。此示例中使用的测试模块会添加 x-wasm-custom: FOO 响应头:
curl -i -H "Host: www.example.com" http://<GATEWAY_ADDRESS>/<PATH>
预期响应头:
本示例中的 Wasm 模块 URL 来自上游 Envoy Gateway Wasm task。若要构建并使用你自己的 Wasm 过滤器,请遵循上游任务,并将 url 和 sha256 替换为你自己的制品详细信息。
有关更多 Wasm 配置选项,请参见上游
Envoy Gateway Wasm task。
配置 Dynamic Module WAF 扩展
当你需要从共享对象文件加载原生 Envoy 扩展时,请使用 Dynamic Module。此示例使用带有 Coraza WAF 规则的 Composer Dynamic Module。WAF 过滤器会阻止可疑请求,例如 SQL 注入载荷。
Dynamic Module 配置分为两部分:
- 配置
EnvoyProxy.spec.dynamicModules,以允许 Envoy 加载该模块。
- 配置
EnvoyExtensionPolicy.spec.dynamicModule,将该模块作为 HTTP 过滤器附加。
准备辅助镜像
Composer 模块以 libcomposer.so 形式提供。准备一个包含该文件的辅助镜像,并且能够在 init container 中运行 shell 命令。
Kubernetes 1.35 或更高版本支持将 OCI 镜像或制品直接作为 image 卷挂载。如果运行此配置的所有集群都使用 Kubernetes 1.35 或更高版本,你可以将 Composer 制品挂载为 image 卷,而不是在 init container 中复制文件。
此示例使用 init container 和共享的 emptyDir 卷,以兼容较旧的 Kubernetes 版本。采用这种方式时,init container 会将 libcomposer.so 从辅助镜像复制到共享卷中,而 Envoy 容器则从同一卷加载该模块。
下面的 Dockerfile 会将 libcomposer.so 从 Composer 镜像复制到一个基于 Alpine 的普通镜像中:
ARG ALPINE_IMAGE=alpine:3.20
FROM ghcr.io/tetratelabs/built-on-envoy/composer:0.6.0-dev AS composer
FROM ${ALPINE_IMAGE}
COPY --from=composer /libcomposer.so /opt/envoy-dynamic-modules/libcomposer.so
RUN chmod 755 /opt/envoy-dynamic-modules/libcomposer.so
构建并将辅助镜像推送到集群可访问的 registry:
docker build -t <REGISTRY>/envoy-gateway-composer-provider:0.6.0-dev-alpine -f Dockerfile .
docker push <REGISTRY>/envoy-gateway-composer-provider:0.6.0-dev-alpine
配置 EnvoyProxy
创建或更新 Gateway 使用的 EnvoyProxy。以下配置使用 init container 将 libcomposer.so 复制到共享的 emptyDir 卷中。Envoy 容器挂载同一卷,并从 /etc/envoy/dynamic-modules/libcomposer.so 加载该模块。
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
name: example-proxy
namespace: gateway-demo
spec:
provider:
type: Kubernetes
kubernetes:
envoyDeployment:
initContainers:
- name: provide-dynamic-module
image: <REGISTRY>/envoy-gateway-composer-provider:0.6.0-dev-alpine
imagePullPolicy: IfNotPresent
command:
- sh
- -ec
- |
cp /opt/envoy-dynamic-modules/libcomposer.so /etc/envoy/dynamic-modules/libcomposer.so
chmod 755 /etc/envoy/dynamic-modules/libcomposer.so
volumeMounts:
- name: dynamic-modules
mountPath: /etc/envoy/dynamic-modules
pod:
volumes:
- name: dynamic-modules
emptyDir: {}
container:
env:
- name: GODEBUG
value: "cgocheck=0"
volumeMounts:
- name: dynamic-modules
mountPath: /etc/envoy/dynamic-modules
readOnly: true
dynamicModules:
- name: composer
source:
type: Local
local:
path: /etc/envoy/dynamic-modules/libcomposer.so
doNotClose: true
loadGlobally: false
应用 EnvoyProxy:
kubectl apply -f example-proxy.yaml
确保 Gateway 引用了此 EnvoyProxy:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: example-gateway
namespace: gateway-demo
spec:
gatewayClassName: <GATEWAY_CLASS_NAME>
infrastructure:
parametersRef:
group: gateway.envoyproxy.io
kind: EnvoyProxy
name: example-proxy
listeners:
- name: http
protocol: HTTP
port: 80
附加 Coraza WAF 过滤器
创建一个 EnvoyExtensionPolicy,将 Composer 模块附加到 Gateway,并启用 Coraza WAF 规则:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
name: coraza-waf-policy
namespace: gateway-demo
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: example-gateway
dynamicModule:
- name: composer
filterName: coraza-waf
config:
directives:
- Include @coraza.conf
- SecRuleEngine On
- SecResponseBodyAccess Off
- Include @crs-setup.conf
- Include @owasp_crs/*.conf
应用该策略:
kubectl apply -f coraza-waf-policy.yaml
验证普通请求:
curl -i -H "Host: www.example.com" http://<GATEWAY_ADDRESS>/<PATH>
预期状态:
验证 WAF 是否会拦截类似 SQL 注入的请求:
curl -i -H "Host: www.example.com" "http://<GATEWAY_ADDRESS>/<PATH>?id=1'+OR+'1'%3D'1"
预期状态:
有关更多 Dynamic Module 配置选项,请参见上游
Envoy Gateway Dynamic Modules task。
检查扩展状态
应用扩展策略后,检查该策略是否被接受:
kubectl get envoyextensionpolicy -n gateway-demo
kubectl describe envoyextensionpolicy <POLICY_NAME> -n gateway-demo
如果策略未被接受,请检查 Envoy Gateway controller 日志以及生成的 Envoy pods:
kubectl logs -n envoy-gateway-system deploy/envoy-gateway
kubectl get pods -n gateway-demo
kubectl describe pod <ENVOY_POD_NAME> -n gateway-demo
对于 Dynamic Modules,还需要验证以下项目:
清理
当不再需要扩展策略时,请将其删除:
kubectl delete envoyextensionpolicy lua-header-policy -n gateway-demo
kubectl delete envoyextensionpolicy wasm-header-policy -n gateway-demo
kubectl delete envoyextensionpolicy coraza-waf-policy -n gateway-demo
如果你为 Dynamic Module 测试创建了专用的 EnvoyProxy,请在删除或更新引用它的 Gateway 之后将其删除:
kubectl delete envoyproxy example-proxy -n gateway-demo