Hvorfor en Docker-container ikke kan nå værter bag VPN'en
Brocontainere har deres eget namespace, så værtens tunnel er usynlig for dem. Sammenlign værtsnetværk, en tun-enhed og macvlan, før du redigerer DNS.
En container, der ikke kan nå noget bag virksomhedens VPN, bor normalt i et andet netværksnamespace end tunnelen. Værtklientens ruter, DNS-servere og firewallmærker hører til værtens stak; en brocontainer har sin egen. Den ene kendsgerning forklarer de fleste rapporter, der når et platformsteam, og den er også grunden til, at «VPN'en er i stykker» og «Docker omgår VPN'en» kan være forkerte på samme tid. To meget forskellige opsætninger skjuler sig bag ét symptom, så afgør, hvilken du har, før du ændrer en indstilling.
Find ud af, hvis namespace der ejer tunnelen
På Docker Desktop til macOS eller Windows kører containere inde i en virtuel Linux-maskine. En VPN-klient installeret på skrivebordet opretter en tunnel i skrivebordets styresystem, og den virtuelle maskine ser den aldrig. Ingen containerkonfiguration retter det, fordi den grænseflade, containeren ville have brug for, slet ikke findes i dens netværksnamespace.
På en Linux-vært bor tunnelen i værtens namespace, og brocontainere når den normalt gennem værtens routingtabel med kilde-NAT anvendt på vej ud. Når den vej fejler, er årsagen normalt videresendelsespolitik, omvendt sti-filtrering eller et overlappende subnet snarere end en manglende rute. Bekræft, hvilken af de to verdener du er i, før du læser videre:
docker info --format '{{.OperatingSystem}}'
docker run --rm --net=host alpine ip route | head -5
docker run --rm alpine ip route | head -5
Forskellen mellem de to routingtabeller er hele problemet på én skærm. Hvis værtens visning indeholder tunngrænsefladen, og broens visning ikke gør, ser du namespace-isolering, og alt andet er et valg om, hvordan man krydser den.
Værtsnetværk er en test, ikke et design
At køre en container med værtsnetværk, som Docker dokumenterer som deling af værtens netværksnamespace, får den til direkte at arve tunngrænsefladen og dens ruter. Hvis den samme anmodning så lykkes, er ruteteorien bekræftet, og fejlen er namespace-isolering frem for legitimationsoplysninger, DNS eller en adgangsregel.
docker run --rm --net=host curl -sS -o /dev/null -w '%{http_code}\n' https://api.internal/health
Behold det som diagnostik. Værtsnetværk opgiver portudgivelse og det meste af den isolering, du ønskede fra en container, og på Docker Desktop betyder «host» den virtuelle maskine, ikke skrivebordet, så en succes eller fiasko der kan vildlede dig, hvis du glemmer, hvilken vært du henvendte dig til.
En tun-enhed og de privilegier, der følger med
En VPN-klient inde i containeren har brug for en tunenhed og tilladelse til at konfigurere den. Den sædvanlige genvej er --privileged, som giver enhver enhed og lemper sikkerhedspolitikken i hele containeren. Det er langt mere, end denne opgave kræver, og det er svært at forsvare i en gennemgang.
sudo modprobe tun
docker run --rm -it --device /dev/net/tun --cap-add NET_ADMIN myvpn-client
Den snævrere form mapper den enkelte enhedsknude og tilføjer kun netværksadministrationskompetencen. Indlæs først modulet på værten, så knuden findes. Hvis containeren starter, og klienten rapporterer, at den ikke kan åbne tunenheden, skal du kontrollere mappingen, før du mistænker profilen, for den fejl er normalt bogstavelig.
Dette design betyder også, at klienten kører per container. Det er det rigtige svar, når hver arbejdsbyrde har brug for sin egen tunnel, og det forkerte, når du blot ville have værtens tunnel synlig, hvilket platformsteamet sandsynligvis antog, at du gjorde.
Bro-NAT ændrer den kilde, VPN'en ser
Med standardbroen oversættes containernes udgående trafik til værtens adresse. Bag en VPN ser den virksomheds side derfor værtens tunneladresse i stedet for containerens, adgangsregler per kilde opfører sig, som om værten sendte anmodningen, og to containere bliver uadskillelige for VPN-serveren.
macvlan eller ipvlan giver i stedet containeren en LAN-adresse, hvilket hjælper LAN-opdagelse og får containeren til at ligne en jævnbyrdig på segmentet. Det omgår også værtens tunnel fuldstændigt, så en sådan container ikke når kun-VPN-præfikser, medmindre VPN'en også er tilgængelig fra det LAN.
Begge former er legitime; de besvarer forskellige krav. Hvis kravet er «denne container skal nå en kun-VPN-tjeneste», vælger du mellem routing gennem værten og at afslutte tunnelen inde i containeren. Skriv det valg ned før udrulningen, ikke efter den første mislykkede anmodning. Uanset hvad du vælger, noter kildeadressen, som den fjerne ende vil se, for det er den, dens adgangsregler og dens logfiler vil vise. Et design, der ikke kan angive den adresse, er ikke færdigt.
DNS følger daemonen, ikke tunnelen
En container får sin resolverkonfiguration ved start, kopieret fra daemonen eller fra imaget. Adresser, som VPN'en skubber efter forbindelsen, ankommer for sent til den kopi, og de skubbes til værtens resolver i stedet for ind i containeren.
Angiv resolveren eksplicit for tjenesten, eller peg den mod en intern resolver, der er tilgængelig gennem tunnelen. En container, der opløser et privat navn til en offentlig adresse, bruger normalt en offentlig resolver, ikke en brudt rute, og rettelsen hører i compose-filen eller daemonkonfigurationen.
Samme ræsonnement gælder for spørgsmålet om udgangsadressen. Hvis hver container skal fremstå fra en forskellig VPN-adresse, kan én værtstunnel ikke levere det, fordi NAT slår dem sammen til én kilde. De gangbare former er en klient i hver containers namespace eller en sidecar, der ejer tunnelen og deler sin stak, og begge ændrer, hvordan applikationen adresseres.
Tjekliste, før du lukker sagen: identificer det namespace, der ejer tunnelen, bevis vejen med værtsnetværk, map kun den nødvendige tunenhed, husk kildeadressen efter NAT, angiv resolveren eksplicit, og behandl udgangsadresser per container som en arkitekturbeslutning frem for et flag.