Sudo-hærdning på Linux i 2026: sudoers, CVE-patches, sudo_logsrvd og run0
Sådan hærder du sudo på Linux i 2026: patch CVE-2025-32462/32463, skriv sudoers efter mindsteprivilegie-princippet, centralisér I/O-logning med sudo_logsrvd, og vurdér om run0 skal erstatte sudo på nye systemer.
Sudo-hærdning på Linux betyder at reducere angrebsfladen for privilegie-eskalering ved at patche til sudo 1.9.17p1 eller nyere, skrive sudoers-regler efter mindsteprivilegie-princippet, aktivere I/O-logning via use_pty og log_input/log_output, sende sessionslogs til en central sudo_logsrvd-instans og overveje run0 som setuid-fri erstatning. I 2026 er det her blevet akut efter CVE-2025-32462 og CVE-2025-32463, to bugs der lå i træet i over ti år og gav lokal root uden sudoers-adgang. Så lad os se, hvordan man faktisk gør det.
Opgrader til sudo 1.9.17p1 (eller distro-backport). CVE-2025-32463 tillader root via --chroot uden regel i sudoers.
Fjern alle NOPASSWD: ALL-regler, og erstat med kommandospecifikke, gruppe-baserede regler.
Aktivér Defaults use_pty, log_input, log_output og send I/O-strømme til en central sudo_logsrvd-server for revisionsbestandig logning.
Overvåg /etc/sudoers og /etc/sudoers.d/ med auditd og AIDE for at fange uautoriserede ændringer.
run0 (systemd 256+) erstatter sudo uden setuid-binær og bruger polkit. Velegnet til nye installationer, men endnu ikke universelt.
Kombinér sudo med PAM-baseret MFA (pam_u2f, pam_google_authenticator) for at kræve fysisk faktor ved eskalering.
Hvad betyder sudo-hærdning i praksis?
Sudo-hærdning er den proces, hvor man reducerer risikoen ved at give slutbrugere og driftskonti mulighed for at eskalere til root. I mine otte år på Red Hats konsulentbænk var det sudoers-filerne, der næsten altid bekymrede mig mest ved en compliance-gennemgang. Ikke SELinux, ikke firewall'en, men den /etc/sudoers.d/-mappe, som gennem årene havde samlet NOPASSWD: ALL-regler til hver anden konsulent, der nogensinde havde rørt boksen.
Hærdning består af fire lag, der arbejder sammen: patch-hygiejne (bliv på en versionsstreng uden kendte lokale eskaleringer), regel-hygiejne (skriv kun det, der er nødvendigt, og gør det gruppebaseret), audit-spor (I/O-logning, sudoreplay, sudo_logsrvd, auditd), og autentifikationsforstærkning (PAM, MFA, valgfrit run0 med polkit). Hvis blot ét af lagene mangler, kan et hul i de andre koste dig root. Rækkefølgen i denne guide afspejler den rækkefølge, jeg selv følger på et nyt engagement: først patch, så regler, så logning, så autentifikation.
CVE-2025-32462 og CVE-2025-32463: Patch nu
De to sudo-CVE'er, der landede i sommeren 2025, er allerede blevet en fast del af min pre-flight-tjekliste, fordi de begge tillader lokal privilegie-eskalering på systemer, der ellers ser velkonfigurerede ud. Stratascale-forskeren Rich Mirch afdækkede begge fejl, og de påvirker sudo-versioner før 1.9.17p1.
CVE-2025-32462: Host-flaget -h tillader en bruger at få sudo-privilegier evalueret, som var kaldet fra en anden vært. Reglen har ligget i træet siden 2013 og betyder, at en Host_Alias-baseret regel, der aldrig var tænkt til den lokale maskine, alligevel kan bruges.
CVE-2025-32463: --chroot-optionen læser /etc/nsswitch.conf og NSS-moduler fra den bruger-kontrollerede chroot. En angriber lægger et ondsindet NSS-modul i sin chroot og får sudo til at loade det med root-rettigheder, helt uden en matchende regel i sudoers.
Patchen er triviel, kontrollen er ikke. Kør på hver værtsklasse:
# RHEL / Rocky / Alma
sudo dnf update sudo
sudo -V | head -1
# Debian / Ubuntu
sudo apt-get update && sudo apt-get install --only-upgrade sudo
sudo -V | head -1
# Verificér at chroot-funktionen er deaktiveret, uanset patch-niveau
grep -rE '^\s*Defaults\s+.*(use_chroot|runchroot)' /etc/sudoers /etc/sudoers.d/ 2>/dev/null
# Ingen output er det rigtige resultat
På systemer, hvor du ikke straks kan patche (typisk en ældre RHEL 7-boks, der venter på et vedligeholdelsesvindue), tilføj en katastrofelinje til /etc/sudoers.d/00-cve-mitigation: Defaults !use_chroot. Det er ikke en fuld beskyttelse, men det lukker den umiddelbare eksekveringssti, indtil pakken er opdateret. Officielle detaljer finder du hos sudo-projektets egen advisory.
Sudoers best practices: mindsteprivilegie i praksis
En sudoers-fil skal læses som en policy, ikke som en bekvemmelighed. Reglen, jeg bruger som fingeregel: hvis en linje indeholder ALL=(ALL) NOPASSWD:ALL, er det næsten altid en fejl. Det er root uden autentifikation, og det gør hele sudo-mekanismen dekorativ.
Skriv i stedet regler, der er kommandospecifikke og bundet til grupper, ikke enkeltbrugere. Nedenstående eksempel viser det mønster, jeg bruger på en typisk webserver-node:
# /etc/sudoers.d/10-webops
# Formål: Webops-teamet må genstarte nginx og læse dens config, intet andet.
# Cmnd-aliases: samlet på ét sted, nemt at revidere
Cmnd_Alias NGINX_MGMT = /usr/bin/systemctl restart nginx, \
/usr/bin/systemctl reload nginx, \
/usr/bin/systemctl status nginx
Cmnd_Alias NGINX_LOGS = /usr/bin/tail -n [0-9]* /var/log/nginx/*, \
/usr/bin/less /var/log/nginx/*
# Ingen wildcards på argumenter der kan misbruges til shell-escape
%webops ALL=(root) NOPASSWD: NGINX_MGMT
%webops ALL=(root) PASSWD: NGINX_LOGS
# Blokér miljø-variabler der kan omgå sikring
Defaults:%webops env_reset, env_delete+="LD_* PYTHONPATH PERL5LIB"
Læg mærke til fire ting: (1) Ingen brug af ALL i kommandokolonnen. (2) Wildcards er begrænset til talklasse [0-9]*, ikke den vilde *. Sudo tillader nemlig shell-escape, hvis wildcard'et matcher en -c "sh"-lignende streng. (3) NOPASSWD bruges kun til den handling, der skal automatiseres, ikke som standard. (4) env_reset er obligatorisk. Den tømmer miljøet og undgår, at LD_PRELOAD eller lignende følger med.
Validér altid med visudo -c -f /etc/sudoers.d/10-webops, inden du deployer. Jeg har set produktionshosts blive låst ude, fordi en Ansible-rolle skrev en syntaksfejl direkte til /etc/sudoers. Brug altid visudo-mode i din konfigurationsstyring (Ansible's lineinfile/copy med validate: /usr/sbin/visudo -cf %s).
Aktivér I/O-logning og centraliseret sudo_logsrvd
Uden I/O-logning ved du, hvem der kørte sudo, men ikke hvad. Med logning kan du afspille sessionen. Grundopsætningen tilføjes til en dedikeret fil, så det gælder globalt:
# /etc/sudoers.d/00-defaults
Defaults use_pty
Defaults log_input, log_output
Defaults iolog_dir="/var/log/sudo-io/%{user}"
Defaults iolog_flush
Defaults log_format=json
Defaults lecture=once
Defaults passwd_timeout=1
Defaults timestamp_timeout=5
# Behold miljø der er sikkert, drop resten
Defaults env_reset
Defaults env_keep += "SSH_AUTH_SOCK COLORTERM LANG LC_*"
use_pty er kritisk. Den kører hver sudo-kommando i sin egen pseudo-terminal, hvilket forhindrer, at et TTY-hijacking-angreb (kommandoen, der har fået root, prøver at skrive tegn tilbage til den kaldende TTY) lykkes. Det er så vigtigt, at det i sudo 1.9.14+ er tændt som standard. Men du bør ikke stole på det på systemer med backports.
Afspil en session med sudoreplay -d /var/log/sudo-io <seq-id>. På revisionsdage har det reddet mig timer at kunne vise en compliance-auditør præcis, hvad en ekstern konsulent tastede kl. 23:14 en torsdag. Kombinér gerne med vores guide til auditd og systemrevision for et fuldt revisionsspor.
Bør du erstatte sudo med run0?
Kort svar: på nye systemer med systemd 256 eller nyere, ja, som supplement til sudo, ikke som total udskiftning. run0 er et symbollink til systemd-run, der starter kommandoen i en fersk, isoleret cgroup uden at nedarve nogen credentials fra den kaldende proces. Det afgørende design-valg er, at run0 ikke er en setuid-binær. Sudo har været målet for et sikkerhedsflåd af CVE'er netop fordi setuid-programmer skal håndtere alt fra kernemiljøet og opefter uden at fejle, og de fejler jo, som CVE-2021-3156 (Baron Samedit) og de nye 2025-fejl viser.
run0's autentifikation håndteres af polkit i stedet for en dedikeret regel-DSL. Det betyder, at du skriver dine regler som JavaScript i /etc/polkit-1/rules.d/:
Kald derefter run0 systemctl restart nginx. Polkit spørger via agenten (ikke via TTY, hvilket gør phishing sværere), og systemd starter processen som root i en frisk cgroup. Terminalens baggrund skifter til rødt som visuel indikator på forhøjede rettigheder.
Der er to reservationer, jeg altid nævner over for kunder: (1) Ubuntu 24.04 LTS kører systemd 255 og har derfor ikke run0 uden opgradering til 26.04. (2) På headless servere uden desktop kører der ikke en polkit-agent by default. Du skal enten køre systemd-inhibit --list for at bekræfte, eller installere polkitd og en tekstbaseret agent. På hosts uden agent falder run0 tilbage til at nægte autentifikation, hvilket er sikkert, men bryder eksisterende automation.
Sudo vs run0 vs doas: hvilken skal du bruge?
Der er tre reelle valg i 2026, og de har hver deres profil. Nedenstående tabel opsummerer de dimensioner, jeg vejer, når jeg vælger for en kunde:
Egenskab
sudo 1.9.17+
run0 (systemd 256+)
doas (OpenBSD)
Setuid-binær
Ja (angrebsflade)
Nej (bedst)
Ja
Konfigurations-DSL
sudoers (moden)
polkit JavaScript
doas.conf (minimal)
I/O-logning
Indbygget (sudoreplay)
Via journald
Ingen
Centraliseret log
sudo_logsrvd over TLS
journal-remote
Ingen
MFA / PAM
Fuld PAM-stack
polkit-agenter
PAM (Linux-port)
Codebase-størrelse
~200k LOC
Del af systemd
~2k LOC (mindst)
Distro-tilgængelighed
Universel
Fedora 40+, Arch, Ubuntu 26.04+
De fleste, som ekstra pakke
Enterprise / STIG
Accepteret
Kommer i STIG v2.1+
Ikke i STIG
Min anbefaling: sudo forbliver standard på enhver reguleret RHEL-flåde, indtil STIG- og CIS-benchmarks eksplicit tilføjer run0-varianter. På personlige workstations og nye greenfield-Fedora-installationer er run0 det mere sikkerhedsbevidste valg. doas er charmerende i sin minimalisme, men mangler I/O-logning, hvilket er en dealbreaker for enhver regulering (PCI-DSS, ISO 27001, NIS2), der kræver revisionsspor på privilegie-eskalering. Kombinér gerne med vores OpenSCAP-guide til CIS-compliance, hvis du skal dokumentere valget over for en auditør.
Overvågning med auditd og AIDE: fang ændringer i realtid
Selv den bedst skrevne sudoers-fil er værdiløs, hvis en angriber (eller en velmenende junior) tilføjer attacker ALL=(ALL) NOPASSWD:ALL i en kladdefil i /etc/sudoers.d/. Løsningen er dobbelt: auditd fanger ændringen, når den sker, og AIDE bekræfter det efterfølgende.
# /etc/audit/rules.d/50-sudoers.rules
-w /etc/sudoers -p wa -k sudoers_changes
-w /etc/sudoers.d/ -p wa -k sudoers_changes
-w /etc/sudo.conf -p wa -k sudoers_changes
# Fang eskalerings-syscalls
-a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -F auid!=unset -k root_exec
-a always,exit -F arch=b64 -S setuid,setgid,setresuid,setresgid -F key=priv_esc
# Genindlæs regler
augenrules --load
Kør derefter ausearch -k sudoers_changes -ts today for at se enhver skrivning til filerne, inklusive hvem der gjorde det, hvilken proces og hvilken tid. Send resultaterne til jeres SIEM med audispd-plugin. Detaljerede eksempler på, hvordan du håndterer regelsæt og logrotering, findes i vores auditd-guide fra april 2026.
For AIDE tilføj sudoers-filerne til hash-databasen:
# /etc/aide.conf
/etc/sudoers NORMAL
/etc/sudoers.d NORMAL
/etc/sudo.conf NORMAL
# Initialisér database og kør daglig kontrol via cron
aide --init && mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
echo "0 3 * * * root /usr/sbin/aide --check | mail -s '[AIDE] $(hostname)' [email protected]" \
> /etc/cron.d/aide-check
PAM-hærdning og MFA foran sudo
Den sidste bastion mod stjålne credentials er en anden faktor. Sudo bruger PAM som standard, hvilket betyder, at du kan indsætte MFA-krav uden at røre sudoers. På RHEL 9 med U2F/FIDO2-nøgler (som passer godt til vores SSH-hærdningsopsætning med FIDO2-nøgler) redigér /etc/pam.d/sudo:
#%PAM-1.0
auth required pam_u2f.so cue authfile=/etc/u2f_mappings
auth include system-auth
account include system-auth
password include system-auth
session include system-auth
Registrér nøgler pr. bruger med pamu2fcfg -o pam://sudo >> /etc/u2f_mappings. Herefter kræver enhver sudo-kommando et fysisk tryk på YubiKey'en, også hvis en angriber har stjålet kontoens kodeord. For miljøer uden hardware-nøgler er pam_google_authenticator et acceptabelt TOTP-alternativ.
Sæt derudover pam_faillock til at låse konti efter fem forgæves sudo-forsøg. Det er en simpel modforanstaltning mod credential stuffing, hvor angriberen har fået shell-adgang, men gætter på sudo-kodeordet:
Hvilken version af sudo er sårbar over for CVE-2025-32463?
Alle sudo-versioner før 1.9.17p1 er sårbare. Rettelsen blev udgivet 30. juni 2025, og distributions-backports fulgte i løbet af juli 2025. Verificér din version med sudo -V | head -1 og patch straks. Hvis du ikke kan patche, tilføj Defaults !use_chroot til /etc/sudoers.d/ som midlertidig afhjælpning.
Er run0 bedre end sudo i 2026?
Arkitektonisk, ja. Run0 undgår setuid og bruger polkit, hvilket eliminerer en hel klasse af eskaleringsbugs. Praktisk set forbliver sudo standard i regulerede miljøer, indtil compliance-benchmarks (CIS, STIG) tilføjer run0-profiler. Brug run0 på personlige og greenfield-installationer, behold sudo på RHEL-flåder under compliance-krav.
Hvordan logger jeg alle sudo-kommandoer centralt?
Kør sudo_logsrvd-daemonen på en dedikeret log-vært, konfigurér den til at lytte på port 30344 over TLS, og pegér klienterne mod den med Defaults log_servers = logsrv.example:30344(tls) plus log_input, log_output, use_pty. Afspil derefter sessioner med sudoreplay -d /var/log/sudo-io <seq>.
Bør jeg bruge NOPASSWD:ALL for at gøre automatisering nemmere?
Nej. NOPASSWD: ALL gør sudo funktionelt værdiløst, fordi enhver bruger med den regel er reelt root. Brug i stedet kommandospecifikke NOPASSWD-regler bundet til en dedikeret servicekonto, f.eks. deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart myapp. Kombinér med en SSH-nøgle, der er restricted til den præcise kommando (command="/usr/bin/sudo systemctl restart myapp" i authorized_keys).
Kan jeg kræve MFA (YubiKey) før sudo tillader en kommando?
Ja, via PAM. Tilføj auth required pam_u2f.so cue authfile=/etc/u2f_mappings øverst i /etc/pam.d/sudo, og registrér hver brugers FIDO2-nøgle med pamu2fcfg. Sudo vil derefter kræve både kodeord og et fysisk tryk på nøglen. Test altid i en parallel root-session for at undgå at låse dig selv ude.
Mateusz spent eight years on the Red Hat consulting bench before going independent in 2024, embedded with banks and telcos rolling out RHEL 8 and 9 across regulated estates. Most of that work was SELinux policy debugging, FIPS-mode enablement, and cleaning up the kind of sudoers files that grow organically over a decade.
He holds OSCP and RHCE, and maintains a small set of Ansible roles for STIG-hardened RHEL builds that a few European credit unions now run in production. Before Red Hat he was a junior sysadmin at Allegro in Poznan, mostly babysitting Postfix and learning why you don't run updatedb on an NFS root.
Mateusz writes about the boring half of Linux security: package signing, audit daemon tuning, and the unglamorous work of actually reading journalctl output before paging anyone.
Praktisk guide til fapolicyd på RHEL 10 og Fedora: trust database, DNF-plugin, custom rules, fejlfinding med debug-deny og produktions-checklist for STIG og CIS compliance.
Praktisk AppArmor-guide til Debian, Ubuntu og openSUSE i 2026: profil-tilstande, aa-genprof-workflow, exec-overgange, fejlfinding af denials, systemd og Kubernetes 1.30+ appArmorProfile.
Komplet 2026-guide til SSH-hærdning på Linux: FIDO2-hardware-nøgler, certifikat-baseret CA, post-kvante mlkem768x25519, kopier-klar sshd_config og audit med ssh-audit.