En container som inte når något bakom företagets VPN lever vanligtvis i ett annat nätverksnamnutrymme än tunneln. Värdklientens rutter, DNS-servrar och brandväggsmarkeringar tillhör värdens stack; en brocontainer har sin egen. Detta enda faktum förklarar de flesta rapporter som når ett plattformsteam, och det är också anledningen till att «VPN:et är trasigt» och «Docker kringgår VPN:et» kan vara fel samtidigt. Två mycket olika uppsättningar gömmer sig bakom ett symptom, så ta reda på vilken du har innan du ändrar en inställning.

Ta reda på vems namnutrymme som äger tunneln

På Docker Desktop för macOS eller Windows körs containrar inuti en virtuell Linux-maskin. En VPN-klient installerad på skrivbordet skapar en tunnel i skrivbordets operativsystem, och den virtuella maskinen ser den aldrig. Ingen containerkonfiguration åtgärdar det, eftersom gränssnittet som containern skulle behöva inte finns i dess nätverksnamnutrymme alls.

På en Linux-värd bor tunneln i värdens namnutrymme, och brocontainrar når den vanligtvis genom värdens routingtabell med käll-NAT tillämpat på väg ut. När den vägen misslyckas är orsaken vanligtvis vidarebefordringspolicy, filtrering av omvänd väg eller ett överlappande delnät snarare än en saknad rutt. Bekräfta vilken av de två världarna du är i innan du läser vidare:

docker info --format '{{.OperatingSystem}}'
docker run --rm --net=host alpine ip route | head -5
docker run --rm alpine ip route | head -5

Skillnaden mellan de två routingtabellerna är hela problemet på en skärm. Om värdens vy innehåller tunnelgränssnittet och brons vy inte gör det, tittar du på namnutrymmesisolering, och allt annat är ett val om hur man korsar den.

Värdnätverk är ett test, inte en design

Att köra en container med värdnätverk, vilket Docker dokumenterar som delning av värdens nätverksnamnutrymme, får den att ärva tunnelgränssnittet och dess rutter direkt. Om samma begäran då lyckas är rutteorin bekräftad, och felet är namnutrymmesisolering snarare än autentiseringsuppgifter, DNS eller en åtkomstregel.

docker run --rm --net=host curl -sS -o /dev/null -w '%{http_code}\n' https://api.internal/health

Behåll det som diagnostik. Värdnätverk ger upp portpublicering och det mesta av den isolering du ville ha från en container, och på Docker Desktop betyder «host» den virtuella maskinen, inte skrivbordet, så framgång eller misslyckande där kan vilseleda dig om du glömmer vilken värd du vände dig till.

En tun-enhet och privilegierna som följer med

En VPN-klient inuti containern behöver en tunnelenhet och tillstånd att konfigurera den. Den vanliga genvägen är --privileged, som ger varje enhet och luckrar upp säkerhetspolicyn i hela containern. Det är mycket mer än den här uppgiften kräver, och det är svårt att motivera i en granskning.

sudo modprobe tun
docker run --rm -it --device /dev/net/tun --cap-add NET_ADMIN myvpn-client

Den smalare formen mappar den enda enhetsnoden och lägger bara till nätverksadministrationsförmågan. Ladda modulen på värden först så att noden finns. Om containern startar och klienten rapporterar att den inte kan öppna tunnelenheten, kontrollera mappningen innan du misstänker profilen, eftersom det felet vanligtvis är bokstavligt.

Den här designen innebär också att klienten körs per container. Det är rätt svar när varje arbetsbelastning behöver sin egen tunnel, och fel svar när du bara ville att värdens tunnel skulle vara synlig, vilket plattformsteamet förmodligen antog att du gjorde.

Bro-NAT ändrar källan som VPN:et ser

Med standardbron översätts containrarnas utgående trafik till värdens adress. Bakom ett VPN ser företagssidan därför värdens tunneladress i stället för containerns, åtkomstregler per källa beter sig som om värden skickade begäran, och två containrar blir oskiljbara för VPN-servern.

macvlan eller ipvlan ger i stället containern en LAN-adress, vilket hjälper LAN-upptäckt och får containern att se ut som en jämlike på segmentet. Det kringgår också värdens tunnel helt, så en sådan container når inte endast-VPN-prefix om inte VPN:et också är nåbart från det LAN:et.

Båda formerna är legitima; de svarar på olika krav. Om kravet är «den här containern måste nå en endast-VPN-tjänst», väljer du mellan routning genom värden och att avsluta tunneln inuti containern. Skriv ner det valet före utrullningen, inte efter den första misslyckade begäran. Vad du än väljer, registrera källadressen som fjärrsidan kommer att se, för det är den dess åtkomstregler och dess loggar visar. En design som inte kan ange den adressen är inte färdig.

DNS följer daemonen, inte tunneln

En container får sin resolverkonfiguration vid start, kopierad från daemonen eller från avbildningen. Adresser som VPN:et skjuter in efter anslutning kommer för sent för den kopian, och de skjuts till värdens resolver i stället för in i containern.

Ange resolvern explicit för tjänsten, eller peka den mot en intern resolver som är nåbar via tunneln. En container som löser ett privat namn till en offentlig adress använder vanligtvis en offentlig resolver, inte en trasig rutt, och rättelsen hör hemma i compose-filen eller daemonkonfigurationen.

Samma resonemang gäller frågan om utgångsadressen. Om varje container måste framträda från en annan VPN-adress kan en enda värds-tunnel inte leverera det eftersom NAT slår ihop dem till en källa. De gångbara formerna är en klient i varje containers namnutrymme eller en sidecar som äger tunneln och delar sin stack, och båda ändrar hur applikationen adresseras.

Checklista innan du stänger ärendet: identifiera namnutrymmet som äger tunneln, bevisa vägen med värdnätverk, mappa bara den nödvändiga tun-enheten, kom ihåg källadressen efter NAT, ange resolvern explicit och behandla utgångsadresser per container som ett arkitekturbeslut snarare än en flagga.

Relaterade artiklar