Защо macvlan контейнер не може да отговори на VPN клиент
Контейнер macvlan не може да говори със собствения си хост и отговорите му може да излизат през грешен шлюз. Добавете маршрут-посредник от страната на хоста и след това изберете модел на източника.
Представете си Linux хост, който прекратява VPN и също пуска контейнер в macvlan мрежа. LAN е 192.168.60.0/24, контейнерът държи 192.168.60.210, а VPN клиентите идват от 10.95.0.0/24. Клиентът достига услугата, отговорът никога не се връща и всяко правило на защитната стена на хоста изглежда правилно. Този симптом се създава от две отделни ограничения и поправянето на едното оставя другото на място.
Две ограничения, един симптом
Първото ограничение е изолацията: macvlan драйверът на Docker не позволява на контейнер да говори със собствения си хост през родителския интерфейс. Трафикът между стека на хоста и контейнера няма път, независимо как са записани маршрутите на хоста.
Второто ограничение е обратният път. Шлюзът по подразбиране на контейнера обикновено е LAN рутерът, така че отговор, адресиран до VPN клиент, излиза през този рутер. Ако рутерът няма маршрут обратно към VPN пула, отговорът се изхвърля някъде по средата.
Двете повреди изглеждат еднакво от страна на клиента: заявка, която пристига, и отговор, който не идва никога. Те изискват различни поправки и широко masquerade правило може да скрие кое от двете още е счупено. Затова първият тест е снемане на пакети от страната на контейнера, а не още една промяна на защитната стена. Ако заявката там не се появи изобщо, в сила е ограничението за изолация.
Изградете посредника от страната на хоста, тясно
Втори macvlan интерфейс на хоста, прикачен към същия родител в режим на мост, дава на стека на хоста собствена идентичност в този LAN сегмент. Заделете за него адрес извън DHCP пула и извън диапазона на контейнерите и насочвайте само контейнера през него.
ip link add macvlan-vpn link eth0 type macvlan mode bridge ip address add 192.168.60.250/32 dev macvlan-vpn ip link set macvlan-vpn up ip route add 192.168.60.210/32 dev macvlan-vpn src 192.168.60.250
Първата команда създава интерфейса в режим на мост, което е документираната настройка по подразбиране за този драйвер и режимът, който искате за трафик между хост и контейнер. Втората задава /32, за да не се сблъска адресът с LAN префикса, а четвъртата изпраща само адреса на контейнера през посредника.
Не пренасочвайте целия LAN през новия интерфейс. Обикновеният свързан маршрут остава както е, а маршрутът до хоста е умишлено тесен, така че един контейнер да получи път, без останалата част от сегмента да променя поведението си. Маршрут по подразбиране към посредника би бил различен дизайн с различни последствия. Дръжте го конкретен и радиусът на поражение остава малък.
Тези команди променят мрежовите настройки на работещ хост. На устройство или управлявана платформа използвайте поддържания механизъм за конфигурация на платформата, защото интерактивна промяна през root-shell може да не преживее надграждане.
Решете как се запазва източникът
С посредника на място контейнерът може да достигне хоста и въпросът става какъв адрес на източника носи отговорът. Запазването на оригиналния VPN източник е по-чистият модел: контейнерът вижда истинския адрес на клиента и журналите и правилата за достъп на услугата могат да го използват.
За да работи това, мрежовата конфигурация на контейнера трябва за този път да изпраща трафика за 10.95.0.0/24 към 192.168.60.250 като свой шлюз. Това е поддържана настройка на маршрут или шлюз в собствената конфигурация на контейнера, а не трик от страната на хоста. Потвърдете я отвътре в контейнера, вместо да предполагате, че настройката е влязла в сила. Шлюз по подразбиране, който още сочи към LAN рутера, ще продължи да изпраща отговори в същата дупка.
Ако одобреният дизайн вместо това скрива VPN източниците, ограничете транслацията тясно: истинският VPN пул, посредникът като изходящ интерфейс и конкретният контейнер и услуга.
iptables -t nat -A POSTROUTING -s 10.95.0.0/24 -o macvlan-vpn -j SNAT --to-source 192.168.60.250
Съпоставете посредника като изходящ интерфейс, а не тунела. Правило, което посочва тунела като изходящ интерфейс, няма да съвпадне с пакет, насочен към контейнера, а това е грешката, която подобна подредба обикновено съдържа. Дръжте правилото толкова тясно, колкото изречението по-горе, и го преглеждайте, когато пулът се промени.
Проверете от клиента, не от хоста
Заявка от самия хост, вързана към адреса на посредника, доказва, че посредникът може да достигне контейнера. Тя не доказва, че контейнерът може да върне трафик към запазен източник 10.95.0.x, защото адресът на източника в този тест е собственият адрес на посредника.
curl -sS --interface 192.168.60.250 -o /dev/null -w '%{http_code}\n' http://192.168.60.210:8080/health
sudo tcpdump -ni macvlan-vpn host 192.168.60.210Първата команда тества отсечката от хоста до контейнера, а втората показва какво всъщност преминава през посредника, докато истински VPN клиент прави заявката. Погледнете адреса на източника по пътя на входа и дали се появява отговор със същия поток.
На хоста трябва да е включено препращането и пътят за препращане се нуждае от разрешение за VPN пула към посредника на порта на услугата плюс установените отговори. Правило INPUT на хоста не разрешава препращан трафик и това е честа причина пакетът да бъде изхвърлен, след като маршрутизацията изглежда правилна.
Пуснете истинското приложение с истински идентификационни данни, после проверете дали втора, несвързана услуга на същия контейнер все още ви отказва. Ако единственият начин да го накарате да работи беше да отворите всяко правило за препращане, дизайнът не е завършен. Отбележете и кой адрес на източника е записала услугата, защото точно него ще използват собствените ѝ правила за достъп.