...

Linux-capabilities i stedet for root: Minimalprincippet for servertjenester

Jeg sætter Linux-kapaciteter for at drive servertjenester efter minimalprincippet og dermed kun tildele de absolut nødvendige delrettigheder. Dermed reducerer jeg Angrebsoverflade mærkbart, uden at blokere funktioner.

Centrale punkter

  • Mindste privilegium Konsekvent: Tjenesterne får kun præcis de kompetencer, der er behov for.
  • Finkornet I stedet for Root: Ca. 40–50 capabilities erstatter fuld adgang.
  • Adskillelse om processer: Adskillelse af privilegier mindsker skaderne ved udnyttelse af sårbarheder.
  • Fil Funktioner: Knytte rettigheder direkte til binære filer.
  • Kan revideres: getcap giver et klart overblik over særrettigheder.

Hvorfor root-adgang er risikabel – og hvordan »capabilities« ændrer på det

Tidligere kørte næsten alle servertjenester med Rodrettigheder, hvilket i tilfælde af et sikkerhedsbrud straks kunne føre til, at systemet blev overtaget. I dag fordeler jeg rettighederne målrettet ved at anvende kapaciteter som CAP_NET_BIND_SERVICE tildeler rettigheder til porte under 1024 og fjerner alle andre omfattende rettigheder. På den måde må webserveren binde sig, men ikke indlæse kernemoduler eller ændre filejere, hvilket Sikkerhed stiger markant. En klar opdeling af opgaverne gør angreb mindre effektive, fordi en proces, der udnyttes, kun må udføre et begrænset antal handlinger. Hvis man ønsker at indføre mere struktur i dette koncept, kan man indstille rettighederne meget præcist opdele i detaljer og dermed systematisk begrænse sådanne kritiske operationer. En monolitisk root-tjeneste omdannes dermed til et sæt af tjenester med minimale, klart definerede beføjelser.

Sådan fungerer capability-sæt i kernen

Hver proces har flere Kompetencesæt, som kernen kontrollerer ved følsomme handlinger. Effective-set bestemmer, hvad en proces må gøre lige nu, mens Permitted-set indeholder den samling af mulige rettigheder. Via Inheritable-set kan jeg styre, hvad der sker ved execve() overføres til underprocesser, hvilket især er vigtigt i forbindelse med wrappere og startskripter. Bounding-sættet definerer en fast øvre grænse, således at visse beføjelser aldrig igen kan opnås, selv ikke i tilfælde af fejl i applikationen. Med Ambient-sættet videregiver jeg beføjelser uden SUID til almindelige programmer og opretholder Angrebssti lille. Sammen giver disse sæt mig mulighed for en meget finjusteret styring, der går langt ud over det klassiske »alt eller intet« ved UID 0.

Sæt Formål Typisk brug Risiko for fejlkonfiguration
Effektiv Færdigheder, der virker nu Kontrol af hver enkelt privilegeret operation Processen kan straks blive for omfattende
Tilladt Udvalg af tilladte færdigheder Kilde til Effective-Set Unødvendige reserver forbliver tilgængelige
Arvelig Arvelige evner Kontrolleret videregivelse ved execve() Børn arver rettigheder unødvendigt
Afgrænsning Den øvre grænse for alle rettigheder Definere permanente udelukkelser Det er muligt at genvinde vigtige rettigheder
Ambient Videresendelse uden SUID Almindelige programmer får capabilities En bredere og mere diskret tildeling af rettigheder

I praksis er der to yderligere aspekter, der er vigtige: For det første er det afgørende, at Securebits om en proces efter et skift af bruger-ID (f.eks. via setuid()) bevarer sine funktioner. Med PR_SET_KEEPCAPS kan dette styres målrettet – typisk fremgangsmåde: start kortvarigt som root, opret de nødvendige sockets eller ressourcer, skift UID til en bruger uden privilegier og behold kun de nødvendige beføjelser. For det andet gælder det, at Afgrænsningsmængde er endelig en del af den aktuelle proceskæde. Hvis man her tidligt i startforløbet fjerner overflødige rettigheder, kan man senere ikke længere opnå „forbudte“ rettigheder, selv ikke som følge af fejlkonfigurationer.

