Ansible playbook to harden your Linux system.
- Debian (Trixie)
- π Kali
- Ο Raspberry Pi OS
- Slackware (>= 15.0)
- Bastille is obsolete
- Not a member of CIS, so no downloading of the ready made scripts
- Also to go "beyond CIS" with things like:
- Reducing CA certs
- Hardening PAM
- Making smart audit rules that don't spam your logs with unnecessary and useless information
- Properly locking down system accounts
- Other stuff that is not covered by CIS benchmarks
- Also to go "beyond CIS" with things like:
- For learning
- For minimizing the effort needed to tweak fresh installations
- Also for consistency
For a complete list you can run ansible-playbook --list-tasks harden.yml.
- Enables TCP wrappers
- π‘ Some people consider TCP wrappers as obsolete and unnecessary, because nowadays firewall(s) take care of this kind of network level access. I disagree, because TCP wrappers still provide an additional layer of control in a case where the firewall(s) might fail for any number of reasons (usually misconfiguration). TCP wrappers also work as an network level ACL for the programs that utilize it and is a "native" control for those programs.
- IP stack hardening via sysctl settings
- For the complete list, see network.conf.new
- Creates a basic firewall
- Configures NetworkManager as follows:
- For each existing connection:
- Disables IPv6 (
ipv6.method->disabled)
- Disables IPv6 (
- Configures few defaults to
/etc/NetworkManager/conf.d/:- Sets
dhcp-send-hostnametofalse - Sets
wifi.scan-rand-mac-addresstotrue
- Sets
- For each existing connection:
- π Configure log retention time to be 6 months
- Configures
logrotatetoshredfiles- βΉοΈ NOTE: Read the fine print in SHRED(1): "CAUTION: shred assumes the file system and hardware overwrite data in place. Although this is common, many platforms operate otherwise."
- Configure
journaldto use Forward Secure Sealing (FSS) and enable auditing (see notes on how to create keys for FSS) - Enables auditing
- Run
ansible-playbook --list-tasks --tags logging harden.ymlfor a full list
- Enables system accounting (sysstat)
- π Sets it's log retention to 99999 days (the logs are really small, so it doesn't eat up disk space)
- Enables process accounting
- Run
ansible-playbook --list-tasks --tags accounting harden.ymlfor a full list
- β Disables the use of certain kernel modules via
modprobe(see files/modprobe.d/)- Disable Firewire
β οΈ WARNING: Also disablesusb-storage, which will disable support for USB mass medias
- sysctl settings hardening
- β¨οΈ Enables Secure Attention Key (SAK) and disables the other magic SysRq stuff
- β Restricts the use of
dmesgby regular users - β Enable YAMA (disallow
ptrace) - For the complete list, see sysctl.conf.new
- Run
ansible-playbook --list-tasks --tags kernel harden.ymlfor a full list
- Hardens mount options (creates
/etc/fstab.new) (see fstab.awk) - π Sets strict permissions to users home directories
- β Limits permissions to various configuration files and directories that might contain sensitive content (see
permissionstag for a complete list) - π― Clean up
/tmpduring boot (see tmp.conf.new) - Removes SUID and/or SGID bits from various binaries (see
ansible-playbook --list-tasks --tags suid,sgid harden.ymlfor details)
- Configures basic auditing based on stig.rules if audit is installed (see audit.yml)
- π‘ Configures
sshd_configandssh_config(seeansible-playbook --list-tasks --tags ssh harden.ymlfor details)- Removes 2048-bit moduli from
/etc/ssh/moduli - βΉοΈ Removes SUID bit from
ssh-keysign, so host-based authentication will stop working. Host-based authentication shouldn't be used anyway. - βΉοΈ Password authentication is not disabled so you wouldn't lock yourself out of your system accidentally
- See ssh_config.j2 and sshd_config.j2
- Removes 2048-bit moduli from
- π₯ͺ Configures sudo (see sudoers.j2)
β οΈ WARNING: If there are rules in/etc/sudoers.d/that match ourbecome: truetasks that do not have explicitEXEC, it can "break"sudoas we defineDefaults noexecin the mainsudoersfile. There is a "Fix generic rules" task insudoers.ymlwhich tries to tackle this problem, but it's not guaranteed to work.β οΈ WARNING: Sudo binary/usr/bin/sudoischmodded so, that onlysudo_group(seevars.yml) can run it- πͺ΅ You can set the
sudo_iologinvars.ymltotrueto enable I/O logging - You can set the
sudo_idsinvars.ymltotrueto enable "Intrusion Detection" as described in Sudo Mastery chapter 9 (#59) - See also notes
- π ClamAV configuration (see clamav.yml)
- Configures
clamd&freshclamby first generating fresh configurations with clamconf - Configured ClamAV to unarchive with password "infected" (see Passwords for archive files & ClamAV and ZIP File Decryption)
- Downloads YARA rules from Neo23x0, GCTI, Elastic, YaraRules Project, JPCERT/CC, Malpedia, Citizen Lab, GoDaddy, Didier Stevens & Open-Source-YARA-rules for ClamAV to use
β οΈ WARNING: ClamAV consumes a lot of memory, so it might not be suitable for all systems. See Recommended System Requirements.- βΉοΈ
harden.ymlskips the ClamAV installation completely if there's less than 3 GiB of memory available
- Configures
- rkhunter configuration (see rkhunter.yml)
- π― Tiger: Configures
tigerrc&tiger.ignore - Lynis configuration (see lynis.yml)
- Configures AIDE (see aide.yml)
- Display managers:
- Disables user lists in GDM3 & LightDM
- β Disables guest sessions and VNC in LightDM
- πͺΆ Minor Apache HTTP server hardening
- Minor PHP (
php.ini) hardening
- Sets default umask to a more stricter
077(see https://github.com/pyllyukko/harden.yml/wiki/umask) - β²οΈ Sets console session timeout via
$TMOUT(Bash) - ποΈ Properly locks down system accounts (0 -
SYS_UID_MAX&& !root)- β Lock the user's password
- π Sets shell to
/sbin/nologin - Set
maxloginsto0inlimits.conf(enforced bypam_limits)- βΉοΈ You can see it in the logs as:
pam_open_session: Permission denied
- βΉοΈ You can see it in the logs as:
- Expire the account
- β Set
RLIMIT_NPROCandRLIMIT_NOFILEto0in pam_limits for those system accounts that don't need to run any processes- βΉοΈ You can see this in action in the PAM limits test
- βΉοΈ See
unnecessary_system_accountsinvars.ymlfor the list of accounts - βΉοΈ
RLIMIT_NOFILEwill causepam_open_session: Too many open fileserrors andRLIMIT_NPROCwill causefork: Resource temporarily unavailableerrors
- π₯ Makes minor modifications to existing accounts. See
ansible-playbook --list-tasks --tags accounts harden.ymlfor details.
-
ποΈ Configures the default password inactivity period
-
Configures the password aging values to
/etc/login.defsPASS_MAX_DAYSPASS_MIN_DAYSPASS_WARN_AGE
-
These settings are also applied to existing user accounts
-
Two password quality backends are supported. The playbook auto-detects which is installed and prefers passwdqc over
libpwquality(see passwdqc.conf.j2 and pwquality.conf.j2) -
Creates a CrackLib dictionary to be used with libpwquality (see
ansible-playbook --list-tasks --tags cracklib harden.ymland the CrackLib related handlers in handlers.yml)- The small dictionary (derived from
cracklib-small) that usually comes bundled with CrackLib packages contains 51526 words and the one we generate (from cracklib-words) contains 1911477 words
- The small dictionary (derived from
-
Creates a
passwdqccuckoo filter file based on RockYou -
Downloads John the Ripper's password.lst to be used with
passwdqc'swordlistoption -
Configures
/etc/security/pwhistory.conf- βΉοΈ
pam_pwhistoryneeds to be manually enabled withpam-auth-updatein Debian
- βΉοΈ
-
Run
ansible-playbook --list-tasks --tags passwords harden.ymlto list all password related tasks
You can set the password_policy variable to nist_sp800_63 in vars.yml for NIST Special Publication (SP) 800-63-4 style password policy.
β οΈ This is an experimental feature and π§ under construction π§- See New password policies according to NIST SP 800-63 #88
- βΉοΈ If you opt to use this, it is highly recommended to use
passwdqcinstead oflibpwquality, aspasswdqc'swordlist&filterfeatures are superior compared tolibpwquality's use of CrackLib
The main differences are:
| Property | Traditional | SP 800-63 |
|---|---|---|
| Password maximum age (days) | 365 | 99999 |
| Password minimum length | 14 | 15 |
| Composition/complexity requirements | β | β |
- Create a strict
securetty - Creates
/etc/ftpusers - Restricts the use of cron and
at - Disallow non-admin users from authenticating as other users in polkit
- Run
ansible-playbook --list-tasks --tags authorizationfor a full list
- Configures
/etc/security/namespace.conf - ποΈ Configures
/etc/security/access.confforpam_access(authorization) (see access.conf.j2) - Configures password quality β
/etc/security/pwquality.confor/etc/passwdqc.confβ depending on which is installed (see Password policy section) - π Require pam_wheel in
/etc/pam.d/su - β Creates a secure /etc/pam.d/other
- See also A strong /etc/pam.d/other
- π‘ Fun fact: As Debian 13 doesn't seem to ship
/etc/pam.d/systemd-run0, this will also block the use of run0
- Configures
/etc/security/limits.confas follows:- Disable core dumps
- Sets maximum amount of processes (or threads, see setrlimit(2))
- β Sets
nprocto 0 for system users that don't need to run any processes
- Run
ansible-playbook --list-tasks --tags pam harden.ymlto list all PAM related tasks - You can also run
ansible-playbook --check --diff --tags pam harden.ymlto see details of the changes
- πͺ§ Creates legal banners (see banners.yml)
- Reduce the amount of trusted CAs (see ca-certificates.conf.new)
- π Restricts the number of available shells (
/etc/shells) - π Creates an option to use a restricted shell (rbash)
- Only available for Debian & Slackware and for the
sshdservice because of the required PAM configuration changes (regardingpam_env& enforcingPATH) - βΉοΈ See Restricted shell
β οΈ WARNING: Contains plenty of caveats, details and hazards. Make sure you read and understand (at least) everything in the aforementioned wiki page, test it thoroughly and accept the risk that it may contain escapes.
- Only available for Debian & Slackware and for the
- Disable core dumps via
/etc/systemd/coredump.conf - Kerberos hardening via
/etc/krb5.conf
- Disables unnecessary services
- See
slackware_servicesin vars.yml
- See
- Run
ansible-playbook --list-tasks --tags slackware harden.ymlfor a full list - Make Xorg rootless
- πͺ΅ Makes default log files group
admreadable (as in Debian) - π Restricts the use of
cronso that only users in the wheel group are able to create cronjobs (as described in /usr/doc/dcron-4.5/README) - Mount /proc with
hidepid=2 - πͺ΅ Make
installpkgstore the MD5 checksums - π Enable process accounting (
acct) - π₯ Does some housekeeping regarding group memberships (see login_defs-slackware.yml)
- ποΈ Configures
inittabto useshutdown -a(and/etc/shutdown.allow) - Reconfigured bunch of services (run
ansible-playbook --list-tasks --tags slackware harden.yml | grep '\bservices\b'for a full list) - Configures cgroups (v1, because of too old
libcgroup) into/etc/cg{config,rules}.conf - Enables
bootlogd- βΉοΈ NOTE: Requires
CONFIG_LEGACY_PTYS(which KSPP recommends to disable)
- βΉοΈ NOTE: Requires
- Creates a custom
/etc/pam.d/system-auth, which has the following changes:- β²οΈ Use
pam_faildelay - ποΈ Use
pam_faillock - ποΈ Use
pam_access - β Removes
nullokfrompam_unix - Sets crypt rounds for
pam_unix - Change password
minlenfrom 6 to 14 - Enables
pam_pwhistory - See system-auth.j2
- β²οΈ Use
- The following PAM modules are added to
/etc/pam.d/postlogin:pam_umaskpam_cgrouppam_keyinit
- Add
pam_namespaceto/etc/pam.d/{login,sddm,sshd,xdm} - Removes
auth include postloginfrom several files, aspostloginshould (and has) onlysessionmodule types - π₯ͺ Creates
/etc/pam.d/sudo, as that seemed to be missing - ποΈ Disallows the use of
su(see su.new)- βΉοΈ Filesystem/permissions hardening will also remove the SUID bit from
su, so it won't even be able to switch privileges
- βΉοΈ Filesystem/permissions hardening will also remove the SUID bit from
- β Block
/etc/pam.d/remote(see /etc/pam.d/remote) - Adds
pam_shellsto/etc/pam.d/chsh(require a valid shell in order to change your shell)
- Disables unnecessary systemd services
- See
debian_servicesin vars.yml
- See
- π‘οΈ Enables AppArmor
- Configure
SUITEindebsecan - Install
debsumsand enable weekly cron job - Installs a bunch of security related packages (see debian_packages.yml)
- Configures
chkrootkitand enables daily checks - Configures APT not to install suggested packages
Creates bunch of pam-configs that are toggleable with pam-auth-update:
| PAM module | Type | Description |
|---|---|---|
| π pam_wheel1 | auth | Require wheel group membership (su) |
| ποΈ pam_succeed_if | auth & account | Require UID >= 1000 && UID <= 60000 (or 0 & login) |
| β pam_unix1 | auth | Remove nullok |
| β²οΈ pam_faildelay | auth | Delay on authentication failure |
| pam_ssh_agent_auth | auth | SSH agent authentication for sudo3 |
ποΈ pam_faillock |
auth & account | Deter brute-force attacks |
| ποΈ pam_access | account | Use login ACL (/etc/security/access.conf) |
| ποΈ pam_time | account | /etc/security/time.conf |
| ποΈ pam_lastlog | account | Lock out inactive users (no login in 90 days) |
| pam_namespace | session | Polyinstantiated temp directories |
| pam_lastlog | session | Display info about last login and update the lastlog and wtmp files2 |
| pam_pwhistory | password | Limit password reuse |
- Not a
pam-config, but a modification to existing/etc/pam.d/files - For all login methods and not just the console login
- Disabled by default and requires libpam-ssh-agent-auth package. Needs to have higher priority than
krb5or other password auths.sshdneeds to haveAllowAgentForwarding yes- You need to configure
sudowithDefaults env_keep += "SSH_AUTH_SOCK"
At least the following hardening areas are currently not covered at all:
- Bootloader password enforcement
- Secure Boot / UEFI Hardening
- Network:
- DNS
- DNSSEC
- Defence against ARP cache poisoning
- DNS
- X11/Wayland hardening
- Automatic security updates (beyond installing
unattended-upgradesin Debian) - Wireless interfaces like WiFi and Bluetooth
- Authentication:
- Biometric authentication
- MFA
- Remote logging
- Compiler restrictions (e.g. removing/blocking development tools like
gcc,makeetc.)
- Edit the
harden.ymland modifyhostsor create a completely new playbook by making a copy of theharden.ymlfile- You can comment out the "task sets" that you don't need
- Check
vars.ymlin case you want to tweak some of the settings - You can check all the tasks before running the playbook by running
ansible-playbook --list-tasks harden.yml - Harden your system by running
ansible-playbook harden.yml
- π₯ Make sure regular users that should be able to login are members of the
allowed_groupgroup - π₯ͺ Sudo hardening:
noexecis on by default, so you need to take this into account in your custom rules- β²οΈ Interactive shells to
roothave timeout, so usescreenfor those longer administrative tasks
- π Rebooting the system after running this is highly recommended
- The AIDE DB creation is made asynchronously and without polling, so let that finish before rebooting
- π‘ You might want to get additional (unofficial) rules for ClamAV with clamav-unofficial-sigs (although see #425). At least the following rulesets are freely available:
- Sanesecurity
- Porcupine ("The following databases are distributed by Sanesecurity, but produced by Porcupine Signatures")
- bofhland ("The following databases are distributed by Sanesecurity, but produced by bofhland")
- Foxhole
- Linux Malware Detect
- InterServer
- URLhaus
- Sanesecurity
β οΈ WARNING: There is a hazard with immutableloginuidenabled in auditing in non-systemd systems (Slackware). See longer description of this in the wiki.- π Review
/etc/fstab.newmanually and deploy applicable changes to/etc/fstab - π‘ Consider running a hardened kernel. For Slackware you can check out my other project kspp_confnbuild that has been (mostly) configured according to KSPP's recommendations. You can use kernel-hardening-checker to check your kernel configs.
- βοΈ Make sure your system is able to send e-mails somehow. Many of the tools will be sending alerts about various anomalies.
- Customize the firewall to suit your needs
- π You can use Nftables geoip script to block certain parts of the world (see also GeoIP matching)
- πͺ΅ Logging:
- π Consider installing and configuring Logwatch
- π Run
journalctl --setup-keysto generate a new key pair for Forward Secure Sealing (FSS) - Configure remote logging
- Consider purchasing Openwall passwdqc filter files to check for leaked credentials during password change (see "passwdqc filter" tasks in
pam.yml) - Variable
sudo_groupis also considered as administrator group (see tagpolkit) - Consider setting
PasswordAuthenticationtonoin/etc/ssh/sshd_config - Consider running arpwatch to detect ARP cache poisoning
passwdqc>libpwquality
Tags that you can use with ansible-playbook --tags:
pkikernelrngnetworkfirewallipv6networkmanager
- πͺ΅
logging - π Filesystem related:
- β
permissions fstabsuid&sgid
- β
- Specific software:
- π
sysstat - π‘
ssh rkhunterchkrootkitaideaudit(use--skip-tags auditin Slackware if you don't have audit installed)debsecandebsumslynis(to only configure Lynis you can use--tags lynis --skip-tags packages)- π₯ͺ
sudo kerberos- π
clamav(use--skip-tags clamavin Slackware if you don't have clamav installed)yara
- π‘οΈ
apparmor cron(also includes tasks regardingat)php- πͺΆ
apachehsts
- π
ntp lightdmgnome- π―
tiger john- π
unattended-upgrades
- π
- πͺ§
banners - AAA:
- π
accounting(includessysstat) - ποΈ
authorization passwordscracklib
- π₯
accounts pamlimits
- π
cgroup(Slackware)hidepid(Slackware)inittab(Slackware)- π
shells umask- β²οΈ
timeout polkitsystemd(experimental, enable withharden_systemd_services)
There are also operating system tags for tasks that only apply to specific OS.
You can speed up the hardening by skipping OSs that don't apply. E.g. if you're
hardening a Slackware system you can use --skip-tags debian.
Other tags are just metadata for now. You can list all the tags with
ansible-playbook --list-tags harden.yml.
- β There is a
lock_account.ymlplaybook that you can use to lock user accounts. Just modify thehosts&user. - Limited hardening for FreeBSD (see freebsd.yml)
- π₯ͺ Experimental feature: If you enable
sudo_idsinvars.yml, it enables "Sudo Intrusion Detection" as seen in chapter 9 of Sudo Mastery- Only for
SHELLSCmnd_Aliasfor now
- Only for
- Experimental and limited systemd service hardening (see services-systemd.yml)
- Needs to be enabled with
harden_systemd_services
- Needs to be enabled with
| Target | Description |
|---|---|
pamcheck |
Check (and diff) your Slackware's PAM configs |
π‘ /etc/ssh/moduli.new |
Create a new SSH moduli |
/etc/audit/rules.d/31-privileged.rules.new |
Find privileged binaries to be audited |
/etc/audit/rules.d/40-authorized_keys.rules.new |
Find SSH authorized_keys from /home/ to be audited |
crls |
Download CRLs |
/etc/ssl/certs/ca-certificates.crt |
Create limited/reduced CA list |
A recent version of Ansible is recommended to run harden.yml. If you want to do this with virtualenv, you can install it as follows:
virtualenv venv. venv/bin/activatepip install ansible jmespath
See tests README
Some of these documents are quite old, but most of the stuff still applies.
- Slackware System Hardening by Jeffrey Denton
- Center for Internet Security:
- CIS Slackware Linux 10.2 Benchmark v1.1.0
- CIS Debian Linux Benchmark
- CIS Distribution Independent Linux
- CIS MIT Kerberos 1.10 Benchmark v1.0.0
- CIS Password Policy Guide
- SlackDocs: Security HOWTOs
- π½ Alien's Wiki: Security issues
- SlackWiki: Basic Security Fixes
- π£ Wikipedia: Fork bomb Prevention
- Configuration recommendations of a gnu/linux system (ANSSI-BP-028)
- How to harden a systemd service unit
- Linux Standard Base Core Specification 4.1
- π Filesystem Hierarchy Standard 2.3
- https://iase.disa.mil/stigs/os/unix-linux/Pages/index.aspx
- π PAM Mastery book by Michael W Lucas
- The Linux-PAM System Administrators' Guide
- π Sudo Mastery, 2nd Edition
- π Linux Firewalls
- π‘ Secure Secure Shell
- Securing Debian Manual
- π‘οΈ AppArmor HowToUse
- ArchWiki: limits.conf
- Effectiveness of Linux Rootkit Detection Tools
- How to keep a detailed audit trail of whatβs being done on your Linux systems
- Announcing systemd v257:
- The GNU C Library (glibc): Limiting Resource Usage
- Protect your VPN from TunnelVision attacks