Сервер, на котором не ставятся обновления безопасности, рано или поздно превращается в дыру в инфраструктуре. Не через неделю, так через месяц, не через месяц, так через полгода появится критическая уязвимость в одной из библиотек, и злоумышленники с автоматическими сканерами найдут эту незакрытую дыру быстрее, чем администратор успеет среагировать. История знает десятки случаев, когда крупные взломы происходили именно из-за неустановленных вовремя обновлений, хотя патчи лежали в репозиториях дистрибутива неделями, а то и месяцами.
С другой стороны, любой администратор, обслуживающий хотя бы десяток машин, знает, насколько утомительно вручную проверять обновления на каждом сервере. Заходить по SSH, запускать apt update, просматривать список изменений, выполнять apt upgrade, отвечать на возможные интерактивные вопросы установщиков пакетов. Один-два сервера это терпимо, но при тридцати машинах процесс превращается в полный рабочий день, который повторяется каждую неделю.
Решение этой задачи существует давно и работает надёжно. Пакет unattended-upgrades делает всё то же самое, что делал бы администратор вручную, только без участия человека и по расписанию. Стабильные обновления безопасности накатываются автоматически, логи фиксируют все действия, на электронную почту приходят уведомления о результатах. Получается режим автопилота, при котором серверы сами поддерживают себя в актуальном состоянии, а админ имеет возможность спокойно спать по ночам.
Быстрая установка unattended-upgrades и первоначальная проверка работоспособности на сервере
Базовая настройка автоматических обновлений делается двумя командами. Сначала ставится сам пакет, потом запускается интерактивная перенастройка с минимальным уровнем критичности вопросов.
apt install unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades
Команда dpkg-reconfigure с флагом -plow показывает диалоговое окно, где спрашивается, нужно ли автоматически скачивать и устанавливать стабильные обновления безопасности. Ответ должен быть yes, иначе вся последующая магия не заработает. Флаг plow означает priority low, то есть показывать все вопросы конфигурации, включая некритичные.
После этого unattended-upgrades начинает работать в фоне и проверять обновления дважды в день в случайно выбранные моменты времени. Случайность важна, и об этом будет отдельный разговор ниже. Стабильные обновления безопасности устанавливаются без вмешательства человека.
Контроль за работой утилиты ведётся через логи. Журналы складываются в директорию /var/log/unattended-upgrades/, где хранятся подробные записи о каждом запуске. Дополнительно полезный файл /var/log/dpkg.log содержит общий лог пакетной системы и фиксирует все установки и удаления пакетов вне зависимости от того, через кого они инициированы.
Существует распространённое опасение, что параллельный запуск apt вручную и unattended-upgrades приведёт к конфликту и порче пакетной базы. Беспокойство напрасное. Система apt использует блокировки, и при попытке запустить apt в момент, когда работает unattended-upgrades, появится сообщение о том, что другая операция уже идёт, и пользователю предложат подождать её завершения. Никакого риска повредить базу пакетов нет, можно спокойно работать руками и параллельно иметь автообновления.
Где искать справочные материалы и официальную документацию по тонким настройкам утилиты
Документация по unattended-upgrades разбросана по нескольким местам, и знание этих источников экономит часы поиска информации. Главный файл конфигурации /etc/apt/apt.conf.d/50unattended-upgrades сам по себе является справочником. Его комментарии описывают каждый параметр, дают примеры значений и объясняют поведение системы при разных настройках. По сути это первый источник, в который стоит заглянуть при возникновении вопросов. Дальше в статье этот файл будет упоминаться сокращённо как 50unattended-upgrades.
Второй важный источник это readme-файл, входящий в пакет /usr/share/doc/unattended-upgrades/README.md.gz. Файл сжат gzip, и читать его удобно командой zless из пакета gzip. Внутри подробно описаны все поддерживаемые настройки, особенности работы и рекомендации по конфигурации в разных сценариях. В дальнейшем этот документ называется просто README.
Дополнительно существует страница на wiki Debian по адресу https://wiki.debian.org/UnattendedUpgrades. Документация Ubuntu Server содержит главу Automatic Updates про unattended-upgrades. И, конечно, классическая страница руководства, доступная по команде man unattended-upgrade в терминале. Каждый из этих источников освещает тему под своим углом, и при углублённом изучении стоит обратиться ко всем.
Расширенная настройка с почтовыми уведомлениями и грамотный подход к локальным правкам конфигурации
При использовании быстрой настройки администратор быстро замечает, что не все обновления ставятся автоматически. Часть пакетов остаётся без внимания, и без объяснения причин понять происходящее сложно. Хочется также большего контроля над тем, что именно происходит автоматически. Расширенная настройка решает эти вопросы.
Главный файл конфигурации 50unattended-upgrades содержит документацию прямо в комментариях. Чтение его сверху донизу даёт полное представление обо всех доступных опциях. Особенно полезна настройка отправки писем при срабатывании обновлений, потому что без неё узнать о проблемах можно только при проактивной проверке логов.
Здесь возникает важный нюанс, который обходят стороной многие туториалы. Файл 50unattended-upgrades создаётся самим пакетом unattended-upgrades при установке или обновлении. Это означает, что при следующем апгрейде пакета или при переходе на новую версию ОС любые правки в этом файле приведут к конфликту, который придётся решать вручную. Документация README рекомендует другой путь. Создавать отдельный файл 52unattended-upgrades-local и вносить все локальные правки именно в него. Apt прочитает оба файла, и настройки из 52unattended-upgrades-local переопределят дефолтные.
Перед тем как лезть в настройки писем, разумно убедиться, что включение работает корректно. Файл /etc/apt/apt.conf.d/20auto-upgrades должен содержать две строки.
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
Первая включает периодическое обновление списка пакетов, вторая активирует сами автообновления. Если запускался dpkg-reconfigure с ответом yes, эти строки должны быть на месте. Их отсутствие означает, что вся настройка ниже бесполезна, потому что планировщик не будет запускать обновления.
Для работы почтовых уведомлений на сервере должна быть настроена и проверена система отправки писем. Это может быть локальный postfix или sendmail, который умеет отдавать письма наружу через smtp-релей провайдера, или просто отправка через локальный mail-агент. Без работающей почтовой системы все настройки писем в unattended-upgrades останутся декорацией.
Включение отправки писем делается через копирование одной строки из 50unattended-upgrades в локальный файл с раскомментированием.
//Unattended-Upgrade::Mail "";
Двойной слэш в начале это стиль комментариев в конфигурации apt, который похож на синтаксис C. Раскомментировав строку и вписав почтовый адрес между кавычек, получаем целевой адрес для уведомлений. Туда будут уходить отчёты о каждой операции unattended-upgrades.
По умолчанию письма приходят при каждом обновлении, что может быть избыточно для серверов с активной жизнью пакетов. Можно настроить отправку только при ошибках, что для большинства случаев разумнее.
// Set this value to "true" to get emails only on errors. Default
// is to always send a mail if Unattended-Upgrade::Mail is set
//Unattended-Upgrade::MailOnlyOnError "false";
Изменение значения на true означает, что письма пойдут только в случае проблем. На сервере без инцидентов почтовый ящик будет молчать, а появление письма станет сигналом к действию. Это удобнее, чем разбирать сотни писем "всё хорошо" в поисках одного важного.
После любых правок конфигурации обязательная проверка через тестовый запуск без реальных изменений.
unattended-upgrade --dry-run -d
Флаг --dry-run означает прогон без реальных установок, а -d включает подробный отладочный вывод. Команда покажет, какие пакеты были бы обновлены, какие репозитории включены в проверку, какие настройки применяются. Без этой проверки изменения легко могут оказаться неработающими, и обнаружить это получится только при следующем плановом запуске, который произойдёт в случайный момент в течение суток.
Интересная деталь связана с именем команды. На Debian 10, 11 и Ubuntu 22.04 пакет создаёт символическую ссылку с unattended-upgrades на unattended-upgrade в директории /usr/bin/ или /bin/. Обе команды работают одинаково, и можно использовать любую.
$ ls -lhi /bin/unattended-upgrade*
11404505 -rwxr-xr-x 1 root root 98K tammi 15 2022 /bin/unattended-upgrade
11407087 lrwxrwxrwx 1 root root 18 tammi 15 2022 /bin/unattended-upgrades -> unattended-upgrade
В выводе видна сама команда и символическая ссылка на неё с другим именем. Стрелочка -> указывает направление ссылки. Можно писать и с s, и без s, эффект одинаковый.
Подключение сторонних репозиториев к автоматическим обновлениям через настройку Origins-Pattern
По умолчанию unattended-upgrades обновляет только пакеты из основных репозиториев безопасности дистрибутива. Это разумная политика, потому что сторонние репозитории менее проверены, и автоматическое обновление из них может привести к проблемам. Но если репозиторий проверен и в его обновлениях есть уверенность, его можно добавить в список разрешённых источников.
Добавление делается через настройку Unattended-Upgrade::Origins-Pattern. В файле конфигурации есть документация по синтаксису. README указывает, что настройки из 52unattended-upgrades-local переопределяют дефолтные. На практике поведение немного другое. Origins-Pattern в локальном файле не полностью заменяет дефолтное значение, а добавляется к нему. Это удобно, потому что не нужно копировать весь список стандартных источников, достаточно дописать только свои.
Конкретный пример помогает понять механику. Допустим, на сервере стоит пакет goaccess, установленный из официального репозитория GoAccess. Этот пакет не обновляется автоматически, потому что его репозиторий не входит в список разрешённых. Если бы тот же пакет был установлен из обычного репозитория Debian, он бы обновлялся, потому что в обоих местах он доступен.
Изучение текущей ситуации делается через apt list.
root@posti:~# LANG=C apt list --upgradable
Listing... Done
goaccess/unknown 2:1.6.3-buster amd64 [upgradable from: 2:1.6.2-buster]
php-tcpdf/buster-backports 6.5.0+dfsg1-1~bpo10+1 all [upgradable from: 6.3.5+dfsg1-1~bpo10+1]
root@posti:~#
Видно два пакета, которые могли бы обновиться, но не делают этого автоматически. Первый goaccess из стороннего репозитория, второй php-tcpdf из секции buster-backports официального Debian. Проверка происхождения пакета делается через apt policy.
root@posti:~# LANG=C apt policy goaccess
goaccess:
Installed: 2:1.6.2-buster
Candidate: 2:1.6.3-buster
Version table:
2:1.6.3-buster 500
500 https://deb.goaccess.io buster/main amd64 Packages
*** 2:1.6.2-buster 100
100 /var/lib/dpkg/status
1:1.2-4+b10 500
500 http://mirror.hetzner.de/debian/packages buster/main amd64 Packages
500 http://deb.debian.org/debian buster/main amd64 Packages
root@posti:~#
Информации много. Текущая установленная версия отмечена тремя звёздочками. Видны разные источники с разными приоритетами, обозначенными цифрами 100 и 500. Чем больше число, тем выше приоритет источника для apt. Версия 1.6.3 доступна с deb.goaccess.io, версия 1.2 из обычных репозиториев Debian.
Запуск unattended-upgrade --dry-run -d покажет, какие источники сейчас разрешены. Лог последнего реального запуска тоже даёт эту информацию.
2022-09-05 08:28:08,955 INFO Checking if system is running on battery is skipped. Please install
powermgmt-base package to check power status and skip installing updates when the system
is running on battery.
2022-09-05 08:28:08,960 INFO Initial blacklist :
2022-09-05 08:28:08,960 INFO Initial whitelist:
2022-09-05 08:28:08,960 INFO Starting unattended upgrades script
2022-09-05 08:28:08,960 INFO Allowed origins are:
origin=Debian,codename=buster,label=Debian,
origin=Debian,codename=buster,label=Debian-Security
Видно, что разрешены только два источника, оба официальные Debian. Репозитория GoAccess в списке нет, отсюда и отсутствие автообновления. Решение это добавить его в Origins-Pattern в локальном файле.
Полезный совет про ноутбуки и сообщение про батарею в логе. Если unattended-upgrades установлен на ноутбук, разумно поставить пакет powermgmt-base. С ним unattended-upgrades не будет запускать обновления, когда машина работает от батареи, потому что энергозатратное обновление пакетов может посадить аккумулятор в неподходящий момент. На серверах, которые всегда подключены к сети, это сообщение надоедает, и его можно убрать через настройку.
Unattended-Upgrade::Origins-Pattern {
// Taleman added GoAccess 2022-09-05
"o=GoAccess Repository, n=buster, l=Official GoAccess Repository";
};
Unattended-Upgrade::OnlyOnACPower "false";
Запись внутри Origins-Pattern содержит несколько полей через запятую. Поле o это origin, имя репозитория, под которым он представляется системе. Поле n это codename, кодовое имя дистрибутива, для которого собран пакет. Поле l это label, метка репозитория. Эти значения берутся из вывода apt policy. Параметр OnlyOnACPower false говорит unattended-upgrades не проверять, работает ли машина от сети, что устраняет надоедливое сообщение в логе.
Поддерживается подстановка переменных. Конструкция ${distro_id} содержит вывод lsb_release -i, а ${distro_codename} вывод lsb_release -c. Вместо явного указания n=buster можно было бы написать n=${distro_codename}, что делает конфиг переносимым между версиями дистрибутива.
Второй пакет php-tcpdf тоже нужно научить обновляться. Он стоит из buster-backports, и этот источник уже есть в дефолтном файле, но закомментирован. Чтобы его включить, копируем закомментированную строку в локальный файл и убираем слэши.
// "o=Debian Backports,a=${distro_codename}-backports,l=Debian Backports";
После всех правок обязательно проверяется работа через --dry-run -d. В выводе должны появиться новые источники в Allowed origins, а php-tcpdf и goaccess должны оказаться в списке пакетов, которые будут обновлены.
Управление расписанием запусков и почему случайное время это не баг, а фича
unattended-upgrades запускается в случайные моменты времени, и это сделано не случайно. Если бы все серверы по всему миру начинали скачивать обновления в один и тот же момент, на серверы репозиториев пошла бы огромная пиковая нагрузка. С учётом того, что Debian и Ubuntu обслуживают десятки миллионов установок, такая синхронность могла бы положить любую инфраструктуру зеркал. Случайные задержки размазывают нагрузку во времени и спасают сетевую инфраструктуру дистрибутива.
Менять это поведение стоит только при наличии очень веских причин. Если организация держит собственный репозиторий или зеркало, тогда пиковая нагрузка идёт на её серверы, и можно настраивать что угодно. Для большинства случаев лучше оставить настройки по умолчанию.
Управление временем запуска идёт через systemd. Файл /lib/systemd/system/apt-daily.timer содержит секцию Timer, которая запускает скачивание дважды в день со случайной задержкой до 12 часов. Менять этот файл напрямую не стоит, потому что при обновлении пакета systemd-юнитов изменения потеряются.
Остальные временные настройки делаются в файлах 50unattended-upgrades и 52unattended-upgrades-local. Параметр Unattended-Upgrade::Update-Days определяет дни недели, в которые могут происходить обновления. Пустое значение по умолчанию означает работу каждый день. Можно настроить запуск только в выходные, например указав Saturday и Sunday. Это полезно для серверов, где не хочется получать неожиданные обновления в рабочие дни.
Автоматическая перезагрузка после обновлений настраивается через отдельный блок параметров. По умолчанию перезагрузка не делается, что разумно для большинства случаев.
//Unattended-Upgrade::Automatic-Reboot "false";
//Unattended-Upgrade::Automatic-Reboot-WithUsers "true";
//Unattended-Upgrade::Automatic-Reboot-Time "02:00";
Включение Automatic-Reboot в true приводит к немедленной перезагрузке, как только устанавливаются обновления, требующие этого. Поведение довольно агрессивное, и для серверов с реальными пользователями обычно неприемлемое. Параметр Automatic-Reboot-WithUsers контролирует, перезагружаться ли при наличии активных пользовательских сессий. Более мягкий вариант это Automatic-Reboot-Time, который задаёт конкретное время для перезагрузки. Тогда обновление установится сразу, а сама перезагрузка произойдёт в указанное время, обычно ночью, когда нагрузка на сервер минимальна.
Чёрный и белый списки пакетов для исключения и отбора конкретных программ из автообновлений
Иногда нужно тонко контролировать, какие именно пакеты обновлять автоматически, а какие оставить под ручным контролем. Для этого существуют чёрные и белые списки.
Чёрный список Package-Blacklist принимает регулярные выражения. Если имя пакета соответствует регулярному выражению, этот пакет исключается из автообновлений. На стабильных релизах функция используется редко, потому что в стабильных репозиториях обновления безопасности обычно безболезненны. Полезнее она на тестовых или разрабатываемых ветках, где может потребоваться зафиксировать версию критичного компонента, чтобы обновление не сломало внезапно работающую систему.
Файл 50unattended-upgrades содержит примеры заблокированных пакетов, по которым можно ориентироваться при написании своих правил.
Белый список Package-Whitelist работает наоборот. По описанию из README только пакеты, соответствующие регулярным выражениям из списка, попадут под автообновление. Документация не даёт конкретных примеров, когда такой подход полезен. На практике это означает строжайший фильтр, при котором обновляются только явно перечисленные пакеты, а всё остальное игнорируется. Применяется в редких сценариях, когда нужен максимально консервативный подход к автоматизации.
Что делать с пакетами, которые apt отказывается обновлять автоматически
Существуют ситуации, когда unattended-upgrades не выполняет обновление, потому что apt сам решает удержать пакет. Происходит это в случаях, когда обновление потребовало бы удаления другого пакета или установки нового, ранее не установленного. Команда apt upgrade принципиально не делает таких изменений, чтобы не сломать систему неожиданным удалением чего-то важного.
Если unattended-upgrades настроен на отправку писем, в уведомлении будет строка про удержанные пакеты.
Packages with upgradable origin but kept back:
Обнаружив такое сообщение, администратор должен зайти на сервер и выполнить обновление вручную с пониманием того, что произойдёт.
Полноценное обновление с возможностью удаления и установки пакетов делается командой apt full-upgrade. Она ведёт себя более агрессивно, чем обычный apt upgrade, и готова перестраивать зависимости как нужно для применения всех доступных обновлений. Перед запуском этой команды разумно посмотреть, что именно она планирует сделать, через apt full-upgrade --dry-run или просто apt full-upgrade без подтверждения, отвечая n на финальный вопрос.
В конце разумно привести пример реально работающего файла 52unattended-upgrades-local, чтобы было от чего отталкиваться.
Unattended-Upgrade::Origins-Pattern {
// Taleman added 2022-09-05
"o=GoAccess Repository, n=buster, l=Official GoAccess Repository";
"o=Debian Backports,a=${distro_codename}-backports,l=Debian Backports";
"origin=deb.sury.org,archive=${distro_codename}";
};
Unattended-Upgrade::Mail "Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript. ";
Unattended-Upgrade::OnlyOnACPower "false";
В этом примере добавлены три источника обновлений сверх дефолтных: репозиторий GoAccess, бэкпорты Debian и репозиторий deb.sury.org, известный своими свежими сборками PHP. Настроена отправка писем на указанный адрес и отключена проверка питания от сети.
Почему автоматизация обновлений стала обязательным элементом современной инфраструктуры
Внедрение unattended-upgrades это не просто экономия времени администратора. Это принципиальный сдвиг в подходе к безопасности инфраструктуры. Без автоматизации обновлений типичный сервер проводит в уязвимом состоянии дни и недели после публикации патчей, и каждый такой день это окно для атаки. С автоматизацией окно сокращается до часов, а часто и минут после появления обновления в репозитории.
Современная разработка ПО развивается с такой скоростью, что критические уязвимости находятся регулярно. Heartbleed, Shellshock, Log4Shell это только самые громкие случаи, которые сотрясали индустрию. Тысячи менее известных, но не менее опасных уязвимостей закрываются обновлениями каждый месяц. Сервер без автообновлений это сервер, который медленно но верно накапливает уязвимости, и вопрос времени, когда какая-то из них будет использована.
С другой стороны, страх перед автообновлениями имеет основания. Истории про сломанные обновлением серверы бродят в среде администраторов десятилетиями. Реальность такова, что в стабильных репозиториях Debian и Ubuntu пакеты обновляются крайне осторожно. Команда сопровождающих специально следит за тем, чтобы обновления безопасности не приносили несовместимых изменений API или поведения. Случаи поломки крайне редки, и обычно касаются специфических конфигураций.
Для критичных продакшн-серверов разумная стратегия выглядит так. Сначала автообновления катятся на staging-окружение, которое максимально близко копирует продакшн. Если за неделю всё работает нормально, обновления автоматически идут и на боевые серверы. Такой подход даёт буфер для отлова потенциальных проблем без потери преимуществ автоматизации.
Освоение unattended-upgrades это не разовая задача, а часть более широкого подхода к управлению инфраструктурой. Те же принципы применяются при работе с ansible, puppet, salt и другими системами автоматизации. Идея о том, что рутинные задачи должны выполняться машиной, а не человеком, лежит в основе всей современной философии devops и инфраструктуры как кода. Сервер, поддерживающий себя сам, это не научная фантастика, а вполне рабочая реальность, которая доступна любому администратору, потратившему пару часов на правильную настройку.