Обработка "цепочки доверия" реального IP-адреса конечного пользователя

Введение

Discourse должен знать реальный IP-адрес конечного пользователя.

Однако конечный пользователь никогда не подключается к Discourse напрямую, поскольку всегда присутствует один или несколько вышестоящих веб-серверов (nginx, работающий в контейнере Discourse). Таким образом, нам необходим способ надежной передачи этой информации в Discourse.

Решением является заголовок x-forwarded-for. В этой теме я опишу конкретные механизмы корректной обработки этой информации и то, как мы ожидаем её распространения.

Шаблоны

Различные шаблоны для доверия вышестоящим прокси-серверам (например, cloudflare.template.yml или fastly.template.yml) были обновлены, чтобы использовать предсказуемые имена файлов в outlet-ах, вместо того чтобы полагаться на подстановку текста (которая является ненадежной).

Имена файлов

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), и если да, обрабатывает последний IP-адрес в заголовке x-forwarded-for.

Поскольку этот 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 и у вас есть ALB перед контейнером Discourse, вы можете добавить дополнительный файл, добавив следующее в определение вашего контейнера (адаптированное под вашу среду):

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 лайка