Использует ли контейнер Discourse unattended-upgrades?

Использует ли Docker-контейнер Discourse unattended-upgrades для обновления пакетов ОС Debian, на котором он основан?

Я заметил, что руководство INSTALL-cloud.md рекомендует устанавливать unattended-upgrades на хост-машину Docker, поэтому у меня возник вопрос о состоянии пакетов ОС внутри Docker-контейнера. Я искал в репозиториях discourse и discourse_docker на GitHub, но единственное упоминание unattended-upgrades, которое я нашел, — это тот же документ по установке.

Но что насчет самого Docker-контейнера Discourse? Использует ли он unattended-upgrades?

После дальнейшего расследования выяснилось, что unattended-upgrades установлен, но не запущен в контейнере Docker для Discourse.

Во-первых, он явно установлен:

root@osestaging1-discourse-ose:/var/www/discourse# dpkg -l | grep -i unatt
ii  unattended-upgrades             1.11.2                       all          automatic installation of security upgrades
root@osestaging1-discourse-ose:/var/www/discourse# 

Дальнейшая проверка конфигурации пакета unattended-upgrades согласно соответствующей статье в вики Debian показывает:

Конфигурация по умолчанию выглядит разумной:

root@osestaging1-discourse-ose:/var/www/discourse# grep -ir 'origin=' /etc/apt/apt.conf.d/50unattended-upgrades 
//      "origin=Debian,codename=${distro_codename}-updates";
//      "origin=Debian,codename=${distro_codename}-proposed-updates";
		"origin=Debian,codename=${distro_codename},label=Debian";
		"origin=Debian,codename=${distro_codename},label=Debian-Security";
root@osestaging1-discourse-ose:/var/www/discourse# cat /etc/apt/apt.conf.d/20auto-upgrades 
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
root@osestaging1-discourse-ose:/var/www/discourse# 

Однако проверка логов показывает, что последняя запись была месяц назад:

root@osestaging1-discourse-ose:/var/www/discourse# tail -f /var/log/unattended-upgrades/unattended-upgrades*.log
==> /var/log/unattended-upgrades/unattended-upgrades-dpkg.log <==
Log started: 2019-11-17  12:34:54
(Reading database ... 44559 files and directories currently installed.)
Removing freetype2-doc (2.9.1-3+deb10u1) ...
Log ended: 2019-11-17  12:34:54

Log started: 2019-11-17  12:34:56
(Reading database ... 44389 files and directories currently installed.)
Removing libjs-jquery (3.3.1~dfsg-3) ...
Log ended: 2019-11-17  12:34:57


==> /var/log/unattended-upgrades/unattended-upgrades.log <==
2019-11-26 16:37:47,549 INFO Initial blacklist : 
2019-11-26 16:37:47,550 INFO Initial whitelist: 
2019-11-26 16:37:47,551 INFO Starting unattended upgrades script
2019-11-26 16:37:47,552 INFO Allowed origins are: origin=Debian,codename=buster,label=Debian, origin=Debian,codename=buster,label=Debian-Security
2019-11-26 16:37:50,811 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.
2019-11-26 16:37:50,814 INFO Initial blacklist : 
2019-11-26 16:37:50,815 INFO Initial whitelist: 
2019-11-26 16:37:50,815 INFO Starting unattended upgrades script
2019-11-26 16:37:50,815 INFO Allowed origins are: origin=Debian,codename=buster,label=Debian, origin=Debian,codename=buster,label=Debian-Security
2019-11-26 16:37:53,119 INFO No packages found that can be upgraded unattended and no pending auto-removals
^C
root@osestaging1-discourse-ose:/var/www/discourse# 

…Хотя таймеры systemd по умолчанию, определенные для unattended-upgrades, настроены на запуск как минимум раз в день:

root@osestaging1-discourse-ose:/var/www/discourse# cat /lib/systemd/system/apt-daily.timer
[Unit]
Description=Daily apt download activities

[Timer]
OnCalendar=*-*-* 6,18:00
RandomizedDelaySec=12h
Persistent=true

[Install]
WantedBy=timers.target
root@osestaging1-discourse-ose:/var/www/discourse# cat /etc/systemd/system/apt-daily.timer.d/override.conf
cat: /etc/systemd/system/apt-daily.timer.d/override.conf: No such file or directory
root@osestaging1-discourse-ose:/var/www/discourse# cat /lib/systemd/system/apt-daily-upgrade.timer
[Unit]
Description=Daily apt upgrade and clean activities
After=apt-daily.timer

[Timer]
OnCalendar=*-*-* 6:00
RandomizedDelaySec=60m
Persistent=true

[Install]
WantedBy=timers.target
root@osestaging1-discourse-ose:/var/www/discourse# cat /etc/systemd/system/apt-daily-upgrade.timer.d/override.conf
cat: /etc/systemd/system/apt-daily-upgrade.timer.d/override.conf: No such file or directory
root@osestaging1-discourse-ose:/var/www/discourse# 

Но, действительно, эти таймеры отключены.

root@osestaging1-discourse-ose:/var/www/discourse# sudo systemctl status apt-daily.timer
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
root@osestaging1-discourse-ose:/var/www/discourse# sudo systemctl status apt-daily-upgrade.timer
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
root@osestaging1-discourse-ose:/var/www/discourse# 

Это дополнительно подтверждается ручным запуском unattended-upgrades, который как раз потребовал обновления двух пакетов, связанных с git:

