SkillAgentSearch skills...

Hardening

Hardening Ubuntu. Systemd edition.

Install / Use

/learn @konstruktoid/Hardening

README

image::logo/horizontal.png[Ubuntu Hardening] = Hardening Ubuntu. Systemd edition.

:icons: font

A quick way to make a Ubuntu server a bit more secure.

NOTE: Read the code and do not run this script without first testing in a non-operational environment. The code is not idempotent, use the https://github.com/konstruktoid/ansible-role-hardening[Ansible role] in instead.

Use the newly installed and configured system as a reference, or golden, image. Use that image as a baseline installation media and ensure that any future installation comply with benchmarks and policies using a configuration management tool, e.g https://www.ansible.com/[Ansible] or https://puppet.com/[Puppet].

Tested on Ubuntu 22.04 (Jammy Jellyfish) and Ubuntu 24.04 (Noble Numbat).

If you're interested in testing your host settings, you'll find the link:README.adoc#tests[instructions here].

NOTE: There is a https://slsa.dev/[SLSA] artifact present under the https://github.com/konstruktoid/hardening/actions/workflows/slsa.yml[slsa workflow] for file checksum verification.

== Ansible playbook

An Ansible playbook is available in the https://github.com/konstruktoid/ansible-role-hardening[konstruktoid/ansible-role-hardening] repository.

== Howto

. Start the server installation. . Pick language and keyboard layout. . Select "Ubuntu Server (minimized)". . Configure network connections. . Partition the system, see below for recommendations. . Do not install the OpenSSH server, "Featured Server Snaps", or any other packages. . Finish the installation and reboot. . Log in. . If wanted, set a Grub2 password with grub-mkpasswd-pbkdf2. See https://help.ubuntu.com/community/Grub2/Passwords[https://help.ubuntu.com/community/Grub2/Passwords] for more information. . Install necessary packages: sudo apt-get -y install git net-tools procps --no-install-recommends. . Download the script: git clone https://github.com/konstruktoid/hardening.git. . Change the configuration options in the ubuntu.cfg file. Make sure to update the CHANGEME variable otherwise the script will fail. . Run the script: sudo bash ubuntu.sh. . Reboot.

=== Recommended partitions and options

[source,shell]

/boot (rw) /home (rw,nosuid,nodev) /var/log (rw,nosuid,nodev,noexec) /var/log/audit (rw,nosuid,nodev,noexec) /var/tmp (rw,nosuid,nodev,noexec)

Note that /tmp will be added automatically by the script.

== Configuration options

[source,shell]

FW_ADMIN='127.0.0.1' // <1> SSH_GRPS='sudo' // <2> SSH_PORT='22' // <3> SYSCTL_CONF='./misc/sysctl.conf' // <4> AUDITD_MODE='1' // <5> AUDITD_RULES='./misc/audit-base.rules ./misc/audit-aggressive.rules ./misc/audit-docker.rules' // <6> LOGROTATE_CONF='./misc/logrotate.conf' // <7> NTPSERVERPOOL='0.ubuntu.pool.ntp.org 1.ubuntu.pool.ntp.org 2.ubuntu.pool.ntp.org 3.ubuntu.pool.ntp.org pool.ntp.org' // <8> TIMEDATECTL='' // <9> VERBOSE='N' // <10> AUTOFILL='N' // <11> ADMINEMAIL="root@localhost" // <12> KEEP_SNAPD='Y' // <13> CHANGEME='' // <14>

Configuration files // <15>

