Executive Summary

This project implements a complete security hardening solution for Ubuntu Server 24.04 LTS, combining CIS Benchmark v1.0.0 controls with Lynis security auditing and comprehensive security tooling. The solution provides both standalone Bash scripts for manual execution and a production-ready Ansible role for automated deployment at scale.

Key Results

Metric Before After Change
Lynis Hardening Score 62 84 +22 points
Unconfined Profiles 7 0 -7
Lynis Suggestions 35 23 -12
Security Tools Installed 0 7 +7

Key Features

  • 30+ CIS Controls across 6 security domains (Levels 1 and 2)
  • Lynis Integration with automated scoring and improvement tracking
  • Security Tools Suite including AIDE, rkhunter, chkrootkit, and Fail2Ban
  • Enterprise nftables Firewall with SSH rate limiting and default-deny policy
  • Complete Workflow Automation from initial analysis to final reporting
  • Ansible Vault Integration for secure GRUB password management

Project Scope

Security Domains Covered

Domain Description Controls
Filesystem USB storage, mount options, unused filesystems 5
Mandatory Access Control AppArmor configuration and enforcement 2
Bootloader GRUB password protection and permissions 2
Kernel ASLR, ptrace scope, core dumps, memory protection 3
Services Unnecessary service removal and configuration 3
Network IP forwarding, ICMP, SYN cookies, protocol disabling 8
Firewall nftables with default deny, rate limiting 4
SSH Ciphers, MACs, authentication hardening 6
Authentication Password policies, PAM, sudo configuration 8
Auditing auditd rules and configuration 6
File Integrity AIDE and debsums verification 2

CIS Controls Implemented

Section Control ID Description Level
Filesystem 1.1.1.9 Disable USB storage kernel module L1
Filesystem 1.1.1.10 Disable unused filesystems L1
Filesystem 1.1.2.1.1 Configure /tmp as separate partition L1
Filesystem 1.1.2.1.4 Set noexec option on /tmp L1
Filesystem 1.1.2.2.4 Set noexec option on /dev/shm L1
AppArmor 1.3.1.2 Enable AppArmor in bootloader L1
AppArmor 1.3.1.4 Enforce all AppArmor profiles L2
Bootloader 1.4.1 Set bootloader password L1
Bootloader 1.4.2 Restrict bootloader config permissions L1
Kernel 1.5.1 Enable ASLR L1
Kernel 1.5.2 Restrict ptrace scope L1
Kernel 1.5.3 Restrict core dumps L1
Services 2.1.1 Disable autofs service L1
Services 2.1.21 Configure MTA for local-only mode L1
Services 2.2.4 Remove telnet client L1
Network 3.1.2 Disable wireless interfaces L1
Network 3.3.1 Disable IP forwarding L1
Network 3.3.2 Disable packet redirect sending L1
Network 3.3.3 Reject ICMP redirects L1
Network 3.3.4 Ignore broadcast ICMP L1
Network 3.3.5 Reject secure ICMP redirects L1
Network 3.3.9 Log suspicious packets (martians) L1
Network 3.3.10 Enable TCP SYN cookies L1
Firewall x Configure nftables firewall L1
SSH x SSH server hardening L1
Sudo x Sudo configuration L1
PAM x PAM password policies L1
Auth 5.4.1.4 Enforce SHA512 password hashing L1
Auth 5.4.1.5 Configure inactive password lock L1
Auth 5.4.2.1 Ensure root is only UID 0 account L1
Logging 6.1.3.4 Configure rsyslog file permissions L1
Audit 6.2.1.2 Enable auditd service L2
Audit 6.2.2.3 Configure disk full action L2
Audit x Comprehensive audit rules L2
Audit 6.2.3.20 Make audit configuration immutable L2
Integrity 6.3.1 Install and configure AIDE L1

Architecture

Hardening Workflow

The solution implements a six-phase hardening workflow:

