Il contenitore Discourse utilizza unattended-upgrades?

Il contenitore Docker di Discourse utilizza unattended-upgrades per mantenere aggiornati i pacchetti del sistema operativo del contenitore Docker basato su Debian?

Ho notato che la guida INSTALL-cloud.md consiglia di installare unattended-upgrades sulla macchina host Docker, quindi mi sono chiesto sullo stato dei pacchetti del sistema operativo all’interno del contenitore Docker. Ho cercato sia nei repository discourse che discourse_docker su GitHub, ma l’unico riferimento a unattended-upgrades che ho trovato è lo stesso documento di installazione.

Ma per quanto riguarda il contenitore Docker di Discourse? Lo utilizza unattended-upgrades?

Dopo ulteriori indagini, sembra che unattended-upgrades sia installato ma non in esecuzione sul contenitore Docker di Discourse.

Innanzitutto, è chiaramente installato:

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# 

Un’ulteriore ispezione della configurazione del pacchetto unattended-upgrades, in base al relativo articolo sulla wiki Debian, mostra:

La configurazione predefinita sembra sensata:

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# 

Tuttavia, la verifica dei log mostra che l’ultima voce risale a un mese fa:

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# 

…anche se i timer systemd predefiniti definiti per unattended-upgrades sono impostati per eseguire almeno una volta al giorno:

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# 

Tuttavia, in effetti, quei timer sono disabilitati.

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# 

Ciò è ulteriormente confermato dall’esecuzione manuale di unattended-upgrades, che ha casualmente richiesto un aggiornamento per due pacchetti correlati a 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 versione di git aggiornata nell’esecuzione di unattended-upgrades sopra riportata era git (1:2.20.1-2+deb10u1). Ho eseguito questo test oggi (2019-12-24), ma l’aggiornamento di sicurezza era disponibile per Debian Buster (il sistema operativo su cui è basato l’immagine Docker di Discourse) da due settimane (dal 2019-12-10)!

Si tratta effettivamente di un aggiornamento piuttosto importante che risolve diverse vulnerabilità, inclusi due vettori per l’esecuzione remota di codice. Ulteriori informazioni sono disponibili nell’Avviso di Sicurezza Debian 4581-1:

Ma git è solo un esempio su cui sono casualmente inciampato. È estremamente preoccupante se il contenitore Docker di Discourse non applica (di default) effettivamente le patch relative alla sicurezza al suo sistema operativo.

Si tratta di un bug? O è stata una decisione intenzionale del team di Discourse? O è semplicemente lo stato predefinito in attesa di una richiesta di funzionalità per abilitare unattended-upgrades sul contenitore Docker di Discourse?

Immagino che sia disattivato intenzionalmente perché potrebbe causare problemi, e l’immagine stessa viene aggiornata solo quando viene rilevata una grave vulnerabilità di sicurezza.

Puoi attivarlo se lo desideri, basta entrare nel container.

In realtà, mi sono appena reso conto che l’immagine Docker di Discourse è configurata per utilizzare runit. systemd è addirittura installato nel container Docker di Discourse?

Immagino che la mancata installazione di systemd sia la causa del malfunzionamento di unattended-upgrades.

Sembra corretto. Alcune persone non amano davvero systemd. Quindi puoi fidarti del fatto che il container base venga aggiornato regolarmente da un team di professionisti che ne dipende, oppure puoi farlo in un altro modo da solo, sperando di non rompere nulla.

No, non lo fa e non abbiamo intenzione di farlo usare. La raccomandazione è mantenere aggiornato il tuo sistema operativo host con gli ultimi patch di sicurezza.

Cosa che, per la cronaca, è vera.

FYI, ho risolto l’installazione rotta di unattended-upgrades (che di fatto non viene eseguita senza systemd nel container Docker di Discourse) avviandola tramite un job cron.

Ho creato il seguente file template YAML nella directory /var/discourse/templates/ per creare il job cron necessario (nota che include anche un comando per risolvere un bug con cron presente nell’immagine Docker di Discourse basata su 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

Per abilitare il file template sopra, devi aggiungerlo alla tua lista di templates nel file YAML della tua applicazione. Ad esempio,

[root@osestaging1 discourse]# head -n20 /var/discourse/containers/app.yml
## questo è il template del container Docker Discourse standalone "all-in-one"
##
## Dopo aver apportato modifiche a questo file, DEVI ricostruire
## /var/discourse/launcher rebuild app
##
## FAI MOLTA ATTENZIONE DURANTE LA MODIFICA!
## I FILE YAML SONO MOLTO, MOLTO SENSIBILI A ERRORI NEGLI SPAZI O NELL'ALLINEAMENTO!
## visita http://www.yamllint.com/ per validare questo file quando necessario

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"
## Rimuovi il commento da queste due righe se desideri aggiungere Lets Encrypt (https)
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"
[root@osestaging1 discourse]# 

Sembra che sia abilitato su una nuova immagine Docker di Discourse (in esecuzione su Debian 10). Viene avviato tramite runit → cron → /etc/cron.daily/apt-compat → /usr/lib/apt/apt.systemd.daily

Funzionava anche su un’immagine Docker basata su Ubuntu 16 di un anno fa (basata su discourse/base:2.0.20190321-0122), sono quasi certo che senza alcuna personalizzazione.

systemd non è installato, quindi non viene mai effettivamente eseguito.