The blog posts have slowed down a bit lately because I’ve been heads down on a security project at work. I’m working with people in the OpenStack community to create a new Ansible role called openstack-ansible-security. The role aims to improve host security by using hardening standards to improve the configuration of various parts of the operating system.
This means applying security hardening to Ubuntu 14.04 systems since that’s the only host operating system supported by openstack-ansible at the moment. I have plenty of experience with securing Red Hat-based systems like Red Hat Enteprise Linux, CentOS and Fedora; but Ubuntu is new territory entirely. The rest of this post is full of lessons learned along the way.
Searching for hardening standards
Finding a complete hardening standard for Ubuntu 14.04 is challenging. The Center for Internet Security offers Ubuntu security benchmarks with two big caveats:
- There are very few controls to apply (relative to what’s available for RHEL)
- The terms of use are highly restrictive (no derivative works allowed)
With that idea off the table, I examined the other options that meet Requirement 2.2 of PCI-DSS 3.1 [PDF]. Anther choice was ISO 27002, but it’s not terribly specific or easy to automate with scripts. The same goes for NIST 800-53.
After plenty of searching, the decision was made to go forth with the Security Technical Implementation Guide (STIG) from the Defense Information Systems Agency (DISA) (part of the US Department of Defense). The STIGs aren’t licensed and they’re in the public domain. The only downside is that the closest STIG for use with Ubuntu 14.04 is the RHEL 6 STIG.
Using the RHEL 6 STIG meant that plenty of things will need to be translated for the different tools, configuration files, and package names that come with Ubuntu. It was frustrating to search all over for a hardening standard that applies well to Ubuntu and comes with decent auditing tools, but this was the best we could find.
Automatically starting daemons
The standard Ubuntu and Debian practice of automatically starting daemons has perplexed me before and it still continues to do so. Starting a daemon before I’ve had a chance to configure it makes little sense. The main argument is that the daemons come up with a highly secure configuration, so starting it automatically shouldn’t be a big deal. I’d prefer to install a package, have a look at the configuration, alter the configuration, and then start the daemon. Also, it had better not start after a reboot unless I explicitly ask it to do so.
There are plenty of examples where automatically starting a daemon with its default configuration is a bad idea. Take the postfix package as an example. If you install the package in non-interactive mode (as Ansible does by default), postfix will come online wth the following configuration option set:
|
1 |
inet_interfaces = all |
Since Ubuntu doesn’t come with a firewall enabled by default, your postfix server is listening on all interfaces for mail immediately. The mynetworks configuration should prevent relaying, but any potential vulnerabilities in your postfix daemon are exposed to the network without your consent. I would prefer to configure postfix first before I ever allow it to run on my server.
Verifying packages
Say what you will about RPM packages and the rpm command, but the verification portions of the rpm command are quite helpful. Here’s an example of verifying the aide RPM in Fedora:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# rpm -Vv aide ......... c /etc/aide.conf ......... c /etc/logrotate.d/aide ......... /usr/sbin/aide ......... /usr/share/doc/aide ......... d /usr/share/doc/aide/AUTHORS ......... d /usr/share/doc/aide/COPYING ......... d /usr/share/doc/aide/ChangeLog ......... d /usr/share/doc/aide/NEWS ......... d /usr/share/doc/aide/README ......... d /usr/share/doc/aide/README.quickstart ......... /usr/share/doc/aide/contrib ......... d /usr/share/doc/aide/contrib/aide-attributes.sh ......... d /usr/share/doc/aide/contrib/bzip2.sh ......... d /usr/share/doc/aide/contrib/gpg2_check.sh ......... d /usr/share/doc/aide/contrib/gpg2_update.sh ......... d /usr/share/doc/aide/contrib/gpg_check.sh ......... d /usr/share/doc/aide/contrib/gpg_update.sh ......... d /usr/share/doc/aide/contrib/sshaide.sh ......... d /usr/share/doc/aide/manual.html ......... d /usr/share/man/man1/aide.1.gz ......... d /usr/share/man/man5/aide.conf.5.gz ......... /var/lib/aide ......... /var/log/aide |
If the verification finds that nothing in the package has changed, it won’t print anything. I’ve added the -v here to ensure that everything is printed to the console. In the output, you can see that everything is checked. That includes configuration files, log directories, libraries, and documentation. If I change the content of the aide.conf by adding a comment, I see that change:
|
1 2 3 |
# echo "# Comment" >> /etc/aide.conf # rpm -V aide S.5....T. c /etc/aide.conf |
The 5 denotes that the MD5 checksum on the file has changed since the package was installed. What happens if I change the owner, group, and mode of the aide.conf?
|
1 2 3 |
# chown major:major /etc/aide.conf # rpm -V aide S.5..UGT. c /etc/aide.conf |
Now I have a UG there that denotes a user/group ownership change. Similar messages appear for changes to the permissions on files or directories. The restorecon command even lets you figure out when SELinux contexts have changed. If you set a file to have the wrong ownership or permission, one rpm command gets you back to normal:
|
1 |
# rpm --setperms --setugids aide |
On the Ubuntu side, you can use the debsums package to help with some verification:
|
1 2 3 4 5 6 7 8 9 10 |
# debsums aide /usr/bin/aide OK /usr/share/doc/aide/NEWS.Debian.gz OK /usr/share/doc/aide/changelog.Debian.gz OK ... # debums aide-common /usr/bin/aide-attributes OK /usr/bin/aide.wrapper OK /usr/sbin/aideinit OK ... |
But wait — where are the configuration files? Where are the log and library directories? If you type these commands on an Ubuntu system, you’ll see that the configuration files and directories aren’t checked. In addition, there’s not a method for querying whether a particular file in a package has changed ownership or has had its mode changed. There’s also no option to restore the right permissions and ownership after an errant chown -R or chmod -R.
Managing AIDE
The AIDE package is critical for secure deployments since it helps administrators monitor for file integrity on a regular basis. However, Ubuntu ships with some interesting configuration files and wrappers for AIDE.
One of the unique configuration files is this one:
|
1 2 |
# cat /etc/aide/aide.conf.d/99_aide_root / Full |
This causes AIDE to wander all over the system, indexing all types of files. It’s best to limit AIDE to a small number of directories whenever possible so that the AIDE runs complete quickly and the database file remains relatively small. Plenty of disk I/O can be used during AIDE runs, so it’s best to limit the scope.
Also, trying to initialize the database provides an unhelpful error:
|
1 2 |
# aide --init Couldn't open file /var/lib/aide/please-dont-call-aide-without-parameters/aide.db.new for writing |
That path doesn’t exist, and I’m confused because I did pass a parameter to aide. Long story short, you must use the aideinit command to initialize the aide database. That’s actually a bash script which then calls on aide.wrapper (another bash script) to actually run the aide binary for you. Better yet, aideinit is in /usr/sbin while aide.wrapper is in /usr/bin. This leads to plenty of confusion.
Linux Security Modules
It’s possible to run SELinux on Ubuntu, but the policies aren’t as well maintained as they are on other distributions. AppArmor is the recommended LSM on Ubuntu, but it doesn’t provide the granularity of SELinux. For example, SELinux confines almost every single process on a minimal Fedora system, but AppArmor confines almost nothing on a minimal Ubuntu-based system. AppArmor policies aren’t terribly restrictive and it’s possible to work around them due to their reliance on path names.
Fortunately, both LSM’s provide decent coverage with virtual machines and containers (using libvirt’s sVirt capability).
Summary
The upside is that there is plenty of room for security improvements, especially around usability, in Ubuntu. Ubuntu-centric hardening standards are difficult to find and challenging to apply. Every distribution has its quirks and differences, but it seems like securing Ubuntu comes with more unusual hoops to jump through relative to Red Hat-based distributions, OpenSUSE, and even Arch.
I plan to open some bugs for some of these smaller issues in the coming days. However, some of the larger philosophical issues (like automatically starting daemons) will be tougher to tackle.

