Set en VPN-klient i en container, og du får ett navnerom med en tunnel inne i det, ikke en vert som ruter all trafikken sin gjennom en VPN. Dette er separate prosjekter, og å behandle dem som ett er nettopp måten containere ender opp med privilegier ved et uhell. Denne kjøreboken dekker bare det første: ett gjennomgått image, én beskyttet profil og en klientprosess begrenset til sitt eget nettverksnavnerom.

Start med et artefakt som noen allerede har godkjent. Trinnene nedenfor forutsetter et image som inneholder den kjørbare filen openvpn og en fullstendig klientprofil med sertifikat og nøkkelmateriale allerede løst inne i monteringen. De bygger ikke programvare, utsteder ikke påloggingsdata og dekker ikke rootløse kjøretidsmiljøer eller native Windows-containere, som hver for seg endrer svaret.

Hva containeren får, og hva den ikke får

Hold profilen og alt den viser til i en lokal mappe med begrensede rettigheter, montert skrivebeskyttet. Relative stier i profilen må løses innenfor den monteringen; dette er en detalj folk overser når et sertifikat ligger én mappe over profilen og containeren aldri ser det.

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"]

Den filen gir tre ting og krever ikke noe annet. Imagereferansen bør festes med digest hvis distribusjonspolitikken din sier det, og profilen bør være den gjennomgåtte, ikke en kopi noen har redigert på stedet på verten.

Skrivebeskyttet her betyr at containeren ikke kan endre filene dine på verten; det betyr ikke at containeren ikke kan lese den private nøkkelen du monterte. Det er hele poenget med monteringen, og derfor spiller filrettigheter, eierskap og hvordan hemmeligheten kom inn på verten fortsatt en rolle. Gi aldri et passord på kommandolinjen og bak det aldri inn i et imagelag, for begge overlever på steder du ikke kan rydde opp senere.

Kapabiliteter, entrypoint og fellen mellom dem

Det trengs to innstillinger, og de gjør uavhengige oppgaver. NET_ADMIN tillater manipulering av grensesnitt og ruter i navnerommet til containeren. Apparatoppføringen /dev/net/tun tillater prosessen å åpne tunneleenheten i det hele tatt. Å gi den ene uten den andre gir en tydelig feil, noe som er praktisk: en manglende TUN-enhet feiler ved åpning, mens en manglende kapabilitet feiler når klienten prøver å konfigurere grensesnittet.

Ingen av dem rettferdiggjør privileged: true. En privilegert container får alle kapabiliteter pluss tilgang til enheter, og det er en mye større innvilgelse enn denne arbeidsmengden trenger. referansen om kjøretidsprivilegier og kapabiliteter forklarer hvor langt den innvilgelsen rekker. Hvis et chart eller et blogginnlegg ber om det, sjekk først om kravet egentlig var en manglende enhetssti eller en manglende kapabilitet.

Overstyringen av entrypoint er den delen som biter. Å kalle openvpn direkte er riktig for et vanlig image og galt for ethvert produktimage der oppstartsskriptet forbereder brannmurregler, resolverfiler eller påloggingsdata før daemonen kjøres. Å overstyre det skriptet hopper over forberedelsen og lar deg feilsøke en tunnel som kom opp i et halvkonfigurert navnerom.

Kjør klienten i forgrunnen og la den være containerens hovedprosess. En prosess som daemoniserer, avsluttes umiddelbart, containeren starter på nytt i en løkke, og loggene du trenger er spredt over omstarter som alle ser like ut.

Verifiser innenfra navnerommet, ikke fra verten

Reis stacken, bekreft i loggen at klienten nådde en tilkoblet tilstand, og undersøk deretter navnerommet som faktisk holder tunnelen.

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

Adresselisten bør vise et tunnelgrensesnitt med en adresse fra bassenget, og rutetabellen bør vise de pushede målene som peker mot det. Hvis grensesnittet mangler, nådde klienten aldri frem til å lage det. Hvis det finnes, men ingen rute bruker det, er stedet å lete push eller rutevalgene.

Test deretter målet du bryr deg om, fra navnerommet som skal bruke tunnelen, med applikasjonen og ikke bare med ping. Navneoppslag er en egen feil som er verdt å teste eksplisitt: en pushet DNS-adresse oppdaterer ikke resolveren til en container av seg selv, og en frittstående klient som ignorerer pushen vil løse navn gjennom det imaget har konfigurert.

Den frakoblede tilstanden er en del av kontrakten

Gjenoppkoblingsatferd trenger sin egen kontroll, for en omstartspolicy beviser at prosessen starter på nytt og sier ingenting om hva trafikken gjør i mellomtiden. Stopp tunnelen, prøv det tiltenkte målet og se om forbindelsen avvises, henger eller lykkes stille gjennom containerens vanlige rute. Det siste utfallet er det som betyr noe, og det er usynlig i en sunn logg.

Hvis arbeidsmengden aldri må bruke den vanlige veien, design det eksplisitt med brannmurregler og et beredskapssignal i navnerommet. Kill switch er en policy du skriver og tester, ikke en egenskap du arver ved å kjøre en klient i en container.

Til slutt, husk grensen: disse rutene lever i containerens navnerom og erstatter ikke vertens rutetabell. Dockers videresendings-, oversettelses- og brannmurregler er fortsatt en del av den ytre veien, og en publisert port er ikke et VPN-grensesnitt.

Relaterte artikler