...

Linux-funktioner: Säker och detaljerad fördelning av root-behörigheter

Med Linux Capabilities delar jag upp root-rättigheterna i små, tydligt definierade behörigheter och minskar därmed risken avsevärt. På så sätt styr jag specifikt vilka processer som får utföra särskilda åtgärder och begränsar varje applikations angreppsyta.

Centrala punkter

  • Finkornig I stället för att vara allsmäktig: dela upp root-rättigheterna i mindre privilegier.
  • Filfunktioner I stället för Set-UID: koppla nödvändiga behörigheter direkt till binärfilerna.
  • Kompetensuppsättningar konfigurera: Permitted, Effective, Inheritable, Bounding på ett målinriktat sätt.
  • Åtskillnad av privilegier: Håll tjänster, verktyg och uppgifter strikt åtskilda.
  • Försvar på djupet: Komplettera funktionerna med sudo, roller och loggar.

Varför avbryta root-behörigheterna?

Ett root-konto ger Full tillgång på fil- och processnivå, men just detta bäddar för allvarliga fel. Ett felaktigt kommando eller en säkerhetslucka räcker för att en hel installation ska krascha. Därför begränsar jag omfattande åtgärder till det absolut nödvändiga och minskar på så sätt skadans omfattning och återställningstiden. Principen om minimala behörigheter håller tjänsterna små och hanterbara. Jag inaktiverar direkt inloggning som root, satsar på roller och skriver fullständiga loggar.

Linux-kapaciteter – en kort förklaring

Linux-kapaciteter delar upp den traditionella root-behörigheten i tydligt avgränsade Privilegier. Varje process får endast de byggstenar som den verkligen behöver för sin uppgift, till exempel att binda till portar under 1024 eller att sända särskilda signaler. På så sätt undviker jag det tidigare ”allt eller inget”-principen. Kärnan hanterar dessa byggstenar per process och tillämpar dem strikt. På så sätt förblir kontrollen detaljerad och spårbar.