Styring af filrettigheder med filfunktioner

I stedet for en tjeneste, der er varig Særlige rettigheder For at undgå dette foretrækker jeg at knytte dem direkte til den binære fil. Via setcap cap_net_bind_service=+eip /usr/bin/node tillader jeg port-bindinger, uden at processen behøver at køre som root. Med getcap /usr/bin/node eller rekursivt getcap -r / 2>/dev/null kontrollerer jeg tildelingen og bevarer kontrollen. Sletning foregår via setcap -r /sti/til/binærfilen, så jeg trækker de midlertidige rettigheder tilbage efter opgaven. Ved kopiering går capabilities ofte tabt, derfor sikrer jeg dem eksplicit under implementeringen for at Regression for at undgå dette. På den måde forbliver build-processerne reproducerbare, og rettighederne dokumenteres altid på en måde, der gør det muligt at spore dem.

Filfunktioner findes som udvidede attributter (sikkerhed.kapacitet) på filsystemet. Dette forudsætter et kompatibelt filsystem og passende monteringsindstillinger. Værktøjer som tjære og rsync skal XAttrs medtages eksplicit (f.eks. tar --xattrs, rsync -XA), ellers forsvinder rettighederne uden varsel. Pakkehåndteringsprogrammer kan indstille kapaciteter i trin efter installationen; jeg foretrækker at fastlægge dette i build-/release-processen for at undgå overraskelser ved opgraderinger. Det er desuden vigtigt at bemærke, at interpreter-scripts (f.eks. med shebang) ikke arver filkapaciteter på samme måde som ELF-binærfiler. Kraftfulde kapaciteter på Tolke Det er under alle omstændigheder risikabelt at integrere – jeg foretrækker at adskille det og arbejde med dedikerede, små hjælpebinærfiler.

Minimalprincippet for servertjenester i praksis

Jeg starter webserveren som en bruger uden administratorrettigheder og tildeler udelukkende CAP_NET_BIND_SERVICE, så processen kan binde sig til 80/443, og der ikke opstår yderligere Privilegier medfører. Filer og mapper styrer jeg fortsat via POSIX-rettigheder samt eventuelt MAC-profiler, hvorved konfiguration og indhold forbliver adskilt og beskyttet. Overvågnings- eller logningsagenter tildeles målrettede netværksrettigheder og læserettigheder til logfiler, men ingen beføjelser til at foretage systemændringer. I containermiljøer reducerer jeg desuden sæt af kapaciteter og kombinerer det med systemkaldsfiltre for at holde adfærden stramt. Denne kombination mindsker virkningen af vellykkede exploits og øger Gennemsigtighed de faktiske beføjelser. Tjenesterne fungerer fortsat, men handlingsrummet er fortsat begrænset.

I stedet for at tildele capabiliteter fjerner jeg dem nogle gange helt: Socket-aktivering stiller privilegerede lyttere (f.eks. 443/tcp) til rådighed via Init-processen og overfører kun den åbne filbeskrivelse til tjenesten. Applikationsprocessen behøver så ingen CAP_NET_BIND_SERVICE mere. Ligeledes kan engangs-root-handlinger (f.eks. oprettelse af PID-mappen) udføres på forhånd, hvorefter rettighederne konsekvent kan afgives. Jo færre beføjelser overhovedet jo flere der er med i spillet, desto mere robust er systemet over for kædefejl.

Gennemføre privilegieadskillelse korrekt