ADDUSER='/etc/adduser.conf' AUDITDCONF='/etc/audit/auditd.conf' AUDITRULES='/etc/audit/rules.d/hardening.rules' COMMONPASSWD='/etc/pam.d/common-password' COMMONACCOUNT='/etc/pam.d/common-account' COMMONAUTH='/etc/pam.d/common-auth' COREDUMPCONF='/etc/systemd/coredump.conf' DEFAULTGRUB='/etc/default/grub.d' DISABLEFS='/etc/modprobe.d/disablefs.conf' DISABLEMOD='/etc/modprobe.d/disablemod.conf' DISABLENET='/etc/modprobe.d/disablenet.conf' FAILLOCKCONF='/etc/security/faillock.conf' JOURNALDCONF='/etc/systemd/journald.conf' LIMITSCONF='/etc/security/limits.conf' LOGINDCONF='/etc/systemd/logind.conf' LOGINDEFS='/etc/login.defs' LOGROTATE='/etc/logrotate.conf' PAMLOGIN='/etc/pam.d/login' PSADCONF='/etc/psad/psad.conf' PSADDL='/etc/psad/auto_dl' RESOLVEDCONF='/etc/systemd/resolved.conf' RKHUNTERCONF='/etc/default/rkhunter' RSYSLOGCONF='/etc/rsyslog.conf' SECURITYACCESS='/etc/security/access.conf' SSHFILE='/etc/ssh/ssh_config' SSHDFILE='/etc/ssh/sshd_config' SYSCTL='/etc/sysctl.conf' SYSTEMCONF='/etc/systemd/system.conf' TIMESYNCD='/etc/systemd/timesyncd.conf' UFWDEFAULT='/etc/default/ufw' USERADD='/etc/default/useradd' USERCONF='/etc/systemd/user.conf'


<1> The IP addresses that will be able to connect with SSH, separated by spaces. <2> Which group the users have to be member of in order to acess via SSH, separated by spaces. <3> Configure SSH port. <4> Stricter sysctl settings. <5> Auditd failure mode. 0=silent 1=printk 2=panic. <6> Auditd rules. <7> Logrotate settings. <8> NTP server pool. <9> Add a specific time zone or use the system default by leaving it empty. <10> If you want all the details or not. <11> Let the script guess the FW_ADMIN and SSH_GRPS settings. <12> Add a valid email address, so PSAD can send notifications. <13> If 'Y' then the snapd package will be held to prevent removal. <14> Add something just to verify that you actually glanced the code. <15> Default configuration file locations.

== Functions

=== Function list in execution order

Note that all functions has the f_ prefix in the code.

==== pre

Sets apt flags and performs basic permission check.

The pre function is located in link:scripts/pre[./scripts/pre].

==== kernel

Sets https://github.com/jeffmurphy/NetPass/blob/master/doc/netfilter_conntrack_perf.txt#L175[/sys/module/nf_conntrack/parameters/hashsize] to 1048576 if hashsize exists and is writable.

Sets https://man7.org/linux/man-pages/man7/kernel_lockdown.7.html[/sys/kernel/security/lockdown] to confidentiality if lockdown exists and is writable.

The kernel function is located in link:scripts/kernel[./scripts/kernel].

==== firewall

Configures https://help.ubuntu.com/community/UFW[UFW] if installed.

Allows connections from the adresses in $FW_ADMIN to the $SSH_PORT.

Sets logging and IPT_SYSCTL=/etc/sysctl.conf.

The firewall function is located in link:scripts/ufw[./scripts/ufw].

==== disablenet

Disables the dccp, sctp, rds and tipc kernel modules.

The disablenet function is located in link:scripts/disablenet[./scripts/disablenet].

==== disablefs

Disables the cramfs freevxfs jffs2 ksmbd hfs hfsplus udf kernel modules.

The disablefs function is located in link:scripts/disablefs[./scripts/disablefs].

==== disablemod

Disables the bluetooth, bnep, btusb, cpia2, firewire-core, floppy, n_hdlc, net-pf-31, pcspkr, soundcore, thunderbolt, usb-midi, usb-storage, uvcvideo, v4l2_common kernel modules.

Note that disabling the usb-storage module will disable any usage of USB storage devices, if such devices are needed USBGuard should be configured accordingly and usb-storage removed from the disablemod function.

