новая версия модуля ngx_http_realip_module
Maxim Dounin
mdounin на mdounin.ru
Пн Июн 12 01:26:57 UTC 2023
Hello!
On Mon, Jun 12, 2023 at 02:31:04AM +0300, Gena Makhomed wrote:
> On 09.06.2023 9:29, Maxim Dounin wrote:
>
> >> (1) client ==> vps_server ==> main_server
> >>
> >> (2) client ==> cloudflare => vps_server ==> main_server
>
> > Если у вас в обоих случаях vps_server проксирует всё через stream
> > с proxy_protocol, то на принимающей стороне вам в любом случае
> > надо сначала достать реальный адрес клиента из proxy_protocol.
> > А уже потом смотреть в заголовки (или не смотреть, если на
> > vps_server пришли не с IP-адресов Cloudflare).
> >
> > То есть, фактически, для корректной работы такой схемы - нужен
> > "real_ip_recursive on;" (http://nginx.org/r/real_ip_recursive)
> > и заголовок со списком нужных адресов.
> >
> > Сейчас из коробки такое можно сделать дополнительным
> > проксированием с установкой заголовка. Для стандартного заголовка
> > X-Forwarded-For, благо Cloudflare его ставит, конфигурация будет
> > выглядеть как-то так:
> >
> > server {
> > listen 8080 proxy_protocol;
> >
> > set_real_ip_from <vps>;
> > real_ip_header proxy_protocol;
> >
> > location / {
> > proxy_pass http://127.0.0.1:8081;
> > proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
> > }
> > }
> >
> > server {
> > listen 8081;
> >
> > set_real_ip_from 127.0.0.1;
> > set_real_ip_from <cloudflare>;
> >
> > real_ip_header X-Forwarded-For;
> > real_ip_recursive on;
> >
> > ...
> > }
>
> Это будет работать только в том случае, если система защиты от DDoS
> указывает IP адрес клиента в заголовке X-Forwarded-For. Если же какая-то
> экзотическая система защиты от DDoS будет указывать реальный IP клиента
> в каком-то другом заголовке, например, только в загловке X-Real-IP -
> тогда этот метод работать не будет, потому что в nginx есть переменная
> $proxy_add_x_forwarded_for но в nginx нет перменной $proxy_add_x_real_ip
>
> Что же нам делать в том случае, если какая-то система защиты от DDoS
> передает реальный IP клиента в заголовке отличном от X-Forwarded-For ?
Если нужно работать с нестандартными заголовками - это можно
сделать с помощью модуля map, благо сейчас его возможностей с
лихвой хватает для реализации логики, аналогичной работе
переменной $proxy_add_x_forwarded_for.
Не говоря уже о том, что, по большому счёту, в данной конкретной
задаче полная логика $proxy_add_x_forwarded_for не важна, и вполне
можно обойтись безусловным добавлением адреса через запятую:
proxy_set_header X-Real-IP "$http_x_real_ip, $remote_addr";
В вырожденном случае пустого $http_x_real_ip будет лишняя запятая
в начале, но на работоспособность это не влияет.
> >> Или существует какой-то еще лучший вариант решения этой задачи?
> >
> > Я периодически думаю о том, чтобы научить модуль realip брать
> > список IP-адресов не из заголовка, а непосредственно из
> > переменной. Тогда необходимость в дополнительном проксировании в
> > подобных странных конфигурациях отпадёт.
>
> Каким же образом тут можно будет обойтись без двойного проксирования,
> если необходимо будет сначала указывать real_ip_header proxy_protocol;
> чтобы узнать реальный IP сервера cloudflare, который подключился к VPS,
> и при этом - несколько директив real_ip_header нельзя указывать в одном
> контексте. А если указать одну директиву real_ip_header одновременно
> и в контексте server и одну в контексте location, то согласно правил
> наследования директив в nginx - директива real_ip_header в контексте
> location будет выполняться, а директива real_ip_header в контексте
> server выполняться не будет, и всегда будет просто проигнорирована.
>
> Максим, можете пояснить в чем тут моя ошибка и что я не так понял?
Идея состоит в том, что вместо указания названия заголовка в
директиве real_ip_header - указать непосредственно адреса. Тогда
вместо
real_ip_header proxy_protocol;
можно будет написать что-то вроде:
real_ip_address $proxy_protocol_addr;
А для последующего рекурсивного поиска в заголовке X-Forwarded-For
(если он получен с доверенного адреса), соответственно, будет
достаточно написать:
real_ip_address "$http_x_forwarded_for, $proxy_protocol_addr";
И, соответственно, полная конфигурация будет выглядеть как:
server {
listen 8080 proxy_protocol;
set_real_ip_from <vps>;
set_real_ip_from <cloudflare>;
real_ip_address "$http_x_forwarded_for, $proxy_protocol_addr";
real_ip_recursive on;
...
}
То есть ровно то, что в примере выше делается с помощью
дополнительного проксирования - в такой схеме будет сделано с
помощью установки переменной.
[...]
> Максим, вопрос в том, можно ли будет в основной ветке nginx заменить
> текущую версию модуля ngx_http_realip_module новой версией модуля,
> в которой будет реализован вариант директивы set_real_ip_from
> с одним, тремя и пятью параметрами?
Я не вижу решительно никаких причин переусложнять работу модуля
подобным образом. Имеющиеся задачи вполне решаются с помощью
существующих возможностей модуля, что и было продемонстрировано в
исходном ответе. С помощью минимальных (в первую очередь с точки
зрения пользователя) доработок можно сделать так, чтобы подобные
задачи решались эффективнее - однако, как уже было сказано, острой
необходимости в этом пока не прослеживается.
[...]
--
Maxim Dounin
http://mdounin.ru/
Подробная информация о списке рассылки nginx-ru