配置 APISIX 和上游之间的双向 TLS
双向 TLS (mTLS) 是一种双向 TLS,其中客户端和服务器相互验证身份。它通常在高安全性环境中实施,以防止未经授权的访问并加强安全性。
本指南将向你介绍如何在 APISIX 和上游服务之间配置 mTLS,使用 NGINX 作为示例上游服务。
前置条件
- 安装 Docker。
- 安装 cURL 以向服务发送请求进行测试。
- 安装 jq,用于安全地将 PEM 证书编码到 JSON 中。
- 安装 OpenSSL,用于生成示例证书。
- 按照 快速入门教程 在 Docker 或 Kubernetes 中启动一个新的 APISIX 实例。
生成证书和密钥
生成证书颁发机构 (CA) 密钥和证书:
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 36500 -sha256 \
-key ca.key \
-out ca.crt \
-subj "/CN=MyTestCA" \
-extensions v3_ca \
-config <(printf "[req]\ndistinguished_name=req\n[ v3_ca ]\nbasicConstraints=critical,CA:TRUE\nkeyUsage=critical,keyCertSign,cRLSign\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid:always,issuer")
生成密钥和证书签名请求 (CSR):
openssl genrsa -out server.key 2048
openssl req -new -sha256 \
-key server.key \
-out server.csr \
-subj "/CN=test.com"
使用 CA 证书对服务器 CSR 进行签名以生成服务器证书:
openssl x509 -req -days 36500 -sha256 \
-in server.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt \
-extensions v3_req \
-extfile <(printf "[v3_req]\nbasicConstraints=CA:FALSE\nkeyUsage=digitalSignature,keyEncipherment\nextendedKeyUsage=serverAuth\nsubjectAltName=DNS:test.com")
为客户端生成密钥和证书签名请求 (CSR):
openssl genrsa -out client.key 2048
openssl req -new -sha256 \
-key client.key \
-out client.csr \
-subj "/CN=CLIENT"
使用 CA 证书对客户端 CSR 进行签名以生成客户端证书:
openssl x509 -req -days 36500 -sha256 \
-in client.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out client.crt \
-extensions v3_req \
-extfile <(printf "[v3_req]\nbasicConstraints=CA:FALSE\nkeyUsage=digitalSignature,keyEncipherment\nextendedKeyUsage=clientAuth")
配置上游服务
在与 APISIX 相同的 Docker 网络中启动 NGINX 服务器作为示例上游服务:
docker run -d \
--name quickstart-nginx \
--network=apisix-quickstart-net \
-p 8443:8443 \
nginx
将 CA 证书、服务器证书公钥和私钥复制到 NGINX 中:
docker cp ca.crt quickstart-nginx:/var/ca.crt
docker cp server.crt quickstart-nginx:/var/server.crt
docker cp server.key quickstart-nginx:/var/server.key
在 NGINX 配置 文件中配置一个监听 /hello 和端口 8443 的 HTTPS 服务器:
http {
# ...
server {
listen 8443 ssl;
server_name test.com;
ssl_certificate /var/server.crt;
ssl_certificate_key /var/server.key;
ssl_client_certificate /var/ca.crt;
ssl_verify_client on;
location /hello {
return 200 "Hello APISIX!";
}
}
}
❶ server_name 与直接请求和 APISIX 请求使用的 test.com 主机名匹配。
❷ ssl_certificate 和 ssl_certificate_key 配置 NGINX 服务器身份。
❸ ssl_client_certificate 加载 NGINX 用于信任客户端证书的 CA。
❹ ssl_verify_client 要求每个客户端都提供受信任的证书。
重新加载 NGINX 服务器以应用配置更改:
docker exec quickstart-nginx nginx -s reload
为了验证 NGINX 实例配置正确,请使用客户端证书和密钥向 NGINX 服务的路由发送请求:
curl -i "https://test.com:8443/hello" \
--resolve "test.com:8443:127.0.0.1" --cacert ca.crt \
--cert client.crt --key client.key
你应该收到 HTTP/1.1 200 OK 响应并看到以下消息:
Hello APISIX!
如果你在没有任何客户端证书或密钥的情况下向 NGINX 服务的路由发送请求:
curl -i "https://test.com:8443/hello" \
--resolve "test.com:8443:127.0.0.1" --cacert ca.crt
你应该收到 HTTP/1.1 400 Bad Request 响应。
为 APISIX 配置 mTLS
将证书文件编码为 JSON 字符串,以便在请求正文中保留换行:
client_cert=$(jq -Rs . < client.crt)
client_key=$(jq -Rs . < client.key)
ca_cert=$(jq -Rs . < ca.crt)
创建一条路由,在向上游服务器出示客户端证书的同时验证其证书。CA 用于建立对服务器的信任,客户端证书和密钥用于让 APISIX 向 NGINX 进行身份认证:
curl -i "http://127.0.0.1:9180/apisix/admin/routes/mtls-nginx" \
-X PUT -H "X-API-KEY: ${ADMIN_API_KEY}" --data-binary @- <<EOF
{
"uri": "/hello",
"upstream": {
"type": "roundrobin",
"scheme": "https",
"nodes": {
"quickstart-nginx:8443": 1
},
"pass_host": "rewrite",
"upstream_host": "test.com",
"tls": {
"client_cert": ${client_cert},
"client_key": ${client_key},
"verify": true,
"ca_certs": [${ca_cert}]
}
}
}
EOF
❶ pass_host 和 upstream_host 使用 test.com 作为上游 Host 请求头和 TLS 名称,而节点地址用于选择 Docker 服务。
❷ client_cert 和 client_key 用于让 APISIX 向 NGINX 进行身份认证。
❸ verify 启用服务器验证,ca_certs 信任示例 CA。该上游专用的 CA 列表会替代该上游的共享信任存储。
验证 APISIX 和上游服务之间的 mTLS
向路由发送请求:
curl -i "http://127.0.0.1:9080/hello"
你应该收到 HTTP/1.1 200 OK 响应并看到以下消息:
Hello APISIX!
这验证了 APISIX 和上游服务之间已成功建立 mTLS。
下一步
你已经了解了如何在 APISIX 和上游服务之间设置 mTLS。APISIX 还支持客户端和 APISIX 之间的 mTLS。请参阅 配置客户端和 APISIX 之间的 mTLS 以了解更多信息。