CentOS is one of my favourite Linux distros, a great option for anyone wanting to run an incredibly stable server. However there is one area where CentOS is lacking, and that is a default mechanism to view and install security patches. To make matters worse, it actually looks like there is a way to install security updates using yum:

$ sudo yum --security update 

The problem is that the above command doesn’t actually do anything, and unless you specifically research the issue chances are you would never know the command does nothing. This problem has caused widespread confusion and many otherwise good Linux resources online are also unaware of the limitation. You can find countless guides on the web which instruct CentOS admins to configure updates using ‘yum –security update‘, but these guides result in a false sense of security where server admins believe updates are occurring which never actually happen.

So why doesn’t ‘yum –security update‘ work? It is due to the fact that the default CentOS repos do not contain the necessary metadata which specifies whether an update is related to security issues or not. As a result ‘yum –security update‘ will run without issue, but it will never find any security related updates and simple say the system is fully updated for security patches.

This has been confirmed multiple times on the CentOS forums by the moderation TrevorH, eg:

There is no security metadata in the CentOS yum repos which means that running yum –security update does nothing useful.

https://forums.centos.org/viewtopic.php?t=70084#p294493

Once you are aware of the issue, it is quite simple to verify it for yourself.

$ sudo yum --security update
Loaded plugins: changelog, fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirror.trouble-free.net
 * epel: fedora-epel.mirrors.tds.net
 * extras: mirror.cc.columbia.edu
 * updates: mirror.centos.iad1.serverforge.org
<SNIP>
No packages needed for security; 233 packages available

Here you can see that ‘yum –security update‘ states that no security updates are needed. But if we do a bit more digging we can prove this is incorrect.

$ yum list available | grep bash
bash.x86_64                               4.2.46-34.el7                  base

Checking the CentOS security advisories we can see that the ‘bash.x86_64 4.2.46-34.el7’ update is in fact a security update: https://lists.centos.org/pipermail/centos-cr-announce/2020-April/012412.html

One solution to this problem would be to simply run ‘yum update‘ to update all packages, and considering the nature of CentOS it would actually be fairly safe. However the paranoid sysadmin in me would much prefer to only automatically update security patches. After looking into the various solutions, I personally decided the most straight forward way of implementing security updates automatically is to use the centos-package-cron GitHub project.

This project works by comparing the CentOS/RHEL security advisories to the packages installed on the server and it is very simple to install and use.

centos-package-cron installation

All you need to do is grab the release RPM from their GitHub page and install it using yum:

$ curl -L "https://github.com/wied03/centos-package-cron/releases/download/releases%2F1.0.10/centos-package-cron-1.0-10.el7.centos.x86_64.rpm" > centos-package-cron-1.0-10.el7.centos.x86_64.rpm
$ sudo yum localinstall centos-package-cron-1.0-10.el7.centos.x86_64.rpm

Using centos-package-cron

Once centos-package-cron is installed, you can get a very detailed report of all outstanding security updates simply by running:

$ centos-package-cron --output stdout --forceold

However if you want to automate security updates, all we really need is a list of the packages that need a security update. We can get that easily enough simply by piping the centos-package-cron results through a few filters:

$ centos-package-cron --output stdout --forceold | awk '/Packages:/,/References:/' | grep -o "[^* ]*" | grep -v 'Packages:' | grep -v 'References:' | sort | uniq

Let’s do some more testing and see what happens when we run the above command on the same server where ‘yum –security update‘ stated that no security patches needed to be installed:

$ sudo centos-package-cron --output stdout --forceold | awk '/Packages:/,/References:/' | grep -o "[^* ]*" | grep -v 'Packages:' | grep -v 'References:' | sort | uniq

bash-4.2.46-29.el7_4
bind-libs-lite-9.9.4-51.el7
bind-license-9.9.4-51.el7
curl-7.29.0-42.el7
expat-2.1.0-10.el7_3
file-5.11-33.el7
file-libs-5.11-33.el7
gettext-0.19.8.1-2.el7
gettext-libs-0.19.8.1-2.el7
httpd-2.4.6-67.el7.centos.5
httpd-tools-2.4.6-67.el7.centos.5
kernel-3.10.0-693.2.2.el7
kernel-3.10.0-693.el7
kernel-headers-3.10.0-693.2.2.el7
kernel-tools-3.10.0-693.2.2.el7
kernel-tools-libs-3.10.0-693.2.2.el7
libcurl-7.29.0-42.el7
libX11-1.6.5-1.el7
libX11-common-1.6.5-1.el7
libxml2-2.9.1-6.el7_2.3
libxml2-python-2.9.1-6.el7_2.3
mariadb-libs-5.5.56-2.el7
nss-3.28.4-12.el7_4
nss-softokn-3.28.3-8.el7_4
nss-softokn-freebl-3.28.3-8.el7_4
nss-sysinit-3.28.4-12.el7_4
nss-tools-3.28.4-12.el7_4
nss-util-3.28.4-3.el7
php-5.4.16-42.el7
php-cli-5.4.16-42.el7
php-common-5.4.16-42.el7
php-fpm-5.4.16-42.el7
polkit-0.112-12.el7_3
python-2.7.5-58.el7
python-libs-2.7.5-58.el7
python-perf-3.10.0-693.2.2.el7
rsyslog-8.24.0-12.el7
shared-mime-info-1.8-3.el7
sqlite-3.7.17-8.el7
sudo-1.8.19p2-11.el7_4
telnet-0.17-64.el7
unzip-6.0-20.el7

As you can see the results are very different. yum –security update identifies 0 packages that have security updates whereas centos-package-cron finds 41 packages with security updates. You may also have noticed that centos-package-cron did correctly identify that bash-4.2.46-29.el7_4 needs to be updated.

Now if we want to have completely automated updates, we can just setup a daily cron which pipes the above results straight to yum update, like this:

$ sudo centos-package-cron --output stdout --forceold | awk '/Packages:/,/References:/' | grep -o "[^* ]*" | grep -v 'Packages:' | grep -v 'References:' | sort | uniq | xargs -r yum -y update