如何配置两台NGINX传递客户端证书至后端应用?
问题解答
可行性结论
这个场景完全可以通过NGINX配置实现,核心是确保客户端证书信息在两台NGINX间正确传递,同时规避NGINX默认请求头处理逻辑的干扰。
两台NGINX具体配置方案
1. NGINX-A(前端反向代理)配置
先确保NGINX-A开启双向SSL认证,再将原始客户端证书处理后放入请求头转发至NGINX-B:
server { listen 443 ssl; server_name your-domain.com; # 双向SSL认证配置 ssl_certificate /path/to/nginx-a-cert.pem; ssl_certificate_key /path/to/nginx-a-key.pem; ssl_client_certificate /path/to/ca-cert.pem; # 验证客户端证书的CA根证书 ssl_verify_client on; # 强制开启双向认证 location / { proxy_pass https://nginx-b-ingress-address; # NGINX-A与NGINX-B之间也开启双向认证 proxy_ssl_certificate /path/to/nginx-a-client-cert.pem; proxy_ssl_certificate_key /path/to/nginx-a-client-key.pem; proxy_ssl_trusted_certificate /path/to/nginx-b-ca-cert.pem; proxy_ssl_verify on; # 传递原始客户端证书:处理换行符避免HTTP头截断 proxy_set_header X-Original-Client-Cert $ssl_client_cert; # 兼容NGINX-B默认的ssl-client-cert字段 proxy_set_header ssl-client-cert $ssl_client_cert; # 可选:传递客户端证书的DN信息 proxy_set_header X-Client-DN $ssl_client_s_dn; } }
注意:
$ssl_client_cert包含带换行的PEM格式证书,部分代理会截断换行,可借助ngx_http_set_misc_module统一格式:set $formatted_cert $ssl_client_cert; replace $formatted_cert '\n' '\n'; proxy_set_header ssl-client-cert $formatted_cert;
2. NGINX-B(K8S Ingress NGINX)配置
NGINX-B默认会将自身SSL连接拿到的客户端证书(即NGINX-A的证书)转发给上游,需修改配置,用NGINX-A传递的原始证书覆盖默认字段:
方式1:Ingress Annotation配置(推荐)
在K8S Ingress资源中添加以下注解:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx-b-ingress annotations: nginx.ingress.kubernetes.io/ssl-verify-client: "on" # 开启与NGINX-A的双向认证 nginx.ingress.kubernetes.io/ssl-certificate: "namespace/nginx-b-cert-secret" nginx.ingress.kubernetes.io/ssl-client-certificate: "namespace/ca-cert-secret" # 验证NGINX-A证书的CA # 覆盖默认的ssl-client-cert转发逻辑 nginx.ingress.kubernetes.io/proxy-set-header: "ssl-client-cert $http_x_original_client_cert" # 确保自定义头不被丢弃 nginx.ingress.kubernetes.io/configuration-snippet: | proxy_set_header ssl-client-cert $http_ssl_client_cert;
方式2:自定义NGINX配置片段
若注解不够灵活,可通过ConfigMap添加自定义配置:
server { # 保留Ingress默认配置... # 开启与NGINX-A的双向认证 ssl_client_certificate /etc/nginx/ssl/ca-cert.pem; ssl_verify_client on; location / { # 使用NGINX-A传递的原始证书覆盖默认字段 proxy_set_header ssl-client-cert $http_x_original_client_cert; # 可选:保留NGINX-A的证书信息用于审计 proxy_set_header X-Nginx-A-Cert $ssl_client_cert; } }
NGINX对ssl-client-cert等请求头的处理逻辑
- 变量优先级规则:当NGINX开启双向认证时,
$ssl_client_cert存储的是当前直接连接的客户端证书(比如NGINX-B的该变量是NGINX-A的证书,而非原始客户端的),因此必须手动传递原始证书的请求头,不能依赖NGINX默认转发。 - 请求头标准化:NGINX默认会将请求头中的下划线转为连字符(如
X_Original_Client_Cert会被转为X-Original-Client-Cert),传递时尽量使用连字符格式,或在配置中明确指定头名。 - 头过滤机制:NGINX反向代理时默认会丢弃部分敏感头,自定义头必须通过
proxy_set_header显式设置才能传递到上游。 - 证书格式兼容:PEM格式证书含换行符,直接放入HTTP头可能被解析为多个头或截断,需统一换行格式(如替换为
\n),确保上游应用能正确解析。
内容的提问来源于stack exchange,提问作者PatS
相关产品推荐
相关产品推荐

