Чаму кантэйнер Docker не дасягае хастоў за VPN
Кантэйнеры моста маюць уласную прастору імёнаў, таму тунель хоста ім не бачны. Параўнайце сетку хоста, прыладу tun і macvlan, перш чым правіць DNS.
Кантэйнер, які не дасягае нічога за карпаратыўным VPN, звычайна жыве ў іншай сеткавай прасторы імёнаў, чым тунель. Маршруты кліента хоста, DNS-серверы і пазнакі міжсеткавага экрана належаць стэку хоста; кантэйнер сеткі моста мае свой. Гэты адзіны факт тлумачыць большасць паведамленняў, якія атрымлівае каманда платформы, і ён жа тлумачыць, чаму «VPN зламаны» і «Docker абыходзіць VPN» могуць быць памылковымі адначасова. За адным сімптомам хаваюцца два цалкам розныя ўладкаванні, таму вызначце, якое ў вас, перш чым змяняць наладу.
Вызначце, чыя прастора імёнаў валодае тунелем
У Docker Desktop для macOS або Windows кантэйнеры працуюць унутры віртуальнай машыны Linux. VPN-кліент, усталяваны на працоўным стале, стварае тунель у аперацыйнай сістэме працоўнага стала, і віртуальная машына яго ніколі не бачыць. Ніякая налада кантэйнера гэтага не выправіць, бо інтэрфейс, які патрэбны кантэйнеру, у яго сеткавай прасторы імёнаў наогул не існуе.
На хосце Linux тунель жыве ў прасторы імёнаў хоста, і кантэйнеры моста звычайна дасягаюць яго праз табліцу маршрутызацыі хоста з трансляцыяй крынічнага адраса на выхадзе. Калі гэты шлях адмаўляе, прычынай звычайна бывае палітыка перасылкі, фільтрацыя зваротнага шляху або сетка, якая перасякаецца, а не адсутны маршрут. Пацвердзіце, у якім з двух светах знаходзіцеся, перш чым чытаць далей:
docker info --format '{{.OperatingSystem}}'
docker run --rm --net=host alpine ip route | head -5
docker run --rm alpine ip route | head -5
Розніца паміж гэтымі дзвюма табліцамі маршрутызацыі — гэта ўся праблема на адным экране. Калі від хоста змяшчае тунельны інтэрфейс, а від моста не, вы бачыце ізаляцыю прастор імёнаў, і ўсё астатняе — гэта выбар, як яе перасекчы.
Сетка хоста — гэта тэст, а не дызайн
Запуск кантэйнера з сеткай хоста, якую Docker апісвае як супольнае выкарыстанне сеткавай прасторы імёнаў хоста, прымушае яго напрамую ўспадкаваць тунельны інтэрфейс і яго маршруты. Калі той жа запыт пасля гэтага паспяховы, тэорыя маршрутаў пацверджана, і збой — гэта ізаляцыя прастор імёнаў, а не ўліковыя даныя, DNS або правіла доступу.
docker run --rm --net=host curl -sS -o /dev/null -w '%{http_code}\n' https://api.internal/health
Пакіньце гэта як сродак дыягностыкі. Сетка хоста адмаўляецца ад публікацыі партоў і большай часткі ізаляцыі, якую вы хацелі ад кантэйнера, а ў Docker Desktop «host» азначае віртуальную машыну, а не працоўны стол, таму поспех або збой там можа ўвесці ў зман, калі вы забудзецеся, да якога хоста звярталіся.
Прылада tun і прывілеі, якія да яе дадаюцца
VPN-кліенту ўнутры кантэйнера патрэбна тунельная прылада і дазвол на яе наладку. Звычайны кароткі шлях — --privileged, які дае доступ да ўсіх прылад і паслабляе палітыку бяспекі ва ўсім кантэйнеры. Гэта значна больш, чым патрабуе гэтая задача, і гэта цяжка апраўдаць на разглядзе.
sudo modprobe tun
docker run --rm -it --device /dev/net/tun --cap-add NET_ADMIN myvpn-client
Больш вузкая форма адлюстроўвае адзін вузел прылады і дадае толькі магчымасць адміністравання сеткі. Спачатку загрузіце модуль на хосце, каб вузел існаваў. Калі кантэйнер запускаецца і кліент паведамляе, што не можа адкрыць тунельную прыладу, праверце адлюстраванне, перш чым падазраваць профіль, бо гэтая памылка звычайна літаральная.
Гэты дызайн таксама азначае, што кліент працуе асобна для кожнага кантэйнера. Гэта правільны адказ, калі кожнаму працоўнаму напружанню патрэбен уласны тунель, і няправільны, калі вы проста хацелі, каб тунель хоста быў бачны, што каманда платформы, верагодна, і меркавала.
NAT моста змяняе крыніцу, якую бачыць VPN
Пры стандартным мосце зыходны трафік кантэйнера транслюецца ў адрас хоста. Таму за VPN карпаратыўны бок бачыць тунельны адрас хоста, а не кантэйнера, правілы доступу па крыніцы паводзяць сябе так, нібы запыт зрабіў хост, і два кантэйнеры становяцца неадрознымі для VPN-сервера.
macvlan або ipvlan замест гэтага дае кантэйнеру адрас LAN, што дапамагае выяўленню ў LAN і робіць кантэйнер падобным на роўнага ў сегменце. Ён таксама цалкам абыходзіць тунель хоста, таму такі кантэйнер не дасягне прэфіксаў толькі-VPN, калі VPN недасяжны і з гэтай LAN.
Абедзве формы законныя; яны адказваюць на розныя патрабаванні. Калі патрабаванне — «гэты кантэйнер павінен дасягаць сэрвісу толькі-VPN», вы выбіраеце паміж маршрутызацыяй праз хост і завяршэннем тунеля ўнутры кантэйнера. Запішыце гэты выбар да разгортвання, а не пасля першага няўдалага запыту. Што б вы ні выбралі, запішыце адрас крыніцы, які ўбачыць далёкі бок, бо менавіта яго пакажуць яго правілы доступу і яго журналы. Дызайн, які не можа назваць гэты адрас, не завершаны.
DNS ідзе за дэманам, а не за тунелем
Кантэйнер атрымлівае наладу рэзалвера пры запуску, скапіяваную з дэмана або з вобраза. Адрасы, якія VPN штурхае пасля падключэння, прыходзяць запозна для гэтай копіі, і яны штурхаюцца ў рэзалвер хоста, а не ў кантэйнер.
Задайце рэзалвер яўна для сэрвісу або накіруйце яго на ўнутраны рэзалвер, дасяжны праз тунель. Кантэйнер, які вырашае прыватнае імя ў публічны адрас, звычайна выкарыстоўвае публічны рэзалвер, а не пакутуе ад зламанага маршруту, і выпраўленне належыць у файл compose або наладу дэмана.
Тое ж разважанне датычыць пытання адраса выхаду. Калі кожны кантэйнер павінен выглядаць з рознага VPN-адраса, адзін тунель хоста гэтага не забяспечыць, бо NAT згортвае іх у адну крыніцу. Працаздольныя формы — кліент у прасторы імёнаў кожнага кантэйнера або sidecar, які валодае тунелем і дзеліць свой стэк, і абедзве змяняюць тое, як адрасуецца праграма.
Кантрольны спіс перад закрыццём заяўкі: вызначце прастору імёнаў, якая валодае тунелем, дакажыце шлях сеткай хоста, адлюструйце толькі патрэбную прыладу tun, запомніце адрас крыніцы пасля NAT, задайце рэзалвер яўна і стаўцеся да адрасоў выхаду на кантэйнер як да архітэктурнага рашэння, а не сцяга.