Higress 鉴权限流插件架构深度解析:从原理到生产实战
上一篇文章我们聊了怎么在 EKS 上用 Higress 替换 nginx-ingress,顺带提了一嘴认证授权和限流。但说实话,那篇只是"能用"的程度,离"用好"还差得远。
这篇文章,我们把 Higress 的插件体系拆开来看。不只是贴配置,而是搞清楚:请求进来之后到底经历了什么?插件之间是怎么协作的?为什么有些插件要放在前面,有些要放在后面?
搞懂这些,你才能在生产环境里把鉴权和限流玩出花来,而不是照着文档抄一遍配置然后祈祷它能跑。
一、Higress 插件架构:请求的一生
在聊具体插件之前,先搞清楚 Higress 的插件是怎么运行的。这是理解后面所有内容的基础。
1.1 Wasm 沙箱:插件的安全屋
Higress 的插件跑在 WebAssembly(Wasm)沙箱里。这不是什么花哨的技术选型,而是实打实的工程考量:
- 插件代码跑在独立的内存空间里,一个插件崩了不会拖垮整个网关
- 支持 Go、Rust、JS 多语言编写,不像 nginx 的 Lua 插件那样只能用一种语言
- 热加载,更新插件不需要重启网关进程
用大白话说:Wasm 沙箱就像是给每个插件分了一间独立的办公室,门锁好了,空调独立控制,隔壁同事摔杯子不影响你干活。
1.2 插件执行阶段与优先级
Higress 把请求处理分成了几个阶段,每个插件都有自己的"执行阶段"和"优先级"。这决定了谁先跑、谁后跑。
这个执行顺序非常重要。举个例子:如果你把限流插件放在认证插件前面,那恶意用户可以用大量无效请求把你的限流配额耗光,导致合法用户也被限流。正确的做法是先认证(挡掉无效请求),再限流(保护后端服务)。
Higress 的默认优先级已经帮你安排好了这个顺序,但理解背后的逻辑,能帮你在自定义插件时做出正确的决策。
1.3 插件配置的三个层级
Higress 的插件配置有三个层级,从粗到细:
关键规则:路由级别 > 域名级别 > 全局级别。如果同一个插件在多个层级都有配置,细粒度的配置会覆盖粗粒度的。
一个常见的用法:全局开启 JWT 认证(global_auth: true),但在健康检查路由上单独关闭。这样就不用给每个路由都配一遍认证了。
二、鉴权插件深度解析
Higress 内置了五种鉴权插件,覆盖了从简单到复杂的各种场景。我们逐个拆解。
2.1 JWT Auth:最主流的 API 鉴权方案
JWT(JSON Web Token)是目前最流行的无状态认证方案。Higress 的 jwt-auth 插件不只是验证 Token,还能识别调用者身份,支持不同调用者使用不同的 JWT 凭证。
来看一个生产级的 JWT 配置,比上篇文章的示例更完整:
# WasmPlugin CRD 方式配置 jwt-auth(推荐)
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: jwt-auth
namespace: higress-system
spec:
defaultConfig:
# 全局认证开关:false 表示只对配置了 allow 的路由生效
global_auth: false
consumers:
# Consumer 1:移动端 App,用 RSA 非对称密钥
- name: mobile-app
issuer: "https://auth.example.com"
jwks: |
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"kid": "mobile-app-key-2025",
"alg": "RS256",
"n": "你的RSA公钥N值..."
}
]
}
# 从 Authorization: Bearer xxx 提取 Token
from_headers:
- name: Authorization
value_prefix: "Bearer "
# 把 Token 中的字段透传给后端
claims_to_headers:
- claim: sub
header: X-User-Id
- claim: role
header: X-User-Role
- claim: tenant_id
header: X-Tenant-Id
# 允许 5 秒的时钟偏差(分布式系统时钟不完全同步)
clock_skew_seconds: 5
# 转发给后端时保留原始 Token
keep_token: true
# Consumer 2:内部微服务,用 HMAC 对称密钥(简单高效)
- name: internal-service
issuer: "higress-internal"
jwks: |
{
"keys": [
{
"kty": "oct",
"kid": "internal-key-v1",
"k": "你的256位对称密钥Base64编码...",
"alg": "HS256"
}
]
}
from_headers:
- name: X-Internal-Token
value_prefix: ""
# Consumer 3:第三方合作伙伴,从 URL 参数提取 Token
- name: partner-sdk
issuer: "partner-auth"
jwks: |
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"kid": "partner-key-v1",
"alg": "RS256",
"n": "合作伙伴的RSA公钥N值..."
}
]
}
# 从 URL 参数 token 提取
from_params:
- token
# 也支持从 Cookie 提取(Web SDK 场景)
from_cookies:
- session_token
# 路由级别授权:只允许特定 Consumer 访问
# 用户 API:只允许移动端和合作伙伴
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: user-api
annotations:
higress.io/jwt-auth: |
allow:
- mobile-app
- partner-sdk
spec:
ingressClassName: higress
rules:
- host: api.example.com
http:
paths:
- path: /api/v1/users
pathType: Prefix
backend:
service:
name: user-service
port:
number: 80
---
# 内部管理 API:只允许内部服务
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: admin-api
annotations:
higress.io/jwt-auth: |
allow:
- internal-service
spec:
ingressClassName: higress
rules:
- host: api.example.com
http:
paths:
- path: /api/internal
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 80
几个关键细节:
- RSA vs HMAC:对外用 RSA(公钥验证,私钥不需要放在网关上),对内用 HMAC(性能更好,但密钥需要双方共享)
- clock_skew_seconds:分布式系统的时钟不可能完全同步,给 5 秒的容差是合理的
- global_auth: false:不要轻易设为 true,否则健康检查、公开页面等都需要带 Token
- 多 Consumer 匹配:如果一个 JWT 能匹配多个 Consumer 的 JWKS,按配置顺序取第一个匹配的
2.2 Key Auth:简单粗暴但好用
不是所有场景都需要 JWT 那么复杂的认证。对接第三方、开放 API、内部工具调用,一个 API Key 就够了。
# key-auth 插件配置
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: key-auth
namespace: higress-system
spec:
defaultConfig:
global_auth: false
consumers:
- name: data-team
credential: "dk-2025-data-team-a1b2c3d4e5f6"
- name: frontend-bff
credential: "dk-2025-frontend-bff-x7y8z9"
- name: partner-webhook
credential: "dk-2025-partner-wh-m3n4o5"
# 从请求头提取 API Key
keys:
- name: X-API-Key
in: header
# 也可以从 URL 参数提取(不推荐,会出现在日志和浏览器历史中)
# keys:
# - name: api_key
# in: query
Key Auth 的优势是简单:生成一个随机字符串,给到调用方,完事。缺点也很明显:密钥泄露了只能换新的,没有过期时间的概念。适合内部系统和可信合作伙伴,不适合面向公众的 API。
2.3 HMAC Auth:防篡改的签名认证
如果你需要比 API Key 更安全,但又不想上 JWT 那么重的方案,HMAC 签名认证是个好选择。它不只验证身份,还能防止请求被篡改。
# hmac-auth 插件配置(兼容 APISIX 格式)
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: hmac-auth
namespace: higress-system
spec:
defaultConfig:
consumers:
- name: partner-payment
key: "payment-app-id-001"
secret: "a]随机生成的256位密钥..."
# 签名中必须包含的请求头
signed_headers:
- x-date
- x-request-id
# 签名算法
algorithm: "hmac-sha256"
# 签名有效期(防重放攻击)
date_offset: 300 # 签名时间戳与服务器时间差不超过 5 分钟
HMAC 认证的核心优势:防篡改。即使攻击者截获了请求,修改任何一个被签名的字段(URL、请求头、Body),签名就会对不上。再加上时间戳校验,还能防止重放攻击。支付回调、金融接口这类对安全性要求高的场景,HMAC 是标配。
2.4 Ext Auth:接入你自己的认证服务
如果你已经有一套成熟的认证体系(比如 Keycloak、Auth0、自研的用户中心),不想把认证逻辑迁移到网关插件里,ext-auth 就是你的菜。
# ext-auth 插件配置
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: ext-auth
namespace: higress-system
spec:
defaultConfig:
http_service:
# 认证服务的地址(K8s 内部服务)
endpoint_url: "http://auth-service.auth.svc.cluster.local:8080/verify"
# 超时设置:认证服务挂了不能拖垮整个网关
timeout: 1000 # 1 秒超时
# 转发给认证服务的请求头(只转发必要的,不要全转发)
authorization_request:
allowed_headers:
- Authorization
- Cookie
- X-Forwarded-For
- X-Request-Id
# 额外添加的请求头
headers_to_add:
X-Auth-Source: "higress-gateway"
# 认证服务返回的头,透传给后端
authorization_response:
allowed_upstream_headers:
- X-User-Id
- X-User-Role
- X-Tenant-Id
- X-User-Permissions
# 认证服务返回的头,透传给客户端
allowed_client_headers:
- X-Auth-Error
- WWW-Authenticate
Ext Auth 的精髓在于解耦:认证逻辑完全由你的认证服务控制,网关只负责"问一嘴"和"传话"。认证服务返回 200 就放行,返回其他状态码就拒绝。这意味着你可以在认证服务里实现任意复杂的逻辑:多因素认证、设备指纹、风控规则,网关完全不需要改。
2.5 鉴权插件选型指南
| 场景 | 推荐插件 | 理由 |
| 移动端 App / SPA 前端 | jwt-auth (RSA) | 无状态、公钥验证、支持密钥轮转 |
| 内部微服务间调用 | jwt-auth (HMAC) 或 key-auth | 性能好、配置简单 |
| 第三方合作伙伴 API | key-auth 或 hmac-auth | Key Auth 简单对接,HMAC 防篡改 |
| 支付/金融类接口 | hmac-auth | 签名防篡改 + 时间戳防重放 |
| 已有认证体系(SSO/IdP) | ext-auth | 不侵入现有架构,认证逻辑可控 |
| 多种认证方式并存 | 组合使用 | 不同路由配不同插件,互不干扰 |
三、限流插件深度解析
鉴权解决的是"你是谁"和"你能不能进来"的问题。限流解决的是"进来之后别太猛"的问题。Higress 提供了两种限流插件,覆盖从单机到集群的场景。
3.1 本地限流 vs 集群限流:先搞清楚区别
选哪个?简单原则:
- 保护后端不被打垮 -> 本地限流就够了,简单可靠
- 精确控制 API 调用配额(比如免费用户每天 1000 次)-> 必须用集群限流
- 两个都用 -> 本地限流做粗粒度保护(防 DDoS),集群限流做细粒度配额管理
3.2 本地限流实战:key-rate-limit
key-rate-limit 插件基于特定键值做限流,键值可以来自 URL 参数或请求头。每个 Gateway Pod 独立计数,不需要外部依赖。
# 场景 1:按 API Key 区分限流(不同客户不同配额)
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: key-rate-limit-by-apikey
namespace: higress-system
spec:
defaultConfig:
# 从 URL 参数 apikey 提取限流键值
limit_by_param: apikey
limit_keys:
# 付费客户:每秒 50 次
- key: "premium-client-key-001"
query_per_second: 50
# 免费客户:每分钟 100 次
- key: "free-client-key-002"
query_per_minute: 100
# 内部测试:每秒 200 次(不限制)
- key: "internal-test-key"
query_per_second: 200
# 场景 2:按请求头区分限流(多租户场景)
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: key-rate-limit-by-tenant
namespace: higress-system
spec:
defaultConfig:
# 从请求头 X-Tenant-Id 提取限流键值
limit_by_header: x-tenant-id
limit_keys:
# 大客户:每秒 1000 次
- key: "tenant-enterprise-001"
query_per_second: 1000
# 中型客户:每秒 200 次
- key: "tenant-standard-002"
query_per_second: 200
# 试用客户:每小时 500 次
- key: "tenant-trial-003"
query_per_hour: 500
本地限流的配置非常直观:指定从哪里提取 Key,然后给每个 Key 设置配额。支持四种时间窗口:query_per_second、query_per_minute、query_per_hour、query_per_day。
3.3 集群限流实战:cluster-key-rate-limit
集群限流基于 Redis 实现全局计数,所有 Gateway Pod 共享同一个计数器。配置比本地限流复杂一些,但功能强大得多。
# 生产级集群限流配置:多维度组合
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: cluster-rate-limit
namespace: higress-system
spec:
defaultConfig:
rule_name: "api-v1-rate-limit"
# 显示限流配额信息(方便客户端自适应)
show_limit_quota_header: true
# 被限流时返回 429 和 JSON 错误信息
rejected_code: 429
rejected_msg: '{"code":429,"message":"Rate limit exceeded. Please retry later."}'
rule_items:
# 规则 1:按 Consumer 精确限流
- limit_by_consumer: ""
limit_keys:
- key: "mobile-app"
query_per_second: 500 # 移动端:500 QPS
- key: "partner-sdk"
query_per_minute: 3000 # 合作伙伴:3000 QPM
- key: "internal-service"
query_per_second: 2000 # 内部服务:2000 QPS
# 规则 2:按 Consumer 正则匹配(兜底)
- limit_by_per_consumer: ""
limit_keys:
- key: "regexp:^premium-.*"
query_per_second: 100 # premium 开头的:100 QPS
- key: "regexp:^free-.*"
query_per_hour: 1000 # free 开头的:1000 QPH
- key: "*"
query_per_minute: 60 # 其他所有:60 QPM
# 规则 3:按客户端 IP 限流(防爬虫/DDoS)
- limit_by_per_ip: "from-header-x-forwarded-for"
limit_keys:
- key: "10.0.0.0/8"
query_per_second: 1000 # 内网 IP:宽松
- key: "0.0.0.0/0"
query_per_second: 50 # 外网 IP:严格
# Redis 配置
redis:
service_name: "redis.redis-system.svc.cluster.local"
service_port: 6379
password: "your-redis-password"
timeout: 500 # 500ms 超时
database: 1 # 使用 DB 1,和业务数据隔离
几个关键点:
- show_limit_quota_header: true:响应头会包含
X-RateLimit-Limit和X-RateLimit-Remaining,客户端可以据此做自适应限流 - rule_items 按顺序匹配:命中第一条就停止,后面的不再检查。所以精确匹配放前面,正则/通配符放后面
- Redis 超时要设短:Redis 挂了不能拖垮网关。500ms 超时,超时后放行(fail-open),总比全部拒绝好
- 用独立的 Redis DB:限流数据和业务数据隔离,互不影响
3.4 限流 + 鉴权联动:基于身份的差异化限流
这是 Higress 插件体系最强大的地方:鉴权插件识别出调用者身份后,限流插件可以直接基于这个身份做差异化限流。不需要额外的代码或配置,插件之间通过 X-Mse-Consumer 请求头自动传递身份信息。
这个联动是自动的,不需要你写任何胶水代码。只要:
- 鉴权插件(jwt-auth / key-auth)识别出 Consumer 名称
- 限流插件(cluster-key-rate-limit)配置
limit_by_consumer或limit_by_per_consumer
两个插件就能无缝协作。这就是 Higress 插件体系设计的精妙之处:每个插件只做一件事,但通过标准化的请求头传递信息,实现了强大的组合能力。
四、IP 管控与 Bot 检测
鉴权管的是"合法用户",限流管的是"别太猛"。但还有一类流量,根本不该进来:恶意 IP 和自动化爬虫。
4.1 IP 黑白名单:ip-restriction
# 场景 1:管理后台只允许办公网络访问
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: ip-restriction-admin
namespace: higress-system
spec:
defaultConfig:
# 从 X-Forwarded-For 获取真实 IP(经过 ELB 转发后必须这样配)
ip_source_type: header
ip_header_name: X-Forwarded-For
# 白名单模式
allow:
- "10.0.0.0/8" # 公司内网
- "172.16.0.0/12" # VPN 网段
- "203.0.113.50" # 办公室出口 IP
- "198.51.100.0/24" # 远程办公 IP 段
# 场景 2:封禁恶意 IP(黑名单模式)
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: ip-restriction-block
namespace: higress-system
spec:
defaultConfig:
ip_source_type: header
ip_header_name: X-Forwarded-For
deny:
- "192.0.2.0/24" # 已知攻击源
- "198.51.100.100" # 恶意爬虫 IP
- "203.0.113.0/28" # 扫描器 IP 段
一个容易踩的坑:在 AWS EKS 环境中,客户端请求经过 NLB/ALB 转发后,源 IP 变成了负载均衡器的内网 IP。真实客户端 IP 在 X-Forwarded-For 请求头里。如果你用默认的 ip_source_type: origin,拿到的是 ELB 的 IP,白名单就形同虚设了。一定要设置 ip_source_type: header。
4.2 Bot 检测:bot-detect
Bot 检测基于 User-Agent 识别自动化工具和爬虫。虽然 User-Agent 可以伪造,但对于大部分低级爬虫和扫描器来说,这一层过滤已经够用了。
# bot-detect 插件配置
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: bot-detect
namespace: higress-system
spec:
defaultConfig:
# 拦截规则(正则匹配 User-Agent)
block_rules:
# 常见安全扫描工具
- regex: "(sqlmap|nikto|nmap|masscan|zgrab|nuclei)"
# 自动化测试工具(生产环境不该出现)
- regex: "(phantomjs|headless|selenium|puppeteer|playwright)"
# 恶意爬虫框架
- regex: "(scrapy|python-requests|go-http-client|java/|okhttp)"
# 空 User-Agent(正常浏览器不会这样)
- regex: "^$"
# 放行规则(优先级高于拦截规则)
allow_rules:
# 搜索引擎爬虫(SEO 命脉,必须放行)
- regex: "(Googlebot|Bingbot|baiduspider|YandexBot|DuckDuckBot)"
# 社交媒体预览(分享链接时需要抓取 OG 标签)
- regex: "(facebookexternalhit|Twitterbot|LinkedInBot|WhatsApp)"
# 监控工具(你自己的健康检查)
- regex: "(UptimeRobot|Pingdom|Site24x7|Datadog)"
注意 allow_rules 的优先级高于 block_rules。这意味着即使 Googlebot 的 User-Agent 里包含了某些被 block 的关键词,只要它匹配了 allow 规则,就会被放行。
一个实用建议:不要拦截 curl。很多运维工具和健康检查都用 curl,拦了它你会收到一堆误报告警。
五、生产环境完整配置:把所有插件串起来
前面讲了一堆单个插件的配置,现在把它们组合起来,看看一个生产环境的完整防护体系长什么样。
这五层防护的执行顺序是固定的,由 Higress 的插件阶段和优先级保证。每一层都是一道关卡,请求必须全部通过才能到达后端。任何一层拒绝,后续层都不会执行,直接返回错误响应。
下面是一个完整的生产配置示例,把所有插件串在一起:
# === 第 1 层:Bot 检测 ===
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: bot-detect
namespace: higress-system
spec:
defaultConfig:
block_rules:
- regex: "(sqlmap|nikto|nmap|masscan|zgrab|nuclei)"
- regex: "(scrapy|python-requests|go-http-client)"
- regex: "^$"
allow_rules:
- regex: "(Googlebot|Bingbot|baiduspider)"
- regex: "(UptimeRobot|Pingdom)"
---
# === 第 2 层:IP 管控 ===
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: ip-restriction
namespace: higress-system
spec:
defaultConfig:
ip_source_type: header
ip_header_name: X-Forwarded-For
deny:
- "192.0.2.0/24"
---
# === 第 3 层:JWT 认证 ===
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: jwt-auth
namespace: higress-system
spec:
defaultConfig:
global_auth: false
consumers:
- name: mobile-app
issuer: "https://auth.example.com"
jwks: |
{"keys":[{"kty":"RSA","e":"AQAB","kid":"v1","alg":"RS256","n":"..."}]}
from_headers:
- name: Authorization
value_prefix: "Bearer "
claims_to_headers:
- claim: sub
header: X-User-Id
- claim: role
header: X-User-Role
- name: partner-sdk
issuer: "partner-auth"
jwks: |
{"keys":[{"kty":"RSA","e":"AQAB","kid":"p1","alg":"RS256","n":"..."}]}
from_headers:
- name: X-Partner-Token
value_prefix: ""
---
# === 第 4 层:集群限流 ===
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: cluster-key-rate-limit
namespace: higress-system
spec:
defaultConfig:
rule_name: "production-rate-limit"
show_limit_quota_header: true
rejected_code: 429
rejected_msg: '{"error":"rate_limit_exceeded","retry_after":60}'
rule_items:
- limit_by_per_consumer: ""
limit_keys:
- key: "mobile-app"
query_per_second: 500
- key: "partner-sdk"
query_per_minute: 3000
- key: "*"
query_per_minute: 60
- limit_by_per_ip: "from-header-x-forwarded-for"
limit_keys:
- key: "10.0.0.0/8"
query_per_second: 1000
- key: "0.0.0.0/0"
query_per_second: 50
redis:
service_name: "redis.redis-system.svc.cluster.local"
service_port: 6379
timeout: 500
六、自定义 Wasm 插件:当内置插件不够用时
Higress 内置了几十个插件,覆盖了大部分场景。但总有些需求是内置插件搞不定的,比如:
- 根据请求 Body 中的某个字段做限流
- 调用外部风控系统做实时决策
- 自定义的 Token 格式(不是标准 JWT)
这时候就需要自己写 Wasm 插件了。Higress 支持用 Go、Rust、JS 编写插件,其中 Go 是最推荐的(生态好、上手快)。
// 一个简单的自定义限流插件示例(Go)
// 根据请求 Body 中的 user_level 字段做差异化限流
package main
import (
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
"github.com/tidwall/gjson"
)
func main() {
wrapper.SetCtx(
"custom-body-rate-limit",
wrapper.ParseConfigBy(parseConfig),
wrapper.ProcessRequestHeadersBy(onHttpRequestHeaders),
wrapper.ProcessRequestBodyBy(onHttpRequestBody),
)
}
type Config struct {
VipQPS int64 `json:"vip_qps"`
NormalQPS int64 `json:"normal_qps"`
}
func parseConfig(json gjson.Result, config *Config, log wrapper.Log) error {
config.VipQPS = json.Get("vip_qps").Int()
config.NormalQPS = json.Get("normal_qps").Int()
return nil
}
func onHttpRequestHeaders(ctx wrapper.HttpContext, config Config, log wrapper.Log) types.Action {
// 需要读取 Body,告诉 Envoy 先缓存
proxywasm.RemoveHttpRequestHeader("content-length")
return types.ActionContinue
}
func onHttpRequestBody(ctx wrapper.HttpContext, config Config, body []byte, log wrapper.Log) types.Action {
// 从 Body 中提取 user_level
userLevel := gjson.GetBytes(body, "user_level").String()
// 根据用户等级设置不同的限流标记
if userLevel == "vip" {
proxywasm.AddHttpRequestHeader("X-Rate-Limit-Key", "vip")
} else {
proxywasm.AddHttpRequestHeader("X-Rate-Limit-Key", "normal")
}
return types.ActionContinue
}
Go 1.24 已经原生支持编译 Wasm,不再需要 TinyGo。编译命令:
# 编译 Wasm 插件
GOOS=wasip1 GOARCH=wasm go build -o plugin.wasm main.go
# 构建 OCI 镜像(Higress 从 OCI 镜像加载插件)
docker build -t your-registry/custom-plugin:v1 .
docker push your-registry/custom-plugin:v1
# 部署自定义插件
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: custom-body-rate-limit
namespace: higress-system
spec:
url: oci://your-registry/custom-plugin:v1
# 指定执行阶段和优先级
phase: DEFAULT
priority: 5 # 在内置限流插件之后执行
defaultConfig:
vip_qps: 1000
normal_qps: 100
自定义插件的开发门槛不高,但有几个注意事项:
- 内存限制:Wasm 沙箱默认内存有限,不要在插件里做大量数据处理
- 网络调用:插件可以通过
wrapper.HttpCall调用外部服务,但要注意超时设置 - 状态管理:插件实例之间不共享状态,需要共享状态请用 Redis 或 SharedData API
七、踩坑指南与最佳实践
最后分享几个在生产环境中踩过的坑,帮你少走弯路。
坑 1:限流配额和 Gateway 副本数的关系
本地限流(key-rate-limit)是每个 Pod 独立计数的。如果你配了 100 QPS,跑了 3 个 Pod,实际总限流是 300 QPS。HPA 扩缩容时,总限流会跟着变。
解决方案:要么用集群限流(cluster-key-rate-limit),要么在配置时除以预期的 Pod 数量。
坑 2:Redis 挂了,集群限流怎么办?
默认行为是 fail-open(Redis 不可用时放行所有请求)。这在大多数场景下是合理的:宁可暂时不限流,也不能因为 Redis 故障导致所有请求被拒绝。
但如果你的场景对限流精度要求极高(比如计费相关),需要额外的兜底方案:
- Redis 用主从 + Sentinel 或 Redis Cluster 保证高可用
- 同时配置本地限流作为兜底,设一个比较宽松的阈值
坑 3:JWT 时钟偏差导致间歇性 401
分布式系统的时钟不可能完全同步。如果 Token 签发服务器的时间比网关快几秒,刚签发的 Token 可能因为 iat(签发时间)在"未来"而被拒绝。
解决方案:设置 clock_skew_seconds: 5,允许 5 秒的时钟偏差。同时确保所有服务器都配置了 NTP 时间同步。
坑 4:X-Forwarded-For 伪造
客户端可以自己设置 X-Forwarded-For 请求头来伪造 IP。在 EKS 环境中,NLB 会把真实客户端 IP 追加到 X-Forwarded-For 的末尾。所以 IP 限制插件应该取最后一个 IP(NLB 追加的),而不是第一个(可能是伪造的)。
Higress 的 ip-restriction 插件默认取第一个 IP。如果你的架构是 Client -> NLB -> Higress,需要注意这个行为,必要时在 NLB 层面做 IP 过滤。
坑 5:插件配置更新的生效时间
Higress 的插件配置通过 xDS 协议推送,通常在几秒内生效。但如果你同时更新了大量插件配置,可能会有短暂的不一致窗口(部分 Pod 已更新,部分还没有)。
建议:重要的配置变更在低峰期操作,更新后观察几分钟确认所有 Pod 都已生效。
最佳实践清单
| 实践 | 说明 |
| 先认证后限流 | 利用 Higress 默认的插件优先级,不要手动调整 |
| 限流配额留余量 | 配置值设为预期峰值的 1.5-2 倍,避免正常流量被误杀 |
| 集群限流 + 本地限流双保险 | 集群限流做精确配额,本地限流做粗粒度兜底 |
| Redis 高可用 | 集群限流依赖 Redis,务必用主从 + Sentinel |
| 监控限流指标 | 关注 429 响应比例,过高说明配额太紧或有攻击 |
| JWT 密钥定期轮转 | RSA 密钥建议每 90 天轮转,JWKS 支持多 kid 平滑过渡 |
| 不要拦截搜索引擎 | Bot 检测的 allow_rules 里加上 Googlebot 等 |
| 日志记录被拒请求 | 方便事后分析攻击模式和误杀情况 |
总结
这篇文章从 Higress 的插件架构讲起,深入拆解了鉴权和限流两大核心能力:
| 模块 | 核心插件 | 适用场景 |
| 插件架构 | Wasm 沙箱 + 三阶段执行 | 理解插件协作机制 |
| 身份认证 | jwt-auth / key-auth / hmac-auth / ext-auth | 从简单到复杂的认证需求 |
| 流量限制 | key-rate-limit / cluster-key-rate-limit | 单机限流 / 全局精确限流 |
| 访问控制 | ip-restriction / bot-detect | IP 黑白名单 / 爬虫拦截 |
| 鉴权+限流联动 | Consumer 身份透传 | 基于身份的差异化配额 |
| 自定义扩展 | Go Wasm 插件 | 内置插件无法满足的场景 |
Higress 的插件体系设计得很克制:每个插件只做一件事,但通过标准化的接口(请求头、Consumer 身份)实现了强大的组合能力。这种"Unix 哲学"式的设计,让你可以像搭积木一样组合出复杂的安全策略。
记住一个核心原则:先挡坏人(Bot 检测 + IP 管控),再验身份(鉴权),最后管流量(限流)。这个顺序不是随便定的,而是经过无数生产事故验证出来的最佳实践。
我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=xdbp05fgqmd
📜 版权声明
本文作者:王梓 | 原文链接:https://www.bthlt.com/note/14846733-TegHigress鉴权限流插件架构深度解析
出处:葫芦的运维日志 | 转载请注明出处并保留原文链接
📜 留言板
留言提交后需管理员审核通过才会显示