Змясціце VPN-кліент у кантэйнер — і вы атрымаеце адну прастору імёнаў з тунэлем унутры, а не хост, які накіроўвае ўвесь свой трафік праз VPN. Гэта асобныя праекты, і менавіта звядзенне іх у адзін прыводзіць да таго, што кантэйнеры выпадкова становяцца прывілеяванымі. Гэтая інструкцыя ахоплівае толькі першае: адзін правераны вобраз, адзін абаронены профіль і працэс кліента, абмежаваны ўласнай сеткавай прасторай імёнаў.

Пачніце з артэфакта, які хтосьці ўжо ўхваліў. Крокі ніжэй мяркуюць вобраз, які змяшчае выканальны файл openvpn і поўны профіль кліента з сертыфікатам і ключавым матэрыялам, ужо развязанымі ўнутры мантавання. Яны не збіраюць праграмнае забеспячэнне, не ствараюць уліковыя даныя і не ахопліваюць бяскорэнныя асяроддзі выканання і родныя кантэйнеры Windows, кожнае з якіх змяняе адказ.

Што кантэйнер атрымлівае, а што не

Трымайце профіль і ўсё, на што ён спасылаецца, у лакальным каталогу з абмежавальнымі правамі, змантаваным толькі для чытання. Адносныя шляхі ўнутры профілю павінны развязвацца ў межах гэтага мантавання; гэта дэталь, якую людзі прапускаюць, калі сертыфікат ляжыць на адзін каталог вышэй за профіль і кантэйнер яго ніколі не бачыць.

services:
  vpn:
    image: ${VPN_CLIENT_IMAGE:?set the reviewed image reference}
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun:/dev/net/tun
    volumes:
      - ./vpn:/vpn:ro
    working_dir: /vpn
    entrypoint: ["openvpn"]
    command: ["--config", "/vpn/client.ovpn"]

Гэты файл дае тры рэчы і не патрабуе нічога іншага. Спасылку на вобраз варта замацаваць дайджастам, калі ваша палітыка разгортвання гэтага патрабуе, а профілем павінен быць правераны, а не копія, якую хтосьці адрэдагаваў на хосце.

Толькі для чытання тут азначае, што кантэйнер не можа змяняць вашыя файлы на хосце; гэта не азначае, што ён не можа прачытаць прыватны ключ, які вы змантавалі. У гэтым і сэнс мантавання, і таму правы да файлаў, уласнасць і тое, як сакрэт трапіў на хост, па-ранейшаму маюць значэнне. Ніколі не перадавайце пароль у камандным радку і не ўпісвайце яго ў слайс вобраза, бо абодва застаюцца ў месцах, якія вы не зможаце пазней ачысціць.

Магчымасці, entrypoint і пастка паміж імі

Патрэбны дзве налады, і яны выконваюць незвязаныя задачы. NET_ADMIN дазваляе кіраванне інтэрфейсам і маршрутамі ўнутры прасторы імёнаў кантэйнера. Запіс прылады /dev/net/tun дазваляе працэсу наогул адкрыць прыладу тунэлю. Выдача аднаго без другога дае ясны збой, што зручна: адсутная прылада TUN збіваецца пры адкрыцці, а адсутная магчымасць збіваецца, калі кліент спрабуе наладзіць інтэрфейс.

Ні адно з гэтага не апраўдвае privileged: true. Прывілеяваны кантэйнер атрымлівае ўсе магчымасці плюс доступ да прылад, і гэта значна большая выдача, чым патрэбна гэтай нагрузцы. даведка пра прывілеі і магчымасці асяроддзя выканання удакладняе, наколькі далёка сягае гэтая выдача. Калі чарт або допіс у блогу просіць яго, спачатку праверце, ці патрабаваннем насамрэч не быў адсутны шлях да прылады ці адсутная магчымасць.

Перавызначэнне entrypoint — гэта частка, якая кусае. Прамы выклік openvpn правільны для звычайнага вобраза і няправільны для любога вобраза прадукту, чый стартавы скрыпт падрыхтоўвае правілы файрвола, файлы рэзалвера або ўліковыя даныя перад запускам дэмана. Перавызначэнне гэтага скрыпта прапускае падрыхтоўку і пакідае вас адладжваць тунэль, які ўзняўся ў напалову наладжанай прасторы імёнаў.

Запускайце кліент на пярэднім плане і дазвольце яму быць галоўным працэсам кантэйнера. Працэс, які дэманізуецца, выходзіць адразу, кантэйнер перазапускаецца ў цыкле, а патрэбныя вам журналы раскіданыя па перазапусках, якія выглядаюць аднолькава.

Правярайце знутры прасторы імёнаў, а не з хоста

Узніміце стэк, пацвердзіце ў журнале, што кліент дасягнуў злучанага стану, а затым агледзьце прастору імёнаў, якая насамрэч трымае тунэль.

docker compose up -d
docker compose logs --tail 40 vpn
docker compose exec vpn ip -br addr
docker compose exec vpn ip route

Спіс адрасоў павінен паказваць інтэрфейс тунэлю з адрасам з пула, а табліца маршрутаў — перададзеныя прызначэнні, якія паказваюць на яго. Калі інтэрфейса няма, кліент ніколі не дайшоў да моманту яго стварэння. Калі ён ёсць, але ніводны маршрут не выкарыстоўвае яго, шукаць трэба ў push або опцыях маршрутызацыі.

Затым праверце патрэбнае вам прызначэнне з прасторы імёнаў, якая павінна выкарыстоўваць тунэль, праз праграму, а не толькі праз ping. Развязанне імёнаў — асобны збой, які варта праверыць яўна: перададзены адрас DNS сам не абнаўляе рэзалвер кантэйнера, а самастойны кліент, які ігнаруе push, будзе развязваць імёны праз тое, што наладзіў вобраз.

Адлучаны стан — частка кантракта

Паводзіны пры перападлучэнні патрабуюць уласнай праверкі, бо палітыка перазапуску даказвае, што працэс перазапускаецца, і нічога не кажа пра тое, што робіць трафік паміж. Спыніце тунэль, паспрабуйце мэтавае прызначэнне і паназірайце, ці злучэнне адхіляецца, ці завісае, ці ціха ўдаецца праз звычайны маршрут кантэйнера. Апошні вынік — той, што мае значэнне, і ён нябачны ў здаровым журнале.

Калі нагрузка ніколі не павінна выкарыстоўваць звычайны шлях, спраектуйце гэта яўна з дапамогай правілаў файрвола і сігналу гатоўнасці ўнутры прасторы імёнаў. Kill switch — гэта палітыка, якую вы пішаце і правяраеце, а не ўласцівасць, якую вы атрымліваеце ў спадчыну ад запуску кліента ў кантэйнеры.

Нарэшце, памятайце пра мяжу: гэтыя маршруты жывуць у прасторы імёнаў кантэйнера і не замяняюць табліцу маршрутызацыі хоста. Правілы перасылкі, трансляцыі і файрвола у Docker застаюцца часткай знешняга шляху, а апублікаваны порт — не інтэрфейс VPN.

Падобныя артыкулы