...

Seccomp under Linux: Målrettet begrænsning af programmer for øget sikkerhed

Seccomp Linux begrænser applikationerne til netop de systemkald, de rent faktisk har brug for, og reducerer dermed kernens angrebsflade betydeligt. Jeg bruger denne mekanisme målrettet til at placere containere, mikrotjenester og følsomme tjenester i en Sandkasse at spærre dem uden at blokere deres kernefunktioner.

Centrale punkter

Jeg opsummerer de vigtigste aspekter for at give et hurtigt overblik og fremhæver, hvordan jeg anvender Seccomp i praksis. Dette giver en klar indføring i politikker, filtre og beskyttelse af arbejdsbelastninger. Disse punkter fungerer som en rød tråd for mig i forbindelse med planlægning, drift og kontrol. De hjælper med at prioritere risici og vælge fornuftige standardindstillinger. Med disse kernepunkter for øje forbliver Sikkerhed forståeligt og håndterbart.

  • Filtermodus: BPF-profiler med fin granularitet tillader kun de nødvendige systemkald.
  • Angrebsoverflade: Færre tilgængelige kernelstier mindsker risikoen for udnyttelse.
  • Container: Standardprofiler blokerer pålideligt risikable opkald.
  • Kubernetes: seccompProfile og seccompDefault sikrer ensartet beskyttelse.
  • Arbejdsgang: Analysere, profilere, hærde, teste, implementere.

Jeg gennemgår hver enkelt arbejdsbelastning, fastlægger en passende profil og overvåger dens effekt i praksis. På den måde opbygges en robust Baseline-beskyttelse, som senere kan udvides målrettet.

Seccomp kort forklaret: Secure Computing Mode

Seccomp står for „Secure Computing Mode“ og begrænser Systemkald af en proces til en klart defineret mængde. Jeg placerer filteret dér, hvor applikationer kommunikerer med kernen, f.eks. når der åbnes filer, sockets eller oprettes yderligere processer. Ideen er enkel: Tillad det, der er nødvendigt, og forhindr det uønskede ved hjælp af fejlkoder eller kill-kommandoer. Den, der forstår interaktionen med kernen, kan hurtigt oprette solide profiler; en god start er artiklen At forstå systemkald. Sådan skabes en effektiv Sandkasse, hvilket gør det sværere at udnytte sårbarheder og lukker uønskede kernel-stier.

Hvorfor Seccomp Linux mindsker angrebsfladen

Hvert yderligere systemkald øger potentielt Angrebsoverflade. Jeg reducerer dette område ved kun at give adgang til de systemkald, som applikationen påviseligt bruger. Dermed mister mange exploit-kæder adgangen til kritiske kernefunktioner. Selv ved kodeudførelse i processen støder en angriber ofte på lukkede døre. På denne måde forhindrer jeg adgang til følsomme undersystemer som ptrace, BPF eller bestemte debug-grænseflader.

Tilladelsesliste i stedet for blokeringsliste: den rigtige strategi

I produktive miljøer satser jeg på Tilladelsesliste: Standardindstillingen er „forbudt“, og kun et nøje udvalgt sæt systemkald er tilladt. Mange runtime-miljøer leverer af kompatibilitetshensyn blokkeringslisteprofiler, der kun blokerer særligt risikable kald. For følsomme tjenester strammer jeg grebet og tillader kun det, som runtime-analysen reelt viser. Det mindsker overraskelser ved ændringer i kernen og flytter fokus fra „Hvad er farligt?“ til „Hvad er nødvendigt?“. For generiske arbejdsbelastninger kan en solid blokeringsliste være et godt udgangspunkt, men for gateways, betalingsforløb eller godkendelsestjenester er det værd at skifte til en tilladelseslistepolitik med eksplicitte undtagelser.

Modus og filterlogik: fra streng til BPF

