跳到主要内容
版本:3.10.x

上游 mTLS

当上游服务要求双向 TLS(mTLS)时,API7 网关可以提供客户端证书,并使用受信任的证书颁发机构验证上游服务器证书。将客户端证书和 CA 作为证书对象存储在网关组中,再在服务的上游配置中引用它们的 ID。

信息

本文介绍网关与上游服务之间的 mTLS。如需配置 API 客户端与网关之间的 mTLS,请参阅客户端 mTLS 认证。如需配置控制面与数据面之间的 mTLS,请参阅控制面与数据面之间的双向 TLS。

工作原理​

上游配置使用以下三个字段:

字段值用途
client_certificate证书对象 ID选择网关向上游提供的证书和私钥。
ca_certificatesCA 证书对象 ID 数组选择用于验证上游服务器证书的 CA 证书。
tls_verify布尔值启用或禁用对上游服务器证书的验证。

较旧的 upstream.tls 对象已弃用。请勿在新配置的 tls.client_cert、tls.client_key 或 tls.ca_certs 中放入内联 PEM 值。

前置条件​

  • 按照从控制台获取 Token中的步骤获取 Token。
  • 用于构建 JSON 请求体和读取已创建对象 ID 的 jq。
  • 已启用 TLS 且会请求客户端证书的上游。
  • 由上游信任的 CA 签发的客户端证书和私钥。
  • 签发上游服务器证书的 CA 证书。

上游证书的主体备选名称必须与网关作为 SNI 发送的主机名匹配。示例使用 upstream.test.local,网关节点必须能够将其解析到测试上游。

设置本指南使用的变量:

export API7_GATEWAY_GROUP_ID="default"
export API7_DASHBOARD="https://localhost:7443"

将网关组 ID 和控制台来源替换为适用于你的环境的值。发送请求前,将控制台 Token 导出为 API_KEY。

创建证书对象​

创建网关将提供给上游的证书对象:

CLIENT_CERTIFICATE_ID=$(
jq -n \
--rawfile cert client.crt \
--rawfile key client.key \
'{name: "upstream-mtls-client", cert: $cert, key: $key}' |
curl -fsSk "${API7_DASHBOARD}/apisix/admin/certificates?gateway_group_id=${API7_GATEWAY_GROUP_ID}" \
-X POST \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- |
jq -r '.value.id'
)

创建用于验证上游的 CA 证书对象:

UPSTREAM_CA_CERTIFICATE_ID=$(
jq -n \
--rawfile cert ca.crt \
'{name: "upstream-mtls-ca", cert: $cert}' |
curl -fsSk "${API7_DASHBOARD}/apisix/admin/ca_certificates?gateway_group_id=${API7_GATEWAY_GROUP_ID}" \
-X POST \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- |
jq -r '.value.id'
)

确认两个请求都返回了 ID:

printf 'client certificate: %s\nupstream CA: %s\n' \
"${CLIENT_CERTIFICATE_ID}" \
"${UPSTREAM_CA_CERTIFICATE_ID}"

配置 HTTPS 上游​

创建引用证书对象的服务。即使节点使用其他主机名或 IP 地址寻址,pass_host: rewrite 和 upstream_host 也会使网关发送与上游证书匹配的 SNI 名称。

jq -n \
--arg client_certificate "${CLIENT_CERTIFICATE_ID}" \
--arg ca_certificate "${UPSTREAM_CA_CERTIFICATE_ID}" \
'{
name: "upstream-mtls",
upstream: {
type: "roundrobin",
scheme: "https",
pass_host: "rewrite",
upstream_host: "upstream.test.local",
nodes: [
{
host: "upstream.test.local",
port: 8443,
weight: 100
}
],
client_certificate: $client_certificate,
ca_certificates: [$ca_certificate],
tls_verify: true
}
}' |
curl -fsSk "${API7_DASHBOARD}/apisix/admin/services/upstream-mtls?gateway_group_id=${API7_GATEWAY_GROUP_ID}" \
-X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @-

对于生产流量,请保持 tls_verify: true。将其设为 false 后,网关仍会提供客户端证书,但不会验证上游服务器的身份。

备注

ADC v0.30.5 仅对已弃用的 upstream.tls 字段建模,无法配置 client_certificate、ca_certificates 和 tls_verify。请使用控制台或 Admin API 完成此工作流。

创建路由并验证​

将路由关联到服务:

curl -fsSk "${API7_DASHBOARD}/apisix/admin/routes/upstream-mtls?gateway_group_id=${API7_GATEWAY_GROUP_ID}" \
-X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "upstream-mtls",
"service_id": "upstream-mtls",
"paths": ["/*"]
}'

通过网关发送请求:

curl -i "http://127.0.0.1:9080/anything"

请求成功证明网关已验证上游证书,且上游已接受网关的客户端证书。如需验证网关提供的是哪一张客户端证书,请检查上游访问日志,或在测试响应中输出已认证的客户端主体。

故障排查​

现象可能原因解决方案
启用上游 mTLS 后出现 502 Bad Gateway上游拒绝了网关的客户端证书。验证客户端证书有效,且由上游信任的 CA 签发。检查上游 TLS 日志。
启用 tls_verify: true 时出现 502 Bad Gateway网关无法构建从上游证书到某个已引用 CA 证书的信任链。引用签发上游证书的 CA,并包含所有必需的中间证书。
证书名称不匹配SNI 名称与上游证书的主体备选名称不匹配。将 pass_host: rewrite 和 upstream_host 设置为证书覆盖的主机名。
连接被拒绝或出现明文协议错误上游协议或端口错误。使用 https 或 grpcs 以及上游服务的 TLS 端口。
无法删除证书对象某个上游仍引用该对象。删除证书对象之前,请从上游中移除证书 ID。

后续步骤​