jwe-decrypt
jwe-decrypt 插件从请求头读取五段式紧凑 Token,根据 Token 的 kid 选择 Consumer,并使用 AES-256-GCM 解密加密 Payload。在代理请求之前,插件会将明文写入配置的请求头。你可以在 APISIX 路由或服务上启用该插件,并在 Consumer 上配置 32 字节的解密 Secret。
该 Token 类似于 JWE 紧凑序列化,但它是插件专用格式。实现会从解码后的请求头读取 kid,但不校验 alg 或 enc 字段,也不会将受保护请求头段用作 AES-GCM 附加认证数据(AAD)。因此,标准 RFC 7516 JWE 库不能直接互操作。请严格按照下文所述格式生成 Token,使用固定且可信的 Token 生成器,并且不要将请求头字段视为已经过认证。
解密后的明文会通过请求头转发。对于敏感明文,不要仅依赖 APISIX 的 HTTPS 上游:APISIX 在代理到标准 HTTPS 上游时不会验证上游服务器证书。请通过能够验证上游服务器身份的代理或服务网格等经过认证和保护的网络路径发送请求,同时限制对上游的访问,并避免记录配置的转发请求头。
示例
以下示例演示了如何在不同场景下使用 jwe-decrypt 插件。
解密插件 Token 中的数据
以下示例演示如何解密插件 Token。在 APISIX 外部生成 Token,在 Consumer 上配置匹配的解密密钥,并创建启用 jwe-decrypt 插件的路由来解密 Authorization 请求头。
- Admin API
- ADC
- Ingress Controller
创建一个启用 jwe-decrypt 的 Consumer 并配置解密密钥:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jack",
"plugins": {
"jwe-decrypt": {
"key": "jack-key",
"secret": "key-length-should-be-32-chars123"
}
}
}'
创建一个启用 jwe-decrypt 的路由以解密 Authorization 头:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "jwe-decrypt-route",
"uri": "/anything/jwe",
"plugins": {
"jwe-decrypt": {
"header": "Authorization",
"forward_header": "Authorization"
}
},
"upstream": {
"type": "roundrobin",
"scheme": "https",
"nodes": {
"httpbin.org:443": 1
}
}
}'
consumers:
- username: jack
plugins:
jwe-decrypt:
key: jack-key
secret: key-length-should-be-32-chars123
services:
- name: jwe-decrypt-service
routes:
- name: jwe-decrypt-route
uris:
- /anything/jwe
plugins:
jwe-decrypt:
header: Authorization
forward_header: Authorization
upstream:
type: roundrobin
scheme: https
nodes:
- host: httpbin.org
port: 443
weight: 1
将配置同步到网关:
adc sync -f adc.yaml
以下 Ingress Controller 配置仅将公共 HTTPBin 用于本页所示的非敏感演示 Payload。转发真实的解密数据之前,请将其替换为受控上游,并使用经过认证和保护的网络路径。APISIX 在代理到标准 HTTPS 上游时不会验证上游服务器证书;请使用能够验证上游服务器身份的代理或服务网格。
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: Consumer
metadata:
namespace: aic
name: jack
spec:
gatewayRef:
name: apisix
plugins:
- name: jwe-decrypt
config:
key: jack-key
secret: key-length-should-be-32-chars123
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: jwe-decrypt-plugin-config
spec:
plugins:
- name: jwe-decrypt
config:
header: Authorization
forward_header: Authorization
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: jwe-decrypt-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /anything/jwe
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: jwe-decrypt-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
将配置应用到集群:
kubectl apply -f jwe-decrypt-ic.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixConsumer
metadata:
namespace: aic
name: jack
spec:
ingressClassName: apisix
plugins:
- name: jwe-decrypt
config:
key: jack-key
secret: key-length-should-be-32-chars123
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: jwe-decrypt-route
spec:
ingressClassName: apisix
http:
- name: jwe-decrypt-route
match:
paths:
- /anything/jwe
upstreams:
- name: httpbin-external-domain
plugins:
- name: jwe-decrypt
config:
header: Authorization
forward_header: Authorization
将配置应用到集群:
kubectl apply -f jwe-decrypt-apisix-crd.yaml
在 APISIX 外部生成插件 Token:使用 AES-256-GCM 在不采用受保护请求头 AAD 的情况下加密 Payload,并使用 Consumer Secret 作为密钥。标准 RFC 7516 库通常将受保护请求头作为 AAD 进行认证,因此不能与此插件直接互操作。请严格使用以下 Token 结构:
base64url(header)..base64url(iv).base64url(ciphertext).base64url(tag)
其中,请求头为 {"alg":"dir","enc":"A256GCM","kid":"<consumer-key>"}。这些字段描述预期算法并标识 Consumer,但当前插件不会认证或校验这些字段。请为每个 Token 使用唯一且随机生成的 IV;切勿对同一个密钥重复使用 IV。
APISIX 使用 AES-256-GCM 直接解密加密 Payload 和认证标签,不会将受保护请求头作为 AAD 传入。使用标准受保护请求头 AAD 生成的 Token 会被拒绝,并报告 failed to decrypt JWE token。
在 Authorization 请求头中携带加密的插件 Token 向路由发送请求。例如,以下 Token 使用上面配置的 Secret 和 Consumer Key jack-key,对 Payload {"uid":10000,"uname":"test"} 进行加密:
curl "http://127.0.0.1:9080/anything/jwe" -H 'Authorization: eyJraWQiOiJqYWNrLWtleSIsImFsZyI6ImRpciIsImVuYyI6IkEyNTZHQ00ifQ..vi29KBCQKcVmPwTT.VToyPMFbq-ZY05MIpntP1N3AmYeq3zELQ0B6iQ.vuTPG2ODc-DjUTjNCzfA2A'
你应该看到类似于以下的响应,其中 Authorization 头显示了 Payload 的明文:
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Authorization": "{\"uid\":10000,\"uname\":\"test\"}",
"Host": "127.0.0.1",
"User-Agent": "curl/8.1.2",
"X-Amzn-Trace-Id": "Root=1-6510f2c3-1586ec011a22b5094dbe1896",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "GET",
"origin": "127.0.0.1, 119.143.79.94",
"url": "http://127.0.0.1/anything/jwe"
}