#!/usr/bin/env bash
##############################################################
# GMLM Platform — Server Hardening Script
#
# Applies security hardening to a fresh Ubuntu 22.04 server.
# Run ONCE after initial server setup, before deploying GMLM.
#
# What this script does:
#   1.  Configure SSH (disable password auth, disable root login)
#   2.  Configure UFW firewall (allow only 22, 80, 443)
#   3.  Install and configure Fail2ban (block brute-force)
#   4.  Apply sysctl hardening (network stack security)
#   5.  Install unattended-upgrades (automatic security patches)
#   6.  Configure logrotate for GMLM logs
#   7.  Set up swap (prevent OOM on small instances)
#   8.  Configure Docker daemon securely
#   9.  Disable unnecessary services
#   10. Install and configure ClamAV (optional malware scanner)
#
# Usage: sudo bash server-harden.sh [--skip-swap] [--ssh-port 2222]
##############################################################

set -euo pipefail

SSH_PORT=22
SKIP_SWAP=false

while [[ "$#" -gt 0 ]]; do
    case $1 in
        --ssh-port)  SSH_PORT="$2"; shift ;;
        --skip-swap) SKIP_SWAP=true ;;
        *) echo "Unknown: $1" ;;
    esac
    shift
done

GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

step() { echo -e "${YELLOW}▶ $1${NC}"; }
ok()   { echo -e "${GREEN}✓ $1${NC}"; }

echo ""
echo "╔══════════════════════════════════════════╗"
echo "║   GMLM Server Hardening                  ║"
echo "╚══════════════════════════════════════════╝"
echo ""

# ── Update system ─────────────────────────────────────────────
step "Updating system packages..."
apt-get update -qq && apt-get upgrade -y -qq
ok "System updated."

# ── Step 1: SSH Hardening ─────────────────────────────────────
step "Hardening SSH configuration..."

# Backup original config
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup

cat >> /etc/ssh/sshd_config << EOF

# GMLM Security Hardening
Port ${SSH_PORT}
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
X11Forwarding no
MaxAuthTries 3
MaxSessions 5
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
Protocol 2
AllowUsers ${SUDO_USER:-ubuntu}  # Restrict to specific user
EOF

systemctl restart sshd
ok "SSH hardened (port ${SSH_PORT}, key-only auth, no root)."

# ── Step 2: UFW Firewall ─────────────────────────────────────
step "Configuring UFW firewall..."
ufw --force reset
ufw default deny incoming
ufw default allow outgoing
ufw allow "${SSH_PORT}/tcp"   comment "SSH"
ufw allow 80/tcp              comment "HTTP"
ufw allow 443/tcp             comment "HTTPS"
# Internal ports are NOT exposed externally:
# 3306 (MySQL), 6379 (Redis), 9090 (Prometheus), 3000 (Grafana)
ufw --force enable
ok "Firewall configured: only ports ${SSH_PORT}, 80, 443 are open."

# ── Step 3: Fail2ban ─────────────────────────────────────────
step "Installing and configuring Fail2ban..."
apt-get install -y -qq fail2ban

cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime  = 3600     # 1 hour ban
findtime = 600      # 10-minute window
maxretry = 5        # 5 failures before ban

# Ignore Cloudflare IPs and localhost
ignoreip = 127.0.0.1/8 ::1

[sshd]
enabled  = true
port     = SSH_PORT_PLACEHOLDER
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 3
bantime  = 86400  # 24 hours for SSH brute force

[nginx-http-auth]
enabled  = true
filter   = nginx-http-auth
logpath  = /var/log/nginx/error.log

[nginx-limit-req]
enabled  = true
filter   = nginx-limit-req
logpath  = /var/log/nginx/error.log
findtime = 60
maxretry = 20
bantime  = 600
EOF

# Replace SSH port placeholder
sed -i "s/SSH_PORT_PLACEHOLDER/${SSH_PORT}/" /etc/fail2ban/jail.local

# GMLM-specific filter for login brute force
cat > /etc/fail2ban/filter.d/gmlm-login.conf << 'EOF'
[Definition]
failregex = ^.*\[warning\].*Invalid credentials.*ip=<HOST>.*$
            ^.*Login attempt for .* failed.*ip=<HOST>.*$
ignoreregex =
EOF

cat >> /etc/fail2ban/jail.local << 'EOF'
[gmlm-login]
enabled  = true
port     = 443
filter   = gmlm-login
logpath  = /var/www/gmlm/storage/logs/security.log
maxretry = 10
bantime  = 3600
EOF

systemctl enable fail2ban
systemctl start fail2ban
ok "Fail2ban configured."

# ── Step 4: Sysctl kernel hardening ──────────────────────────
step "Applying kernel security parameters..."

cat > /etc/sysctl.d/99-gmlm-security.conf << 'EOF'
# ── Network security ──────────────────────────────────────────
# Disable IP forwarding (not a router)
net.ipv4.ip_forward = 0

# Disable accepting ICMP redirects
net.ipv4.conf.all.accept_redirects     = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects     = 0

