处理终端用户真实IP的“信任链”

背景

Discourse 需要能够识别最终用户的真实 IP 地址。

然而,由于始终存在一个或多个上游 Web 服务器(运行在 Discourse 容器中的 nginx),最终用户从不直接连接到 Discourse。因此,我们需要一种以可信的方式将该信息传递给 Discourse 的方法。

x-forwarded-for 头信息就是解决方案。在本主题中,我将描述正确处理该信息的具体机制,以及我们期望它是如何传播的。

模板

用于信任上游代理的各种模板(例如 cloudflare.template.ymlfastly.template.yml)已更新为在 outlets 中使用可预测的文件名,而不是依赖文本替换(这种方式容易出错)。

文件名

server/real-ip-header.conf

此文件包含运行在容器中的 nginx 将用作真实来源的头信息,例如:

real_ip_header x-forwarded-for;

或者在 Cloudflare 模板中设置的:

real_ip_header cf-connecting-ip;

server/real-ip-recursive.conf

如果此文件存在,它将控制“真实 IP”头信息的递归处理。如果在 Discourse 容器 前面有多个代理,则需要启用此功能。

real_ip_recursive on;

示例

Cloudflare → 负载均衡器 → Discourse 容器(即 nginx + Discourse 本身)

在此设置下,nginx 将收到如下所示的 x-forwarded-for

x-forwarded-for: real_end_user_ip, cloudflare_ip

来自负载均衡器 IP 的连接。

为了处理这种情况,首先 nginx 确定连接的源地址(负载均衡器 IP)是否可信(参见 set_real_ip_from),如果是,则处理 x-forwarded-for 头信息中的最后一个 IP。

由于该 IP 地址是 cloudflare_ip,nginx 需要再次执行此操作,检查 cloudflare_ip 是否可信,并使用下一个 IP 地址 real_end_user_ip

server/set-real-ip-from-ENVIRONMENT.conf

此文件包含告诉 nginx 哪些 IP 地址可信的指令,我们可以根据需要添加尽可能多的文件和指令。

discourse_docker 中的模板会根据需要创建这些文件(例如 set-real-ip-from-cloudflare.conf),如果你有额外需求,可以自行添加。

示例:

如果你在 AWS 中运行,并且在 Discourse 容器前面有一个 ALB,你可以通过将以下内容添加到你的容器定义中(根据你的环境进行调整)来添加一个额外的文件:

run:
  - file:
      path: /etc/nginx/conf.d/outlets/server/set-real-ip-from-aws.conf
      chmod: 644
      # AWS VPC 是 10.42.0.0/16,信任来自 ALB 网络的任何连接
      contents: |
        set_real_ip_from 10.42.66.0/24;
        set_real_ip_from 10.42.67.0/24;
  - file:
      path: /etc/nginx/conf.d/outlets/server/real-ip-header.conf
      chmod: 644
      contents: |
        real_ip_header x-forwarded-for;
4 个赞