Seccomp har en streng tilstand, der kun tillader read, write, exit og sigreturn, samt den meget fleksible Filtermodus om BPF. I praksis bruger jeg næsten altid filtre, da jeg dermed kan analysere systemkald og deres argumenter i detaljer. Kernen kontrollerer hvert opkald i forhold til det gemte program og beslutter, om det er tilladt, returnerer en fejl eller afslutter processen. På den måde kan jeg blokere enkelte varianter af et systemkald, f.eks. specifikke flag fra `clone` eller `unshare`. Denne granularitet gør Politikker slank og effektiv på samme tid.

Tilbagekaldelsesaktioner og kontrolomfang

Jeg styrer adfærden ved overtrædelser målrettet gennem handlinger: tillade, definerede fejl (for det meste EPERM eller EACCES) returnerer, via TRAP udløse et signal med TRACE Aktiver fejlfinding, eller afslut processen/tråden konsekvent. En ren fejlretur er ofte tilstrækkelig og forbedrer fejltolerancen; til særligt følsomme forløb anvender jeg derimod »kill«-handlinger. Når jeg har brug for diagnosticering, bruger jeg kernellogning eller logningshandlinger til gradvist at indsnævre profilen i staging-miljøer uden unødigt at forstyrre driften.

Sandboxing og containerbeskyttelse i praksis

Container-runtimes leverer gennemprøvede Standard-profiler, der blokerer risikable systemkald. Med udgangspunkt heri indfører jeg yderligere begrænsninger for mount, unshare, bpf, ptrace samt keyctl og perf_event_open. Programmer, der behandler upålidelig inddata, drager dobbelt fordel: færre kernelfunktioner og tydeligere fejlhåndtering ved overtrædelser. Selv webbrowsere og sandkasseværktøjer bygger på denne adskillelse mellem nødvendig og farlig adgang. På den måde forbliver kørselssystemet overskueligt og forudsigelig.

Meddelelse i brugerrummet: kontrollerede undtagelser

I sjældne, men berettigede undtagelsestilfælde bruger jeg User-Space-Notifier-Tilgang: En overvågningsproces modtager anmodninger om blokerede systemkald og kan målrettet godkende eller afvise dem. På den måde implementerer jeg broker-mønstre, for eksempel for kun at tillade bestemte mount-at tillade operationer i bestemte mapper. Det mindsker behovet for at indføje generelle undtagelser i politikken og sikrer samtidig fleksibilitet i driften. Her er det vigtigt med en klar styring: Hvilke kommandoer må udføres, hvordan kontrolleres de, og hvordan undgår jeg, at notifikationssystemet selv bliver et enkelt fejlopstået punkt?

Seccomp i Kubernetes og OpenShift

I Kubernetes angiver jeg i pod-manifestet via SecurityContext, hvilken profil der er aktiv. seccompDefault på noden sikrer, at workloads, der ikke har en egen angivelse, automatisk får tildelt en passende Standard-profil. OpenShift og Podman integrerer også dette, herunder overførsel via –security-opt. Jeg kan stille profiler til rådighed centralt og tilknytte dem via annotationer eller feltbinding. På denne måde fastlægger jeg klare regler på tværs af alle Navnerum væk.

Udformning af retningslinjer for teams og platforme

Jeg strukturerer profiler efter Arbejdsbelastningsklasser i stedet for efter teams: web-frontends, worker, DB-klienter, datapipelines. Hver klasse får tildelt en testet profil, som jeg kun supplerer minimalt i særlige tilfælde. I Kubernetes sikrer jeg via en adgangsregler, at pods mindst RuntimeDefault udnytte, mens særligt følsomme navneområder kræver en streng Localhost-Tvinge profil. Til fejlfindings- eller hændelsessituationer findes der en veldefineret undtagelsesvej med begrænset gyldighedsperiode og yderligere begrænsning af netværksadgang og kapacitet, så diagnosticering fortsat er mulig uden at sænke sikkerhedsniveauet generelt.