# Disable sending ICMP redirects
net.ipv4.conf.all.send_redirects     = 0
net.ipv4.conf.default.send_redirects = 0

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

# Enable SYN flood protection
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries  = 2
net.ipv4.tcp_syn_retries     = 5

# Log suspicious packets
net.ipv4.conf.all.log_martians     = 1
net.ipv4.conf.default.log_martians = 1

# Disable ICMP broadcast
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Ignore bogus ICMP error responses
net.ipv4.icmp_ignore_bogus_error_responses = 1

# ── File system security ──────────────────────────────────────
# Protect symlinks (prevent symlink-based attacks)
fs.protected_symlinks  = 1
fs.protected_hardlinks = 1

# Restrict core dumps
fs.suid_dumpable = 0

# ── Performance + stability (bonus) ──────────────────────────
# Increase max connections
net.core.somaxconn           = 65536
net.ipv4.tcp_max_tw_buckets  = 1440000

# Reduce TIME_WAIT sockets
net.ipv4.tcp_tw_reuse = 1

# Increase local port range
net.ipv4.ip_local_port_range = 1024 65535
EOF

sysctl -p /etc/sysctl.d/99-gmlm-security.conf
ok "Kernel hardening applied."

# ── Step 5: Automatic security updates ────────────────────────
step "Configuring unattended security updates..."

apt-get install -y -qq unattended-upgrades apt-listchanges

cat > /etc/apt/apt.conf.d/50unattended-upgrades << 'EOF'
Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";  // Manual reboots only
Unattended-Upgrade::Mail "${ADMIN_EMAIL:-root}";
EOF

systemctl enable unattended-upgrades
ok "Automatic security updates configured."

# ── Step 6: Log rotation ─────────────────────────────────────
step "Configuring GMLM log rotation..."

cat > /etc/logrotate.d/gmlm << 'EOF'
/var/www/gmlm/storage/logs/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data www-data
    sharedscripts
    postrotate
        # Signal PHP-FPM to reopen log files
        docker exec gmlm-app kill -USR1 1 2>/dev/null || true
    endscript
}

/var/www/gmlm/storage/logs/security.log {
    monthly
    missingok
    rotate 36      # 3 years
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
}

/var/www/gmlm/storage/logs/commissions.log {
    monthly
    missingok
    rotate 84      # 7 years (financial retention)
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
}
EOF

ok "Log rotation configured."

# ── Step 7: Swap setup ────────────────────────────────────────
if [[ "$SKIP_SWAP" != "true" ]]; then
    step "Configuring swap space..."
    RAM_MB=$(free -m | awk 'NR==2{print $2}')
    SWAP_SIZE_GB=$(( (RAM_MB / 1024) + 1 ))

    if [ ! -f /swapfile ]; then
        fallocate -l "${SWAP_SIZE_GB}G" /swapfile
        chmod 600 /swapfile
        mkswap /swapfile
        swapon /swapfile
        echo '/swapfile none swap sw 0 0' >> /etc/fstab
        # Reduce swappiness (prefer RAM over swap)
        echo 'vm.swappiness=10' >> /etc/sysctl.d/99-gmlm-security.conf
        sysctl -p /etc/sysctl.d/99-gmlm-security.conf
    fi
    ok "${SWAP_SIZE_GB}GB swap configured."
fi

# ── Step 8: Secure Docker daemon ──────────────────────────────
step "Securing Docker daemon..."

mkdir -p /etc/docker
cat > /etc/docker/daemon.json << 'EOF'
{
  "live-restore":       true,
  "log-driver":         "json-file",
  "log-opts": {
    "max-size":         "50m",
    "max-file":         "5"
  },
  "no-new-privileges":  true,
  "icc":                false,
  "userland-proxy":     false
}
EOF

systemctl restart docker
ok "Docker daemon secured."

# ── Step 9: Disable unnecessary services ─────────────────────
step "Disabling unnecessary services..."
for service in avahi-daemon cups bluetooth; do
    systemctl disable "$service" 2>/dev/null || true
    systemctl stop    "$service" 2>/dev/null || true
done
ok "Unnecessary services disabled."

# ── Summary ────────────────────────────────────────────────────
echo ""
echo "╔══════════════════════════════════════════╗"
echo "║   ✓ Server Hardening Complete            ║"
echo "╚══════════════════════════════════════════╝"
echo ""
echo -e "  SSH Port:      ${SSH_PORT}"
echo -e "  Root Login:    Disabled"
echo -e "  Password Auth: Disabled (key only)"
echo -e "  Firewall:      Active (${SSH_PORT}/80/443)"
echo -e "  Fail2ban:      Active"
echo -e "  Auto-updates:  Security patches only"
echo ""
echo -e "${YELLOW}IMPORTANT: Test SSH access with your key before closing this session.${NC}"
echo -e "  ssh -p ${SSH_PORT} ${SUDO_USER:-ubuntu}@$(curl -s ifconfig.me)"
echo ""