Jeg opdeler omfattende tjenester i flere Delprocesser, som hver især kun har de nødvendige beføjelser. En frontend-proces opretter TLS-forbindelser og binder til porte, men har ingen filsystemrettigheder til kritiske ændringer. En backend-proces behandler data internt, har minimale læserettigheder til konfigurationen og kommunikerer med databaser uden egne netværksfunktioner. Administrative opgaver som logrotation eller vedligeholdelse udføres via dedikerede værktøjer med tidsbegrænsede beføjelser. Hvis en angriber angriber en del af systemet, forbliver resten af systemet uberørt, fordi Tilladelser er defineret snævert. Sikkerheden tilpasses således applikationens struktur i stedet for at basere sig på ubegrænsede systemrettigheder.

Til denne opdeling er en klar startkoordinering oplagt. I klassiske opsætninger varetages dette af en supervisor; på nutidige systemer foretrækker jeg at bruge systemd, fordi det integrerer capabilities, cgroups og namespaces direkte. På den måde kan jeg starte netværksfrontend, worker og admin-værktøjer i hver deres sandkasse, begrænse ressourcerne og lade dem genstarte automatisk i tilfælde af fejl – uden nogensinde at tildele root-rettigheder generelt.

Kombination af sikkerhedskontrolmekanismer: POSIX, MAC og Capabilities

Funktioner fungerer bedst, når jeg kombinerer dem med klassiske Filerettigheder og MAC-systemer. SELinux eller AppArmor kan yderligere begrænse handlinger på trods af tildelte capabilities og dermed skabe flerlagsbeskyttelse. Således kan en proces ganske vist binde sig til en port, men forhindres gennem en politik i at læse følsomme filer. Hvis man ønsker at fordybe sig i forskellen mellem disse tilgange, finder man en tydelig sammenligning i SELinux kontra AppArmor og kan derefter vælge en passende sikkerhedsstrategi. Alt i alt skabes der et forsvarsnetværk, der afværger angreb på flere niveauer og Angrebsoverflade yderligere reduceret. Tildelingen af rettigheder forbliver dermed kontrollerbar, gentagelig og konsekvent.

Det bliver især restriktivt, når jeg desuden NoNewPrivileges Aktivér: Processer og underprocesser må derefter ikke opnå nye privilegier (f.eks. via SUID eller nyligt indstillede filkapaciteter). Sammen med en streng liste over kapacitetsbegrænsninger skabes der en sikkerhedsbarriere, der forhindrer senere udvidelse af privilegier, selv ved fejlagtig konfiguration.

Sikker fordeling og revision af kapaciteter

Jeg anser den tildelte Kompetencesæt så lille som muligt, og undgå alt, der lyder som en „anden root“, for eksempel CAP_SYS_ADMIN. Tolke som Python, Perl eller shell-skripter får ikke adgang til kraftfulde funktioner, fordi deres funktionalitet let kan misbruges. Gennem regelmæssige revisioner af getcap -r / 2>/dev/null opdager jeg afvigelser og rydder op. Binærfiler med capabilities er skrivebeskyttede, tilhører root og findes ikke i stier, som almindelige brugere har tilladelse til at ændre. Derudover tjekker jeg mine egne binærfiler før hver udgivelse og dokumenterer ændringer, så Anmeldelse og reproduktionen fungerer pålideligt. På den måde forbliver tildelingen af rettigheder overskuelig, og ændringer forbliver gennemsigtige.

Under kørselen kontrollerer jeg processer via /proc//status (Felter CapEff, CapPrm, CapInh). Det viser hex-værdierne for de aktive sæt og afslører straks, om et program kan mere, end det er tiltænkt. Værktøjer som capsh --print eller getpcaps gør fejlfinding nemmere. Med Linux-Audit-undersystemet logger jeg desuden ændringer i capabilities eller i sikkerhed.kapacitet-attributter for filer for at kunne spore manipulationer. Hvis man behandler capabilities som et konfigurationsobjekt og nøje gennemgår ændringer, bliver revisioner reproducerbare, og det bliver nemmere at dokumentere overholdelse af reglerne.