Opbygning af profiler: Arbejdsgangen fra analyse til implementering

Jeg starter med en løbetidsanalyse og ser, hvilke Systemkald som applikationen bruger i normal drift. Derefter udarbejder jeg en startprofil, der netop tillader disse opkald og udelukker sjældne forløb. Herefter strammer jeg yderligere op ved at fjerne sjældne eller risikable opkald eller indsnævre dem. En testfase afdækker huller og viser, om der mangler funktioner, eller om fejlkoder er hensigtsmæssige. Først derefter implementerer jeg Politik i produktion og tildeler hver ændring en versionsnummer.

Arkitektoniske og ABI-aspekter

Syscalls varierer afhængigt af arkitektur og kerneversion. Jeg sørger for, at profilerne Multi-Arch dækker det fuldt ud (f.eks. x86_64 og arm64), og at nyere varianter som openat2 eller time64-systemkald er taget i betragtning. I containere med ældre basisoperativsystemer tjekker jeg, om der er legacy-stier (f.eks. via socketcall eller bestemte IPC-kald). Hvem libseccomp eller bruger runtime til generering, drager fordel af stabile tilknytninger mellem symbolnavne og syscall-numre – jeg undgår bevidst at bruge faste numre for at bevare portabiliteten. Vigtigt: Filtre er arvelig og kun monoton kan skærpes; det, der én gang er forbudt, forbliver forbudt, også efter execve.

Opgraderings- og kompatibilitetsstyring

Biblioteks- og kerneopdateringer medfører nye systemkald eller ændrer opkaldsmønstre. Jeg planlægger derfor målrettede Røgprøver efter opgraderinger og har et testmiljø klar, som i tvivlstilfælde kan bruges til LOG-aktioner. På den måde kan jeg se, hvad der anmodes om af nyt, inden jeg sætter det i produktion. Desuden dokumenterer jeg bevidst forskelle mellem images (f.eks. musl-baserede vs. glibc-baserede containere), da disse kan benytte forskellige stier til kernel-API’en. For rollbacks er en klar versionering af profilerne afgørende; i tilfælde af en hændelse skifter jeg midlertidigt til en mindre streng politik med kort udløbstid og tæt overvågning.

Identificering af fejlmønstre: Logning og prioritering

Blokerede systemkald skal kunne findes, ellers famler man i mørket Mørk. Jeg aktiverer logning i runtime og analyserer målinger, der viser hyppige forekomster og afvigelser. Meldinger med EPERM eller EACCES tyder ofte på for snævre regler. Uventede afbrydelser tilskriver jeg den berørte komponent og tjekker de relevante flag eller argumenter. Derefter tilpasser jeg Filtre Indstil den til »minimal« og prøv igen.

Playbook til fejlfinding

  • Gengive: gentage nøjagtig den samme indgang/trafik og sammenholde logfilerne.
  • Identificer: Registrer det pågældende systemkald med argumenter (f.eks. via runtime-log eller audit-udskrift).
  • Vurder: Er denne kommando nødvendig? Findes der en variant med lavere risiko (f.eks. »openat« i stedet for »open«, mere specifikke flag)?
  • Tilpas: Tillad minimalt, helst med argumentfiltre; lad standardhandlingen være streng.
  • Sikre: Ved kritiske undtagelser skal man desuden skærpe begrænsningen af funktioner, Read-Only-FS eller navneområder.
  • Gentest & telemetri: Efter rettelsen skal man udføre målrettede test, overvåge nøgletal og oprette alarmer.

Sammenligning med SELinux, AppArmor og Capabilities

Seccomp griber ind ved grænsefladen mellem applikation og kerne, mens SELinux og AppArmor primært regulerer adgangen til objekter. Capabilities styrer privilegerede operationer, som jeg desuden reducerer kraftigt. Sammen med Navneområder og cgroups Der opstår et flerlags beskyttelseskoncept. Jeg adskiller ressourcer, begrænser unødvendige privilegier og begrænser kernelstier via Seccomp. Denne kombination sikrer, at arbejdsbelastningerne holdes inden for snævre rammer og er lette at kontrollere.

