Met Linux Capabilities verdeel ik root-rechten in kleine, duidelijk omschreven bevoegdheden en verminder ik zo het risico drastisch. Op die manier bepaal ik gericht welke processen bepaalde acties mogen uitvoeren en beperk ik het aanvalsoppervlak van elke toepassing.
Centrale punten
- Fijnkorrelig In plaats van almachtig: root-rechten opsplitsen in kleinere rechten.
- Bestandsmogelijkheden in plaats van Set-UID: de benodigde rechten rechtstreeks aan de binaire bestanden koppelen.
- Capability-sets configureren: Permitted, Effective, Inheritable, Bounding gericht configureren.
- Scheiding van bevoegdheden: Diensten, tools en taken strikt van elkaar scheiden.
- Verdediging in de diepte: Functies aanvullen met sudo, rollen en logbestanden.
Waarom root-rechten scheiden?
Een root-account biedt Volledige toegang op het niveau van bestanden en processen, maar juist dat nodigt uit tot ernstige fouten. Eén verkeerde opdracht of één exploit is genoeg om een complete installatie te laten crashen. Daarom beperk ik ingrijpende acties tot het strikt noodzakelijke en verminder zo de omvang van de schade en de hersteltijd. Het principe van minimale rechten houdt diensten klein en beheersbaar. Ik schakel de directe root-login uit, werk met rollen en houd volledige logboeken bij.
Linux-capabilities kort uitgelegd
Linux-capabilities splitsen de klassieke root-bevoegdheden op in duidelijk afgebakende Privileges. Elk proces krijgt alleen de bouwstenen die het echt nodig heeft voor zijn taak, zoals het toewijzen van poorten onder 1024 of het verzenden van speciale signalen. Zo omzeil ik het vroegere ‘alles-of-niets’-principe. De kernel beheert deze bouwstenen per proces en past ze strikt toe. Zo blijft de controle gedetailleerd en traceerbaar.
Op technisch vlak koppel ik vaardigheden aan ofwel Processen (via hun capaciteiten) of aan Bestanden (als uitgebreide attributen beveiligingscapaciteit (ELF-binaire bestanden). Bij de execve()-Bij het opstarten voegt de kernel de bestandscapabilities samen met de proces-sets: eenvoudig gezegd worden de toegestane capabilities uit het bestandsattribuut en de overerfbare rechten van het aanroepende proces gecombineerd tot de nieuwe Permitted-set en – indien zo gemarkeerd – tegelijkertijd geactiveerd in de Effective-set. Dit voorkomt Set-UID-omwegen en houdt privileges zichtbaar en controleerbaar.
Capability-sets begrijpen in de context van processen
Elk proces beschikt over verschillende sets rechten, die ik gericht controle. De Permitted-Set bepaalt welke rechten een proces in principe mag hebben. De Effective-Set bepaalt wat op dat moment actief is. De Inheritable-Set regelt welke rechten kunnen worden overgedragen aan onderliggende processen. De Bounding-Set stelt een strikte bovengrens vast en voorkomt dat processen deze grens overschrijden.
Ambient Capabilities en Securebits
Naast de bekende sets is er ook de Ambient-set, dat bij de execve() niet automatisch verloopt. Ik gebruik het wanneer een proces zonder speciale rechten doelgericht minimale rechten nodig heeft voor meerdere uitvoeren-sprongen moet overslaan (bijvoorbeeld bij het aanroepen van externe hulpprogramma's). Ambient-rechten worden alleen meegenomen in de effectieve rechten als het aangeroepen bestand zelf geen bestandscapaciteiten instelt – zo voorkom ik ongewenste escalatie.
Met de Securebits Ik bepaal de details van de overgangen, bijvoorbeeld of een proces na het wijzigen van de UID zijn eerder ingestelde vaardigheden mag behouden (keepcaps) of dat hij in het algemeen geen nieuwe privileges mag verkrijgen (no_new_privs). In de praktijk stel ik Securebits strak in en zie ik af van gebruiksgemak om exploitketens te doorbreken.
Bestandsmogelijkheden in plaats van Set-UID
Ik vervang Set-UID-binaire bestanden door bestandscapaciteiten om het risico te verlagen. In plaats van een programma rootrechten te geven, stel ik alleen de benodigde rechten in. Een typische wijziging ziet er als volgt uit: setcap 'cap_net_bind_service=+ep' /usr/bin/meinserver. Met getcap -r / controleer ik welke bestanden vaardigheden bevatten. Dat vermindert het aantal escalaties aanzienlijk.
Het is belangrijk dat bestandsmogelijkheden alleen worden toegepast op ELF-binaire bestanden werken. Interpreter-scripts (bijv. Python, Bash) nemen deze niet altijd betrouwbaar over. In dergelijke gevallen verpak ik de bevoorrechte actie in een klein, statisch gecontroleerd hulpprogramma of maak ik gebruik van socket-activering, zodat mijn dienst helemaal niet zelf een verbinding hoeft te maken. Daarnaast houd ik de bestandsrechten goed in de gaten: capabilities verlenen speciale rechten ten opzichte van de kernel, maar vervangen geen gebruikelijke ACL's of POSIX-rechten.
Tijdens het kopiëren of inpakken gaan vaardigheden snel verloren: cp zonder XATTR-ondersteuning, verkeerd ingestelde umask of een build-artefact verwijderen uit een bestandssysteem zonder uitgebreide attributen beveiligingscapaciteit zonder dat dit expliciet wordt vermeld. Daarom werk ik op een reproduceerbare manier en maak ik gebruik van: cp --preserve=xattr ..., tar --xattrs, rsync -X. Bij het bouwen van pakketten stel ik de bestandscapabilities expliciet in het installatiescript in, test ik de installatie in een schone VM en controleer ik getcap in het CI.
Privilege Separation met realistische scenario's
Een webserver heeft toegang nodig tot poort 80/443, maar niet tot kernelmodules of systeemherstarts, daarom stel ik in CAP_NET_BIND_SERVICE en verder niets. Een back-upagent mag bestanden lezen en schrijven, maar mag de netwerkconfiguratie niet wijzigen. Een monitoringtool krijgt leestoegang tot kengetallen, maar heeft geen wijzigingsrechten. Door deze afbakening blijven aanvallen lokaal beperkt, in plaats van dat ze systeemwijd effect hebben. Juist deze scheiding houdt diensten beheersbaar en houdt verkeerde configuraties binnen de perken.
Combineren met sudo en rollen
Capabilities zijn geen vervanging voor een nette Rolenstructuur, ze vullen deze aan. Ik verleen sudo-rechten zeer selectief, gebruik volledige opdrachtpaden en vermijd algemene regels zoals „ALL=(ALL) ALL“. Elke toewijzing leg ik vast in een logboek. Groepen bundelen verantwoordelijkheden, terwijl capabilities technische grenzen stellen aan processen. Zo ontstaan duidelijke verantwoordelijkheden zonder overmatige rechten.
Veelvoorkomende valkuilen en best practices
- Geen CAP_SYS_ADMIN als afkorting: Dit recht is een verzamelbak. Ik vervang het door meer specifieke alternatieven (bijv.
CAP_SYS_CHROOT,CAP_SYS_TIME,CAP_SYS_NICE) of laat het helemaal achterwege. - De bestandsrechten blijven strikt: Capabilities schakelen DAC niet in het algemeen uit. Zonder
CAP_DAC_OVERRIDEDe kernel houdt nog steeds rekening met de eigenaar en de modusbits. Ik ken dus nog steeds zo min mogelijk leesrechten toe. - Uitharding van het spoor: Als ik een binair bestand van bestandsmogelijkheden voorzie, voorkom ik PATH-spoofing (absolute paden in
sudoers, beperkte schrijfrechten voor mappen in het zoekpad). - Begin vroeg, doe het vaak: Processen worden soms met meer rechten dan nodig gestart. Ik verwijder overbodige rechten direct na de gevoelige stap (
prctl()/libcap) en stel inno_new_privs, waar mogelijk. - Erfelijkheid beperken: Ik houd de Inheritable- en Ambient-set klein. Kindprocessen mogen geen nieuwe deuren openen.
- De build- en deploy-pijplijn controleren: Ik bevestig dat
beveiligingscapaciteitbehouden blijft en dat er geen staging-stappen (containerlagen, NFS, artefactscanners) zijn die XATTR's verwijderen.
Overzicht van belangrijke capaciteiten en risico's
Voordat ik rechten toeken, stel ik duidelijk vast welke rechten nodig zijn en beoordeel ik het risico ervan. De volgende tabel toont typische voorbeelden met hun effect en indeling. Ik houd altijd rekening met alternatieven om te vergaande rechten te vermijden. Juist CAP_SYS_ADMIN Ik ken deze uiterst spaarzaam toe. Waar mogelijk vervang ik ruim opgezette privileges door gerichte, beperkte varianten.
| Capaciteit | Doel | Risico | Voorbeeld |
|---|---|---|---|
| CAP_NET_BIND_SERVICE | Binden aan poorten < 1024 | Laag tot gemiddeld | Webserver op 80/443 |
| CAP_SYS_BOOT | Systeem opnieuw opstarten | Hoog | Geplande herstart |
| CAP_SYS_MODULE | Kernelmodules laden/verwijderen | Zeer hoog | Beheer van stuurprogramma's |
| CAP_SYS_ADMIN | Veelzijdige beheerfuncties | Zeer hoog | Diverse onderhoudstaken |
| CAP_SETUID / CAP_SETGID | UID/GID wijzigen | Gemiddeld tot hoog | Overdracht van rechten tijdens de dienst |
Naast de tabel ben ik momenteel bezig met het beoordelen van CAP_SYS_PTRACE (processen debuggen), CAP_NET_ADMIN (netwerkparametrisering) en CAP_DAC_OVERRIDE (het omzeilen van bestandstoegangsbeperkingen) uiterst kritisch. Vaak zijn er patronen waarmee deze rechten kunnen worden omzeild: speciale metriek-eindpunten in plaats van processnooping, socket-activering of poortdoorsturing in plaats van bind-rechten, en duidelijke bestandsrechten in plaats van het algemeen omzeilen van DAC.
Beveiliging van containers en hosting
In multi-tenant-omgevingen vind ik vaardigheden van cruciaal belang kleine en voorkom dat processen worden overgedragen aan onderliggende processen. Containers profiteren er aanzienlijk van zodra de bounding-set strak is ingesteld. Ik combineer dit met geïsoleerde bestandssysteem- en procesruimten. Deze inleiding helpt me om een overzicht te krijgen van isolatiemethoden Procesisolatie. Zo blijven diensten gescheiden, zelfs als een applicatie hapert.
In de praktijk stel ik containers standaard in op „alles verwijderen, selectief toevoegen“: --cap-drop=ALL --cap-add=NET_BIND_SERVICE voor webservices, geen mount-rechten, geen SYS_ADMIN. In georkestreerde omgevingen beheer ik het profiel centraal en controleer ik het in beleidsregels. Belangrijk: ik vertrouw niet op bestandsrechten in de image, maar wijs rechten tijdens de uitvoering toe in de orchestrator – op een reproduceerbare en controleerbare manier.
Interactie met SELinux en AppArmor
Capabilities bepalen wat een proces mag doen, terwijl MAC-profielen vastleggen waartoe het toegang heeft, en beide werken naadloos samen goed. Ik definieer capabilities strikt en laat SELinux of AppArmor de toegang tot bestanden en sockets beperken. Hierdoor ontstaat een gelaagde beveiliging die exploits met meerdere hindernissen confronteert. Een korte vergelijking vind ik hier: SELinux versus AppArmor. Hierdoor blijft een gehackte dienst geïsoleerd en kan deze minder schade aanrichten.
Praktijk: stap voor stap te werk gaan
Ik begin met een inventarisatie van alle diensten en hun Vereisten. Vervolgens verwijder ik overbodige Set-UID-binaire bestanden of vervang ik ze door gerichte bestandsrechten. Ik configureer sudo op een restrictieve manier en documenteer elke instelling. Ik wijs taken toe aan rollen en groepen en houd de rechten tot een minimum beperkt. Vervolgens voer ik belastingstests uit en controleer ik logboekvermeldingen op onverwachte weigeringen.
Een korte checklist helpt me bij de overstap:
- Leg de vereisten per dienst schriftelijk vast (alleen wat echt nodig is).
- Een inventarisatie maken van bestaande speciale rechten (
find / -perm -4000,getcap -r /). - Gericht vervangen: Set-UID afschaffen, bestandscapabilities instellen, rechten tijdig intrekken.
- Erfelijkheid uitschakelen: Bounding-Set verkleinen, Inheritable/Ambient minimaliseren.
- Systemd-/containerprofielen beveiligen (
CapabilityBoundingSet=,NoNewPrivileges=yes). - Testen onder belasting, logbestanden en auditvermeldingen controleren, uitzonderingen documenteren.
Monitoring, naamruimten en doorlopende audits
Ik controleer logbestanden, waarschuwingen en systeemaanroepen, zodat ongewenste acties onmiddellijk opvallen. Wijzigingen in capabilities, sudo-regels en rollen controleer ik regelmatig. Waar dat zinvol is, scheid ik workloads bovendien via isolatiemechanismen van de kernel. Dit overzicht biedt een goed uitgangspunt voor Naamruimten en cgroups. Zo kan ik afwijkingen vroeg opmerken en de omgeving schoon houden.
In het dagelijks leven maak ik gebruik van eenvoudige tests: capsh --print toont mij de huidige set vaardigheden, getpcaps geeft een overzicht van procesrechten en in /proc//status ik lees CapEff, CapPrm, CapBnd. Met auditd houd ik wijzigingen in de status van de capability bij (bijv. regel op capset), breng ik gebeurtenissen in verband met implementaties en stel ik waarschuwingen in wanneer er plotseling uitgebreide rechten verschijnen. Bij lastige gevallen helpt het mij om strace -e capget,capset, om manipulaties van rechten zichtbaar te maken.
Praktijkvoorbeelden van systemd en containers
Veel diensten draai ik als systemd-units en daarin kapsel ik de rechten in:
CapabilityBoundingSet=CAP_NET_BIND_SERVICEbeperkt het beschikbare venster tot het strikt noodzakelijke.AmbientCapabilities=CAP_NET_BIND_SERVICEgeeft de dienst het recht om zonder bestandsmogelijkheden verbinding te maken via poort 80/443.NoNewPrivileges=yesvoorkomt latere uitbreidingen van de bevoegdheden.Gebruiker=,Groep=,ProtectSystem=strict,PrivateTmp=yesmaken de isolatie compleet.
In containers start ik processen zo minimaal mogelijk: docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE --read-only. Voor tijdelijke taken gebruik ik runtime-capabilities in plaats van file-capabilities in de image, zodat builds reproduceerbaar blijven en rechten aan de omgeving zijn gekoppeld.
Concrete migraties uit de praktijk
- ping zonder Set-UID: In plaats van
setuid rootik zetsetcap 'cap_net_raw=+ep' /bin/ping. Hierdoor kan elke gebruiker ICMP-sockets openen zonder volledige root-rechten. Ik controleer dit regelmatig metgetcap /bin/ping, of het attribuut bewaard is gebleven. - Webservice op poort 80/443: Ik laat mijn dienst draaien als gebruiker zonder speciale rechten en geef alleen
cap_net_bind_service. Als de dienst sowieso achter een reverse proxy staat, kan ik als alternatief ook daar op poort 80/443 koppelen en intern een hoge poort gebruiken – zonder dat ik daarvoor extra kennis nodig heb. - Verandering van partij in de procedure: Voor tools die tijdelijk verhoogde rechten nodig hebben (bijvoorbeeld voor het instellen van nice-levels), stel ik
cap_sys_nice, voer de actie vroeg uit en laat de vaardigheid daarna weer vallen. Ik vermijd blijvend verhoogde rechten.
Grenzen en alternatieven
Niet elke toepassing vereist deze mogelijkheden. Vaak zijn er veilige alternatieven met een lager risico:
- Socket-activering: De Init-dienst (bijvoorbeeld systemd) opent bevoorrechte sockets en draagt deze over aan het proces. Mijn dienst heeft dan geen bind-rechten nodig.
- Poortdoorsturing: Met firewallregels leid ik poort 80/443 om naar een hoge poort. De dienst blijft zonder speciale rechten, het systeemgedrag verandert niet.
- Niet-bevoorrechte low-poorten: Waar dat mogelijk is, kan ik de drempel voor niet-bevoorrechte poorten verhogen. Dat vergroot echter de speelruimte voor alle processen – ik weeg risico’s en gebruiksgemak zorgvuldig tegen elkaar af.
- Kleine hulpjes in plaats van alleskunners: Liever een piepklein, gecontroleerd binair bestand met precies één vaardigheid dan een groot monolithisch bestand met een uitgebreide lijst aan rechten.
Kort samengevat
Met Linux-mogelijkheden Ik verdeel root-bevoegdheden in kleine, goed beheersbare rechten. Bestandscapaciteiten vervangen risicovolle Set-UID-binaire bestanden en beperken de gevolgen van een aanval. In combinatie met strikte sudo-regels, rollen en MAC-profielen ontstaat zo een gelaagde beveiliging met duidelijke grenzen. Bounding- en Inheritable-sets beperken overerving en houden processen op koers. Wie op deze manier te werk gaat, vermindert het aanvalsoppervlak aanzienlijk en houdt de beheersinspanningen overzichtelijk.


