Większość udanych włamań na serwery odbywa się nie przez wymyślne exploity, lecz przez podatność, do której poprawka wyszła kilka miesięcy temu. Powodem zwykle nie jest lenistwo: aktualizowanie ręczne na działającym serwerze budzi obawy, bo apt upgrade potrafi zrestartować coś, o co nikt nie prosił. Automatyczne aktualizacje zamykają sprawę, ale mają złą sławę — zasłużoną dokładnie w tej mierze, w jakiej konfiguruje się je naprędce.

Przyjrzyjmy się konfiguracji, przy której poprawki bezpieczeństwa przychodzą same, a wersja PHP nie zmienia się w nocy.

Instalacja

sudo apt install unattended-upgrades apt-listchanges
sudo dpkg-reconfigure -plow unattended-upgrades

Okno dialogowe tworzy /etc/apt/apt.conf.d/20auto-upgrades. Sprawdźmy, co z tego wyszło:

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

Jedynki oznaczają „codziennie”. Uruchamia to wszystko licznik czasu systemd, a nie klasyczny cron:

systemctl list-timers | grep apt

Najważniejsze: tylko bezpieczeństwo

Główny plik to /etc/apt/apt.conf.d/50unattended-upgrades. Jest w nim lista Allowed-Origins (w Debianie Origins-Pattern) i domyślnie włączone jest tam tylko repozytorium bezpieczeństwa. Tak należy to zostawić.

Pokusa, żeby odkomentować wiersz z -updates — „niech wszystko się aktualizuje” — jest duża. Nie warto: repozytorium aktualizacji przynosi nowe wersje, a nie tylko poprawki, i to właśnie stamtąd biorą się nocne niespodzianki. Bezpieczeństwo i świeżość to różne zadania, a drugie lepiej wykonywać ręcznie, siedząc przy klawiaturze.

Jeśli jakiegoś pakietu nie wolno aktualizować automatycznie, jest na to czarna lista:

Unattended-Upgrade::Package-Blacklist {
    "mariadb-server";
    "php8.3-fpm";
};

Korzystajmy z niej świadomie: każdy wiersz oznacza „ten pakiet aktualizuję sam” — a tej obietnicy trzeba będzie dotrzymać.

Restarty

Kluczowy wiersz:

Unattended-Upgrade::Automatic-Reboot "false";

Zostawienie false jest właściwe dla serwera z witryną: restart bez uprzedzenia o trzeciej nad ranem jest gorszy niż poprawka odłożona o dzień. Ale ta decyzja ma obowiązkową drugą połowę i to o niej się zapomina.

Gdy aktualizowane jest jądro, libc albo openssl, system tworzy plik /var/run/reboot-required. Dopóki nie było restartu, na dysku leży wersja poprawiona, a w pamięci działa stara — czyli podatność wcale nie zniknęła, choć pakiet figuruje jako zaktualizowany. Sprawdzać trzeba jawnie:

ls -l /var/run/reboot-required
cat /var/run/reboot-required.pkgs

Drugi plik wylicza, z czego dokładnie wynika potrzeba restartu. Zasada jest prosta: widzimy znacznik — planujemy okno na najbliższą dobę lub dwie, a nie „kiedyś”.

Osobny przypadek to biblioteki. Aktualizuje się openssl, a nginx i PHP-FPM dalej pracują ze starą wersją w pamięci, przy czym żaden znacznik restartu się nie pojawia. Kto wymaga restartu, pokazuje needrestart:

sudo apt install needrestart
sudo needrestart -b

Tylko trzeba przełączyć go w tryb „pokazuj, nie pytaj” — inaczej zacznie zadawać pytania w środku nieinteraktywnej instalacji i ją zawiesi. W tym celu w /etc/needrestart/conf.d/ kładziemy plik z wierszem $nrconf{restart} = 'l';.

Sprawdzić, że to w ogóle działa

Przebieg próbny bez instalowania:

sudo unattended-upgrade --dry-run --debug

W wyniku widać, które pakiety mieszczą się w regułach, a które odrzucono i dlaczego. Co działo się naprawdę — w dziennikach:

sudo tail -50 /var/log/unattended-upgrades/unattended-upgrades.log

Ile aktualizacji czeka w tej chwili:

apt list --upgradable 2>/dev/null | grep -i security

To ostatnie polecenie jest najpożyteczniejsze ze wszystkich. Skonfigurowane automatyczne aktualizacje mają zwyczaj psuć się po cichu: skończyło się miejsce na /boot, repozytorium zmieniło klucz, licznik czasu został wyłączony po jakiejś ręcznej poprawce. Z zewnątrz wszystko w porządku, a poprawki nie instalują się od miesięcy.

Miejsce na /boot

Klasyka: stare jądra nie są usuwane, partycja /boot zapełnia się, instalacja nowego jądra pada i aktualizacje stają w całości. Raz na kilka miesięcy warto zajrzeć:

df -h /boot
sudo apt autoremove --purge

Albo włączyć automatyczne sprzątanie w tym samym 50unattended-upgrades: Remove-Unused-Kernel-Packages "true" i Remove-Unused-Dependencies "true".

Co zostaje człowiekowi

Automatyczne aktualizacje zdejmują rutynę, ale nie obserwację. Dwa pytania, na które trzeba umieć odpowiedzieć w każdej chwili: ile aktualizacji bezpieczeństwa czeka i czy podniesiony jest znacznik restartu. Obie odpowiedzi to po jednym wierszu na stronie, a cały sens polega na tym, żeby ten wiersz sam wpadał w oko, a nie z naszej inicjatywy raz na kwartał.