De dienst start, het log klaagt dat het het tun-apparaat niet kan openen, en routes verschijnen nooit. Voer capsh --print uit in je shell en cap_net_admin staat er meteen, waardoor de fout onmogelijk lijkt. Wat verschilt tussen je shell en de unit is de privilegeovergang, niet de bereidheid van de kernel om de capability te geven. Loop de vier controles hieronder in volgorde door en stop bij de eerste die het verschil verklaart.

Scheid een ontbrekende capability van een verborgen apparaat

Twee fouten lijken hetzelfde in de logregel. Een proces zonder CAP_NET_ADMIN kan de tunnelinterface niet aanmaken of configureren, en een proces waarvan de sandbox /dev/net/tun verbergt, kan het helemaal niet openen. Capabilities toevoegen lost het tweede geval niet op.

Controleer of het apparaat binnen de namespace van de dienst bestaat voordat je iets aanpast. PrivateDevices=yes is een veelgebruikte hardeningregel die de tun-node volledig verwijdert, en een restrictieve ProtectSystem kan het configuratiepad alleen-lezen maken op een manier die als een rechtenfout leest. Beide produceren logregels die de tunnel noemen, waardoor de capabilities de schuld krijgen. Bevestig eerst dat de node aanwezig en te openen is, en ga dan verder.

Weet naar welke capability-set je kijkt

Linux houdt permitted-, effective-, inheritable-, bounding- en ambient-sets bij, en de ambient-set is degene die een exec door een niet-rootgebruiker overleeft. Bestandscapabilities op de binary kunnen bij exec toegestane en effectieve rechten overdragen, maar alleen zolang niets in de keten die overdracht blokkeert.

Hier misleidt sudo mensen. Een opdracht die via sudo -u loopt, begint een nieuwe privilegeovergang en de ambient-set is weg, dus dezelfde controle die als root slaagt, mislukt daar. De servicemanager is weer een andere overgang, en die geeft niets ambients tenzij de unit dat zegt.

Geef de capability in de unit, niet in een wrapper

Een minimale servicesectie voor een tunnel die een apparaat moet aanmaken en routes moet installeren, leest zo.

[Unit]
Description=OpenVPN client, office profile
After=network-online.target

[Service]
Type=notify
User=openvpn
Group=openvpn
NoNewPrivileges=yes
AmbientCapabilities=CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_ADMIN
ExecStart=/usr/sbin/openvpn --config /etc/openvpn/office.conf

AmbientCapabilities zet het recht in de ambient-set voordat het proces start, en CapabilityBoundingSet weerhoudt het proces ervan iets buiten die lijst te houden. NoNewPrivileges=yes blokkeert privilegeverwerving via setuid of bestandscapabilities, terwijl de capability die de unit uitdrukkelijk geeft, nog steeds geldt. Voeg CAP_NET_BIND_SERVICE alleen toe wanneer de dienst een lage poort moet binden, en voeg nooit CAP_SYS_ADMIN toe alleen omdat een forumbericht dat deed.

Als de unit de binary in sudo wikkelt, verwijder de wrapper. systemd past al User= toe, en die extra laag is de waarschijnlijkste reden dat de ambient-set leeg is.

Verifieer tegen het live proces, niet tegen het unitbestand

Lees wat de manager werkelijk heeft toegepast, en lees dan het proces dat hij heeft gestart.

unit=openvpn-client@office
systemctl show -p User -p AmbientCapabilities "$unit"
systemctl show -p MainPID --value "$unit" | xargs -r getpcaps
grep -E '^Cap(Eff|Amb)' /proc/$(systemctl show -p MainPID --value "$unit")/status

Als de unit de capability vermeldt en CapEff heeft hem nog steeds niet, dan overschrijft een drop-in de instelling of verandert een ExecStartPre-stap de omgeving. Zoek de unitnaam in de drop-in-mappen voordat je aanneemt dat het hoofdbestand gezaghebbend is, want een later bestand wint stil. Als zowel de unit als het proces de capability tonen en de tunnel faalt nog steeds, ga dan terug naar de apparaat- en padcontroles in plaats van de bounding-set te verbreden. Verbreden verbergt de echte oorzaak en laat de dienst met meer rechten achter dan voorheen.

Geef er de voorkeur aan rechten na het starten te laten vallen

OpenVPN kan met rechten starten en daarna via zijn eigen user- en group-opties overgaan naar een onbevoorrecht account, waarbij persist-key en persist-tun de tunnel daarna bruikbaar houden. Die opzet verkleint het venster waarin het proces rechten heeft, en het past vaak beter dan de hele daemon onbevoorrecht met permanente capabilities te starten.

Welk model je ook kiest, herstart de unit en herhaal de controles na een herstart, want een dienst die vanuit een interactieve root-shell werkt en bij het opstarten faalt, is meestal een verschil in capability, apparaat of bestandsrechten. Noteer de unitinstellingen naast de capability-uitvoer van het proces, zodat de volgende beoordelaar ziet of een pakketupdate of een drop-in de grens heeft verschoven.

Gerelateerde artikelen