Correctifs, sauvegardes & disponibilitédébutant5 min de lecture

Bien configurer unattended-upgrades — et pourquoi il faut surveiller reboot-required

L'installation par défaut d'unattended-upgrades applique les correctifs de sécurité mais laisse les services tourner sur d'anciennes bibliothèques et le nouveau noyau sur le disque. Voici la configuration qui corrige cela pour Ubuntu 24.04 et Debian 12 : origines, liste noire, needrestart, politique de redémarrage, mail — plus le script cron qui signale quels hôtes attendent un redémarrage depuis des jours.

Sommaire
  1. Étape 1 : installer et vérifier la base
  2. Étape 2 : la configuration que vous voulez
  3. Étape 3 : redémarrer les services après une mise à jour de bibliothèque (needrestart)
  4. Étape 4 : rendre reboot-required visible sur toute la flotte
  5. Étape 5 : maîtriser l'horaire
  6. Pièges
  7. Ce qu'il vous manque encore
  8. Comment monsys fait
  9. FAQ

apt install unattended-upgrades et c'est fini — c'est ce qu'ont la plupart des serveurs, et c'est mieux que rien. Mais la configuration par défaut a trois trous : les services continuent de tourner avec l'ancienne bibliothèque en mémoire après une mise à jour de libssl (la CVE est donc toujours active), un nouveau noyau est installé mais jamais démarré, et personne n'est informé de ce qui s'est passé. Cet article bouche ces trois trous et ajoute une vérification de redémarrage à l'échelle de la flotte.

Étape 1 : installer et vérifier la base

sudo apt install -y unattended-upgrades apt-listchanges needrestart
# Les timers périodiques sont-ils actifs ?
cat /etc/apt/apt.conf.d/20auto-upgrades
# APT::Periodic::Update-Package-Lists "1";
# APT::Periodic::Unattended-Upgrade "1";
systemctl list-timers 'apt-daily*' --no-legend

Si 20auto-upgrades manque (parfois sur Debian minimal) : sudo dpkg-reconfigure -plow unattended-upgrades le crée.

Étape 2 : la configuration que vous voulez

Tout dans /etc/apt/apt.conf.d/52unattended-upgrades-local — votre propre fichier avec un numéro plus élevé remplace les valeurs par défaut de 50unattended-upgrades sans qu'une mise à jour du paquet n'écrase vos modifications.

sudo tee /etc/apt/apt.conf.d/52unattended-upgrades-local >/dev/null <<'EOF'
// Ubuntu : security + ESM. Les -updates ordinaires délibérément PAS automatiques (elles
// contiennent des changements fonctionnels ; ça se planifie). Debian utilise Origins-Pattern, voir plus bas.
Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
    "${distro_id}ESMApps:${distro_codename}-apps-security";
    "${distro_id}ESM:${distro_codename}-infra-security";
};

// Ce que vous ne voulez JAMAIS sans planification : noyau (guide séparé), Docker, bases de données.
Unattended-Upgrade::Package-Blacklist {
    "linux-image-";
    "linux-headers-";
    "docker-ce";
    "containerd.io";
    "postgresql-";
    "mysql-server";
    "mariadb-server";
};

// Nettoyage
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";

// Redémarrage : PAS automatique en production. Mais signaler (étape 4).
Unattended-Upgrade::Automatic-Reboot "false";
// Sur dev/staging, c'est acceptable, dans une fenêtre fixe, et pas si quelqu'un est connecté :
// Unattended-Upgrade::Automatic-Reboot "true";
// Unattended-Upgrade::Automatic-Reboot-Time "03:30";
// Unattended-Upgrade::Automatic-Reboot-WithUsers "false";

// Mail en cas de changements ou d'erreurs (nécessite un mailer local fonctionnel ou msmtp)
Unattended-Upgrade::Mail "ops@example.be";
Unattended-Upgrade::MailReport "on-change";

// Vers syslog/journal, pour que ce soit dans vos logs
Unattended-Upgrade::SyslogEnable "true";

// Terminer les installations à moitié faites plutôt que s'arrêter
Unattended-Upgrade::MinimalSteps "true";
Unattended-Upgrade::InstallOnShutdown "false";
EOF

Sur Debian 12, remplacez le bloc Allowed-Origins par :

Unattended-Upgrade::Origins-Pattern {
    "origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
    "origin=Debian,codename=${distro_codename},label=Debian-Security";
};

Testez toujours à blanc d'abord :

sudo unattended-upgrade --dry-run --debug 2>&1 | grep -E 'Allowed origins|Packages that will be upgraded|blacklist|No packages'

