+39 3662317539/+34 620899163
info@simonecosci.com

unattended-upgrades su Debian: gli aggiornamenti di sicurezza che si installano da soli

Sviluppo Siti Web a Tenerife

unattended-upgrades su Debian: gli aggiornamenti di sicurezza che si installano da soli

Su un VPS che nessuno guarda, la finestra fra l’uscita di una patch di sicurezza e la sua installazione è il vero rischio. unattended-upgrades la chiude da solo. È il pacchetto che Debian usa per questo, e la sua pagina di manuale lo descrive così: «This program can download and install security upgrades automatically and unattended, taking care to only install packages from the configured APT source, and checking for dpkg prompts about configuration file changes».

Le due parti importanti di quella frase sono only install packages from the configured APT source e checking for dpkg prompts: non aggiorna tutto, e non si blocca su una domanda a cui nessuno risponderà mai. Tutto quello che segue è verificato sulla versione in Debian 13 (trixie), unattended-upgrades 2.12, e su apt 3.0.3.

Cosa succede appena lo installi

L’installazione fa una domanda debconf sola, unattended-upgrades/enable_auto_updates, con Default: true:

Automatically download and install stable updates?

Se rispondi di sì — o se non risponde nessuno, perché il default è quello — il pacchetto scrive /etc/apt/apt.conf.d/20auto-upgrades con due righe:

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

Quel valore non è un booleano, è un intervallo. Lo script /usr/lib/apt/apt.systemd.daily lo legge con apt-config shell, tratta 0 come “disattivato”, always come “salta il controllo del timestamp” e un numero come un tempo, con i suffissi s, m, h, d e i giorni come unità predefinita. Quindi "1" significa al massimo una volta al giorno, e il conto viene tenuto con dei file vuoti in /var/lib/apt/periodic/ (update-stamp, upgrade-stamp, e compagnia). Il file gemello 20auto-upgrades-disabled, che il pacchetto si porta dietro, ha le stesse due righe con "0".

A far partire il lavoro sono due timer systemd di apt, non di unattended-upgrades:

# apt-daily.timer           → scarica gli indici
OnCalendar=*-*-* 6,18:00
RandomizedDelaySec=12h
Persistent=true

# apt-daily-upgrade.timer   → installa
OnCalendar=*-*-* 6:00
RandomizedDelaySec=60m
Persistent=true

RandomizedDelaySec è il motivo per cui la macchina non si aggiorna alle 6:00 in punto: sparpaglia le richieste sui mirror. Il servizio che ne esce, apt-daily-upgrade.service, ha ConditionACPower=true e TimeoutStopSec=900, e lancia /usr/lib/apt/apt.systemd.daily install.

Cosa non tocca, di proposito

Qui sta la parte che più spesso viene data per scontata. Quello che viene aggiornato è deciso da Unattended-Upgrade::Origins-Pattern in /etc/apt/apt.conf.d/50unattended-upgrades, e su Debian arriva con esattamente tre righe attive:

"origin=Debian,codename=${distro_codename},label=Debian";
"origin=Debian,codename=${distro_codename},label=Debian-Security";
"origin=Debian,codename=${distro_codename}-security,label=Debian-Security";

Le righe per -updates, -proposed-updates e i backports ci sono, ma commentate. La regola, spiegata nel file stesso, è che «a package will be upgraded only if the values in its metadata match all the supplied keywords in a line. (In other words, omitted keywords are wild cards.)».

Tradotto in pratica: i repository di terze parti non sono coperti. Docker, nginx.org, i pacchetti PHP di Sury, il repo di PostgreSQL — nessuno di questi ha origin=Debian, quindi nessuno di questi viene aggiornato. Se sul server il web server o il PHP vengono da un repo esterno, il pezzo esposto su internet è proprio quello che resta fermo. Per vedere le chiavi disponibili sul tuo sistema il file rimanda a apt-cache policy, e per il debug a unattended-upgrades -d guardando il log.

L’altra cosa che non fa è riavviare i servizi. Aggiorna libssl, ma i processi già partiti continuano a usare la libreria vecchia finché non li riavvii: il pacchetto aggiornato non basta. Quel lavoro lo fa needrestart, che «checks which daemons need to be restarted after library upgrades» ed è «fully integrated into apt/dpkg using hooks».