On the AIDE on Debian/Ubuntu front, that particular set of defaults frustrates me too — they’ve basically chosen to (a) configure stupid defaults into the aide binary, and then (b) provide aide.wrapper which runs aide with appropriate command line flags to “work sensibly”. Effectively this means that you always need to run “aide.wrapper” rather than the “aide” command directly, for basically all aide interactions.
It’s been like this for years (IIRC around 10 years; ISTR reporting it at the time to the maintainer, but I can’t quickly find the bug report/email now). There’s “sort of” a rationalisation for it (the Debian config is an auto-generated concatenation of bits), but it could have been handled so much better — including just making “aide” be the wrapper script, and calling the underlying binary something users wouldn’t try to run standalone…
Ewen
Right time Major!. I am building an infra for a small firm and unfortunately it is on Ubuntu. So, you can imagine how much hard time am having. Moreover my negligence and dislike about Ubuntu over long time, make it more problematic. Trying to finding out best possible method to get around it. Thanks a bunch for the heads up man!.
> The standard Ubuntu and Debian practice of automatically starting daemons has perplexed me before and it still continues to do so.
I agree! It drives me batty when I’m trying to write configuration management code (e.g. Chef cookbooks) and I have to account for some distros starting the daemon, like Ubuntu, when others don’t.
Hey, that was an excellent job. I don’t know why they close their eyes so much to obvious points in the security. But I completely agree the lack of default secure settings is a little bit more than stupid.
If you these commands on an Ubuntu system ?
Typo?
You can decide if a daemon should start on install by adding /usr/sbin/policy-rc.d file. It is described in /usr/share/doc/sysv-rc/README.policy-rc.d. Notably, just putting “exit 101” should give you something similar to what you expect on Redhat.
You can get the original MD5 sums of the configuration files with dpkg –status. You could also just install tripwire that would cover all files.
Please be aware that it could break something in your system. for example log rotation scripts and cron jobs are relying on that policy so you script should be smarter that just alway return 101. You probably should allow ‘reload’ and ‘rotate’ actions
Grep your /etc folder for
invoke-rc.dbefore make any changes.Since dpkg v1.17.2 you can run ‘dpkg -V’ to verify integrity of packages, including config files.
Let’s hope that more packages adopt the practice of using /etc/default/ to control enabling/disabling the service.
I hope that more packages adopt the practice of using /etc/default/ to control enabling/disabling the service.
Hello major.io. Thanks for the great post.
Can you provide an update as to how far you have been able to progress in applying security hardening to Ubuntu 14.04 systems?
Thanks
I’m interested in your progress as well. I have some experience locking down RedHat/CentOS using DISA STIGs but Ubuntu is a whole new animal.
DISA STIGs for Ubuntu 14.04 were released on 9/18/17.