Тек Docker контейнерлерінің трафигін OpenVPN арқылы бағыттау жолы
Хостты әдеттегі uplink-те қалдырып, бір контейнер ішкі желісін туннельге салыңыз: NAT реті, бастау ережелері, OpenVPN iroute және MSS тексерулері.
Контейнер пакеті ешқашан tun0 -ға жетпейді және контейнердегі қосымша мүмкіндіктер оны өзгертпейді. Қонақ пен туннель арасында екі маршрут іздеуі бар: біреуі қонақтың желілік аттар кеңістігінде, екіншісі кадр көпірге түскеннен кейін хостта, ал екіншісі басқа сәйкестік ережелері бар басқа кестеден сұрайды. Менің эталондық схемам — Linux хосты, онда OpenVPN клиенті жұмыс істейді, ол 10.8.0.10 -ны tun0 -да ұстайды, 172.18.0.0/16 -да Docker көпірі және тек туннель жағы жете алатын жеке мекенжай бар. Мақсат тар күйінде қалады: сол қонақ ішкі желісі туннель арқылы шығады, ал хост әдеттегі uplink-ін сақтайды.
VPN клиентін контейнердің ішінде жүргізу — басқа дизайн, қысқа жол емес. Сонда контейнер өз туннелі мен тіркелгі деректеріне ие болады, ал жұмыс iptables-те қалмай Dockerfile-ға көшеді.
Қайта жіберу маршрутты межелі орын бойынша таңдайды, содан кейін NAT бастауды қайта жазады
Орнатылған кезде net.ipv4.ip_forward=1 , қайта жіберілген пакет тек межелі орын бойынша, негізгі кестеде маршрутталады. Бастау бұл шешімге қатыспайды. Маршрут таңдалғаннан кейін ғана ядро POSTROUTING -ны орындайды, және дәл сол жерде Docker-тің өз ережесі тұр: -s 172.18.0.0/16 ! -o br-appnet -j MASQUERADE. Көпірден басқа интерфейске шығатынның бәрі аударылады, ал ол қандай мекенжайға айналатыны маршрут оны қай интерфейске жібергеніне байланысты.
Бұл ереже маған жиі қойылатын симптомдардың көбін түсіндіреді. Егер негізгі кестеде жеке межелі орынға маршрут болмаса, пакет хосттың физикалық мекенжайымен uplink-тен шығады. Провайдеріңіз межелі орынды тастайды, немесе алыс сайт күтпеген RFC 1918 бастауын тастайды, ал туннель тұрып, сау күйінде контейнер уақыттан өтеді. tun0 -дағы түсірілім ештеңе көрсетпейді, және бұл — белгі. Егер маршрут шынымен tun0 -ға нұсқаса, MASQUERADE бастауды 10.8.0.10 -ға қайта жазады, және сол контейнер сіз ештеңеге тиіспей-ақ жұмыс істейді.
Қонақтың бастауын атайтын іздеуді сұраңыз. from және iif болмаса, хост өз сокеті үшін жауап береді және қайта жіберілген пакет ешқашан түспейтін жолды хабарлайды:
ip route get 192.168.11.222 from 172.18.0.5 iif br-appnetЕгер бұл жауап uplink-ті атаса, туннель суретте жоқ, және туннель жағындағы ешбір параметр көмектеспейді.
Қонақты туннельдің өз мекенжайына көшіріңіз
Ең кішкентай жұмыс істейтін өзгеріс — шығыста бастауды айқын қайта жазу. Оны қосудың орнына кірістіріңіз: Docker әлдеқашан POSTROUTING -ның басында отыр, сондықтан -A -мен қосылған ереже Docker-дікінен кейін бағаланады және ешқашан іске қосылмайды.
iptables -t nat -I POSTROUTING 1 -s 172.18.0.0/16 -o tun0 -j SNAT --to-source 10.8.0.10Бұл сақтала ма, оны екі шарт шешеді. Мекенжай клиент шынымен ұстайтын мекенжай болуы керек, сондықтан оны әр клиент үшін ifconfig-push 10.8.0.10 255.255.255.0 -ны қамтитын жазбамен бекітіңіз; ешқашан берілмеген мекенжайды атайтын ереже тыныш тастаулар тудырады, қате емес. Ал алыс жақ бұл бастауды қабылдап, жауаптарды кері бағыттауы керек, сондықтан ондағы рұқсат тізімі қонақ ішкі желісін емес, туннель мекенжайын атайды. Клиент мекенжайы динамикалық болса, -j MASQUERADE -мен -o tun0 интерфейстегінің соңынан ереді, бірақ тіркелген мәнге қарсы жаза алмайтын алыс саясаттың құнымен.
Сүзгілеу — екінші жарты. Docker FORWARD саясатын drop-қа қояды және әр демон қайта іске қосылғанда өзіне тиесілі тізбектерді тазалайды, сондықтан жергілікті саясатты DOCKER-USER -ға салыңыз, ол аман қалады:
iptables -I DOCKER-USER -i br-appnet -o tun0 -j ACCEPT
iptables -I DOCKER-USER -i tun0 -o br-appnet -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPTҚайтару ережесі маңызды: tun0 -ға келетін жауап көпір арқылы ашылған байланыс үшін тек шығыс бағыты қабылданғандықтан қабылданбайды.
Хостты бастау ережесімен тікелей ұстаңыз
Бүкіл көпір туннельді қолдануы керек, бірақ хостта басқа ештеңе болмауы керек болса, NAT-ты өткізіп жіберіп, сол бастауға өз кестесін беріңіз. Қонақ мекенжайлары содан кейін басынан аяғына дейін көрінеді.
echo "200 vpnbox" >> /etc/iproute2/rt_tables
ip rule add from 172.18.0.0/16 lookup vpnbox pref 1000
ip route add default dev tun0 table vpnboxЕрежелер негізгі кестеден бұрын қаралады, және from бастауға сәйкес келеді. Туннельдің өз сыртқы пакеттері хосттың физикалық бастауын тасиды, сондықтан олар ешқашан from 172.18.0.0/16 -ға сәйкес келмейді, және туннель өзін өзіне кері бағыттай алмайды. Дәл осы өзін-өзі шығарып тастау схеманы тұрақты етеді.
Қайтару жолына енді көмек керек. Алыс жақ аударылмаған 172.18.0.x -ны көреді және оның қайда тұратынын білуге себебі жоқ. Серверде әр клиент үшін файлға iroute 172.18.0.0 255.255.0.0 керек, сервердің ішкі кестесі сол префиксті осы клиентке берсін, және итерілген route 172.18.0.0 255.255.0.0 керек, басқа клиенттер оның бар екенін білсін.
Сенудің алдында екі тексеру. Іске қосыңыз ip route show default -ды: redirect-gateway def1 -мен кестеде 0.0.0.0/1 және 128.0.0.0/1 бар tun0 арқылы, ал хост мүлде тікелей емес, өйткені бұл жарты-әдепкілер default -ны алмастырмай жеңеді. ip rule add -мен қосылған ережелер де қайта жүктеуде жоғалады, сондықтан оларды up скриптіне алып жүріңіз.
Пакет өлшемі — екінші кездесетін ақау
1500 байттық көпір интерфейсі сыртқы UDP және IP тақырыптары қосылғанда туннельге ол көтере алатыннан көбірек береді. Кіші алмасулар өтеді, сондықтан DNS шешіледі және TLS қол алысуы аяқталады, содан кейін үлкенірек жүктеу еш жерде қатесіз ілініп қалады. Жіберуші сол сегмент өлшемін қайталай береді, өйткені оған кішірею керек деп айтатын ICMP фрагментация қажеттілігі туралы хабарлама ешқашан жетпейді.
Оны интерфейсте, MSS-те немесе екеуінде де түзетіңіз. Қысу қонақтың ынтымақтастығын қажет етпейді:
ip link set dev tun0 mtu 1400
iptables -t mangle -A FORWARD -o tun0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtuҚысу тек TCP-ны қайта жазады. UDP, QUIC қоса, оның орнына төмендетілген қонақ интерфейсін қажет етеді, --opt com.docker.network.driver.mtu=1400 -мен желі құру кезінде немесе сәйкес compose кілтімен.
DNS және қайталауға тұрарлық тексерулер
Аттарды шешу сол жолмен жүреді. Docker-дің кіріктірілген шешушісі 127.0.0.11 -да хосттың конфигурацияланған серверлеріне жібереді, сондықтан контейнер хост қолданатынды мұраға алады. Жеке аймаққа тек туннель арқылы жететін шешуші жауап берсе, қонақты сол мекенжайға бағыттаңыз, және getent hosts -мен контейнердің ішінде тексеріңіз, хостта емес.
- Сәтсіз сұранысты қонақтың ішінде іске қосыңыз; хост жағындағы тест басқа бастау мекенжайын қолданады және мәселені жасырады.
- Қосқан NAT және сүзгі ережелерінің санауыштарын оқыңыз. Нөлдік сәйкестігі бар ереже — маршруттау қатесі, саясат қатесі емес.
- SNAT ережеңіздегі туннель мекенжайы клиент шынымен ұстайтын мекенжай екенін растаңыз.
- Серверді тоқырауға кінәламас бұрын қонақтың MTU-ін төмендетіңіз немесе MSS-ті қысыңыз.
Тізіммен төмен жүріп, бірінші ақауда тоқтаңыз. Дәл сол қабатты түзету керек; төменірек қосылғанның бәрі сынып жатқан шекараны ғана жасырады.