跳到主要内容

a6-recipe-mtls

概览

双向 TLS(mTLS)确保客户端和服务端彼此校验 身份。标准 TLS 只校验服务端;mTLS 会额外校验客户端证书。

通过 Apache APISIX和 a6 CLI,你可以配置:

  1. 客户端到 Apache APISIX 的 mTLS:要求客户端提供有效证书。
  2. Apache APISIX到上游的 mTLS:连接后端时提供客户端证书。
  3. 端到端 mTLS:同时启用两个方向的 mTLS。

适用场景

  • 服务间零信任网络。
  • 微服务中的安全服务间通信。
  • 要求双向认证的合规场景。
  • 使用基于证书的认证替代或补充 API Key 认证。
  • 仅授权服务可访问的内部 API。

概念

术语描述
CA 证书用于验证客户端或服务器证书的证书颁发机构证书
服务器证书APISIX 向客户端提供的证书(标准 TLS)
客户端证书客户端向 APISIX 提供的证书(mTLS 验证)
上游 TLSAPISIX 向上游后端提供客户端证书

第一部分:客户端到 APISIX 的 mTLS

要求客户端连接 APISIX 时提供有效的 TLS 证书。

1. 创建带客户端校验 CA 的 SSL 资源

a6 ssl create -f - <<'EOF'
{
"id": "mtls-domain",
"cert": "<SERVER_CERTIFICATE_PEM>",
"key": "<SERVER_PRIVATE_KEY_PEM>",
"snis": ["api.example.com"],
"client": {
"ca": "<CA_CERTIFICATE_PEM>"
}
}
EOF

字段:

  • cert / key:服务端证书和私钥(提供给客户端)。
  • snis:服务器名称指示(Server Name Indications),即该证书覆盖的域名。
  • client.ca:用于校验客户端证书的 CA 证书。
  • client.depth:(可选)证书链校验的最大深度。

2. 为受保护域名创建路由

a6 route create -f - <<'EOF'
{
"id": "secure-api",
"uri": "/api/*",
"host": "api.example.com",
"upstream": {
"type": "roundrobin",
"nodes": {
"backend:8080": 1
}
}
}
EOF

3. 用客户端证书进行测试

# With valid client cert — succeeds
curl --cert client.crt --key client.key --cacert ca.crt \
https://api.example.com:9443/api/health

# Without client cert — fails with SSL handshake error
curl --cacert ca.crt https://api.example.com:9443/api/health

第二部分:APISIX 到上游的 mTLS

配置 APISIX 连接后端时提供客户端证书。

1. 用 TLS 客户端证书创建上游

a6 upstream create -f - <<'EOF'
{
"id": "mtls-backend",
"type": "roundrobin",
"scheme": "https",
"nodes": {
"secure-backend:443": 1
},
"tls": {
"client_cert": "<CLIENT_CERTIFICATE_PEM>",
"client_key": "<CLIENT_PRIVATE_KEY_PEM>"
}
}
EOF

字段说明:

  • scheme:连接上游时使用的协议,必须设置为 TLS 协议
  • tls.client_cert:APISIX 向上游提供的客户端证书
  • tls.client_key:客户端证书对应的私钥
  • pass_host:默认为 "pass";上游要求特定 Host 时设置为 "rewrite"

2. 利用上游创建路由

a6 route create -f - <<'EOF'
{
"id": "api",
"uri": "/api/*",
"upstream_id": "mtls-backend"
}
EOF

第 3 部分:端到端 mTLS

组合两者:客户端向 Apache APISIX证明自身身份,Apache APISIX也向 上游证明自身身份。

1. 客户端的SSL — APISIX mTLS

a6 ssl create -f - <<'EOF'
{
"id": "frontend-mtls",
"cert": "<APISIX_SERVER_CERT>",
"key": "<APISIX_SERVER_KEY>",
"snis": ["api.example.com"],
"client": {
"ca": "<CLIENT_CA_CERT>"
}
}
EOF

