ZAWAD / SECURITY / PROJECT 4
Project 4

Linux Server Hardening

Harden Linux servers according to CIS Benchmark recommendations.

System HardeningLinuxCIS Controls

Introduction

This project documents the hardening of a Debian Linux server from a default installation to a security-baseline configuration suitable for internet-facing or internal production use. The work involved reviewing the server's default configuration, identifying weak or unnecessary settings across authentication, network exposure, and logging, applying targeted hardening changes, and verifying that legitimate services continued to function after each change. The end state is a server with a reduced attack surface, enforced least-privilege access, an active host-based firewall, and centralized monitoring through Wazuh.

What is Linux Hardening?

Linux Server Hardening is the process of reducing the attack surface of a Linux server by applying secure configurations, restricting access, removing unnecessary services, strengthening authentication, protecting network services, and improving system monitoring. This project focuses on applying practical hardening techniques to a Linux server based on widely recognized security practices, particularly the CIS Benchmarks. CIS describes its Benchmarks as consensus-based secure configuration recommendations developed by cybersecurity professionals, covering everything from filesystem and boot settings to authentication, network parameters, logging, and auditing. Rather than applying every control in the full benchmark, this project prioritizes the changes with the highest security impact for a general-purpose server: remote access, privilege management, network exposure, patching, and visibility into authentication activity.

Case work

The main objectives of this project were to take a default Debian server build and bring it in line with CIS Benchmark-aligned best practices: locking down SSH, enforcing least-privilege account management, restricting network exposure with a host-based firewall, keeping the system patched, tightening file and directory permissions, and standing up logging and auditing that feeds into Wazuh for ongoing security monitoring.

1. SSH Hardening

The default OpenSSH configuration allowed root login and password authentication, both common brute-force targets. Ed25519 keypairs were generated and deployed for authorized administrators, /etc/ssh/sshd_config was locked down, and Fail2ban was installed with an sshd jail to auto-block IPs after repeated failed logins.

# Generate an Ed25519 keypair for the admin account ssh-keygen -t ed25519 -C "admin@server" # Edit the daemon config sudo nano /etc/ssh/sshd_config PermitRootLogin no PasswordAuthentication no PubkeyAuthentication yes PermitEmptyPasswords no MaxAuthTries 3 X11Forwarding no AllowUsers admin # Validate syntax before restarting (avoids a lockout) sudo sshd -t sudo systemctl restart sshd # Install and enable Fail2ban for SSH sudo apt install fail2ban -y sudo systemctl enable --now fail2ban

2. Least Privilege & Account Management

Default and unused accounts were audited, service accounts without an interactive need were locked down, and administrative access was moved from shared root usage to a named account scoped through sudo. Password quality and lockout policy were enforced via PAM.

# List accounts with a login shell awk -F: '$7 ~ /sh$/ {print $1}' /etc/passwd # Disable shell access for a non-interactive service account sudo usermod -s /usr/sbin/nologin svc-backup # Create a scoped sudoers rule instead of full root sudo visudo -f /etc/sudoers.d/admin admin ALL=(ALL) /usr/bin/apt, /usr/bin/systemctl # Enforce password quality sudo apt install libpam-pwquality -y # /etc/security/pwquality.conf minlen = 14 dcredit = -1 ucredit = -1 # Lock an account after 5 failed attempts sudo nano /etc/pam.d/common-auth auth required pam_faillock.so deny=5 unlock_time=900

3. Host-Based Firewall

UFW (backed by nftables) was enabled with a default-deny inbound policy. Only the ports required for the server's role were explicitly opened, including a rate-limited SSH rule. All other listening sockets were reviewed and unused services disabled.

# Set default-deny policy sudo ufw default deny incoming sudo ufw default allow outgoing # Allow only required services sudo ufw limit OpenSSH sudo ufw allow 443/tcp # Enable and check status sudo ufw enable sudo ufw status verbose # Review what's actually listening sudo ss -tulpn

4. Patch & Package Management

The system was brought fully up to date and configured to apply security patches automatically going forward. Unused packages were removed to reduce the toolset available to an attacker after any future compromise.

# Update and upgrade sudo apt update && sudo apt full-upgrade -y # Enable automatic security updates sudo apt install unattended-upgrades -y sudo dpkg-reconfigure --priority=low unattended-upgrades # Remove unused packages sudo apt autoremove --purge -y

5. File & Directory Permissions

Sensitive files were reviewed and corrected, world-writable directories were located, and mount options were tightened on non-essential partitions. SUID/SGID binaries were enumerated and checked against a known-good baseline.

# Lock down sensitive files sudo chmod 600 /etc/shadow sudo chmod 600 /etc/ssh/ssh_host_*_key # Find world-writable directories sudo find / -xdev -type d -perm -0002 # Harden /tmp mount options (in /etc/fstab) tmpfs /tmp tmpfs defaults,nodev,nosuid,noexec 0 0 # Enumerate SUID/SGID binaries sudo find / -xdev \( -perm -4000 -o -perm -2000 \) -type f

6. Logging, Auditing & Wazuh Monitoring

The Wazuh agent was installed and registered against a central Wazuh manager to provide file integrity monitoring, log collection, and authentication anomaly alerting, correlated with local journal/rsyslog output.

# Install the Wazuh agent and point it at the manager curl -so wazuh-agent.deb https://packages.wazuh.com/4.x/apt/pool/main/w/wazuh-agent/wazuh-agent_amd64.deb sudo WAZUH_MANAGER='manager_ip' dpkg -i ./wazuh-agent.deb sudo systemctl daemon-reload sudo systemctl enable --now wazuh-agent # Confirm the agent is connected sudo /var/ossec/bin/agent-auth -m manager_ip sudo systemctl status wazuh-agent # Tail auth events being forwarded sudo tail -f /var/log/auth.log

What was documented

For each control above, the before-and-after configuration was recorded, along with the specific command used to apply the change and the command used to verify it (for example, sshd -T | grep permitrootlogin, ufw status verbose, and confirmation of active alerts in the Wazuh dashboard). This before/after record is what makes the hardening auditable rather than a one-time, undocumented change.

← Back to Blue Team