13.6.4 双向认证与客户端证书校验
在需要强化安全的内部管理、B2B接口与敏感系统场景下,HAProxy 支持 TLS 双向认证(mTLS),通过校验客户端证书确认访问方身份。mTLS 要求客户端在握手阶段提交证书并完成链路校验,实现“只有持有合法证书的客户端才可访问”的访问控制。
原理草图(握手与校验):
示例:生成 CA 与客户端证书(OpenSSL)
适用于演示环境;生产需加密私钥、规范目录权限与证书生命周期管理。
# 1) 生成根CA
mkdir -p /etc/pki/demoCA/{private,certs,newcerts,crl}
chmod 700 /etc/pki/demoCA/private
openssl genrsa -out /etc/pki/demoCA/private/ca.key 4096
openssl req -x509 -new -key /etc/pki/demoCA/private/ca.key \
-sha256 -days 3650 -out /etc/pki/demoCA/certs/ca.crt \
-subj "/C=CN/O=DemoCA/OU=Ops/CN=Demo Root CA"
# 2) 生成客户端证书
openssl genrsa -out /etc/pki/client01.key 2048
openssl req -new -key /etc/pki/client01.key \
-out /etc/pki/client01.csr \
-subj "/C=CN/O=DemoClient/OU=App/CN=client01"
openssl x509 -req -in /etc/pki/client01.csr \
-CA /etc/pki/demoCA/certs/ca.crt \
-CAkey /etc/pki/demoCA/private/ca.key \
-CAcreateserial -out /etc/pki/client01.crt \
-days 365 -sha256
# 3) 生成服务端证书(HAProxy证书)
openssl genrsa -out /etc/pki/haproxy.key 2048
openssl req -new -key /etc/pki/haproxy.key \
-out /etc/pki/haproxy.csr \
-subj "/C=CN/O=Demo/OU=Ops/CN=haproxy.example.com"
openssl x509 -req -in /etc/pki/haproxy.csr \
-CA /etc/pki/demoCA/certs/ca.crt \
-CAkey /etc/pki/demoCA/private/ca.key \
-CAcreateserial -out /etc/pki/haproxy.crt \
-days 365 -sha256
# 4) 组装HAProxy证书(服务端证书+私钥)
cat /etc/pki/haproxy.crt /etc/pki/haproxy.key > /etc/haproxy/certs/server.pem
HAProxy mTLS 配置示例(完整可运行片段)
# /etc/haproxy/haproxy.cfg
global
log /dev/log local0
maxconn 50000
defaults
mode http
log global
timeout connect 5s
timeout client 30s
timeout server 30s
frontend https_in
bind *:443 ssl crt /etc/haproxy/certs/server.pem \
ca-file /etc/pki/demoCA/certs/ca.crt \
verify required
# 校验状态,0为成功
http-request deny if !{ ssl_c_verify 0 }
# 基于证书CN控制
acl valid_client ssl_c_s_dn(cn) -m str client01
http-request deny if !valid_client
# 透传证书信息给后端
http-request set-header X-Client-CN %[ssl_c_s_dn(cn)]
default_backend app_servers
backend app_servers
server app1 10.0.0.11:8080 check
客户端访问示例与命令解释
# 使用curl携带客户端证书
curl -k https://haproxy.example.com/ \
--cert /etc/pki/client01.crt \
--key /etc/pki/client01.key \
--cacert /etc/pki/demoCA/certs/ca.crt
# 预期:返回后端页面或200状态
--cert/--key:客户端证书与私钥--cacert:用于校验服务端证书的 CA-k:仅用于测试跳过服务端校验,生产不建议使用
常见排错与命令(原因→定位→修复)
1. 握手失败:alert certificate required
- 原因:客户端未携带证书或 verify required 强制校验
- 定位:openssl s_client 查看握手
- 修复:客户端补齐 --cert/--key
openssl s_client -connect haproxy.example.com:443 \
-CAfile /etc/pki/demoCA/certs/ca.crt
-
CA不匹配:
unknown ca
- 原因:ca-file不包含签发客户端证书的 CA
- 修复:将正确 CA 链合并到ca-file -
证书链不完整
- 原因:客户端证书未包含中间链
- 修复:将中间 CA 追加到客户端证书文件 -
时间漂移导致失效
- 定位:openssl x509 -in client01.crt -noout -dates
- 修复:校准系统时间(NTP)
运行与验证命令
# 校验配置语法
haproxy -c -f /etc/haproxy/haproxy.cfg
# 重载
systemctl reload haproxy
# 查看日志(需系统log配置)
tail -f /var/log/haproxy.log
运维实践要点
- 证书分级管理:生产/测试/外部合作方使用不同 CA
- 轮换与吊销:CRL/OCSP 联动,定期替换客户端证书
- 最小权限:仅对关键入口启用 mTLS
- 证书透传与审计:记录 X-Client-CN,用于后端鉴权与审计
练习
1. 为 client02 生成证书并仅允许其访问 /admin 路径。
2. 启用 verify optional,分别测试无证书与有证书访问结果。
3. 配置 ssl_c_serial 白名单,模拟吊销某一序列号客户端。
4. 用 tcpdump -i any port 443 验证握手阶段是否携带证书。