Linux Security Automation with Bash

Linux Security Automation with Bash

Bash scripting provides powerful automation capabilities for Linux systems, leveraging decades of Unix philosophy and tools. Modern bash scripts can implement complex security automation while maintaining portability across different Linux distributions. Understanding bash security features and common pitfalls ensures reliable automation implementation.

Implement comprehensive Linux security hardening automation:

#!/bin/bash
# Linux Security Hardening Automation Script

set -euo pipefail  # Exit on error, undefined variables, pipe failures
IFS=$'\n\t'       # Set secure Internal Field Separator

# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOG_FILE="/var/log/security_hardening.log"
BACKUP_DIR="/var/backups/security_hardening/$(date +%Y%m%d_%H%M%S)"

# Logging functions
log() {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}

log_error() {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $*" | tee -a "$LOG_FILE" >&2
}

# Backup function
backup_file() {
    local file="$1"
    if [[ -f "$file" ]]; then
        mkdir -p "$BACKUP_DIR"
        cp -p "$file" "$BACKUP_DIR/$(basename "$file").$(date +%s)"
        log "Backed up: $file"
    fi
}

# Kernel hardening
harden_kernel() {
    log "Starting kernel hardening"
    
    local sysctl_file="/etc/sysctl.d/99-security.conf"
    backup_file "/etc/sysctl.conf"
    
    cat > "$sysctl_file" << 'EOF'
# IP Spoofing protection
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

# Ignore send redirects
net.ipv4.conf.all.send_redirects = 0

# Disable source packet routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0

# Log Martians
net.ipv4.conf.all.log_martians = 1

# Ignore ICMP ping requests
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Ignore Directed pings
net.ipv4.icmp_ignore_bogus_error_responses = 1

# Enable TCP/IP SYN cookies
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5

# Disable IPv6 if not needed
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1

# Enable ExecShield
kernel.exec-shield = 1
kernel.randomize_va_space = 2

# Restrict core dumps
fs.suid_dumpable = 0
kernel.core_uses_pid = 1

# Restrict access to kernel logs
kernel.dmesg_restrict = 1
kernel.kptr_restrict = 2

# Restrict ptrace scope
kernel.yama.ptrace_scope = 1
EOF
    
    sysctl -p "$sysctl_file" > /dev/null 2>&1
    log "Kernel hardening completed"
}

# SSH hardening
harden_ssh() {
    log "Starting SSH hardening"
    
    local ssh_config="/etc/ssh/sshd_config"
    backup_file "$ssh_config"
    
    # Create hardened SSH configuration
    cat > "${ssh_config}.hardened" << 'EOF'
# SSH Hardened Configuration
Port 22
Protocol 2
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key

# Logging
SyslogFacility AUTH
LogLevel VERBOSE

# Authentication
LoginGraceTime 60
PermitRootLogin no
StrictModes yes
MaxAuthTries 3
MaxSessions 3

# Public key authentication
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

# Password authentication
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no

# Kerberos options
KerberosAuthentication no
GSSAPIAuthentication no

# Other options
X11Forwarding no
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
Compression delayed
ClientAliveInterval 300
ClientAliveCountMax 2
UsePAM yes

# Restrict users and groups
AllowGroups sshusers

# Crypto settings
KexAlgorithms [email protected],diffie-hellman-group-exchange-sha256
Ciphers [email protected],[email protected],[email protected]
MACs [email protected],[email protected]
EOF
    
    # Apply configuration
    mv "${ssh_config}.hardened" "$ssh_config"
    
    # Create SSH users group if not exists
    groupadd -f sshusers
    
    # Test SSH configuration
    if sshd -t; then
        systemctl reload sshd
        log "SSH hardening completed"
    else
        log_error "SSH configuration test failed, restoring backup"
        cp "$BACKUP_DIR/$(basename "$ssh_config")."* "$ssh_config"
        return 1
    fi
}

# Firewall automation
configure_firewall() {
    log "Configuring firewall"
    
    if command -v ufw >/dev/null 2>&1; then
        # UFW configuration
        ufw --force reset
        ufw default deny incoming
        ufw default allow outgoing
        ufw allow 22/tcp comment "SSH"
        ufw allow 443/tcp comment "HTTPS"
        ufw logging on
        echo "y" | ufw enable
        log "UFW firewall configured"
    elif command -v firewall-cmd >/dev/null 2>&1; then
        # FirewallD configuration
        firewall-cmd --set-default-zone=drop
        firewall-cmd --permanent --add-service=ssh
        firewall-cmd --permanent --add-service=https
        firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" service name="ssh" accept'
        firewall-cmd --reload
        log "FirewallD configured"
    else
        log_error "No supported firewall found"
        return 1
    fi
}

# Automated security scanning
security_scan() {
    log "Running security scan"
    
    local scan_report="/tmp/security_scan_$(date +%Y%m%d_%H%M%S).txt"
    
    {
        echo "=== Security Scan Report ==="
        echo "Date: $(date)"
        echo "Hostname: $(hostname)"
        echo
        
        # Check for users with UID 0
        echo "=== Users with UID 0 ==="
        awk -F: '($3 == "0") {print}' /etc/passwd
        echo
        
        # Check for users with empty passwords
        echo "=== Users with empty passwords ==="
        awk -F: '($2 == "") {print $1}' /etc/shadow
        echo
        
        # Check world-writable files
        echo "=== World-writable files ==="
        find / -type f -perm -002 -exec ls -l {} \; 2>/dev/null | head -20
        echo
        
        # Check SUID/SGID files
        echo "=== SUID/SGID files ==="
        find / -type f \( -perm -4000 -o -perm -2000 \) -exec ls -l {} \; 2>/dev/null | head -20
        echo
        
        # Check listening services
        echo "=== Listening services ==="
        ss -tlnp 2>/dev/null || netstat -tlnp 2>/dev/null
        echo
        
    } > "$scan_report"
    
    # Alert if critical issues found
    if grep -q "UID 0" "$scan_report" || grep -q "empty password" "$scan_report"; then
        mail -s "CRITICAL: Security scan found issues on $(hostname)" [email protected] < "$scan_report"
    fi
    
    log "Security scan completed: $scan_report"
}

# Main execution
main() {
    log "Starting security hardening automation"
    
    # Check if running as root
    if [[ $EUID -ne 0 ]]; then
        log_error "This script must be run as root"
        exit 1
    fi
    
    # Create backup directory
    mkdir -p "$BACKUP_DIR"
    
    # Execute hardening functions
    harden_kernel
    harden_ssh
    configure_firewall
    security_scan
    
    log "Security hardening automation completed"
}

# Run main function
main "$@"