E non riavvia la macchina. Unattended-Upgrade::Automatic-Reboot è commentato, quindi non è attivo, e il commento che lo accompagna merita di essere letto per intero prima di toglierlo:

// Automatically reboot *WITHOUT CONFIRMATION* if
//  the file /var/run/reboot-required is found after the upgrade

Due dettagli su questo, se decidi di abilitarlo. Il primo: Automatic-Reboot-WithUsers è documentato con "true", cioè riavvia anche se c’è qualcuno collegato. Il secondo: il default di Automatic-Reboot-Time è "now" — il "02:00" che vedi nel file è solo un esempio. Abilitare il riavvio senza scrivere anche l’orario significa riavviare in mezzo alla mattinata.

Su chi crea quel /var/run/reboot-required c’è un equivoco frequente. Per i kernel lo crea unattended-upgrades stesso, con un hook suo in /etc/kernel/postinst.d/unattended-upgrades che fa touch /var/run/reboot-required e aggiunge il nome del pacchetto a reboot-required.pkgs. Per tutto il resto serve che qualcuno chiami l’helper notify-reboot-required, che su Debian oggi arriva dal pacchetto reboot-notifier — non installato di default, e la sua descrizione parla apertamente del «late update-notifier-common package».

Infine, non ti scrive. Unattended-Upgrade::Mail è commentato e documentato come stringa vuota: «If empty or unset then no email is sent». Se lo imposti, serve un pacchetto che fornisca mailx, e MailReport accetta always, only-on-error o on-change.

Come capire se sta girando davvero

Il punto debole di qualsiasi automatismo silenzioso è che il silenzio somiglia troppo al non funzionare. Tre controlli, in ordine di costo:

apt-config dump APT::Periodic          # i valori effettivi, non quelli che credi
systemctl list-timers 'apt-daily*'     # ultima e prossima esecuzione
unattended-upgrade --dry-run --debug   # simula, senza installare niente

Il terzo è quello che risponde alla domanda vera, perché stampa quali pacchetti rientrano nei pattern configurati e quali no. Il manuale descrive --dry-run come «Just simulate installing updates, do not actually do it». Nota il nome: il binario è /usr/bin/unattended-upgrade, al singolare, anche se il pacchetto è plurale — esistono entrambi.

Poi ci sono i log, in /var/log/unattended-upgrades/: unattended-upgrades.log, unattended-upgrades-dpkg.log e unattended-upgrades-shutdown.log. Occhio alla loro rotazione, perché è generosa in un senso e stretta nell’altro: rotate 6 e monthly. Sei mesi di storia, ma con granularità mensile — se cerchi cosa è successo su una macchina tre settimane fa lo trovi, se cerchi di ricostruire un incidente di due anni fa no.

Le righe che vale la pena cambiare

Su un server esposto, tre modifiche al 50unattended-upgrades ripagano subito:

  1. Aggiungere le origini che ti servono davvero, se usi repo esterni. Senza, stai aggiornando la parte del sistema che nessuno attacca.
  2. Mail più MailReport "only-on-error", così il silenzio torna a significare qualcosa.
  3. Riavvio: o lo abiliti con un orario, o non lo abiliti. Automatic-Reboot da solo, con il default now, è peggio del non averlo.

Quello che conviene lasciare com’è: MinimalSteps, documentato a "true", che spezza l’aggiornamento nei blocchi più piccoli possibili in modo che si possa interrompere con SIGTERM. E Package-Blacklist, che arriva vuoto: è una lista di espressioni regolari Python, e il file avverte che senza $ finale "libc6" le prende tutte, libc6-dev compreso.


Fonti primarie usate per questo articolo: la pagina di manuale unattended-upgrade(8), i file 50unattended-upgrades.Debian, 20auto-upgrades e l’hook kernel/postinst.d/unattended-upgrades del sorgente di unattended-upgrades 2.12, le unit apt-daily.timer e apt-daily-upgrade.service del sorgente di apt 3.0.3, e le pagine dei pacchetti reboot-notifier e needrestart.

Se hai un VPS in produzione e non sai dire con certezza se gli aggiornamenti di sicurezza ci stanno arrivando, è una mezz’ora di lavoro scoprirlo e sistemarlo. Scrivici.