Tekniskt sett kopplar jag färdigheter antingen till Processer (genom deras kompetensuppsättningar) eller till Filer (som utökade attribut säkerhet.kapacitet (ELF-binärfiler). Vid execve()-Vid start slår kärnan samman filkapaciteterna med processuppsättningarna: Enkelt uttryckt kombineras tillåtna kapaciteter från filattributet med de ärvbara rättigheterna hos den anropande processen till en ny tillåten uppsättning (Permitted-Set) och – om så är markerat – aktiveras de samtidigt i den effektiva uppsättningen (Effective-Set). Detta undviker Set-UID-omvägar och gör att behörigheterna förblir synliga och kontrollerbara.

Att förstå kapacitetsuppsättningar i ett processperspektiv

Varje process har flera uppsättningar av rättigheter, som jag målmedvetet kontroll. Permitted-Set definierar vad en process i princip får ha. Effective-Set fastställer vad som för tillfället är aktivt. Inheritable-Set reglerar vilka privilegier som kan överföras till underprocesser. Bounding-Set sätter en strikt övre gräns och förhindrar att processer överskrider den.

Ambient Capabilities och Securebits

Förutom de välkända seten finns det även Ambient-set, som vid execve() inte upphör automatiskt att gälla. Jag använder det när en process utan privilegier specifikt behöver minimala rättigheter över flera avrättning-ska behållas över flera nivåer (till exempel vid anrop av externa hjälpprogram). Ambient-rättigheter räknas endast in i de effektiva rättigheterna om den anropade filen inte själv anger några filkapaciteter – på så sätt förhindrar jag oönskad eskalering.

Med de Securebits jag styr detaljerna kring övergångarna, t.ex. om en process efter att UID har ändrats får behålla sina tidigare inställda förmågor (keepcaps) eller om han generellt sett inte får erhålla några nya privilegier (no_new_privs). I praktiken använder jag Securebits strikt och avstår från bekvämlighet för att bryta exploatkedjor.

Filfunktioner istället för Set-UID

Jag ersätter Set-UID-binärer med filfunktioner för att minska risken för att sänka. Istället för att ge ett program root-behörighet sätter jag bara den behörighet som behövs. En typisk ändring ser ut så här: setcap 'cap_net_bind_service=+ep' /usr/bin/meinserver. Med getcap -r / kontrollerar jag vilka filer som innehåller funktioner. Det minskar antalet eskaleringssteg märkbart.

Det är viktigt att filfunktioner endast tillämpas på ELF-binärfiler fungerar. Tolkskript (t.ex. Python, Bash) ärver dem inte på ett tillförlitligt sätt. I sådana fall kapslar jag in den privilegierade åtgärden i ett litet, statiskt granskat hjälpprogram eller använder socket-aktivering, så att min tjänst inte behöver ansluta själv från början. Dessutom håller jag koll på filrättigheterna: Capabilities ger särskilda rättigheter gentemot kärnan, men ersätter inte ingen vanliga ACL:er eller POSIX-behörigheter.

När man kopierar eller packar går färdigheter snabbt förlorade: cp utan stöd för XATTR, felaktigt inställd umask eller ta bort en build-artefakt i ett filsystem utan utökade attribut säkerhet.kapacitet utan att säga något. Därför arbetar jag på ett reproducerbart sätt och använder: cp --preserve=xattr ..., tar --xattrs, rsync -X. I paketbyggnader anger jag filfunktioner explicit i installationsskriptet, testar installationen i en ren virtuell maskin och kontrollerar getcap i CI.

Privilegieseparation med realistiska scenarier

En webbserver behöver åtkomst till port 80/443, men inte till kärnmoduler eller systemomstarter, därför ställer jag in CAP_NET_BIND_SERVICE och inget annat. En backup-agent får läsa och skriva filer, men får inte ändra nätverkskonfigurationen. Ett övervakningsverktyg får läsbehörighet till nyckeltal, men har inga rättigheter att göra ändringar. Dessa begränsningar gör att attacker förblir lokala istället för att påverka hela systemet. Det är just denna åtskillnad som gör tjänsterna hanterbara och håller felkonfigurationer i schack.

Kombinera med sudo och roller

Funktioner ersätter inte en ordentlig Rollstruktur, de kompletterar dem. Jag beviljar sudo-behörigheter med stor försiktighet, använder fullständiga kommandovägar och undviker generella regler som „ALL=(ALL) ALL“. Jag loggar varje behörighetsbeviljning. Grupper samlar ansvar, medan kapaciteter sätter tekniska gränser i processerna. På så sätt skapas tydliga ansvarsområden utan överdrivna behörigheter.

Vanliga fallgropar och bästa praxis

  • Ingen förkortning för CAP_SYS_ADMIN: Denna rättighet är ett samlingsbegrepp. Jag ersätter den med mer specifika alternativ (t.ex. CAP_SYS_CHROOT, CAP_SYS_TIME, CAP_SYS_NICE) eller låt helt bli.
  • Filrättigheterna förblir strikta: Funktioner inaktiverar inte DAC generellt. Utan CAP_DAC_OVERRIDE Kärnan respekterar fortfarande ägar- och lägesbitar. Jag tilldelar därför fortfarande läsrättigheter i så liten utsträckning som möjligt.
  • Härdning av spår: Om jag förser en binärfil med filfunktioner förhindrar jag PATH-spoofing (absoluta sökvägar i sudoers, begränsade skrivrättigheter för kataloger i sökvägen).
  • Börja tidigt, börja ofta: Processer kan ibland startas med fler behörigheter än nödvändigt. Jag tar bort onödiga behörigheter direkt efter det känsliga steget (prctl()/libcap) och ställ in no_new_privs, där det är möjligt.
  • Begränsa arv: Jag håller Inheritable- och Ambient-uppsättningarna små. Underordnade processer får inte öppna några nya dörrar.
  • Kontrollera bygg- och driftsättningspipeline: Jag bekräftar att säkerhet.kapacitet bevaras och att inga staging-steg (containerlager, NFS, artefaktskanner) tar bort XATTR:er.

Översikt över viktiga kapaciteter och risker

Innan jag tilldelar behörigheter fastställer jag tydligt vilka behörigheter som behövs och bedömer risken med dem. Tabellen nedan visar typiska exempel med deras effekter och klassificering. Jag överväger alltid alternativ för att undvika omfattande behörigheter. Särskilt CAP_SYS_ADMIN Jag beviljar dem ytterst sparsamt. När det är möjligt ersätter jag vidsträckta privilegier med riktade, snävare varianter.

Kapacitet Syfte Risk Exempel
CAP_NET_BIND_SERVICE Binda till portar < 1024 Låg till medelhög Webbserver på 80/443
CAP_SYS_BOOT Starta om systemet Hög Planerad omstart
CAP_SYS_MODULE Ladda/ta bort kärnmoduler Mycket hög Drivrutinshantering
CAP_SYS_ADMIN Mångsidiga administratörsfunktioner Mycket hög Olika underhållsuppgifter
CAP_SETUID / CAP_SETGID Byta UID/GID Medelhög till hög Förändring av befogenheter under tjänstgöring

Utöver tabellen håller jag just nu på att utvärdera CAP_SYS_PTRACE (felsöka processer), CAP_NET_ADMIN (nätverksparametrisering) och CAP_DAC_OVERRIDE (Att kringgå filåtkomstbegränsningar) är ytterst kritiskt. Ofta finns det mönster som gör det möjligt att undvika dessa rättigheter: dedikerade mätningsändpunkter istället för process-snooping, socket-aktivering eller portvidarebefordran istället för bind-rättigheter samt tydliga filrättigheter istället för generell kringgåning av DAC.

Härdning i containrar och webbhotell

I miljöer med flera användare anser jag att kompetensen är avgörande liten och förhindrar arv till underprocesser. Containrar drar stor nytta av detta så snart bounding-setet är väl avgränsat. Jag kombinerar detta med isolerade filsystem och processutrymmen. Denna introduktion hjälper mig att få en överblick över olika isoleringsmetoder Processisolering. På så sätt förblir tjänsterna åtskilda, även om en applikation inte fungerar som den ska.

I praktiken ställer jag in behållarna som standard på „släpp allt, lägg till specifikt“: --cap-drop=ALL --cap-add=NET_BIND_SERVICE för webbtjänster, inga monteringsrättigheter, ingen SYS_ADMIN. I orkestrerade miljöer hanterar jag profilen centralt och kontrollerar den i policyer. Viktigt: Jag förlitar mig inte på filfunktioner i bilden, utan tilldelar behörigheter vid körning i orkestratorn – på ett sätt som går att reproducera och granska.

Samverkan med SELinux och AppArmor

Funktioner styr vad en process får göra, medan MAC-profiler fastställer vad den får komma åt, och de båda fungerar i samklang bra. Jag definierar kapaciteter strikt och låter SELinux eller AppArmor begränsa åtkomsten till filer och socklar. Detta skapar ett skiktat skydd som ställer flera hinder i vägen för exploateringar. Här hittar jag en snabb jämförelse: SELinux jämfört med AppArmor. På så sätt hålls en komprometterad tjänst inlåst och kan orsaka mindre skada.

I praktiken: Gå fram steg för steg

Jag börjar med att göra en översikt över alla tjänster och deras Krav och önskemål. Därefter tar jag bort onödiga Set-UID-binärfiler eller ersätter dem med specifika filbehörigheter. Jag konfigurerar sudo restriktivt och dokumenterar varje post. Jag tilldelar uppgifter till roller och grupper och håller behörigheterna på ett minimum. Därefter testar jag systemet under belastning och granskar loggposterna för oväntade avvisningar.

En kort checklista hjälper mig vid övergången:

  • Fastställ kraven för varje tjänst skriftligen (endast det som verkligen behövs).
  • Göra en inventering av befintliga särrättigheter (find / -perm -4000, getcap -r /).
  • Ersätt på ett målinriktat sätt: Avskaffa Set-UID, ställ in filfunktioner, ta bort behörigheter i ett tidigt skede.
  • Stänga arv: Strama upp avgränsningsmängden, minimera ärftliga/omgivande faktorer.
  • Säkra systemd-/containerprofiler (KapabilitetBegränsningSet=, NoNewPrivileges=yes).
  • Testa under belastning, granska loggar och revisionsposter, dokumentera undantag.

Övervakning, namnutrymmen och kontinuerliga granskningar

Jag övervakar loggfiler, larm och systemanrop så att oönskade åtgärder omedelbart stå ut. Jag kontrollerar regelbundet ändringar av behörigheter, sudo-regler och roller. När det är lämpligt separerar jag dessutom arbetsbelastningar med hjälp av isoleringsmekanismer i kärnan. Denna översikt ger en bra utgångspunkt för Namnrymder och cgroups. På så sätt upptäcker jag avvikelser i ett tidigt skede och håller omgivningen ren.

I vardagen använder jag enkla tester: capsh --print visar mig den aktuella uppsättningen av färdigheter, getpcaps listar processuella rättigheter och i /proc//status jag läser CapEff, CapPrm, CapBnd. Med auditd följer jag upp ändringar i kapacitetsstatusen (t.ex. regel till capset), kopplar ihop händelser med driftsättningar och ställer in larm om omfattande behörigheter plötsligt dyker upp. I knepiga fall hjälper det mig att strace -e capget,capset, för att synliggöra manipuleringar av rättigheter.

Praktiska exempel på systemd och containrar

Jag kör många tjänster som systemd-enheter och kapslar in behörigheterna där:

  • CapabilityBoundingSet=CAP_NET_BIND_SERVICE begränsar det tillgängliga rättighetsfönstret till det absolut nödvändiga.
  • AmbientCapabilities=CAP_NET_BIND_SERVICE ger tjänsten rätt att ansluta till portarna 80/443 utan filfunktioner.
  • NoNewPrivileges=yes förhindrar senare utvidgningar av rättsområdet.
  • Användare=, Grupp=, ProtectSystem=strikt, PrivateTmp=yes kompletterar isoleringen.

I containrar startar jag processer så minimalt som möjligt: docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE --read-only. För tillfälliga jobb använder jag körningsegenskaper istället för filegenskaper i avbildningen, så att byggprocesserna förblir reproducerbara och behörigheterna är knutna till miljön.

Konkreta migreringar från praktiken

  • ping utan Set-UID: I stället för setuid root jag sätter setcap 'cap_net_raw=+ep' /bin/ping. På så sätt kan alla användare öppna ICMP-socklar utan fullständiga root-rättigheter. Jag kontrollerar regelbundet med getcap /bin/ping, om attributet finns kvar.
  • Webbtjänst på port 80/443: Jag kör min tjänst som en användare utan särskilda behörigheter och anger endast cap_net_bind_service. Om tjänsten ändå ligger bakom en omvänd proxy kan jag alternativt även binda den till port 80/443 där och använda en hög port internt – helt utan ytterligare kunskaper.
  • Ändring av parter i rättegången: För verktyg som tillfälligt behöver utökade behörigheter (t.ex. för att ställa in nice-nivåer) ställer jag in cap_sys_nice, utför åtgärden tidigt och släpp sedan förmågan igen. Jag undviker permanent utökade rättigheter.

Gränser och alternativ

Det är inte alla användningsfall som kräver Capabilities. Ofta finns det säkra alternativ med lägre risk:

  • Socket-aktivering: Init-tjänsten (t.ex. systemd) öppnar privilegierade socklar och överlämnar dem till processen. Min tjänst behöver då inga Bind-behörigheter.
  • Portvidarebefordran: Med hjälp av brandväggsregler omdirigerar jag 80/443 till en hög port. Tjänsten förblir utan särskilda behörigheter och systemets beteende förändras inte.
  • Icke-privilegierade lågportar: Om det är lämpligt kan jag höja tröskelvärdet för icke-privilegierade portar. Det utökar dock handlingsutrymmet för alla processer – jag väger noga mellan risk och bekvämlighet.
  • Små hjälpredor istället för universalmaskiner: Hellre en liten, granskad binärfil med exakt en funktion än en stor monolit med ett omfattande utbud av funktioner.

Kortfattat sammanfattat

Med Linux-funktioner Jag delar upp root-behörigheter i små, lätt hanterbara privilegier. Filkapaciteter ersätter riskfyllda Set-UID-binärer och minskar konsekvenserna av en attack. I kombination med strikta sudo-regler, roller och MAC-profiler skapas ett skiktat skydd med tydliga gränser. Bounding- och Inheritable-Sets begränsar arv och håller processerna på rätt spår. Den som tillämpar denna metod minskar attackytorna märkbart och håller administrationsbördan hanterbar.

Aktuella artiklar