Project Writeup · CIS Hardening Scripts

Automating CIS Benchmarks on Ubuntu 24.04 with Bash

I was tasked by my internship to create an automated script to run on Linux systems in order to make sure devices were compliant with the Center for Information Security Benchmarks, which was a project that I was very proud of. It taught me about scripting in Bash, and scripting as a whole. I found scripting to be very different from programming an application; it was much more straightforward, and I very much enjoyed it. I also found out how modular scripts can be and I can now properly diagnose scripts if given to me.

The Problem

The CIS Ubuntu 24.04 Level 1 Server benchmark contains hundreds of individual controls spanning filesystem configuration, kernel modules, service hardening, SSH, PAM, auditd, and logging. Applying them by hand is slow and error-prone, and re-auditing a system after every change is tedious enough that it rarely happens consistently — which defeats the purpose of a benchmark in the first place.

What I Built

I wrote harden.sh, a modular Bash tool organized around the benchmark's own numbering scheme — filesystem (1.1.x), services (2.x), network (3.x), host firewall (4.x), access control (5.x), and logging/auditing (6.x). Each control group is its own module, which means the script can run everything with --all, or a specific subset with --include / --exclude:

./harden.sh --include kernel_modules
./harden.sh --exclude gdm
./harden.sh --all

That flag design mattered more than I expected going in. A benchmark script that forces an all-or-nothing run is nearly unusable on a live system — you inevitably need to skip a control (like disabling a kernel module a workstation still needs) without losing the rest of the hardening pass.

Next Steps

Next up, I am writing a recreation of this script for RHEL systems. I will not be doing a straight "port", rather I want to rewrite this using my new knowledge of scripting to make it as best as I can. So far in the RHEL10 edition, I have been utilizing newt/whiptail to give a TUI interface. If that goes successful, I could port this Ubuntu script, or write a new version based on changes in 26.04 or whatever version is released at the time that I begin writing the script. You can keep tabs on my progress with the RHEL10 version at https://github.com/willr-9/cisrhel10.

← Back to Blog