Skip to content

The Bootloader

GRUB is the menu that loads Linux. Anyone at the console can edit a boot entry, add init=/bin/bash, and get a root shell with no password. A GRUB password stops that (CIS 1.4.1; STIG UBTU-22-212010, CAT I), and a kernel option turns auditing on from the first process.

Set a GRUB password

Generate a hash, then put the superuser and hash into /etc/grub.d/40_custom (or 00_header; both are read into the generated config):

grub-mkpasswd-pbkdf2

Type a password twice; it prints a line starting grub.pbkdf2.sha512.10000.…. Then:

sudo tee -a /etc/grub.d/40_custom > /dev/null <<'EOF'
set superusers="admin"
password_pbkdf2 admin grub.pbkdf2.sha512.10000.PASTE_THE_HASH_HERE
EOF
sudo update-grub

update-grub writes /boot/grub/grub.cfg; the password only exists once that's run. The superuser name is a GRUB-only name, not a Linux account; the README may specify it.

Without more, every boot now asks for the GRUB password, which is fine on a server and annoying on a desktop. To require it only for editing entries, add --unrestricted to the normal menu entry: in /etc/grub.d/10_linux, change CLASS="--class gnu-linux --class gnu --class os" to end with --unrestricted, then update-grub again.

Kernel options: auditing and AppArmor

The kernel command line in /etc/default/grub carries three options the benchmark wants. audit=1 (CIS 6.2.1.3) makes the kernel queue audit events before auditd starts, so nothing in early boot is missed, and audit_backlog_limit=8192 (6.2.1.4) gives that queue room (auditd). apparmor=1 security=apparmor (1.3.1.2) makes sure AppArmor is the active security module (AppArmor).

sudo sed -i 's/^GRUB_CMDLINE_LINUX="\(.*\)"/GRUB_CMDLINE_LINUX="\1 audit=1 audit_backlog_limit=8192 apparmor=1 security=apparmor"/' /etc/default/grub
grep ^GRUB_CMDLINE_LINUX= /etc/default/grub
sudo update-grub

If some of those were already there, remove the duplicates from the line before running update-grub.

Protect the config file

sudo chmod 600 /boot/grub/grub.cfg
sudo chown root:root /boot/grub/grub.cfg

A world-readable grub.cfg shows the password hash to everyone (CIS 1.4.2; the password itself is 1.4.1).

Verify

sudo grep -E 'superusers|password_pbkdf2' /boot/grub/grub.cfg
sudo grep -E 'audit=1' /boot/grub/grub.cfg | head -1
grep -E 'audit=1|apparmor=1' /proc/cmdline    # after a reboot
stat -c '%a %U' /boot/grub/grub.cfg

Example

grep password /boot/grub/grub.cfg prints nothing: anyone at the console can boot to a root shell. Generate a hash, add the two lines to 40_custom, add audit=1 to GRUB_CMDLINE_LINUX, update-grub, chmod 600 grub.cfg. Reboot once to confirm the menu asks for the password and /proc/cmdline shows audit=1.

Try it

  1. Set a GRUB password, reboot, press e at the menu, and see the prompt.
  2. Add audit=1 and confirm in /proc/cmdline after the reboot.

Build it

A grubcheck.sh that greps grub.cfg for password_pbkdf2, reads /proc/cmdline for audit=1 and apparmor=1, and prints the permissions of grub.cfg.

Next

Screen Lock and Login Screen