我在尝试使用Nginx作为反向代理的时候遇到了一个问题,它似乎没有将客户端证书发送到后端资源。
这是服务器块configuration:
server { listen 443; server_name my.server.tld; location / { proxy_pass https://my.realserver.tld; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; proxy_pass_request_body on; proxy_pass_request_headers on; } include ssl_params; ssl_client_certificate /etc/ssl/client-ca.pem; ssl_verify_client optional; }
ssl_params:
ssl on; ssl_certificate /etc/ssl/private/fullchain.pem; ssl_certificate_key /etc/ssl/private/privkey.pem; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_session_tickets off; ssl_protocols TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; ssl_prefer_server_ciphers on; add_header Strict-Transport-Security max-age=15768000;
nginx日志显示502来自后端资源,而后端显示错误: exception reported by IO thread: null cert chain Caused by javax.net.ssl.SSLHandshakeException: null cert chain
后端是一个Tomcat服务器。
编辑:
我从源码构buildnginx来尝试使用ssl_preread的东西,但它是失败的。
这是构build信息:
./nginx -V nginx version: nginx/1.11.10 built by gcc 4.9.2 (Debian 4.9.2-10) built with OpenSSL 1.0.1t 3 May 2016 TLS SNI support enabled configure arguments: --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2' --with-ld-opt=-Wl,-z,relro --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_addition_module --with-http_dav_module --with-http_geoip_module --with-http_gzip_static_module --with-http_image_filter_module --with-http_sub_module --with-http_xslt_module --with-mail --with-mail_ssl_module
我正在使用Debian Jessie 8.7。
当试图使用Alexey的例子时,这是失败的:
./nginx -t nginx: [emerg] unknown directive "stream" in /etc/nginx/nginx.conf:11 nginx: configuration file /etc/nginx/nginx.conf test failed
这个configuration可以工作,但是需要用ngx_stream_ssl_preread_module来构buildnginx。
stream { upstream yandex { server 93.158.134.3:443; } upstream google { server 64.233.164.113:443; } map $ssl_preread_server_name $upstream { hostnames; default yandex; .google.com google; } server { listen 12345; ssl_preread on; proxy_pass $upstream; } }
testing它:
$ openssl s_client -quiet -connect localhost:12345 -servername yandex.ru depth=3 C = PL, O = Unizeto Sp. z oo, CN = Certum CA verify return:1 depth=2 C = PL, O = Unizeto Technologies SA, OU = Certum Certification Authority, CN = Certum Trusted Network CA verify return:1 depth=1 C = RU, O = Yandex LLC, OU = Yandex Certification Authority, CN = Yandex CA verify return:1 depth=0 C = RU, O = Yandex LLC, OU = ITO, L = Moscow, ST = Russian Federation, CN = *.wfarm.yandex.net verify return:1 ^C $ openssl s_client -quiet -connect localhost:12345 -servername google.com depth=3 C = US, O = Equifax, OU = Equifax Secure Certificate Authority verify return:1 depth=2 C = US, O = GeoTrust Inc., CN = GeoTrust Global CA verify return:1 depth=1 C = US, O = Google Inc, CN = Google Internet Authority G2 verify return:1 depth=0 C = US, ST = California, L = Mountain View, O = Google Inc, CN = *.google.com verify return:1 ^C
现在Nginx已经configurationNginx作为第7层负载均衡器。 Nginx将终止HTTPS连接,然后创build另一个连接到您的后端服务器。 Nginx可以访问客户端证书,但Nginx没有理由select通过客户端证书,除非被告知,假设它具有该function。
您需要的是第4层负载平衡器,因此TCP连接将传递到后端服务器。 这可以在Nginx,HAProxy中完成,或者是其他的。 Nginx看起来像这样(从这个文档中获取 )
stream { server { listen 127.0.0.1:12345; proxy_pass backend.example.com:12345; } }
链接的文章向您展示了如何在多个后端服务器之间进行负载平衡。
更新
您添加了一个基于域名的负载平衡的新要求。 您不能使用SNI,因为这是HTTP(第7层)function。 在这种情况下,一种select是将多个IP分配给服务器,并让客户端向正确的IP请求。
stream { server { listen 127.0.0.1:12345; proxy_pass backend.example.com:12345; } server { listen 127.0.0.2:12345; proxy_pass backend2.example.com:12345; } }
替代解决scheme
这个问题的答案build议以下可能在你的代理块中工作。 这是值得一试的。
proxy_set_header X-SSL-CERT $ssl_client_cert;