Ydeevne og overhead

En veludviklet Seccomp-profil medfører kun en minimal Overhead: Kernen kontrollerer et lille BPF-program for hvert syscall. I praksis er dette næppe mærkbart ved almindelige web- og service-workloads. Det kan dog blive kritisk ved højfrekvente, syscall-intensive forløb (f.eks. pakkebehandling, IPC-tunge processer). Derfor holder jeg antallet af regler begrænset, bruger argumentfiltre i stedet for lange lister og tester hotpaths med benchmarks. Hvis en profil medfører en målbar forsinkelse, tjekker jeg først for dubletter, unøjagtige matches og om bestemte sjældne opkald kan flyttes til en separat proces.

Bedste praksis for sikre standardindstillinger

Jeg starter med Runtime-standardprofilen og tilpasser den alt efter Arbejdsbyrde. Tjenester med høj følsomhed, såsom gateways eller autentificeringstjenester, underlægges særligt strenge regler. Ændringer i profiler integrerer jeg i CI/CD og tester dem automatisk. Derudover anbefaler jeg en kraftig begrænsning af rettigheder, skrivebeskyttede filsystemer og NoNewPrivs. En vejledning til overordnede værtsbeskyttelsesmekanismer findes under Kernel-hærdning, som kan suppleres godt med Seccomp.

Udvidet hærdning: hvad jeg desuden tjekker

Ud over de sædvanlige mistænkte (mount, fjern deling, bpf, ptrace, keyctl, perf_event_open) gennemgår jeg følgende anmodninger og begrænser dem kraftigt eller blokerer dem helt, afhængigt af sammenhængen:

  • setns: forhindrer, at man springer over i andre navnerum.
  • process_vm_readv/process_vm_writev: forhindrer direkte adgang til hukommelsen i andre processer.
  • kexec_load og genstart: beskytter mod forsøg på genstart eller udskiftning af kernen.
  • swapon/swapoff og init_module/finit_module: begrænser system- og modulindlæsningsmekanismerne.
  • clone3 med risikable flags (f.eks. navneområder): Begræns dem detaljeret via argumenter.
  • io_uring_setup: Afhængigt af arbejdsbyrden bør man enten give fri adgang eller indføre strenge begrænsninger, da det er et kraftfuldt interface.

Retningslinjen er: Så meget som nødvendigt, så lidt som muligt – og hellere en lille, dokumenteret undtagelse end en vidt åben standardregel.

Integration i CI/CD og Teams

Jeg behandler Seccomp-profiler som Kode: versionering, gennemgang, test. Pipeline-opgaver kontrollerer, om profiler passer til billedet, og om der opstår blokeringer. Smoke-tests med testdata afslører adfærdsændringer hurtigere end manuel klikning. Udviklere modtager en kort vejledning, der forklarer, hvordan logning fungerer, og hvor de kan tilpasse signaturer. Således ender Sikkerhed direkte i udviklingsforløbet og forbliver opdateret.

Kort opsummeret

Seccomp begrænser Systemkald ved at begrænse en applikation til det nødvendige og dermed afskære mange angrebsveje. Jeg starter med en stærk standardindstilling, måler den faktiske adfærd og indsnævrer derefter trin for trin. Containerplatforme som Kubernetes eller OpenShift tager en stor del af det grundlæggende arbejde fra mig, når jeg indstiller seccompDefault og distribuerer profiler centralt. I kombination med Capabilities, SELinux/AppArmor samt Namespaces og Cgroups skabes der en effektiv flerlagsbeskyttelse. Den, der konsekvent følger denne tilgang, mindsker risikoen for kernel-exploits og sikrer samtidig, at arbejdsbelastningerne fungerer godt kontrollerbar.

Aktuelle artikler