nginx之proxy_pass代理后端https请求完全拆解

发布于 2020-12-01  184 次阅读


原文地址

前言

本文解释了怎么对 nginx 和后端服务器组或代理服务器进行加密 http 通信。

内容提纲

  • 前提条件
  • 获取 SSL 服务端证书
  • 获取 SSL 客户端证书
  • 配置 nginx
  • 配置后端服务器
  • 完整示例

前提条件

  • nginx 源码或 nginx plus 源码
  • 一个代理服务器或一个代理服务器组
  • SSL 证书和私钥

获取 SSL 服务端证书

你可以从一个可信证书颁发机构 (CA) 购买一个服务器证书, 或者你可以使用 openssl 库创建一个内部 CA, 并给自己颁发证书。这个服务器端证书和私钥需要部署在后端的每一个服务器上。

获取 SSL 客户端证书

nignx 使用一个 SSL 客户端证书来对后端服务器组来标识自己。这个客户端证书必须是被一个可信 CA 签名的,并且和相匹配的私钥一起部署在 nginx 中。
你还需要在后端服务器上配置好所有的来源 SSL 连接都需要客户端证书,并信任这个 CA 颁发的 nginx 客户端证书。 然后当 nginx 连接后端时,将提供客户端证书,并且后端将会接收这个连接。

配置 nginx

首先,改变相应 URL 到支持 SSL 连接的后端服务器组。在 nginx 的配置文件中,指明 proxy_pass 指令在代理服务器或后端服务器组中使用 "https" 协议:

location /upstream {
    proxy_pass https://backend.example.com;
}

增加客户端证书和私钥,用于验证 nginx 和每个后端服务器。使用proxy_ssl_certificateproxy_ssl_certificate_key指令:

location /upstream {  
    proxy_pass                https://backend.example.com;  
    proxy_ssl_certificate     /etc/nginx/client.pem;  
    proxy_ssl_certificate_key /etc/nginx/client.key  
}

如果你在后端服务器使用了自签名证书或者使用了自建 CA,你需要配置proxy_ssl_trusted_certificate. 这个文件必须是 PEM 格式的。另外还可以配置proxy_ssl_verifyproxy_ssl_verfiy_depth指令, 用来验证安全证书:

location /upstream {
    ...
    proxy_ssl_trusted_certificate /etc/nginx/trusted_ca_cert.crt;
    proxy_ssl_verify       on;
    proxy_ssl_verify_depth 2;
    ...
}

每一个新的 SSL 连接都需要在服务端和客户端进行一个完整的 SSL 握手过程,这非常耗费 CPU 计算资源。为了是 nignx 代理预先协商连接参数,使用一种简略的握手过程,增加proxy_ssl_session_reuse指令配置:

location /upstream {
    ...
    proxy_ssl_session_reuse on;
    ...
}

可选的,你也可以配置使用的 SSL 协议和 SSL 秘钥算法:

location /upstream {
        ...
        proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        proxy_ssl_ciphers   HIGH:!aNULL:!MD5;
}

配置后端服务器

每一个后端服务器都必须配置成接受 https 连接。每一个后端服务器需要使用ssl_certificatessl_certificate_key指令来指定服务器证书和私钥的文件路径:

server {
    listen              443 ssl;
    server_name         backend1.example.com;

    ssl_certificate     /etc/ssl/certs/server.crt;
    ssl_certificate_key /etc/ssl/certs/server.key;
    ...
    location /yourapp {
        proxy_pass http://url_to_app.com;
        ...
    }
}

使用ssl_client_certificat指令来设定客户端证书的文件路径:

server {
    ...
    ssl_client_certificate /etc/ssl/certs/ca.crt;
    ssl_verify_client      off;
    ...
}

完整示例

http {
    ...
    upstream backend.example.com {
        server backend1.example.com:443;
        server backend2.example.com:443;
   }

    server {
        listen      80;
        server_name www.example.com;
        ...

        location /upstream {
            proxy_pass                    https://backend.example.com;
            proxy_ssl_certificate         /etc/nginx/client.pem;
            proxy_ssl_certificate_key     /etc/nginx/client.key
            proxy_ssl_protocols           TLSv1 TLSv1.1 TLSv1.2;
            proxy_ssl_ciphers             HIGH:!aNULL:!MD5;
            proxy_ssl_trusted_certificate /etc/nginx/trusted_ca_cert.crt;

            proxy_ssl_verify        on;
            proxy_ssl_verify_depth  2;
            proxy_ssl_session_reuse on;
        }
    }

    server {
        listen      443 ssl;
        server_name backend1.example.com;

        ssl_certificate        /etc/ssl/certs/server.crt;
        ssl_certificate_key    /etc/ssl/certs/server.key;
        ssl_client_certificate /etc/ssl/certs/ca.crt;
        ssl_verify_client      off;

        location /yourapp {
            proxy_pass http://url_to_app.com;
        ...
        }

    server {
        listen      443 ssl;
        server_name backend2.example.com;

        ssl_certificate        /etc/ssl/certs/server.crt;
        ssl_certificate_key    /etc/ssl/certs/server.key;
        ssl_client_certificate /etc/ssl/certs/ca.crt;
        ssl_verify_client      off;

        location /yourapp {
            proxy_pass http://url_to_app.com;
        ...
        }
    }
}

在这个示例中, proxy_pass指令设置使用了 "https" 协议,所以 nginx 转发到后端服务器的流量是安全的。

当一个安全的连接第一次从 nginx 转发到后端服务器,将会实施一次完整的握手过程。proxy_ssl_certificate指令设置了后端服务器需要的 PEM 格式证书的文件位置。proxy_ssl_certificate_key指令设置了证书的私钥位置。proxy_ssl_protocolsproxy_ssl_ciphers指令控制使用的协议和秘钥算法。

因为proxy_ssl_session_reuse指令配置,当下一次 nginx 转发一个连接到后端服务器时,会话参数会被重复使用,从而更快的建立安全连接。

proxy_ssl_trusted_certificate指令设置的那个可信 CA 证书文件是用来验证后端服务器的证书。proxy_ssl_verify_depth指令指定了证书链检查的深度。proxy_ssl_verify指令验证证书的有效性。

译注

本文为翻译,英文原文地址:https://www.nginx.com/resources/admin-guide/nginx-https-upstreams/ ,尽量遵循原文,不准确的地方,还请指正,谢谢。


或许明日太阳西下倦鸟已归时