root@osestaging1-discourse-ose:/var/www/discourse# sudo unattended-upgrade -d
...
Checking: git ([<Origin component:'main' archive:'stable' origin:'Debian' label:'Debian-Security' site:'security.debian.org' isTrusted:True>])
Checking: git-man ([<Origin component:'main' archive:'stable' origin:'Debian' label:'Debian-Security' site:'security.debian.org' isTrusted:True>])
pkgs that look like they should be upgraded: git   
git-man
...
All upgrades installed
InstCount=0 DelCount=0 BrokenCount=0
Extracting content from /var/log/unattended-upgrades/unattended-upgrades-dpkg.log since 2019-12-24 17:32:55
root@osestaging1-discourse-ose:/var/www/discourse# 

Версия git, обновленная в вышеуказанном запуске unattended-upgrades, была git (1:2.20.1-2+deb10u1). Я провел этот тест сегодня (24 декабря 2019 года), но обновление безопасности было доступно для Debian Buster (ОС, на которой собран образ Docker для Discourse) уже две недели (с 10 декабря 2019 года)!

На самом деле это довольно серьезное обновление, которое устраняет несколько уязвимостей, включая два вектора удаленного выполнения кода. Дополнительная информация доступна в совете по безопасности Debian 4581-1:

Но git — это просто пример, на который я случайно наткнулся. Крайне тревожно, если контейнер Docker для Discourse по умолчанию не применяет патчи безопасности к своей ОС.

Это ошибка? Или это было сознательное решение команды Discourse? Или это просто стандартная практика в ожидании запроса на добавление функции включения unattended-upgrades в контейнер Docker для Discourse?

Мой предположение: это отключено намеренно, так как это может что-то сломать, а само изображение обновляется только при обнаружении серьёзной уязвимости безопасности.

Вы можете включить его, если хотите, просто зайдите в контейнер.

На самом деле, я только что понял, что Docker-образ Discourse настроен на использование runit. Установлен ли systemd в контейнере Docker Discourse?

Я полагаю, что отсутствие systemd и является причиной сбоя unattended-upgrades.

Звучит правильно. Некоторым людям systemd действительно не нравится. Поэтому вы можете либо довериться тому, что базовый контейнер регулярно обновляется командой профессионалов, от которых он зависит, либо сделать это другим способом самостоятельно, надеясь, что ничего не сломаете.

Нет, не использует, и мы не планируем заставлять его это делать. Рекомендуется обновлять вашу хост-ОС последними патчами безопасности.

Что, на всякий случай, и происходит.

К сведению, я исправил неработающую установку unattended-upgrades (которая на самом деле не запускается без systemd в контейнере Docker для Discourse), запустив её через cron-задачу.

Я создал следующий шаблонный файл YAML в директории /var/discourse/templates/ для создания необходимой cron-задачи (обратите внимание, что он также содержит команду для исправления ошибки с cron, присутствующей в образе Docker Discourse на базе Debian):

cat << EOF > /var/discourse/templates/unattended-upgrades.template.yml
run:
  - file:
     path: /etc/cron.d/unattended-upgrades
     contents: |+
        ################################################################################
        # File:    /etc/cron.d/unattended-upgrades
        # Version: 0.2
        # Purpose: run unattended-upgrades in lieu of systemd. For more info see
        #           * https://wiki.opensourceecology.org/wiki/Discourse
        #           * https://meta.discourse.org/t/does-discourse-container-use-unattended-upgrades/136296/3
        # Author:  Michael Altfield <michael@opensourceecology.org>
        # Created: 2020-03-23
        # Updated: 2020-04-23
        ################################################################################
        20 04 * * * root /usr/bin/nice /usr/bin/unattended-upgrades --debug
        

  - exec: /bin/echo -e "\n" >> /etc/cron.d/unattended-upgrades
  # fix the Docker cron bug https://stackoverflow.com/questions/43323754/cannot-make-remove-an-entry-for-the-specified-session-cron
  - exec: /bin/sed --in-place=.\`date "+%Y%m%d_%H%M%S"\` 's%^\([^#]*\)\(session\s\+required\s\+pam_loginuid\.so\)$%\1#\2%' /etc/pam.d/cron
EOF

Чтобы включить указанный выше шаблонный файл, необходимо добавить его в список templates в yaml-файле вашего приложения. Например,

[root@osestaging1 discourse]# head -n20 /var/discourse/containers/app.yml
## this is the all-in-one, standalone Discourse Docker container template
##
## After making changes to this file, you MUST rebuild
## /var/discourse/launcher rebuild app
##
## BE *VERY* CAREFUL WHEN EDITING!
## YAML FILES ARE SUPER SUPER SENSITIVE TO MISTAKES IN WHITESPACE OR ALIGNMENT!
## visit http://www.yamllint.com/ to validate this file as needed

templates:
  - "templates/unattended-upgrades.template.yml"
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
#  - "templates/web.socketed.template.yml"
  - "templates/web.modsecurity.template.yml"
  - "templates/web.ratelimited.template.yml"
## Uncomment these two lines if you wish to add Lets Encrypt (https)
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"
[root@osestaging1 discourse]# 

Похоже, что это включено в свежем образе Docker для Discourse (на базе Debian 10). Запуск осуществляется через runit → cron → /etc/cron.daily/apt-compat → /usr/lib/apt/apt.systemd.daily.

Это также работало на годовалом образе Docker на базе Ubuntu 16 (основанном на discourse/base:2.0.20190321-0122), и я почти уверен, что без каких-либо доработок.

systemd не установлен, поэтому он на самом деле никогда не выполняется.