Защо Port-Share прави всички посетители на сайта да изглеждат като localhost
Бекендът вижда хопа на препращането, а не браузъра. Проверете къде се губи адресът на източника и после решете кой компонент има право да го удостоверява.
Всеки ред в журнала за достъп показва един и същ адрес за loopback, докато страницата се зарежда и сертификатът се проверява успешно. Нищо не е счупено в смисъл на недостъпност и точно затова това положение оцелява с месеци. Счупено е приписването: уеб бекендът записва адреса на хопа, който е препратил връзката, и всяко следващо решение, което се е доверило на журнала, е наследило същия грешен отговор.
Проверките по-долу вървят от кабела навътре. Спрете на първата, която обяснява стойността, която виждате, защото всяка следваща стъпка предполага, че предишните вече са верни. Никоя от тях не изисква да гадаете конфигурацията на фронтенда.
Следвайте двете връзки, а не реда в журнала
Port-Share мултиплексира два протокола на един TCP слушател. OpenVPN преглежда първите байтове на входящата връзка, задържа я, когато изглежда като собствения му протокол, и предава всичко останало на втора дестинация. Тази дестинация обикновено е уеб сървър на същия хост, така че приетият сокет на уеб сървъра има процеса OpenVPN за свой партньор.
ss -ltnp 'sport = :443'
ss -tnp 'dport = :8080'
Първата команда показва кой притежава публичния слушател. Втората показва връзките, пристигащи на порта на бекенда, и адресът на техния партньор е този, който журналът за достъп ще отпечата. Ако този партньор е loopback, журналът е точен и информацията е загубена един слой по-рано. Преименуването на полето в журнала или включването на модул за клиентски IP няма да възстанови адрес, който връзката никога не е носила.
Това е проверката, която решава всичко останало. Ако партньорът на бекенда е адресът на браузъра, споделянето на порт не е вашият проблем, а форматът на журнала.
Пренасочването на транспорта не е инжектиране на хедъри
Препращачът мести байтове. Той не анализира HTTP, затова не може да вмъкне хедър в заявка, която никога не чете като заявка, и не може да добави нищо към TLS поток, който пропуска недокоснат. Модул, който очаква прокси хедър, ще продължи да чака такъв, който нито един компонент не произвежда.
Оригиналният адрес може да се носи от два механизма и двата изискват съгласие от двете страни. Протоколът PROXY добавя малък хедър в началото на връзката и бекендът трябва да е конфигуриран да го очаква; бекенд, който не го очаква, ще приеме тези байтове за начало на заявката и ще се провали по объркващ начин. Доверените прокси хедъри като X-Forwarded-For работят, когато прокси, което разбира HTTP, ги задава, а на бекенда се казва кои партньори имат право да ги твърдят.
Нито едно от двете не е автоматично и нито едно не е безопасно по подразбиране. Бекенд, който вярва на всеки входящ предаден хедър, позволява на клиента да избере собствения си адрес, което превръща неточността в журнала в заобикаляне на контрола за достъп. Изпълнете демонстрацията веднъж на тестов хост, преди да се доверите на който и да е хедър в производствен път.
curl -sS -H 'X-Forwarded-For: 127.0.0.1' https://site.example.com/health
grep -F '127.0.0.1' /var/log/nginx/access.log | tail -n 3
Незадължителната директория за съпоставяне на източници
Споделянето на порт има незадължителен аргумент за директория, който записва съпоставяне между оригиналния адрес на източника и препращащата връзка, на платформи, където функцията е реализирана. Очаква се уеб страната да се допитва до това съпоставяне; то не е хедър и не се вмъква в заявката.
Този дизайн си заслужава да се знае, защото обяснява защо някои разгръщания съобщават реални адреси, а други не, при привидно идентична конфигурация на фронтенда. Разликата е на приемащата страна и обикновено живее в модул или пач, който повечето пакетирани уеб сървъри не включват по подразбиране. Прочетете документацията на вашия уеб сървър за точната кука, която предлага, и потвърдете, че модулът е зареден, вместо да го предполагате.
Ако поемете по този път, третирайте го като интеграция от две половини: съпоставянето, което записва препращачът, и търсенето, което извършва бекендът. Проверете и двете и потвърдете, че директорията оцелява след рестарт и не расте безгранично на натоварен слушател.
Решете кой компонент удостоверява адреса
Преди да промените конфигурацията, назовете компонента, на който е разрешено да твърди адрес на клиент, и компонентите, на които е разрешено да му вярват. Един записан отговор предотвратява обичайното отклонение, при което три различни слоя вярват на различен източник.
Три дизайна покриват повечето нужди. Дръжте публичния слушател и уеб слушателя отделно, така че уеб сървърът да вижда реални партньори и да няма проблем с приписването. Сложете отпред обратен прокси, който разбира HTTP, прекратете или анализирайте заявката там и му позволете да зададе предаден хедър за бекенд, който се доверява само на това прокси. Или запазете споделянето на порт и приемете, че журналите показват хопа, с правила за достъп, написани срещу идентичността на приложението, а не срещу адрес.
Това, което не работи, е да се третира предаден loopback адрес като доказателство, че заявката е възникнала на тази машина. Това заключение е точно обратното: адресът присъства именно защото локален компонент е създал връзката. Правило, написано така, допуска всеки, който може да достигне слушателя.
Тествайте правилото, не страницата
Страница, която се зарежда, доказва, че пътят на препращане работи, и не казва нищо за приписването. Тествайте потребителя на адреса: правилото за достъп, ограничението на честотата, записа в одита, гео справката.
curl -sS -o /dev/null -w '%{http_code}\n' https://site.example.com/
tail -n 5 /var/log/nginx/access.log
grep -c '' /var/log/nginx/access.log
Сравнете разрешена външна заявка с записите както на фронтенда, така и на бекенда и потвърдете, че правило, което трябва да отказва, все още отказва, а това, което трябва да допуска, все още допуска. Ако редът в журнала е правилен, но правилото все още се държи така, сякаш всички са локални, правилото чете друго поле от това, което сте поправили.
Завършете, като запишете веригата на приписване в бележките за разгръщане: кой слушател, кой препращач, кой хедър или съпоставяне и кой бекенд е конфигуриран да му вярва. Следващият човек, който прочете ред в журнала, ще се нуждае от всичките четири, а липсата на тази бележка е начинът, по който същият тикет се отваря отново година по-късно. Дръжте я до конфигурацията, а не в чат нишка.