iptables – в nginx не работает “proxy_bind transparent”

Вопрос или проблема

Я использую nginx для мультиплексирования SSH и HTTPS, используя этот файл /etc/nginx/nginx.config:

stream {
    upstream ssh {
        server 127.0.0.1:22;
    }

    upstream https {
        server 127.0.0.1:8443;
    }
    
    map $ssl_preread_protocol $upstream {
        default ssh;
        "TLSv1.2" https;
        "TLSv1.3" https;
        "TLSv1.1" https;
        "TLSv1.0" https;
    }

    server {
        listen 443;
        proxy_pass $upstream;
        ssl_preread on;
    }
}

Трафик успешно перенаправляется, но имеет побочный эффект: все подключения выглядят как идущие с 127.0.0.1 как для SSH, так и для HTTPS:

$ last
jason    pts/3        127.0.0.1        Wed Feb 19 22:25 - 22:25  (00:00)
...
$ tail -1 /var/log/nginx/access.log
127.0.0.1 - - [19/Feb/2025:20:31:36 +0100] "GET /favicon.ico HTTP/1.1" 200 1406 "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, как Gecko) Chrome/132.0.0.0 Safari/537.36"

Я попробовал прозрачное проксирование, изменив файл /etc/nginx/nginx.config следующим образом:

user root; # было: www-data
...
   server {
      listen 443;
      proxy_bind $remote_addr transparent;
      proxy_pass $upstream;
      ssl_preread on;
   }
...

Однако это вызывает зависание и тайм-аут входящих ssh и https соединений. Я пытался отключить брандмауэр ufw, но это не дает эффекта.

Документация proxy_bind не очень конкретна по поводу того, что нужно делать: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_bind

Для работы этого параметра обычно необходимо запускать рабочие процессы nginx с привилегиями суперпользователя. В Linux это не требуется (1.13.8), поскольку, если задан параметр transparent, рабочие процессы наследуют возможность CAP_NET_RAW от основного процесса. Также необходимо настроить таблицу маршрутизации ядра для перехвата сетевого трафика от проксируемого сервера.

Я изменил на user root; и запускаю nginx через sudo systemctl start nginx, так что, вероятно, с привилегиями суперпользователя я разобрался, верно?

Как мне “настроить таблицу маршрутизации ядра для перехвата сетевого трафика от проксируемого сервера”? Обратите внимание, что я в данный момент использую ufw для настройки iptables, если это имеет значение.

Ответ или решение

Конфигурация прозрачного прокси с использованием nginx может быть сложной задачей, особенно когда необходимо правильно настроить iptables и маршрутизацию ядра для сетевого трафика. Рассмотрим подробнее вашу ситуацию.

Теория

Когда вы используете nginx для проксирования SSH и HTTPS с помощью proxy_bind transparent, цель состоит в том, чтобы конечные серверы (здесь это SSH и HTTPS серверы на локальной машине) видели исходные IP-адреса клиентов, а не IP-адрес прокси (127.0.0.1 в вашем случае). Для этого необходимо выполнить несколько важных шагов.

  1. Прозрачное Проксирование: Во-первых, более чем одной прослойке программного обеспечения необходимо поддерживать прозрачное проксирование. Nginx с proxy_bind transparent позволяет ему перенаправлять исходные IP-адреса дальше, но это также требует поддержки на уровне системы и сети.

  2. Настройка iptables: Вам необходимо настроить правила iptables для изменения исходного IP-адреса в пакетах, проходящих через ваш сервер. Это включает использование маркеров, таких как TPROXY.

  3. Маршрутизация ядра: На уровне ядра Linux, необходимы изменения в таблице маршрутизации, чтобы перехватывать и изменять трафик, проходящий через ваш сервер.

Пример

Рассмотрим практическую конфигурацию и шаги.

  1. Привилегии и права доступа:

    • Убедитесь, что nginx работает от имени root, или что он имеет необходимые права (например, CAP_NET_RAW).
  2. Настройка iptables:

    • Вам нужно использовать механизм mangle в iptables. Вот пример правил:

      iptables -t mangle -N DIVERT
      iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
      iptables -t mangle -A DIVERT -j MARK --set-mark 1
      iptables -t mangle -A DIVERT -j ACCEPT
      
      ip rule add fwmark 1 lookup 100
      ip route add local 0.0.0.0/0 dev lo table 100
    • Эти правила позволяют маркеровать трафик для локальной маршрутизации.
  3. Настройки sysctl:

    • Проверьте, что у вас настроены правильные параметры sysctl:
      sysctl -w net.ipv4.ip_forward=1
      sysctl -w net.ipv4.conf.all.route_localnet=1

Применение

Применив все шаги, вы обеспечиваете, что nginx может действовать как прозрачный прокси. Однако ошибки могут возникнуть, если какой-то из шагов выполнен неправильно.

  1. Проверка nginx:

    • После всех изменений перезапустите nginx и убедитесь, что он работает без ошибок конфигурации.
  2. Журналирование и диагностика:

    • Воспользуйтесь логами nginx и системными журналами, такими как journalctl, для отслеживания потенциалальных ошибок.
  3. Тестирование:

    • Проверьте, что конечные серверы теперь видят правильные удаленные IP-адреса.

Заключение

Ваша конфигурация включает много движущихся частей, и каждая из них должна работать корректно. Если шаги выполнены верно, nginx сможет поддерживать прозрачное проксирование без изменения IP-адресов исходных клиентов. Возможные проблемы могут быть связаны с неправильно установленными правилами iptables или ошибками маршрутизации. Если вы используете ufw, убедитесь, что он не конфликтует с напрямую настроенными правилами iptables, так как это может вызвать неожиданные поведения. Рекомендуется отключить ufw после настройки вышеописанных правил для тестирования корректности работы, или внести необходимые изменения в конфигурацию ufw, чтобы они не конфликтовали.

Оцените материал
Добавить комментарий

Капча загружается...