NET_ADMIN in een VPN-container: wat het kan wijzigen en waar
De capability staat wijzigingen van interfaces, routes en firewall toe binnen één netwerknaamruimte. Met hostnetwerk is die naamruimte de eigen stack van de host.
NET_ADMIN is de Linux-capability waarmee een proces netwerkbeheer kan uitvoeren, en in een container doet die precies dat binnen de netwerknaamruimte waarin het proces draait. Het is geen licentie om een socket te openen en geen vervanging voor een apparaat of een route. De interessante vraag is nooit of de capability is toegekend, maar welke naamruimte de wijziging ontvangt.
Wat de capability dekt
Binnen zijn naamruimte kan een proces met NET_ADMIN interfaces op en neer brengen, adressen toewijzen, routes toevoegen en verwijderen en firewallregels schrijven, de groep bewerkingen die capabilities(7) onder deze capability verzamelt. Het kan ook instellingen op interfaceniveau aanpassen die bepalen hoe de kernel verkeer in de wachtrij zet en filtert. Een VPN-client heeft er bij het starten meestal een paar nodig en daarna niets meer. Daarom vragen de meeste images om meer bereik dan ze gebruiken.
Bewerkingen buiten die naamruimte vallen er niet onder, en aangrenzende privileges zijn apart. Het lezen en schrijven van ruwe pakketten hoort bij NET_RAW, en het maken van een tun-apparaat vereist zowel de capability als toegang tot het apparaatknooppunt. Een proces zonder het apparaat krijgt een toestemmingsfout die op een netwerkprobleem lijkt en dat niet is.
De naamruimte bepaalt de schade
Een container op zijn eigen brugnetwerk bereikt zijn eigen loopback, zijn eigen interfaces en zijn eigen routingtabel. Als daar NET_ADMIN wordt gegeven, kan de VPN-client een tunnel bouwen zonder de routingbeslissingen van de host aan te raken, de opstelling die de meeste container-images aannemen.
Schakel die container over naar hostnetwerk en dezelfde toekenning bewerkt nu de routes van de host en de firewall van de host, omdat er geen aparte naamruimte meer over is. De client die één tunnel moest beheren, kan dan het verkeer van de hele machine omleiden, en een fout in het afbreekscript laat regels achter die niemand heeft geschreven. Niets aan de capability zelf veranderde; de context veranderde. Daarom gedraagt hetzelfde compose-bestand zich anders op twee hosts.
Drie voorwaarden die samensmelten tot één
Opstartfouten in VPN-containers betreffen meestal een van drie afzonderlijke zaken: de capability, het tunnelapparaat en kernelondersteuning voor het protocol. Alle drie tegelijk geven werkt, en het maakt de volgende fout ook niet meer toe te schrijven. Een minimaal compose-fragment geeft de capability en geeft het apparaatknooppunt expliciet door:
services:
vpn:
image: example/vpn-client:latest
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun
sysctls:
- net.ipv4.conf.all.src_valid_mark=1Lees de eigen documentatie van de image voor welke sysctls nodig zijn, want een sysctl in een container kan een extra privilege of een instelling op hostniveau vereisen. Waar de image alleen de gebruikersruimtemodus ondersteunt, is helemaal geen apparaat nodig en krimpt de lijst met capabilities overeenkomstig.
Geef de smalle bewerking, niet de modus
De geprivilegieerde modus levert elke capability over en verbreedt tegelijk de apparaattoegang, dus verbergt welke van de drie voorwaarden ontbrak. Het maakt ook de faalwijzen van de container niet te onderscheiden van wijzigingen op de host. Geef de voorkeur aan een expliciete lijst, ook als die langer is om te schrijven.
Rootless- en gebruikersnaamruimte-implementaties veranderen wat een capability in de praktijk betekent, omdat het proces die alleen binnen een gemapte naamruimte kan houden. Een capabilitylijst uit een rootful voorbeeld naar een rootless runtime kopiëren en hetzelfde bereik verwachten is een gangbare manier om een middag te verliezen.
Geheimen horen bij een aparte beslissing. NET_ADMIN hebben zegt niets over welke peer-identiteit de client presenteert, welke inloggegevens hij laadt of hoe die worden geroteerd. Netwerkbeheer levert geen vertrouwen.
Verifieer de wijziging en leg vast waarom de toekenning bestaat
Controleer wat de container werkelijk heeft gekregen voordat u de tunnel debugt. De inspectie hieronder meldt de toegevoegde capabilities en de netwerkmodus en laat daarna zien hoe de interfacelijst er van binnen uitziet:
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 routeAls de capability aanwezig is en de interfacelijst nog leeg is, is de client mislukt voordat hij iets kon aanmaken, en de containerlogs zijn de volgende plek om te kijken. Als de tunnel bestaat maar het verkeer niet stroomt, beantwoordt de routingtabel in de container de volgende vraag.
Test ook het afbreekpad, want een client die firewallregels schrijft, kan ze achterlaten. Stop de container en controleer de regelset van de host opnieuw als hostnetwerk wordt gebruikt. Een toekenning die alleen bij het starten twee seconden nodig is, hoort niet zonder uitleg in het compose-bestand als permanente eis te staan.
Schrijf de reden naast elke capability: welke bewerking die nodig had en wat zonder die faalt. Die notitie overleeft image-updates, en zij is het verschil tussen een beoordeelde privilegielijst en een die door kopiëren en plakken is gegroeid.