Phase Description Output
1. Initial Analysis Collect baseline state with Lynis audit Score: 62, baseline metrics
2. Install Tools Deploy security tools suite 7 tools configured
3. Apply CIS Controls Implement 30+ CIS Benchmark controls Kernel, SSH, PAM hardened
4. Lynis Improvements Additional hardening based on Lynis suggestions 12 additional fixes
5. Configure Firewall Deploy nftables with SSH rate limiting Default-deny policy
6. Generate Report Post-hardening analysis and comparison Score: 84 (+22 points)

Design Principles

True Idempotency

The Ansible role prioritizes native modules over shell commands:

Operation Module Used Alternative Avoided
Mount configuration ansible.posix.mount shell: echo >> /etc/fstab
Kernel parameters ansible.posix.sysctl shell: sysctl -w
PAM limits community.general.pam_limits shell: echo >> limits.conf
Service management ansible.builtin.systemd shell: systemctl
Package installation ansible.builtin.apt shell: apt-get

Secret Management

Control 1.4.1 (GRUB bootloader password) uses Ansible Vault for encryption:

# group_vars/all/vault.yml (encrypted)
cis_grub_password_hash: "grub.pbkdf2.sha512.600000.ABC123..."

This eliminates interactive password prompts, enabling CI/CD pipeline compatibility.

Level-Based Profiles

The role supports both CIS Level 1 and Level 2 profiles:

Level 1 (default): Practical security for most environments

  • Audit rules without immutable flag
  • AppArmor profiles as-is

Level 2: Enhanced security for high-risk environments

  • Immutable audit configuration (requires reboot to modify)
  • All AppArmor profiles in enforce mode
  • Compiler removal option

Hardening Results

Kernel Security Parameters

Parameter Before After CIS Control
kernel.yama.ptrace_scope 1 2 1.5.2
net.ipv4.conf.all.log_martians 0 1 3.3.9
net.ipv4.conf.all.secure_redirects 1 0 3.3.5
kernel.kptr_restrict 1 2 Lynis
kernel.sysrq 176 0 Lynis
net.ipv4.tcp_rfc1337 0 1 Lynis
fs.protected_fifos 1 2 Lynis
net.ipv6.conf.all.accept_ra 1 0 Lynis

SSH Hardening Applied

Parameter Before After CIS Control
MaxAuthTries 6 3 5.1.6
ClientAliveInterval 0 300 5.1.7
PermitRootLogin yes no 5.1.20
X11Forwarding yes no x
LogLevel INFO VERBOSE x
Banner none /etc/issue.net x
MaxStartups default 10:30:60 x

AppArmor Improvements

Applied 119 profiles in enforce mode, eliminating all unconfined profiles.


Security Tools Integration

Installed Security Tools

Tool Purpose Configuration
Lynis Security auditing and scoring Automated scans with report generation
AIDE File integrity monitoring Daily cron checks, database initialization
rkhunter Rootkit detection Daily scans, automatic updates
chkrootkit Rootkit verification Daily verification runs
Fail2Ban Intrusion prevention SSH jail with nftables integration
auditd System auditing Comprehensive audit rules
debsums Package verification Weekly integrity checks

Lynis Score Progression

Phase Score Change
Initial (default Ubuntu 24.04) 62 baseline
After CIS controls ~75 +13
After Lynis improvements 84 +9

Additional Lynis Improvements Applied

Category Improvements
Kernel dmesg_restrict, kptr_restrict, sysrq disabled
Network DCCP, SCTP, RDS, TIPC protocols disabled
Permissions Secure cron directories (0700), restrictive UMASK (027)
Services Security banners configured
Shell 15-minute timeout (TMOUT=900)
PAM libpam-tmpdir installed

nftables Firewall Configuration

The firewall implements a hardened configuration with SSH rate limiting:

Features

  • Default-Deny Policy: All incoming traffic blocked by default
  • Stateful Filtering: Established/related connections allowed
  • SSH Rate Limiting: 4 connections/minute per source IP (anti-brute-force)
  • ICMP Control: Essential ICMP types only (echo, unreachable, time-exceeded)
  • IPv6 Blocking: Complete IPv6 traffic blocking (configurable)
  • Logging: Rate-limited logging of dropped packets

Configuration

