You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将客户端证书从Acme1 Nginx Ingress转发至Acme2实现故障转移?

问题解决:跨Ingress故障转移时原始客户端mTLS证书转发

问题背景

Acme1和Acme2区域的Nginx Ingress均启用mTLS,当Acme1触发故障转移到Acme2时,Acme2收到的是Acme1的代理证书,而非原始客户端的证书,导致无法识别原始客户端身份。

原因分析

  1. Acme1配置了proxy_ssl_certificate和proxy_ssl_certificate_key,与Acme2建立mTLS连接时,Acme1会以自身证书作为客户端证书完成TLS握手,因此Acme2在TLS层面只能获取到Acme1的代理证书。
  2. Acme2设置了auth-tls-verify-client: "on",强制验证TLS握手阶段的客户端证书,只会处理TLS层面的证书,忽略HTTP头中传递的原始客户端证书。

解决方案

1. 调整Acme1的Ingress配置

保留Acme1与Acme2的mTLS链路安全,同时确保原始客户端证书被正确传递:

  • 保留现有代理证书配置,确保Acme1与Acme2的mTLS连接合法:
    proxy_ssl_session_reuse on;
    proxy_ssl_certificate certs/ca.crt;
    proxy_ssl_certificate_key certs/key.crt;
    proxy_ssl_trusted_certificate certs/rootca.pem;
    
  • 明确传递原始客户端证书的HTTP头(使用更清晰的命名避免冲突):
    proxy_set_header X-Original-Client-Cert $ssl_client_escaped_cert;
    

    注:$ssl_client_escaped_cert是Nginx提供的URL编码后的客户端证书变量,确保证书内容在HTTP头中能安全传输。

2. 调整Acme2的Ingress配置

修改mTLS验证逻辑,同时验证Acme1的代理证书(确保转发来源合法)和HTTP头中的原始客户端证书:

  • 修改auth-tls-verify-client为optional,允许TLS握手时客户端(Acme1)提供证书,但不强制,同时保留对Acme1证书的验证:
    nginx.ingress.kubernetes.io/auth-tls-verify-client: "optional"
    
  • 保留原有验证Acme1证书的配置:
    nginx.ingress.kubernetes.io/auth-tls-secret: root-ca
    nginx.ingress.kubernetes.io/auth-tls-verify-depth: "2"
    
  • 添加自定义配置,解码并传递原始客户端证书到上游服务:
    通过Ingress注解添加Nginx配置片段,解码URL编码的证书并传递给上游:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      rewrite_by_lua_block {
          if ngx.var.http_x_original_client_cert then
              local decoded_cert = ngx.unescape_uri(ngx.var.http_x_original_client_cert)
              ngx.var.decoded_client_cert = decoded_cert
          end
      }
      proxy_set_header X-Decoded-Client-Cert $decoded_client_cert;
    
  • (可选)如果需要在Acme2层面验证原始客户端证书,可在配置片段中添加证书验证逻辑:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      rewrite_by_lua_block {
          if ngx.var.http_x_original_client_cert then
              local decoded_cert = ngx.unescape_uri(ngx.var.http_x_original_client_cert)
              ngx.var.decoded_client_cert = decoded_cert
              -- 验证证书是否由信任CA签发
              local openssl = require "resty.openssl"
              local cert, err = openssl.x509.new(decoded_cert, "PEM")
              if not cert then
                  ngx.log(ngx.ERR, "Invalid client certificate: ", err)
                  return ngx.exit(403)
              end
              local store, err = openssl.x509.store.new()
              store:add_file("/etc/nginx/ssl/rootca.pem")
              local ok, err = store:verify(cert)
              if not ok then
                  ngx.log(ngx.ERR, "Certificate verification failed: ", err)
                  return ngx.exit(403)
              end
          else
              ngx.exit(403)
          end
      }
      proxy_set_header X-Decoded-Client-Cert $decoded_client_cert;
    

    注:需确保Acme2的Ingress容器中安装了lua-resty-openssl库,且信任的CA证书已挂载到指定路径。

3. 上游服务适配

上游服务需要读取X-Decoded-Client-Cert头中的PEM格式证书,完成身份验证逻辑。

关键注意事项

  • 确保Acme1的ssl_verify_client设置为optional或on,这样才能获取到$ssl_client_escaped_cert变量的值。
  • Acme2与Acme1之间的mTLS连接仍然有效,确保只有合法的Acme1节点能转发流量到Acme2,避免未授权转发。
  • 证书传递过程中使用URL编码和解码,避免证书内容中的特殊字符破坏HTTP头结构。

内容的提问来源于stack exchange,提问作者Hare Krshn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 10:16:03