The disablemod function is located in link:scripts/disablemod[./scripts/disablemod].

==== systemdconf

Sets CrashShell=no, DefaultLimitCORE=0, DefaultLimitNOFILE=1024, DefaultLimitNPROC=1024, DumpCore=no in $SYSTEMCONF and $USERCONF.

The systemdconf function is located in link:scripts/systemdconf[./scripts/systemdconf].

==== resolvedconf

Sets DNS=$dnslist, DNSOverTLS=opportunistic, DNSSEC=allow-downgrade, FallbackDNS=1.0.0.1 in $RESOLVEDCONF, where $dnslist is an array with the nameservers present in /etc/resolv.conf.

The resolvedconf function is located in link:scripts/resolvedconf[./scripts/resolvedconf].

==== logindconf

Sets IdleAction=lock, IdleActionSec=15min, KillExcludeUsers=root, KillUserProcesses=1, RemoveIPC=yes in $LOGINDCONF.

The logindconf function is located in link:scripts/logindconf[./scripts/logindconf].

==== journalctl

Copies link:misc/logrotate.conf[./misc/logrotate.conf] to $LOGROTATE.

Sets Compress=yes, ForwardToSyslog=yes, Storage=persistent in $JOURNALDCONF.

Sets $FileCreateMode 0600/ in $RSYSLOGCONF. if RSYSLOGCONF is writable.

The journalctl function is located in link:scripts/journalctl[./scripts/journalctl].

==== timesyncd

Sets NTP=${SERVERARRAY}, FallbackNTP=${FALLBACKARRAY}, RootDistanceMaxSec=1 in $TIMESYNCD where the arrays are up to four time servers with < 50ms latency.

The timesyncd function is located in link:scripts/timesyncd[./scripts/timesyncd].

==== fstab

Configures the /boot and /home partitions with defaults,nosuid,nodev if they are available in /etc/fstab.

Configures the /var/log, /var/log/audit and /var/tmp partitions with defaults,nosuid,nodev,noexec if they are available in /etc/fstab.

Adds /run/shm tmpfs rw,noexec,nosuid,nodev, /dev/shm tmpfs rw,noexec,nosuid,nodev and /proc proc rw,nosuid,nodev,noexec,relatime,hidepid=2 to /etc/fstab if the partition isn't present in /etc/fstab.

Removes any floppy drivers from /etc/fstab.

Copies ./config/tmp.mount[./config/tmp.mount] to /etc/systemd/system/tmp.mount, removes /tmp from /etc/fstab and enables the tmpfs /tmp mount instead.

The /proc hidepid option is described in https://www.kernel.org/doc/html/latest/filesystems/proc.html#mount-options[https://www.kernel.org/doc/html/latest/filesystems/proc.html#mount-options].

The fstab function is located in link:scripts/fstab[./scripts/fstab].

==== prelink

Reverts binaries and libraries to their original content before they were prelinked and uninstalls prelink.

The prelink function is located in link:scripts/prelink[./scripts/prelink].

==== aptget_configure

Sets apt options Acquire::http::AllowRedirect "false";, APT::Get::AllowUnauthenticated "false";, APT::Periodic::AutocleanInterval "7";, APT::Install-Recommends "false";, APT::Get::AutomaticRemove "true";, APT::Install-Suggests "false";, Acquire::AllowDowngradeToInsecureRepositories "false";, Acquire::AllowInsecureRepositories "false";, APT::Sandbox::Seccomp "1";

See https://manpages.ubuntu.com/manpages/jammy/man5/apt.conf.5.html[https://manpages.ubuntu.com/manpages/jammy/man5/apt.conf.5.html].

The aptget_configure func

View on GitHub
GitHub Stars1.7k
CategoryLegal
Updated4h ago
Forks390

Languages

Shell

Security Score

100/100

Audited on Apr 7, 2026

No findings