Linux Administration
Linux Security Best Practices
In this lesson
Linux security best practices go beyond installing a firewall and setting strong passwords. A hardened server reduces its attack surface systematically — minimising exposed services, enforcing kernel-level protections, detecting file tampering, and blocking brute-force attacks automatically. This lesson covers the tools and disciplines that distinguish a secure production server from a default installation.
Security Auditing with Lynis
Lynis is an open-source security auditing tool that scans a running Linux system and scores it against hundreds of security controls — covering filesystem permissions, authentication settings, network configuration, software versions, and more. It produces a hardening index score and a prioritised list of findings.
# Install Lynis
sudo apt install lynis -y # Debian/Ubuntu
sudo dnf install lynis -y # RHEL/Rocky
# Run a full system audit
sudo lynis audit system
# Run silently and save report
sudo lynis audit system --quiet --logfile /var/log/lynis.log
# View the hardening index score (at end of output)
sudo lynis audit system | grep "Hardening index"
# View only warnings and suggestions
sudo grep -E "^\\[WARNING\\]|^\\[SUGGESTION\\]" /var/log/lynis.log================================================================================ Lynis security scan details: Hardening index : 67 [############# ] Tests performed : 248 Plugins enabled : 0 Components: - Firewall [V] - Malware scanner [X] Lynis Modules: - Compliance status [?] - Security audit [V] - Vulnerability scan [V] Files: - Test and debug information : /var/log/lynis.log - Report data : /var/log/lynis-report.dat ================================================================================ [WARNING] Found one or more cronjobs with world-writable files [SUGGESTION] Install libpam-tmpdir to set $TMP and $TMPDIR for PAM sessions [SUGGESTION] Consider restricting access to /proc via hidepid option [SUGGESTION] Enable process accounting (sysstat) [SUGGESTION] Install a file integrity tool (AIDE, Tripwire)
What just happened? Lynis scored the system at 67/100. A fresh default Ubuntu install typically scores 55–65. Each suggestion is a specific, actionable control — not just generic advice. Run Lynis monthly and track the hardening index over time. A score above 80 indicates a well-hardened system.
Kernel Hardening with sysctl
The Linux kernel exposes many security-relevant parameters via sysctl. Hardening these parameters closes common attack vectors — preventing IP spoofing, disabling ICMP redirects, restricting kernel pointer exposure, and controlling how the kernel handles dangerous memory conditions.
| Parameter | What it does |
|---|---|
| net.ipv4.ip_forward = 0 | Disables IP forwarding — prevents server acting as router |
| net.ipv4.conf.all.rp_filter = 1 | Reverse path filtering — blocks IP spoofing attacks |
| net.ipv4.conf.all.accept_redirects = 0 | Reject ICMP redirects — prevents routing table manipulation |
| kernel.randomize_va_space = 2 | Full ASLR — randomises memory layout to defeat exploits |
| kernel.dmesg_restrict = 1 | Restricts dmesg to root only — hides kernel info from attackers |
| kernel.kptr_restrict = 2 | Hides kernel pointer values — defeats KASLR bypass attempts |
# Apply sysctl settings persistently
sudo tee /etc/sysctl.d/99-hardening.conf << 'EOF'
# Network hardening
net.ipv4.ip_forward = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.tcp_syncookies = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Kernel hardening
kernel.randomize_va_space = 2
kernel.dmesg_restrict = 1
kernel.kptr_restrict = 2
kernel.sysrq = 0
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
EOF
# Apply immediately without rebooting
sudo sysctl --system
# Verify a specific setting
sudo sysctl net.ipv4.conf.all.accept_redirectsFile Integrity Monitoring with AIDE
AIDE (Advanced Intrusion Detection Environment) builds a cryptographic database of file checksums, permissions, and metadata. Running AIDE regularly detects any changes to monitored files — catching rootkits, trojaned binaries, and unauthorised configuration changes that other tools miss.
# Install AIDE
sudo apt install aide -y # Debian/Ubuntu
sudo dnf install aide -y # RHEL/Rocky
# Initialise the database (first run — takes 2–5 minutes)
sudo aideinit # Debian/Ubuntu
sudo aide --init # RHEL/Rocky
# On Debian/Ubuntu, move the new DB into place
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
# Run a check against the baseline
sudo aide --check # RHEL/Rocky
sudo aide.wrapper --check # Debian/Ubuntu
# Schedule daily checks via cron
echo "0 3 * * * root /usr/bin/aide.wrapper --check | mail -s 'AIDE report' admin@example.com" \
| sudo tee /etc/cron.d/aide-checkAIDE 0.17.4 found differences between database and filesystem!! Summary: Total number of entries: 46721 Added entries: 0 Removed entries: 0 Changed entries: 3 --------------------------------------------------- Changed entries: --------------------------------------------------- f ... : /etc/passwd f ... : /etc/shadow f ... : /var/log/auth.log --------------------------------------------------- Detailed information about changes: --------------------------------------------------- File: /etc/passwd Mtime : 2025-03-10 08:14:22 | 2025-03-11 09:33:07 Sha256 : abc123... | def456... Start timestamp: 2025-03-11 03:00:01 +0000 (2025-03-11 03:04:33 +0000)
What just happened? AIDE detected three changed files: /etc/passwd and /etc/shadow changed (expected — a new user was added) and /var/log/auth.log changed (expected — logs grow). Any unexpected changes to binaries in /bin, /sbin, or /lib would indicate a serious compromise. Remember to update the AIDE database after every intentional system change.
Brute-Force Protection with Fail2ban
Fail2ban monitors log files for repeated authentication failures and automatically bans offending IP addresses using firewall rules. It protects SSH, web applications, mail servers, and any service that logs failures — turning a bot's repeated attack attempts into a temporary or permanent block.
# Install Fail2ban
sudo apt install fail2ban -y
sudo systemctl enable --now fail2ban
# Default config lives at /etc/fail2ban/jail.conf
# NEVER edit jail.conf directly — create overrides in jail.local
sudo tee /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
# Ban IPs for 1 hour after 5 failures within 10 minutes
bantime = 3600
findtime = 600
maxretry = 5
# Use firewalld on RHEL, ufw/iptables on Debian
banaction = iptables-multiport
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
maxretry = 3
bantime = 86400 # 24h ban for SSH attackers
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
EOF
sudo systemctl restart fail2ban
# Check current bans
sudo fail2ban-client status sshd
# Manually unban an IP
sudo fail2ban-client set sshd unbanip 203.0.113.42# sudo fail2ban-client status sshd Status for the jail: sshd |- Filter | |- Currently failed: 3 | |- Total failed: 847 | `- File list: /var/log/auth.log `- Actions |- Currently banned: 12 |- Total banned: 203 `- Banned IP list: 185.220.101.5 45.33.32.156 198.199.67.210 ...
Minimising the Attack Surface
Every unnecessary service, open port, installed package, and enabled protocol is a potential entry point. Attack surface reduction is the practice of systematically removing everything that is not needed for the server's purpose.
systemctl list-units --state=active --type=service to audit running services. Disable anything not required: sudo systemctl disable --now bluetooth cups avahi-daemon
sudo apt autoremove removes orphaned packages. Audit installed packages periodically and remove compilers, debug tools, and development libraries from production servers.
ss -tlnp shows all listening ports with process names. Any port not explicitly required should be closed — either by disabling the service or adding a firewall rule.
find / -perm /6000 -type f 2>/dev/null lists all SUID/SGID files. These run with elevated privileges and are frequent privilege escalation targets — remove SUID bit from any binary that does not require it.
CIS Benchmarks and Compliance Frameworks
The CIS (Center for Internet Security) Benchmarks are consensus-based security configuration guidelines for Linux distributions. They provide a comprehensive, numbered checklist of controls organised into two levels — Level 1 (practical hardening with minimal impact) and Level 2 (stricter controls for high-security environments). Many compliance frameworks (PCI-DSS, ISO 27001, SOC 2) reference CIS Benchmarks directly.
# OpenSCAP — automated CIS compliance scanning on RHEL/Rocky
sudo dnf install openscap-scanner scap-security-guide -y
# List available profiles
sudo oscap info /usr/share/xml/scap/ssg/content/ssg-rocky9-ds.xml | grep "Id:" | grep cis
# Run a CIS Level 1 scan and generate HTML report
sudo oscap xccdf eval \
--profile xccdf_org.ssgproject.content_profile_cis_server_l1 \
--results /tmp/cis-results.xml \
--report /tmp/cis-report.html \
/usr/share/xml/scap/ssg/content/ssg-rocky9-ds.xml
# View the report in a browser
# copy /tmp/cis-report.html to your workstation
# Check overall pass/fail score
sudo oscap xccdf eval ... 2>&1 | grep "^Score"Security Is a Process, Not a State
A server that was hardened six months ago is not a hardened server today. New CVEs are published daily, configurations drift, packages accumulate, and services get added without review. Production security requires scheduled audits (run Lynis monthly), automated patch management, AIDE checks after every maintenance window, and a process for reviewing Fail2ban logs weekly. The discipline matters more than any single tool.
Lesson Checklist
sysctl.d and understand what each key parameter does
Practice Questions
1. A Lynis audit returns a hardening index of 52 and flags these three warnings: world-writable cron files, no file integrity tool installed, and SSH PermitRootLogin not disabled. Write the specific remediation steps for all three, in order of priority.
/etc/ssh/sshd_config, set PermitRootLogin no, run sudo sshd -t && sudo systemctl reload sshd. Priority 2 — World-writable cron files: find them with find /etc/cron* /var/spool/cron -perm -o+w 2>/dev/null and fix with chmod o-w <file>. Priority 3 — Install AIDE: sudo apt install aide -y && sudo aideinit && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db, then schedule daily checks in cron.
2. Your AIDE integrity check reports that /usr/bin/sudo has changed its SHA-256 hash since the last baseline. No maintenance was performed on the server. What are the possible explanations, how do you investigate, and what should you do?
dpkg -l sudo or rpm -q sudo to see if the package version changed; check /var/log/dpkg.log or /var/log/yum.log for a timestamp matching when the change occurred; verify the binary against the package: debsums sudo (Debian) or rpm -V sudo (RHEL). If unexplained: isolate the server immediately, treat as a compromise, rebuild from a known-good image.
3. Fail2ban is installed but SSH brute-force attacks from the same IP are continuing despite the server logging thousands of failures from that IP. What are three possible reasons Fail2ban is not banning the attacker, and how would you diagnose each?
sudo systemctl status fail2ban. (2) Wrong log path — Fail2ban may be reading a different file than where sshd writes failures; verify with sudo fail2ban-client status sshd and check the "File list" entry matches your actual auth log path. (3) The IP is in the ignoreip whitelist — check /etc/fail2ban/jail.local for ignoreip containing the attacker's IP or subnet. Also check /var/log/fail2ban.log for ban events.
Lesson Quiz
1. You set kernel.randomize_va_space = 2 via sysctl. What does this protect against?
2. After intentionally upgrading the nginx package, you need to update the AIDE baseline so future checks do not keep alerting on the changed nginx binary. What is the correct procedure?
3. What is the difference between CIS Benchmark Level 1 and Level 2?
Up Next
Lesson 32 — File Sharing with NFS and Samba
Sharing filesystems between Linux servers with NFS and between Linux and Windows with Samba