Étape 3 : redémarrer les services après une mise à jour de bibliothèque (needrestart)

C'est le trou le plus souvent laissé ouvert. Après apt upgrade libssl3t64, nginx continue avec l'ancien libssl en mémoire jusqu'à ce que quelqu'un le redémarre. needrestart le détecte et peut le faire automatiquement — mais il est par défaut en mode liste quand il n'y a pas de terminal.

sudo tee /etc/needrestart/conf.d/50-auto.conf >/dev/null <<'EOF'
# a = redémarrer automatiquement, l = lister seulement, i = demander (inutile sans tty)
$nrconf{restart} = 'a';
# Services que vous NE voulez PAS redémarrer automatiquement (regex sur le nom d'unité)
$nrconf{override_rc}{qr(^postgresql)} = 0;
$nrconf{override_rc}{qr(^mariadb)}    = 0;
$nrconf{override_rc}{qr(^docker)}     = 0;
$nrconf{override_rc}{qr(^ssh)}        = 1;   # ssh, oui : les sessions existantes restent ouvertes
EOF
# Que redémarrerait-il maintenant ?
sudo needrestart -r l

needrestart s'exécute automatiquement après chaque passage apt via le hook dans /etc/apt/apt.conf.d/99needrestart. Avec restart = 'a', il redémarre donc tout ce qui tourne sur une bibliothèque obsolète, sauf ce que vous avez exclu. Ces services exclus (bases de données) apparaissent dans la vérification de l'étape 4 comme « needs restart ».

Étape 4 : rendre reboot-required visible sur toute la flotte

Après une mise à jour, le nouveau noyau est sur le disque et /var/run/reboot-required apparaît. Personne ne voit ce fichier. Ce script signale chaque matin quels hôtes attendent, et depuis combien de temps :

sudo tee /usr/local/sbin/reboot-check.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
NTFY="https://ntfy.example.be/patching"
HOST=$(hostname -s)
MSG=()

if [ -f /var/run/reboot-required ]; then
  days=$(( ( $(date +%s) - $(stat -c %Y /var/run/reboot-required) ) / 86400 ))
  pkgs=$(sort -u /var/run/reboot-required.pkgs 2>/dev/null | paste -sd, -)
  MSG+=("reboot-required since ${days}d (${pkgs:-?})")
fi

# Services tournant sur des bibliothèques obsolètes (needrestart en mode liste, batch)
stale=$(needrestart -b 2>/dev/null | awk -F': ' '/^NEEDRESTART-SVC/{print $2}' | paste -sd, -)
[ -n "$stale" ] && MSG+=("services on old libs: $stale")

# Dernier passage réussi d'unattended-upgrade
last=$(grep -h 'Packages that were upgraded' /var/log/unattended-upgrades/unattended-upgrades.log 2>/dev/null | tail -1 | cut -c1-19)
[ -n "$last" ] && MSG+=("last auto-upgrade: $last")

# Mises à jour de sécurité en attente NON installées (liste noire ou erreur)
open=$(apt list --upgradable 2>/dev/null | grep -c security)
[ "$open" -gt 0 ] && MSG+=("$open security updates pending")

