¿Usa el contenedor de Discourse actualizaciones automáticas?

¿Utiliza el contenedor Docker de Discourse unattended-upgrades para mantener actualizados los paquetes del sistema operativo del contenedor Docker basado en Debian?

He notado que la guía INSTALL-cloud.md recomienda instalar unattended-upgrades en la máquina anfitriona de Docker, por lo que me pregunté sobre el estado de los paquetes del sistema operativo dentro del contenedor Docker. Busqué tanto en los repositorios discourse como en discourse_docker en GitHub, pero la única referencia que pude encontrar a unattended-upgrades fue el mismo documento de instalación.

¿Pero qué pasa con el contenedor Docker de Discourse? ¿Lo utiliza él unattended-upgrades?

Tras investigar más a fondo, parece que unattended-upgrades está instalado pero no se está ejecutando en el contenedor Docker de Discourse.

En primer lugar, está claramente instalado:

root@osestaging1-discourse-ose:/var/www/discourse# dpkg -l | grep -i unatt
ii  unattended-upgrades             1.11.2                       all          instalación automática de actualizaciones de seguridad
root@osestaging1-discourse-ose:/var/www/discourse# 

Una inspección más detallada de la configuración del paquete unattended-upgrades, según el artículo correspondiente de la wiki de Debian, muestra:

La configuración predeterminada parece correcta:

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# 

Sin embargo, al revisar los registros, la última entrada data de hace un mes:

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# 

…A pesar de que los temporizadores systemd predeterminados definidos para unattended-upgrades están configurados para ejecutarse al menos una vez al día:

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# 

Pero, de hecho, esos temporizadores están desactivados.

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# 

Esto se confirma aún más al ejecutar manualmente unattended-upgrades, lo cual casualmente requirió una actualización de dos paquetes relacionados con 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# 

La versión de git que se actualizó en la ejecución anterior de unattended-upgrades fue git (1:2.20.1-2+deb10u1). Ejecuté esta prueba hoy (2019-12-24), ¡pero la actualización de seguridad estaba disponible para Debian Buster (el sistema operativo sobre el que se construye la imagen Docker de Discourse) desde hace dos semanas (desde el 2019-12-10)!

Esta es realmente una actualización bastante importante que corrige varias vulnerabilidades, incluidos dos vectores para la ejecución remota de código. Más información está disponible en el Advisory de Seguridad de Debian 4581-1:

Pero git es solo un ejemplo en el que me tropecé por casualidad. Es extremadamente preocupante si el contenedor Docker de Discourse no aplica (por defecto) parches relacionados con la seguridad a su sistema operativo.

¿Es esto un error? ¿O fue una decisión intencional del equipo de Discourse? ¿O es simplemente la configuración predeterminada en lugar de una solicitud de función para habilitar unattended-upgrades en el contenedor Docker de Discourse?

Mi suposición es que está desactivado intencionalmente, ya que podría romper algo, y la imagen en sí se actualiza cuando se detecta un problema de seguridad grave.

Puedes habilitarlo si lo deseas, solo ingresa al contenedor.

En realidad, acabo de darme cuenta de que la imagen de Docker de Discourse está configurada para usar runit. ¿Acaso systemd está instalado en el contenedor de Docker de Discourse?

Mi suposición es que no tener systemd instalado es lo que está rompiendo unattended-upgrades.

Suena bien. A algunas personas realmente no les gusta systemd. Así que puedes confiar en que el contenedor base se actualice regularmente gracias a un equipo grande de profesionales que dependen de él, o puedes hacerlo tú mismo de otra manera y esperar que no rompas nada.

No, no lo hace y no tenemos previsto que lo haga. La recomendación es mantener tu sistema operativo anfitrión actualizado con los últimos parches de seguridad.

Lo cual, por cierto, es así.

FYI, he solucionado la instalación rota de unattended-upgrades (que en realidad no se ejecuta sin systemd en el contenedor Docker de Discourse) activando su ejecución mediante un trabajo cron.

He creado el siguiente archivo de plantilla YAML en mi directorio /var/discourse/templates/ para generar el trabajo cron necesario (ten en cuenta que también incluye un comando para solucionar un error con cron incluido en la imagen Docker de Discourse basada en 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

Para habilitar el archivo de plantilla anterior, debes añadirlo a tu lista de templates en el archivo YAML de tu aplicación. Por ejemplo,

[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]# 

Parece que está habilitado en una imagen fresca de Docker de Discourse (ejecutando Debian 10). Se inicia a través de runit → cron → /etc/cron.daily/apt-compat → /usr/lib/apt/apt.systemd.daily

También se estaba ejecutando en una imagen de Docker basada en Ubuntu 16 con un año de antigüedad (basada en discourse/base:2.0.20190321-0122), y estoy bastante seguro de que sin ninguna personalización.

systemd no está instalado, por lo que en realidad nunca se ejecuta.