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 Linux 2026: Fuld Guide

Opdateret: 1. august 2026

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.

Lokale I/O-logs i /var/log/sudo-io kan slettes af en angriber, der har fået root. Løsningen er sudo_logsrvd, en logging-daemon der har fulgt med sudo siden 1.9.0. Den kører på en dedikeret log-vært og modtager sudo I/O over TLS. På klienterne:

# /etc/sudoers.d/01-remote-log
Defaults log_servers = logsrv.internal.example:30344(tls)
Defaults log_server_cabundle = /etc/pki/ca-trust/source/anchors/internal-ca.pem
Defaults log_server_verify   = true

Og på log-værten, i /etc/sudo_logsrvd.conf:

[server]
listen_address = 0.0.0.0:30344(tls)
pid_file = /run/sudo_logsrvd.pid

[relay]
# Efterfølgende videresendelse til SIEM
relay_host = siem.internal.example:30344(tls)

[iolog]
iolog_dir = /var/log/sudo-io
iolog_file = %{seq}
iolog_group = sudoreplay
iolog_mode = 0640
compress_io = true

[logfile]
path = /var/log/sudo_logsrvd.log
time_format = %Y-%m-%dT%H:%M:%S%z

[server_tls]
tls_cert = /etc/sudo_logsrvd/cert.pem
tls_key  = /etc/sudo_logsrvd/key.pem
tls_cacert = /etc/sudo_logsrvd/ca.pem
tls_verify = true

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/:

// /etc/polkit-1/rules.d/50-run0-webops.rules
polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.systemd1.manage-units" &&
        subject.isInGroup("webops") &&
        action.lookup("unit") == "nginx.service") {
        return polkit.Result.YES;
    }
});

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:

Egenskabsudo 1.9.17+run0 (systemd 256+)doas (OpenBSD)
Setuid-binærJa (angrebsflade)Nej (bedst)Ja
Konfigurations-DSLsudoers (moden)polkit JavaScriptdoas.conf (minimal)
I/O-logningIndbygget (sudoreplay)Via journaldIngen
Centraliseret logsudo_logsrvd over TLSjournal-remoteIngen
MFA / PAMFuld PAM-stackpolkit-agenterPAM (Linux-port)
Codebase-størrelse~200k LOCDel af systemd~2k LOC (mindst)
Distro-tilgængelighedUniverselFedora 40+, Arch, Ubuntu 26.04+De fleste, som ekstra pakke
Enterprise / STIGAccepteretKommer 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:

# /etc/security/faillock.conf
deny = 5
unlock_time = 900
fail_interval = 300
audit
silent

Ofte stillede spørgsmål

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.

Om Forfatteren Mateusz Wojciechowski

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.