Пытаясь выяснить, почему наша установка Varnish 4.1 (на CentOS7 через репозиторий varnish-cache.org) не следовала правилам vcl, установленным для регистрации IP-адреса клиента в заголовке X-Forwarded-For (см. Varnish 4 регистрирует прокси / балансировщик нагрузки вместо IP-адресов клиентов) При просмотре файлов varnishlog я заметил что-то странное:
- Begin req 9353447 rxreq
- Timestamp Start: 1488771709.337974 0.000000 0.000000
- Timestamp Req: 1488771709.337974 0.000000 0.000000
- ReqStart 172.25.20.65 19903
- ReqMethod GET
- ReqURL /about-us/
- ReqProtocol HTTP/1.1
- ReqHeader host: www.<notreallythishost>.com
- ReqHeader Accept: */*
- ReqHeader Accept-Encoding: gzip, deflate
- ReqHeader Cache-Control: no-cache
- ReqHeader From: bingbot(at)microsoft.com
- ReqHeader Pragma: no-cache
- ReqHeader User-Agent: Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)
- ReqHeader X-Forwarded-For: 40.77.167.41
- ReqHeader X-Forwarded-Port: 80
- ReqHeader X-Forwarded-Proto: http
- ReqHeader Connection: keep-alive
- ReqUnset X-Forwarded-For: 40.77.167.41
- ReqHeader X-Forwarded-For: 40.77.167.41, 172.25.20.65
- VCL_call RECV
- ReqUnset X-Forwarded-For: 40.77.167.41, 172.25.20.65
- ReqHeader X-Forwarded-For: 172.25.20.65
- ReqUnset Accept-Encoding: gzip, deflate
- ReqHeader Accept-Encoding: gzip
- ReqUnset User-Agent: Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)
- VCL_return hash
- VCL_call HASH
- VCL_return lookup
- VCL_call MISS
- VCL_return fetch
- Link bereq 9353449 fetch
- Timestamp Fetch: 1488771709.338395 0.000421 0.000421
- RespProtocol HTTP/1.1
Это полностью объясняет, почему мы никогда не могли получить что-либо, кроме IP-адреса балансировщика нагрузки, зарегистрированного через varnishncsa в любой момент, независимо от используемой нами техники ведения журнала.
Похоже, что в процессе обработки запроса он создает заголовок X-Forwarded-For, добавляя IP-адрес AWS Load Balancer в заголовок, но при вызове vc_call он снова отключает его и удаляет исходный IP-адрес клиента. Итак, как мне сохранить целостность X-Forwarded-For и почему Varnish смещает IP-адреса с левой стороны, а не просто добавляет их в заголовок X-Forwarded-For, как следует? Ошибка?
Таким образом, обходной путь для этого (возможная ошибка в 4.1.3-1.el7.x86_64) был подсказкой, которую я нашел при просмотре других вопросов о журналировании лака, в частности, о полное отключение заголовка x-forwarded-for.
Хотя это не то, что я хотел сделать, он дал подсказку о том, как предотвратить добавление varnish собственного содержимого vcl_recv в нижнюю часть моего определения функции vcl_recv. Специально предоставьте свой собственный возврат (поиск) (хотя это лак <= 3) или возврат (хеш) (лак 4.х).
Итак, теперь у меня есть это в верхней части vcl_recv ():
# ensure proper logging of x-forwarded-for IP addresses
std.collect(req.http.x-forwarded-for);
set req.http.x-forwarded-for = regsub ( req.http.x-forwarded-for, "^(([0-9]{1,3}\.){3}[0-9]{1,3})(.*)", "\1" );
if (req.http.x-forwarded-for) {
std.log("ip:" + req.http.x-forwarded-for);
} else {
std.log("ip:" + client.ip);
}
Затем в самом конце функции, как я уже упоминал, у меня есть:
return (hash);
Таким образом, теперь он успешно регистрирует только IP-адрес клиента, как и должно быть, с добавлением опции varnishncsa:
-F "%%{VCL_Log:ip}x %%l %%u %%t \"%%r\" %%s %%b \"%%{Referer}i\" \"%%{User-agent}i\""
Надеюсь, кто-то еще найдет эту информацию полезной.
ОБНОВИТЬ: В качестве примечания я нашел это сообщение о спуфинге в этом ответе nginx и было бы неплохо иметь своего рода real_ip_from или доверенный_ip_from заголовки также в лаке, но в настоящий момент это не так. В этом случае мое первоначальное решение выберет поддельный адрес. Поэтому было бы лучше удалить регулярное выражение с известными IP-адресами, и вместо этого вы выберете первый необработанный IP-адрес клиента. Что-то вроде этого могло бы работать:
set req.http.x-forwarded-for = regsub ( req.http.x-forwarded-for, "(([0-9]{1,3}\.){3}[0-9]{1,3})(, (172.25.20.65|172.25.10.228),?)+$", "\1" );
где 172.25.20.65 и 172.25.10.228 - мои доверенные IP-адреса (прокси или балансировщики нагрузки, выбранные и добавленные в X-Forwarded-For и т. д.). В зависимости от того, ожидаете ли вы увидеть прокси / LB перед ним, ваше регулярное выражение может быть таким, если вы ожидаете, что в вашем заголовке всегда будет хотя бы один балансировщик нагрузки / прокси:
(([0-9]{1,3}\.){3}[0-9]{1,3})(, (<trustedip1>|<trustedip2>|...),?)+$
или это, если допустимо ничего не иметь перед лакировочным сервером:
(([0-9]{1,3}\.){3}[0-9]{1,3})(, (<trustedip1>|<trustedip2>|...),?)*$
Хотя в последнем случае зачем вам искать заголовок x-forwarded-for ...