NET_ADMIN i en VPN-container: vad den kan ändra och var
Kapabiliteten tillåter ändringar av gränssnitt, rutter och brandvägg inom ett enda nätverksnamnrum. Med värdnätverk är det namnrummet värdens egen stack.
NET_ADMIN är Linux-kapabiliteten som låter en process utföra nätverksadministration, och i en container gör den exakt det inom det nätverksnamnrum där processen körs. Det är inte en licens att öppna en socket och inte en ersättning för en enhet eller en rutt. Den intressanta frågan är aldrig om kapabiliteten är beviljad, utan vilket namnrum som tar emot ändringen.
Vad kapabiliteten omfattar
Inom sitt namnrum kan en process med NET_ADMIN ta gränssnitt upp och ner, tilldela adresser, lägga till och ta bort rutter och skriva brandväggsregler, vilket är den grupp operationer som capabilities(7) samlar under denna kapabilitet. Den kan också justera inställningar på gränssnittsnivå som styr hur kärnan köar och filtrerar trafik. En VPN-klient behöver vanligtvis några av dem vid start och inget annat efteråt. Därför begär de flesta images större räckvidd än de använder.
Operationer utanför det namnrummet omfattas inte, och angränsande privilegier är separata. Läsning och skrivning av råa paket tillhör NET_RAW, och att skapa en tun-enhet kräver både kapabiliteten och åtkomst till enhetsnoden. En process utan enheten får ett behörighetsfel som ser ut som ett nätverksproblem och inte är det.
Namnrummet avgör skadans radie
En container på sitt eget bryggnätverk når sin egen loopback, sina egna gränssnitt och sin egen routingtabell. Att ge NET_ADMIN där låter VPN-klienten bygga en tunnel utan att röra värdens routingbeslut, vilket är det arrangemang som de flesta container-images förutsätter.
Byt den containern till värdnätverk och samma beviljande redigerar nu värdens rutter och värdens brandvägg, eftersom inget separat namnrum finns kvar. Klienten som skulle hantera en enda tunnel kan då omdirigera trafik för hela maskinen, och ett fel i dess nedmonteringsskript lämnar värdregler som ingen har skrivit. Ingenting i själva kapabiliteten ändrades; sammanhanget ändrades. Därför beter sig samma compose-fil olika på två värdar.
Tre förutsättningar som smälter samman till en
Startfel i VPN-containrar involverar vanligtvis en av tre separata saker: kapabiliteten, tunneienheten och kärnstöd för protokollet. Att ge alla tre på en gång fungerar, och det gör också nästa fel omöjligt att tillskriva. Ett minimalt compose-utdrag ger kapabiliteten och skickar enhetsnoden explicit:
services:
vpn:
image: example/vpn-client:latest
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun
sysctls:
- net.ipv4.conf.all.src_valid_mark=1Läs imagens egen dokumentation för vilka sysctls den behöver, eftersom en sysctl i en container kan kräva en extra behörighet eller en inställning på värdnivå. Där imagen bara stöder användarläge behövs ingen enhet alls, och kapabilitetslistan krymper i motsvarande grad.
Ge den snäva operationen, inte läget
Privilegierat läge överlämnar varje kapabilitet och utökar enhetsåtkomsten samtidigt, så det döljer vilken av de tre förutsättningarna som saknades. Det gör också containerns fellägen omöjliga att skilja från ändringar på värden. Föredra en explicit lista även när den är längre att skriva.
Rootless- och användarnamnrumsdistributioner ändrar vad en kapabilitet betyder i praktiken, eftersom processen bara kan hålla den inom ett mappat namnrum. Att kopiera en kapabilitetslista från ett rootful exempel till en rootless körmiljö och förvänta sig samma räckvidd är ett vanligt sätt att förlora en eftermiddag.
Hemligheter hör till ett separat beslut. Att hålla NET_ADMIN säger ingenting om vilken peer-identitet klienten presenterar, vilka inloggningsuppgifter den läser in eller hur de roteras. Nätverksadministration ger inte förtroende.
Verifiera ändringen och anteckna varför beviljandet finns
Bekräfta vad containern faktiskt fick innan du felsöker tunneln. Inspektionen nedan rapporterar de tillagda kapabiliteterna och nätverksläget och visar sedan hur gränssnittslistan ser ut inifrån:
docker inspect --format '{{.HostConfig.CapAdd}} {{.HostConfig.NetworkMode}} {{.HostConfig.Privileged}}' vpn
docker exec vpn sh -c 'grep CapEff /proc/self/status'
docker exec vpn ip -br addr
docker exec vpn ip routeOm kapabiliteten finns och gränssnittslistan fortfarande är tom har klienten misslyckats innan den kunde skapa något, och containerloggarna är nästa ställe att titta på. Om tunneln finns men trafiken inte flödar svarar routingtabellen inuti containern på nästa fråga.
Testa även nedmonteringsvägen, eftersom en klient som skriver brandväggsregler kan lämna dem efter sig. Stoppa containern och kontrollera värdens regeluppsättning igen om värdnätverk används. Ett beviljande som bara behövs i två sekunder vid start bör inte beskrivas i compose-filen som ett permanent krav utan en anteckning som förklarar det.
Skriv orsaken bredvid varje kapabilitet: vilken operation som behövde den och vad som misslyckas utan den. Den anteckningen överlever image-uppdateringar, och den är skillnaden mellan en granskad privilegielista och en som vuxit genom kopiering och inklistring.