使用Nginx代理客户端证书认证,在SSL握手时Peer关闭连接,而SSL握手到上游

ny6fqffe  于 6个月前  发布在  Nginx
关注(0)|答案(1)|浏览(130)

我们使用nginx作为反向代理,gitblit作为后端,客户端证书认证。
nginx配置如下。

server {
listen       443 ssl http2 default_server;
server_name  _;

charset utf-8;

ssl_certificate      D:\cert.pem;
ssl_certificate_key  D:\key.pem;

ssl_session_cache    off;
ssl_session_timeout  1h;
ssl_buffer_size 8192;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers  HIGH:!aNULL:!MD5;

ssl_client_certificate D:\Program\GitBlit\gitblit-1.8.0\data\certs\ca.pem;
ssl_verify_client optional;

ssl_prefer_server_ciphers  on;
proxy_intercept_errors on;          

location /git {
    proxy_pass https://127.0.0.1:1111;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    
    proxy_ssl_verify off;
    proxy_ssl_name $host;
    proxy_ssl_server_name on;
    proxy_ssl_session_reuse off;
}
}

字符串
ssl_verify_client optional;语法有web客户端在导航到https://my_server/git时需要客户端证书。但是我得到了502 bad gateway错误。从gitblti没有看到任何错误日志。nginx错误日志如下。

2023/10/25 14:48:14 [error] 29404#2072: *43 peer closed connection in SSL handshake while SSL handshaking to upstream, client: 127.0.0.1, server: _, request: "GET /git/ HTTP/2.0", upstream: "https://127.0.0.1:1111/git/", host: "127.0.0.1"


我已经确保如果我导航到https://127.0.0.1:1111/git并提供相同的客户端证书,身份验证工作正常。gitblit SSL证书由自签名CA签署到my_server(ssl_client_certificate语法为D:\Program\GitBlit\gitblit-1.8.0\data\certs\ca.pem)。
这是因为nginx无法识别gitblit的SSL证书还是无法通过客户端证书进行身份验证?

busg9geu

busg9geu1#

答案需要一点猜测。我假设您的Gitblit安装设置为要求客户端通过HTTPS进行客户端证书认证。(server.requireClientCertificates = required
根据您发布的配置,您的Nginx代理也会请求客户端证书,尽管是可选的。这意味着具有从您指定的CA颁发的TLS客户端证书的客户端将向Nginx服务器提供此证书。服务器验证证书,然后将请求重定向到代理服务器。
但是Nginx代理不会将客户端的证书传递给代理服务器。它终止了来自客户端的TLS连接,并将创建一个新的连接到代理服务器,因为您为代理服务器指定了HTTPS URL。这是一个新的连接,代理是TLS客户端,不再是原来的客户端。因此,这个连接将没有代理服务器将接受的客户端证书,这使得它拒绝连接。
您的问题的解决方案取决于您希望通过现有设置实现的目标。因此,在不了解细节的情况下,我无法提供具体的正确答案。我可以根据猜测您想要实现的目标,提供一个可能的答案。
您代理到127.0.0.1,即 localhost。所以我猜Gitblit服务器不能从外部连接访问,只能从同一服务器内部访问。* 如果 * 是这种情况(你需要通过绑定到 localhost 接口来确保 *),你可以设置一个场景,在这个场景中,Nginx代理验证客户端证书。如果成功,它设置一个HTTP头,Gitblit服务器可以评估并登录用户。
Gitblit提供了一个HTTP头认证提供者。这是 * 仅 * 用于某些情况下,没有直接访问Gitblit服务器,只有通过可信的前端。
将Gitblit设置为不使用客户端证书。(实际上,您也可以在代理和Gitblit之间使用HTTP,因为它只在本地服务器上,并且您需要确保任何人都无法直接访问Gitblit服务器。)Nginx将负责客户端证书验证。
启用HTTP头认证提供程序并定义一个将携带用户名的头。当一个请求带有该头并且值是一个有效的用户名时,用户将登录。

realm.authenticationProviders = httpheader
realm.httpheader.userheader = GitblitTlsClientSDN

字符串
在Nginx上需要客户端证书来确保提供有效的证书。从证书主题DN中提取用户名,并将其设置在Gitblit中定义的头部中以携带用户名。
例如,假设客户端证书中的主题DN是CN=Joe,OU=Gitblit,O=Gibtlit,L=Seattle,ST=WA=C=US

# Map client certificate DN to user name

map $ssl_client_s_dn $gb_username {
    default                                        "";
    "~^CN=(?<cn>[^,]+),OU=Gitblit,O=Gitblit,.*$"  $cn;
}

server {
    listen       443 ssl http2 default_server;
    server_name  _;

    charset utf-8;

    ssl_certificate      D:\cert.pem;
    ssl_certificate_key  D:\key.pem;

    ssl_session_cache    off;
    ssl_session_timeout  1h;
    ssl_buffer_size 8192;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_ciphers  HIGH:!aNULL:!MD5;

    ssl_client_certificate D:\Program\GitBlit\gitblit-1.8.0\data\certs\ca.pem;
    ssl_verify_client on;

    ssl_prefer_server_ciphers  on;
    proxy_intercept_errors on;          

    location /git {
        proxy_pass https://127.0.0.1:1111;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    
        proxy_set_header GitblitTlsClientSDN $gb_username;

        proxy_ssl_verify off;
        proxy_ssl_name $host;
        proxy_ssl_server_name on;
        proxy_ssl_session_reuse off;
    }
}


您还需要采取预防措施,Nginx代理不允许客户端smuggle the header通过代理传输用户名。

相关问题