2. APISIX — 后端mTLS的上游

a6 upstream create -f - <<'EOF'
{
"id": "secure-backend",
"type": "roundrobin",
"scheme": "https",
"nodes": {
"internal-service:443": 1
},
"tls": {
"client_cert": "<APISIX_CLIENT_CERT>",
"client_key": "<APISIX_CLIENT_KEY>"
}
}
EOF

3. 连接两端的路由

a6 route create -f - <<'EOF'
{
"id": "e2e-mtls-api",
"uri": "/api/*",
"host": "api.example.com",
"upstream_id": "secure-backend"
}
EOF

常见模式

使用不同 CA 的多个域名

# Domain A: internal services
a6 ssl create -f - <<'EOF'
{
"id": "internal-mtls",
"cert": "<INTERNAL_CERT>",
"key": "<INTERNAL_KEY>",
"snis": ["internal.example.com"],
"client": {
"ca": "<INTERNAL_CA>"
}
}
EOF

# Domain B: partner services
a6 ssl create -f - <<'EOF'
{
"id": "partner-mtls",
"cert": "<PARTNER_CERT>",
"key": "<PARTNER_KEY>",
"snis": ["partner.example.com"],
"client": {
"ca": "<PARTNER_CA>"
}
}
EOF

使用 APISIX 密钥进行证书管理

将证书存储在外部 Secret 管理器(如 Vault、AWS Secrets Manager)中:

# Create a secret reference
a6 secret create -f - <<'EOF'
{
"id": "vault/mtls-certs",
"uri": "https://vault.example.com/v1/secret/data/mtls"
}
EOF

证书旋转

零停机更新证书 :

a6 ssl update mtls-domain -f - <<'EOF'
{
"cert": "<NEW_CERT>",
"key": "<NEW_KEY>",
"client": {
"ca": "<NEW_OR_SAME_CA>"
}
}
EOF

APISIX 立即加载新证书——不需要重启.

配置同步示例

version: "1"
ssls:
- id: api-mtls
cert: |
-----BEGIN CERTIFICATE-----
<server certificate>
-----END CERTIFICATE-----
key: |
-----BEGIN RSA PRIVATE KEY-----
<server private key>
-----END RSA PRIVATE KEY-----
snis:
- api.example.com
client:
ca: |
-----BEGIN CERTIFICATE-----
<CA certificate for client verification>
-----END CERTIFICATE-----
upstreams:
- id: secure-backend
type: roundrobin
scheme: https
nodes:
"backend:443": 1
tls:
client_cert: |
-----BEGIN CERTIFICATE-----
<client certificate for upstream>
-----END CERTIFICATE-----
client_key: |
-----BEGIN RSA PRIVATE KEY-----
<client private key for upstream>
-----END RSA PRIVATE KEY-----
routes:
- id: mtls-api
uri: /api/*
host: api.example.com
upstream_id: secure-backend

故障排查

现象原因修复方式
SSL 握手失败(客户端侧)客户端证书不是由 client.ca 中的 CA 签发校验 CA 链,确认客户端证书由正确 CA 签发
"no required SSL certificate"客户端未发送证书配置客户端提供证书(curl 中使用 --cert
访问上游返回 502上游拒绝 APISIX 提供的客户端证书确认 tls.client_cert 由上游信任的 CA 签发
证书已过期TLS 证书超过有效期使用 a6 ssl update 轮换证书
SNI 不匹配域名不在 snis 列表中将该域名添加到 snis 数组
unable to verify自签名证书不受正确 CA 信任在 cURL 中使用 --cacert,或将 CA 加入系统信任存储
HTTP/HTTPS 混用路由可从两个端口访问配置 APISIX listen,使 mTLS 域名仅公开 HTTPS 端口

本文根据 api7/a6 仓库中的 a6-recipe-mtls/SKILL.md 生成。可在 AI Agent Skills 页面浏览全部 Skill。