OpenVPN во Docker: договорот за извршување што му е потребен на минимален клиент
Проверена слика, еден заштитен профил, пристап до TUN и NET_ADMIN. Што добива контејнерот, што не смее да добие и како да се докаже дека тунелот работи.
Ставете VPN клиент во контејнер и добивате еден именски простор со тунел внатре, а не домаќин што го насочува целиот свој сообраќај преку VPN. Тоа се одделни проекти, и токму нивното третирање како едно доведува до тоа контејнерите случајно да станат привилегирани. Овој прирачник го покрива само првото: една проверена слика, еден заштитен профил и клиентски процес ограничен на сопствениот мрежен именски простор.
Започнете од артефакт што некој веќе го одобрил. Следните чекори претпоставуваат слика што ја содржи извршната датотека openvpn и целосен клиентски профил чиј сертификат и клучен материјал веќе се решени внатре во монтирањето. Тие не градат софтвер, не издаваат акредитиви и не покриваат средини без root ниту нативни 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"]
Таа датотека дава три работи и не бара ништо друго. Референцата на сликата треба да биде прицврстена со digest ако вашата политика за распоредување го бара тоа, а профилот треба да биде проверениот, а не копија што некој ја уредил на самото место на домаќинот.
Само за читање овде значи дека контејнерот не може да ги менува вашите датотеки на домаќинот; тоа не значи дека контејнерот не може да го прочита приватниот клуч што сте го монтирале. Тоа е целата поента на монтирањето, и затоа дозволите за датотеки, сопственоста и начинот на кој тајната стигнала на домаќинот сѐ уште се важни. Никогаш не пренесувајте лозинка на командната линија и не ја вградувајте во слој на сликата, бидејќи двете преживуваат на места што подоцна не можете да ги исчистите.
Можности, entrypoint и стапицата меѓу нив
Потребни се две поставки и тие вршат неповрзани работи. NET_ADMIN дозволува манипулација со интерфејси и рути во именскиот простор на контејнерот. Записот за уред /dev/net/tun му дозволува на процесот воопшто да го отвори уредот за тунел. Давање на едното без другото произведува јасен неуспех, што е погодно: уредот TUN што недостасува не успева при отворање, а можноста што недостасува не успева кога клиентот се обидува да го конфигурира интерфејсот.
Ниту едно од тоа не го оправдува privileged: true. Привилегиран контејнер добива сите можности плус пристап до уреди, и тоа е многу поголемо доделување отколку што му треба на ова оптоварување. референцата за привилегии и можности на извршната средина објаснува колку далеку стигнува тоа доделување. Ако chart или блог-објава го бара тоа, прво проверете дали барањето всушност не било патека до уред што недостасува или можност што недостасува.
Препишувањето на 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 интерфејс.