基于SNI的Nginx代理无需解密

基于SNI的Nginx代理无需解密

我目前正在使用以下(简化)配置通过同一端口代理 http 和 https 连接(aws elastic beanstalk 需要):

server {
    listen 777 ssl;
    server_name foo.com;
    ssl_certificate /etc/nginx/ssl/foo.crt;
    ssl_certificate_key /etc/nginx/ssl/foo;

    root /usr/share/nginx/www;
    index index.html index.htm;

    error_page 418 = @upstream;
    error_page 497 = @upstream;

    location / {
        return 418;
    }

    location @upstream {
        proxy_set_header  X-Forwarded-Proto  $scheme;
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:8080;
    }
}

我想将上游更改为 uwsgi 并让 uwsgi 处理 ssl,因为它可以简化部署。

如何调整我的配置以适用于 SNI HTTPS 和 HTTP,而无需 Nginx 解密 SSL 流量?

答案1

,您无法使用 Nginx 来实现。默认情况下,Nginx 始终解密内容,因此 Nginx 可以应用请求路由。可以尝试以下解决方案:

  • 有第三方模块称为nginx_tcp_proxy_模块。我还没试过。因为那个模块在网络层做代理,所以它会传递请求而不解密。

  • 首选解决方案是使用 HAProxy。本教程建议您可以使用具有 SNI 功能的 TCP 代理。


边注

默认情况下,Nginx 始终在代理上充当 SSL 卸载/解密进程。以下是执行 SSL 卸载的一些优势(取自这里

  • 提高性能
  • 更好地利用后端服务器
  • 智能路由
  • 证书管理
  • 安全补丁程序

答案2

看起来现在支持使用ngx_stream_ssl_preread_module模块

答案3

执行此操作时需要注意以下几点:

  • 您将必须使用stream块而不是http块,这意味着:
  • 您无法设置error_page指令,因为 HTTP 错误代码位于应用层,而您无法解密该层
  • 您无法proxy_pass连接到http://服务器,因为您不再进行 SSL 终止
  • 你不能,proxy_set_header因为你不能将纯文本注入加密流中

如果您接受这些限制,例如,您将在另一台服务器(作为最终目的地或执行 SSL 终止的中间代理)上进行工作,那么您需要执行以下操作:

  1. 首先,请注意,大多数 nginx 服务器配置都会自动将所有内容包装在一个http块中。因此,如果您习惯于/etc/nginx/conf.d在 Red Hat 类型的安装中直接放入文件,或者在 Debian 类型的安装/etc/nginx/sites-available中使用符号链接/etc/nginx/sites-enabled,那么这在这里行不通。您必须对根配置文件进行至少一些小的更改/etc/nginx.conf,即使只是为了创建一个包含其他文件的流块,如下所示:

    stream {
        include /etc/nginx/stream.d/*.conf;
    }
    
  2. 接下来,您需要创建一个流服务器。您只能使用模块中的指令ngx_stream_*,这些指令不包括所有特定于 HTTP 的内容。正如 Robert Wagner 的回答所指出的那样,您需要使用ngx_stream_ssl_preread1.11.5 之前的 nginx 版本中不存在的模块。.conf/etc/nginx/stream.d或您选择的任何其他目录中创建一个扩展名为 的文件,并定义您的服务器。以下内容逐字摘自模块文档中的内容,并给出了基于 SNI 的过滤示例(还有可用的 ALPN 和 SSL 版本过滤):

    map $ssl_preread_server_name $name {
        backend.example.com      backend;
        default                  backend2;
    }
    
    upstream backend {
        server 192.168.0.1:12345;
        server 192.168.0.2:12345;
    }
    
    upstream backend2 {
        server 192.168.0.3:12345;
        server 192.168.0.4:12345;
    }
    
    server {
        listen      12346;
        proxy_pass  $name;
        ssl_preread on;
    }
    
  3. 现在,您有一台服务器,它不会解密流量,但会根据 SNI 确定将其发送到何处。如果客户端连接并发出请求,backend.example.com则它将被路由到backend,否则它将被路由到backend2

您可能还需要考虑其他事项,例如设置tcp_nodelay或定义流log_format并启用access_logstream,但格式和变量当然与 HTTP 访问日志不同。

相关内容