Hyppige faldgruber og hvordan jeg undgår dem

En typisk fælde: Når man kopierer, sker der følgende Egenskaber går tabt, hvilket kan medføre, at tjenester pludselig ikke længere starter, eller omvendt, at de ikke er tilstrækkeligt begrænset. Derfor sikrer jeg eksplicit capabilities i buildet, eller tildeler dem automatisk i post-install-trinnet. En anden fejl er den generøse brug af universelle capabilities, der åbner mere op end nødvendigt. Det er bedre at anvende konkrete capabilities som CAP_NET_RAW eller CAP_CHOWN kun at bruge dem, hvor de udløser en reel funktion. Også Ambient-sættet bruger jeg sparsomt, så der ikke opstår uønskede At give videre udbredt. Ved målrettet at reducere antallet og foretage regelmæssige kontroller kan man forhindre sikkerhedsbrud som følge af betjeningsfejl.

Lige så vigtigt: Fjern SUID-binærfiler systematisk. Hvor SUID tidligere var nødvendigt (f.eks. ved afsendelse af ICMP), kan man ofte nøjes med CAP_NET_RAW arbejde – eller, endnu bedre, uddelegere funktionen til en så lille hjælpeproces som muligt med et meget snævert kravspecifikation. Desuden undgår jeg at placere capabilities på midlertidige stier eller stier, som brugerne kan skrive til. Et strengt ejerskabs- og implementeringsregime (Root:root, 0755/0555, uforanderlige stier) forhindrer „tab“ af rettigheder som følge af udskiftede binære filer.

Funktioner inden for containere og DevSecOps

I container-miljøer reducerer jeg Kapaciteter aggressivt og fjerner alt, hvad arbejdsbyrden ikke absolut har brug for. Derudover opretter jeg en Seccomp-profil der blokerer risikable systemkald og dermed indfører en yderligere sikkerhedsbarriere. I build-pipelines definerer jeg kapaciteter deklarativt, tester dem i staging-miljøet og registrerer dem med versionsnummer. Det gavner compliance, fordi jeg kan dokumentere overholdelsen af princippet om mindst mulig adgang og fuldstændigt dokumentere ændringer i rettigheder. På den måde holdes containerne stramt styret uden at hæmme deres opgaver, og Angrebsoverflade forbliver lille. I kombination med billeder, der kun indeholder det allermest nødvendige, øges sikkerheden yderligere.

Vigtigt i forbindelse med containere: Capabilities findes i navneområder Relativ. Inden for et bruger-navneområde kan en proces ganske vist være „root“, men dens beføjelser gælder kun for de tilhørende navneområder – hvilket reducerer skaderadiusen betydeligt. Til gengæld er „--privilegeret“ er stort set altid tabu: Det deaktiverer den strenge afgrænsningsgrænse og åbner langt mere end nødvendigt. Derfor starter jeg som standard containere med „sæt alt på drop, tilføj målrettet“ og tilføjer NoNewPrivileges, cgroup-grænser og skrivebeskyttede monteringer. Til tjenester, der kun skal lytte, bruger jeg socket-aktivering eller sidecars for helt at undgå at skulle bruge yderligere capabilities.

Systemd-eksempel: Deklarativ begrænsning af capabilities

I service-enheder fastlægger jeg, hvad en proces højst må gøre – klart, gentageligt og med versionskontrol. Et kortfattet eksempel på en webservice, der kun må binde til port 443 og ellers er stærkt begrænset:

[Unit]
Description=Minimal webservice uden root-rettigheder

[Service]
User=web
Group=web
ExecStart=/usr/bin/my-web
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/lib/my-web
RestrictAddressFamilies=AF_INET AF_INET6
SystemCallFilter=@basic-io @network-io
LockPersonality=yes
MemoryDenyWriteExecute=yes

[Install]
WantedBy=multi-user.target