if [ ${#MSG[@]} -gt 0 ]; then
  printf '%s\n' "${MSG[@]}" | curl -s -H "Title: patch@$HOST" -H "Priority: default" --data-binary @- "$NTFY" >/dev/null
fi
EOF
sudo chmod 0755 /usr/local/sbin/reboot-check.sh
echo '30 7 * * * root /usr/local/sbin/reboot-check.sh' | sudo tee /etc/cron.d/reboot-check

Le topic ntfy patching devient chaque matin votre liste de tâches : les hôtes qui attendent un redémarrage depuis trois jours, et les bases de données pas encore redémarrées après une mise à jour de libssl.

Étape 5 : maîtriser l'horaire

apt-daily-upgrade.timer se déclenche à 06:00 avec jusqu'à 60 minutes de délai aléatoire. Sur une flotte, cela signifie : tous les hôtes patchent en même temps, en plein pic matinal de certains clients. Décalez-le :

sudo systemctl edit apt-daily-upgrade.timer
[Timer]
OnCalendar=
OnCalendar=*-*-* 03:00
RandomizedDelaySec=45min

Donner une heure différente à chaque groupe (web, db, batch) est la forme la plus simple de déploiement progressif : si quelque chose casse sur le groupe web à 03:00, le groupe db n'est pas encore concerné à 04:00 et vous pouvez intervenir.

Pièges

  • -updates dans les origines sur Ubuntu. Certains guides ajoutent ${distro_id}:${distro_codename}-updates. Cela installe aussi des mises à jour non liées à la sécurité avec des changements de comportement (nouvelle mineure PHP, nouveau systemd). Ne le faites que sur les hôtes où vous le voulez délibérément.
  • Mises à jour progressives (phased). Ubuntu déploie certaines mises à jour par phases ; apt list --upgradable les affiche comme « deferred ». C'est normal, pas une erreur. Vous les voulez quand même tout de suite : APT::Get::Always-Include-Phased-Updates "true"; — mais vous vous portez alors volontaire comme cobaye.
  • Conflits de verrou dpkg. Ansible, Puppet ou un apt manuel à 03:00 se heurte au verrou et échoue avec « Could not get lock ». Planifiez votre gestion de configuration en dehors de la fenêtre de l'étape 5.
  • Un mail qui n'arrive nulle part. Mail "ops@example.be" ne fait rien sans MTA. Installez msmtp-mta avec un relais, ou supprimez le mail et fiez-vous à l'étape 4.
  • Automatic-Reboot "true" sur un hôte avec des modules DKMS. Après le redémarrage, un module réseau ou stockage peut manquer. Voir mises à jour du noyau en production avant d'activer les redémarrages automatiques.
  • Les conteneurs Docker ne voient pas les mises à jour de l'hôte. Un libssl corrigé sur l'hôte ne fait rien pour le libssl dans votre image python:3.12. Les images de conteneurs sont un flux de correctifs séparé.

Ce qu'il vous manque encore

  • Une vue d'ensemble. Trente messages ntfy par matin ne font pas un tableau de bord. « Quels hôtes attendent depuis plus de sept jours ? » demande un script sur les messages.
  • La preuve du délai. Un auditeur veut « jours entre publication de l'USN et installation, p95 ». C'est éparpillé dans unattended-upgrades.log et dpkg.log par hôte.
  • Le retour arrière. Une mise à jour de sécurité qui casse un service est installée à 03:00 et découverte à 08:00. unattended-upgrades n'a pas de mécanisme « arrêter en cas d'erreurs sur d'autres hôtes ».

Comment monsys fait

L'agent monsys rapporte par hôte les mises à jour en attente, reboot_required (avec depuis quand) et les services tournant sur des bibliothèques obsolètes ; le hub l'affiche comme une seule liste pour toute la flotte et mesure le délai de correction par rapport à la date de publication de l'USN ou du DSA. Qui veut aller plus loin active l'auto-patch : par hôte et par catégorie (paquets OS, dépendances applicatives), opt-in explicite avec TOTP, exécuté via des Emergency Action Tokens signés, avec une barrière de retour arrière qui met la boucle en pause sur toute la flotte dès qu'un lot échoue. Le principe « observe et rapporte, n'intervient jamais de lui-même » demeure : aucune action sans qu'un humain l'ait autorisée au préalable.

FAQ

Dois-je activer les mises à jour automatiques en production ?

Les mises à jour de sécurité : oui, avec la liste noire de l'étape 2 pour le noyau, les bases de données et Docker. La probabilité qu'une mise à jour de sécurité casse quelque chose est faible ; celle qu'une mise à jour de sécurité non installée soit exploitée est plus grande. Les mises à jour fonctionnelles (-updates), vous les planifiez délibérément.

Pourquoi une mise à jour de sécurité reste-t-elle en attente alors qu'unattended-upgrades tourne ?

Trois causes, par ordre de probabilité : le paquet est sur la liste noire (noyau, base de données), la mise à jour est « phased » et pas encore attribuée à votre hôte, ou la mise à jour nécessite un paquet d'une origine que vous n'avez pas autorisée (p. ex. -updates). unattended-upgrade --dry-run --debug vous dit laquelle.

needrestart remplace-t-il un redémarrage ?

Pour les mises à jour de bibliothèques : oui, il redémarre les services qui utilisent l'ancienne bibliothèque. Pour les mises à jour du noyau, de glibc et de systemd : non, un redémarrage reste nécessaire, et c'est exactement ce qu'indique /var/run/reboot-required.

Rédigé par l'équipe monsys — des sysadmins qui font cela tous les jours.

Fait à la main ? Laissez monsys s'en charger en continu.

Tout ce que contient ce guide tourne dans monsys comme contrôle permanent, avec historique, alertes et preuves d'audit. 5 serveurs gratuits, hébergés en Belgique, installés en 60 secondes.