table inet filter {
    set ssh_limit {
        type ipv4_addr
        size 65535
        flags dynamic,timeout
        timeout 1m
    }

    chain input {
        type filter hook input priority 0; policy drop;
        
        ct state established,related accept
        ct state invalid drop
        iif "lo" accept
        iif != "lo" ip daddr 127.0.0.0/8 drop
        
        # ICMP essential types
        ip protocol icmp icmp type { echo-reply, destination-unreachable, 
            echo-request, time-exceeded, parameter-problem } accept
        
        # SSH with rate limiting
        tcp dport 22 ct state new add @ssh_limit { 
            ip saddr limit rate 4/minute burst 8 packets 
        } accept
        tcp dport 22 ct state new drop
        
        # Log and drop everything else
        limit rate 5/minute burst 10 packets log prefix "nftables-dropped: "
        counter drop
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
        counter drop
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}

table ip6 filter {
    chain input { type filter hook input priority 0; policy drop; }
    chain forward { type filter hook forward priority 0; policy drop; }
    chain output { type filter hook output priority 0; policy drop; }
}

Usage

Full Automated Workflow (Bash)

# Clone the repository
git clone https://github.com/xoelrdgz/hardening-project.git
cd hardening-project

# Run complete hardening with all features
sudo ./scripts/00-cis-hardening-main.sh full

# With custom firewall ports
sudo ./scripts/00-cis-hardening-main.sh full --ssh-port 22 --tcp-ports 80,443

Step-by-Step Execution

# Phase 1: Initial analysis with Lynis
sudo ./scripts/00-cis-hardening-main.sh analyze --phase initial

# Phase 2: Install security tools
sudo ./scripts/00-cis-hardening-main.sh tools

# Phase 3: Apply CIS controls
sudo ./scripts/00-cis-hardening-main.sh harden

# Phase 4: Lynis improvements
sudo ./scripts/00-cis-hardening-main.sh lynis-improve

# Phase 5: Configure firewall
sudo ./scripts/00-cis-hardening-main.sh firewall

# Phase 6: Generate report
sudo ./scripts/00-cis-hardening-main.sh analyze --phase post
sudo ./scripts/00-cis-hardening-main.sh report

Ansible Deployment

cd ansible

# Install dependencies
ansible-galaxy collection install -r requirements.yml

# Dry run (check mode)
ansible-playbook site.yml --check --diff --ask-vault-pass

# Apply Level 1 hardening
ansible-playbook site.yml --ask-vault-pass

# Apply Level 2 hardening
ansible-playbook site.yml -e "cis_level=2" --ask-vault-pass

# Run specific sections
ansible-playbook site.yml --tags "security_tools,lynis_improvements" --ask-vault-pass

Validation

After applying hardening controls:

# Run Lynis audit
sudo lynis audit system

# Verify kernel parameters
sysctl kernel.randomize_va_space    # Expected: 2
sysctl kernel.yama.ptrace_scope     # Expected: 2
sysctl net.ipv4.ip_forward          # Expected: 0
sysctl net.ipv4.tcp_syncookies      # Expected: 1

# Verify security services
systemctl is-enabled auditd fail2ban nftables

# Verify firewall
nft list ruleset

# Verify file integrity tools
aide --check
rkhunter --check

# Verify AppArmor (all profiles enforced)
aa-status | grep -E "profiles|processes"

# Verify mount options
findmnt /tmp -o OPTIONS | grep noexec
findmnt /dev/shm -o OPTIONS | grep noexec

Technical Highlights

Challenges Solved

Challenge Solution
Interactive GRUB password prompts Ansible Vault with pre-generated hash
Audit immutable lockouts Pre-flight safety checks before enabling
Firewall SSH lockouts Rate limiting instead of blocking
Inconsistent Lynis scores Systematic approach with documented improvements
Shell command non-idempotency Native Ansible modules throughout

Key Learnings

  • Enterprise security hardening requires systematic, auditable approaches
  • Automation with proper safeguards prevents operational incidents
  • Security tools integration provides defense-in-depth
  • Lynis scoring provides measurable security improvement metrics
  • Handler-based notifications allow controlled maintenance windows
  • Documentation is critical for reproducibility and compliance audits