Varför en macvlan-container inte kan svara en VPN-klient
En macvlan-container kan inte prata med sin egen värd, och svaren kan gå ut genom fel gateway. Lägg till en shim-route på värdsidan och välj sedan en källmodell.
Föreställ dig en Linux-värd som avslutar en VPN och samtidigt kör en container på ett macvlan-nätverk. LAN:et är 192.168.60.0/24, containern har 192.168.60.210, och VPN-klienter kommer från 10.95.0.0/24. Klienten når tjänsten, svaret kommer aldrig tillbaka, och varje brandväggsregel på värden ser korrekt ut. Två separata begränsningar skapar det symptomet, och att åtgärda den ena lämnar den andra kvar.
Två begränsningar, ett symptom
Den första begränsningen är isolering: Dockers macvlan-drivrutin låter inte en container prata med sin egen värd genom föräldragränssnittet. Trafiken mellan värdens stack och containern har ingen väg, oavsett hur rutterna på värden är skrivna.
Den andra begränsningen är returvägen. Containerns standardgateway är oftast LAN-routern, så ett svar adresserat till en VPN-klient går ut genom den routern. Om routern inte har någon rutt tillbaka till VPN-poolen slängs svaret någonstans i mitten.
De två felen ser identiska ut från klienten: en begäran som anländer och ett svar som aldrig kommer. De behöver olika reparationer, och en bred masquerade-regel kan dölja vilken av dem som fortfarande är trasig. Därför är det första testet en avlyssning på containersidan i stället för ännu en brandväggsändring. Om begäran aldrig dyker upp där är det isoleringsbegränsningen som gäller.
Bygg shimmen på värdsidan, smalt
Ett extra macvlan-gränssnitt på värden, kopplat till samma förälder i bryggläge, ger värdens stack en egen identitet i det LAN-segmentet. Reservera en adress utanför DHCP-poolen och utanför containerområdet för det, och routa bara containern genom det.
ip link add macvlan-vpn link eth0 type macvlan mode bridge ip address add 192.168.60.250/32 dev macvlan-vpn ip link set macvlan-vpn up ip route add 192.168.60.210/32 dev macvlan-vpn src 192.168.60.250
Det första kommandot skapar gränssnittet i bryggläge, vilket är den dokumenterade standarden för den här drivrutinen och det läge du vill ha för trafik mellan värd och container. Det andra tilldelar ett /32 så att adressen inte krockar med LAN-prefixet, och det fjärde skickar bara containerns adress genom shimmen.
Omdirigera inte hela LAN:et genom det nya gränssnittet. Den vanliga anslutna rutten blir kvar som den är, och värdrutten är medvetet smal så att en container får en väg utan att resten av segmentet ändrar beteende. En standardrutt mot shimmen skulle vara en annan design med andra konsekvenser. Håll den specifik, så blir skaderadien liten.
De här kommandona ändrar nätverksinställningarna på en körande värd. På en apparat eller en hanterad plattform använder du den plattformens stödda konfigurationsmekanism, eftersom en interaktiv ändring i root-shell kanske inte överlever en uppgradering.
Bestäm hur källan bevaras
Med shimmen på plats kan containern nå värden, och frågan blir vilken källadress svaret bär. Att bevara den ursprungliga VPN-källan är den renare modellen: containern ser klientens verkliga adress, och tjänstens loggar och åtkomstregler kan använda den.
För att det ska fungera måste containerns nätverkskonfiguration skicka trafik för 10.95.0.0/24 till 192.168.60.250 som sin gateway för den här vägen. Det är en stödd rutt- eller gatewayinställning inne i containerns egen konfiguration, inte ett trick på värdsidan. Bekräfta den inifrån containern i stället för att anta att inställningen har trätt i kraft. En standardgateway som fortfarande pekar på LAN-routern fortsätter att skicka svar i samma hål.
Om den godkända designen i stället döljer VPN-källorna, begränsa översättningen smalt: den verkliga VPN-poolen, shimmen som utgående gränssnitt, och den konkreta containern och tjänsten.
iptables -t nat -A POSTROUTING -s 10.95.0.0/24 -o macvlan-vpn -j SNAT --to-source 192.168.60.250
Matcha shimmen som egress-gränssnitt, inte tunneln. En regel som namnger tunneln som utgående gränssnitt matchar inte ett paket på väg mot containern, och det är just det felet en sådan uppsättning brukar innehålla. Håll regeln lika smal som meningen ovan och se över den när poolen ändras.
Verifiera från klienten, inte från värden
En begäran från värden själv, bunden till shimmens adress, bevisar att shimmen kan nå containern. Den bevisar inte att containern kan skicka trafik tillbaka till en bevarad 10.95.0.x-källa, eftersom källadressen i det testet är shimmens egen.
curl -sS --interface 192.168.60.250 -o /dev/null -w '%{http_code}\n' http://192.168.60.210:8080/health
sudo tcpdump -ni macvlan-vpn host 192.168.60.210Det första kommandot testar sträckan från värd till container, och det andra visar vad som faktiskt passerar shimmen medan en riktig VPN-klient gör begäran. Titta på källadressen på vägen in och om det dyker upp ett svar med samma flöde.
Vidarebefordran måste vara aktiverad på värden, och vidarebefordringsvägen behöver ett tillstånd för VPN-poolen till shimmen på tjänsteporten samt etablerade svar. En INPUT-regel på värden auktoriserar inte vidarebefordrad trafik, och det är en vanlig orsak till att paketet kastas efter att routningen ser korrekt ut.
Kör den riktiga applikationen med riktiga autentiseringsuppgifter och kontrollera sedan att en andra, orelaterad tjänst på samma container fortfarande nekar dig. Om det enda sättet att få det att fungera var att öppna varje vidarebefordringsregel är designen inte klar. Notera också vilken källadress tjänsten registrerade, för det är den som dess egna åtkomstregler kommer att använda från och med nu.