通过命令验证挂载在 Nginx Ingress 上的证书

在使用 Nginx Ingress 并挂载证书的情况下,当通过 curl 携带 Host 请求头访问 Ingress Controller 时,返回的证书为 Kubernetes Ingress Controller Fake Certificate,而不是实际挂载的证书:

直接请求域名的时候,就可以获取到正确的证书:

从用户的角度来看,似乎这是 Ingress Controller 存在问题。其实不然,通过 SNI 可以很好理解这一点。

社区 issue:https://github.com/kubernetes/ingress-nginx/issues/6398

SNI

参考:https://www.cloudflare.com/zh-cn/learning/ssl/what-is-sni/

通常情况下,一台服务器可能托管多个网站,而不同网站使用的证书也可能不同。如果没有额外机制,服务器在 TLS/SSL 握手时无法确定客户端要访问的具体网站,从而可能返回错误的证书。

SNI(服务器名称指示)正是为了解决这一问题。作为 TLS 协议的扩展,SNI 允许客户端在握手阶段就指定目标域名,使服务器能够返回对应的正确证书。例如,即使多个网站共用同一 IP,SNI 也能确保用户访问时获得匹配的证书。

通过命令验证证书是否正确

上述通过 curl 携带 Host 请求头直接访问 IP 的方式,可以视为一种不符合规范的请求。原因是:

  • curl https://x.x.x.x 时,SNI 会被设置为 x.x.x.x
  • curl 并不会将 Host 与 SNI 绑定,且 Host 在 HTTP 层时才会被使用,当流量到达 HTTP 层时,已经完成了 TLS 握手。因此流量到达 Ingress Controller 时,它无法根据 SNI 判断应返回哪一个证书;
  • 结果就是返回默认证书;若未配置默认证书,则会返回 Kubernetes Ingress Controller Fake Certificate

所以,上述的 curl 命令不能够很好的验证挂载了证书的 Ingress(直接请求域名除外),而是需要显式指定域名而不是 IP:

1
curl -kv https://<your_domain_name> --resolve <your_domain_name>:443:<your_nginx_ingress_controller_ip>

openssl 通过 servername 参数,也能够很好的解决这个问题:

1
openssl s_client -showcerts -connect <your_nginx_ingress_controller_ip>:443 -servername <your_domain_name>

Author

Warner Chen

Posted on

2025-09-30

Updated on

2025-09-30

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.
You forgot to set the business or currency_code for Paypal. Please set it in _config.yml.

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.