Kombinationen af AmbientCapabilities og en hård CapabilityBoundingSet sikrer, at tjenesten kun får den nødvendige kapacitet og intet derudover. NoNewPrivileges forhindrer efterfølgende opgradering af privilegier, ProtectSystem og ReadWritePaths regulerer skriveadgangen, og et stramt filter for systemkald forhindrer unødvendige indgange til kernen.

Ofte anvendte funktioner – og sikre alternativer

  • CAP_NET_BIND_SERVICE: Bind til porte under 1024. Alternativ: Socket-aktivering, placering af reverse proxy foran.
  • CAP_NET_RAW: Rohsockets (Ping, DHCP). Alternativ: en lille hjælpeproces i stedet for omfattende fortolkerrettigheder.
  • CAP_CHOWN/CAP_FOWNER: Ejerskab/ACL-justeringer. Alternativ: forberedte mapper, dedikerede vedligeholdelsesværktøjer.
  • CAP_SYS_PTRACE: Fejlfinding/sporing – kun i staging, aldrig bredt i produktion.
  • CAP_SYS_ADMIN: „Andet root“ – undgå dette; præciser, hvad der reelt er brug for.

Jeg vælger altid den mindste mængde, der præcist aktiverer den nødvendige funktion. Hvis en kapacitet åbner op for flere angrebsveje (f.eks. RAW-sockets), indkapsler jeg funktionen i en separat, kortvarig proces og tilbagekalder rettighederne, når opgaven er udført.

Tjekliste til praksis for robuste kompetencer

  • Kører tjenesten uden root-adgang? Hvis ikke: Hvorfor ikke – og kan det løses ved hjælp af socket-aktivering eller små hjælpeprogrammer?
  • Er alle Er de tildelte kapaciteter påviseligt nødvendige (funktionsdokumentation, testtilfælde)?
  • Er afgrænsningsmængden fastlagt så snævert og tidligt som muligt?
  • Bevares XAttrs konsekvent i build, ved deployment og backup (rsync/tar-flags, pakkeskripter)?
  • Undgår jeg konsekvent at bruge »capabilities« i fortolkere og SUID-binærfiler?
  • Er ejer- og filrettigheder (Root:root, 0755/0555) samt stier beskyttet mod ændringer?
  • Virker de ekstra kontrolmekanismer (NoNewPrivileges, Seccomp, MAC-profiler)?
  • Bliver proceskapaciteter auditeret under kørsel (/proc//status, getpcaps) og ændringerne dokumenteret?
  • Er containere som standard konfigureret med „drop all, add minimal“ og uden „privileged“?

Kort opsummeret

Linux Capabilities opdeler klassiske root-rettigheder i små, kontrollerbare enheder og implementerer dermed minimalprincippet på en teknisk velfungerende måde. Jeg tildeler tjenester kun de rettigheder, de reelt har brug for, og kombinerer dette med POSIX-rettigheder samt MAC-politikker. Filkapaciteter sikrer, at rettigheder er direkte knyttet til binærfiler, og at revisioner tydeligt viser, hvem der må hvad. Med adskillelse af privilegier, reducerede containerrettigheder og systemkaldsfiltre begrænser jeg skaderne, hvis en sårbarhed udnyttes. Regelmæssige kontroller, strenge ejer- og skriverettigheder samt en dokumenteret udgivelsesproces holder tildelingen strømlinet. På den måde forbliver servertjenesten funktionsdygtig, men Plads til at manøvrere holdes konsekvent på et lavt niveau for angribere.

Aktuelle artikler

Serverrum med Linux-servere og advarselssymbol for GhostLock-kerne-sikkerhedshul
Sikkerhed

GhostLock CVE – Teknisk analyse af sårbarheden i Linux-kernen

GhostLock CVE-2026-43499 er en kritisk »use-after-free«-sårbarhed i Linux-kernen. I denne analyse af GhostLock CVE viser vi udnyttelseskæden til root-eskalering og giver konkrete sikkerhedsanbefalinger til administratorer.