optional new function applies sysctl security for harden kernel

This commit is contained in:
buildplan
2025-07-15 13:51:34 +01:00
parent 532def1f61
commit 96c5042daf

View File

@@ -1,8 +1,9 @@
#!/bin/bash
# Debian 12 and Ubuntu Server Hardening Interactive Script
# Version: 0.57 | 2025-07-07
# Version: 0.59 | 2025-07-15
# Changelog:
# - v0.59: Add a new optional function that applies a set of recommended sysctl security settings to harden the kernel.
# - v0.58: improved fail2ban to parse ufw logs
# - v0.57: Fix for silent failure at test_backup()
# Option to choose which directories to back up.
@@ -84,6 +85,7 @@ fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOG_FILE="/var/log/du_setup_$(date +%Y%m%d_%H%M%S).log"
BACKUP_LOG="/var/log/backup_rsync.log"
REPORT_FILE="/var/log/du_setup_report_$(date +%Y%m%d_%H%M%S).txt"
VERBOSE=true
BACKUP_DIR="/root/setup_harden_backup_$(date +%Y%m%d_%H%M%S)"
IS_CONTAINER=false
@@ -112,7 +114,7 @@ print_header() {
echo -e "${CYAN}╔═════════════════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║ ║${NC}"
echo -e "${CYAN}║ DEBIAN/UBUNTU SERVER SETUP AND HARDENING SCRIPT ║${NC}"
echo -e "${CYAN}║ v0.58 | 2025-07-07${NC}"
echo -e "${CYAN}║ v0.59 | 2025-07-15${NC}"
echo -e "${CYAN}║ ║${NC}"
echo -e "${CYAN}╚═════════════════════════════════════════════════════════════════╝${NC}"
echo
@@ -1129,6 +1131,86 @@ configure_auto_updates() {
log "Automatic updates configuration completed."
}
configure_kernel_hardening() {
print_section "Kernel Parameter Hardening (sysctl)"
if ! confirm "Apply recommended kernel security settings (sysctl)?"; then
print_info "Skipping kernel hardening."
log "Kernel hardening skipped by user."
return 0
fi
local KERNEL_HARDENING_CONFIG
KERNEL_HARDENING_CONFIG=$(mktemp)
# create the config in a temporary file
tee "$KERNEL_HARDENING_CONFIG" > /dev/null <<'EOF'
# Recommended Security Settings managed by du_setup.sh
# For details, see: https://www.kernel.org/doc/Documentation/sysctl/
# --- IPV4 Networking ---
# Protect against IP spoofing
net.ipv4.conf.default.rp_filter=1
net.ipv4.conf.all.rp_filter=1
# Block SYN-FLOOD attacks
net.ipv4.tcp_syncookies=1
# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects=0
net.ipv4.conf.default.accept_redirects=0
net.ipv4.conf.all.secure_redirects=1
net.ipv4.conf.default.secure_redirects=1
# Ignore source-routed packets
net.ipv4.conf.all.accept_source_route=0
net.ipv4.conf.default.accept_source_route=0
# Log martian packets (packets with impossible source addresses)
net.ipv4.conf.all.log_martians=1
net.ipv4.conf.default.log_martians=1
# --- IPV6 Networking (if enabled) ---
net.ipv6.conf.all.accept_redirects=0
net.ipv6.conf.default.accept_redirects=0
net.ipv6.conf.all.accept_source_route=0
net.ipv6.conf.default.accept_source_route=0
# --- Kernel Security ---
# Enable ASLR (Address Space Layout Randomization) for better security
kernel.randomize_va_space=2
# Restrict access to kernel pointers in /proc to prevent leaks
kernel.kptr_restrict=2
# Restrict access to dmesg for unprivileged users
kernel.dmesg_restrict=1
# Restrict ptrace scope to prevent process injection attacks
kernel.yama.ptrace_scope=1
# --- Filesystem Security ---
# Protect against TOCTOU (Time-of-Check to Time-of-Use) race conditions
fs.protected_hardlinks=1
fs.protected_symlinks=1
EOF
local SYSCTL_CONF_FILE="/etc/sysctl.d/99-du-hardening.conf"
# Idempotency check: only update if the file doesn't exist or has changed
if [[ -f "$SYSCTL_CONF_FILE" ]] && cmp -s "$KERNEL_HARDENING_CONFIG" "$SYSCTL_CONF_FILE"; then
print_info "Kernel security settings are already configured correctly."
rm -f "$KERNEL_HARDENING_CONFIG"
log "Kernel hardening settings already in place."
return 0
fi
print_info "Applying settings to $SYSCTL_CONF_FILE..."
# Move the new config into place
mv "$KERNEL_HARDENING_CONFIG" "$SYSCTL_CONF_FILE"
chmod 644 "$SYSCTL_CONF_FILE"
print_info "Loading new settings..."
if sysctl -p "$SYSCTL_CONF_FILE" >/dev/null 2>&1; then
print_success "Kernel security settings applied successfully."
log "Applied kernel hardening settings."
else
print_error "Failed to apply kernel settings. Check for kernel compatibility."
log "sysctl -p failed for kernel hardening config."
fi
}
install_docker() {
if ! confirm "Install Docker Engine (Optional)?"; then
print_info "Skipping Docker installation."
@@ -2062,61 +2144,65 @@ final_cleanup() {
}
generate_summary() {
touch "$REPORT_FILE" && chmod 600 "$REPORT_FILE"
(
print_section "Setup Complete!"
print_info "Checking critical services..."
echo -e "\n${GREEN}Server setup and hardening script has finished successfully.${NC}\n"
echo -e "A detailed report has been saved to: ${BOLD}$REPORT_FILE${NC}"
echo -e "The full execution log is available at: ${BOLD}$LOG_FILE${NC}"
echo
echo -e "${YELLOW}Final Service Status Check:${NC}"
# --- Service Checks ---
for service in "$SSH_SERVICE" fail2ban chrony; do
if systemctl is-active --quiet "$service"; then
print_success "Service $service is active."
printf " %-20s ${GREEN}✓ Active${NC}\n" "$service"
else
print_error "Service $service is NOT active."
FAILED_SERVICES+=("$service")
printf " %-20s ${RED}✗ INACTIVE${NC}\n" "$service"
fi
done
if ufw status | grep -q "Status: active"; then
print_success "Service ufw is active."
printf " %-20s ${GREEN}✓ Active${NC}\n" "ufw (firewall)"
else
print_error "Service ufw is NOT active."
FAILED_SERVICES+=("ufw")
printf " %-20s ${RED}✗ INACTIVE${NC}\n" "ufw (firewall)"
fi
if command -v docker >/dev/null 2>&1; then
if systemctl is-active --quiet docker; then
print_success "Service docker is active."
printf " %-20s ${GREEN}✓ Active${NC}\n" "docker"
else
print_error "Service docker is NOT active."
FAILED_SERVICES+=("docker")
printf " %-20s ${RED}✗ INACTIVE${NC}\n" "docker"
fi
fi
local TS_COMMAND=""
if command -v tailscale >/dev/null 2>&1; then
if systemctl is-active --quiet tailscaled && tailscale ip >/dev/null 2>&1; then
local TS_IPS TS_IPV4
TS_IPS=$(tailscale ip 2>/dev/null || echo "Unknown")
TS_IPV4=$(echo "$TS_IPS" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -1 || echo "Unknown")
print_success "Service tailscaled is active and connected."
echo "$TS_IPS" > /tmp/tailscale_ips.txt
else
if grep -q "Tailscale connection failed: tailscale up" "$LOG_FILE"; then
print_error "Service tailscaled is NOT active"
FAILED_SERVICES+=("tailscaled")
TS_COMMAND=$(grep "Tailscale connection failed: tailscale up" "$LOG_FILE" | tail -1 | sed 's/.*Tailscale connection failed: //')
TS_COMMAND=${TS_COMMAND:-""}
if systemctl is-active --quiet tailscaled; then
if tailscale ip >/dev/null 2>&1; then
printf " %-20s ${GREEN}✓ Active & Connected${NC}\n" "tailscaled"
else
print_info "Service tailscaled is installed but not configured."
TS_COMMAND=""
printf " %-20s ${YELLOW}⚠ Active but not connected${NC}\n" "tailscaled"
fi
fi
else
printf " %-20s ${RED}✗ INACTIVE${NC}\n" "tailscaled"
fi
fi
if [[ "$AUDIT_RAN" == true ]]; then
print_success "Security audit performed."
else
print_info "Security audit not performed."
fi
echo -e "\n${GREEN}Server setup and hardening script has finished successfully.${NC}\n"
echo
# --- Main Configuration Summary ---
echo -e "${YELLOW}Configuration Summary:${NC}"
printf " %-16s%s\n" "Admin User:" "$USERNAME"
printf " %-16s%s\n" "Hostname:" "$SERVER_NAME"
printf " %-16s%s\n" "SSH Port:" "$SSH_PORT"
printf " %-16s%s\n" "Server IP:" "$SERVER_IP"
printf " %-20s%s\n" "Admin User:" "$USERNAME"
printf " %-20s%s\n" "Hostname:" "$SERVER_NAME"
printf " %-20s%s\n" "SSH Port:" "$SSH_PORT"
printf " %-20s%s\n" "Server IP:" "$SERVER_IP"
# --- Kernel Hardening Status ---
if [[ -f /etc/sysctl.d/99-du-hardening.conf ]]; then
printf " %-20s${GREEN}Applied${NC}\n" "Kernel Hardening:"
else
printf " %-20s${YELLOW}Not Applied${NC}\n" "Kernel Hardening:"
fi
# --- Backup Configuration Summary ---
if [[ -f /root/run_backup.sh ]]; then
local CRON_SCHEDULE=$(crontab -u root -l 2>/dev/null | grep -F "/root/run_backup.sh" | awk '{print $1, $2, $3, $4, $5}' || echo "Not configured")
local NOTIFICATION_STATUS="None"
@@ -2128,82 +2214,84 @@ generate_summary() {
elif grep -q "DISCORD_WEBHOOK=" /root/run_backup.sh && ! grep -q 'DISCORD_WEBHOOK=""' /root/run_backup.sh; then
NOTIFICATION_STATUS="Discord"
fi
echo -e " Remote Backup: ${GREEN}Enabled${NC}"
printf " %-16s%s\n" "- Backup Script:" "/root/run_backup.sh"
printf " %-16s%s\n" "- Destination:" "$BACKUP_DEST"
printf " %-16s%s\n" "- SSH Port:" "$BACKUP_PORT"
printf " %-16s%s\n" "- Remote Path:" "$REMOTE_BACKUP_PATH"
printf " %-16s%s\n" "- Cron Schedule:" "$CRON_SCHEDULE"
printf " %-16s%s\n" "- Notifications:" "$NOTIFICATION_STATUS"
echo -e " Remote Backup: ${GREEN}Enabled${NC}"
printf " %-17s%s\n" "- Backup Script:" "/root/run_backup.sh"
printf " %-17s%s\n" "- Destination:" "$BACKUP_DEST"
printf " %-17s%s\n" "- SSH Port:" "$BACKUP_PORT"
printf " %-17s%s\n" "- Remote Path:" "$REMOTE_BACKUP_PATH"
printf " %-17s%s\n" "- Cron Schedule:" "$CRON_SCHEDULE"
printf " %-17s%s\n" "- Notifications:" "$NOTIFICATION_STATUS"
if [[ -f "$BACKUP_LOG" ]] && grep -q "Test backup successful" "$BACKUP_LOG" 2>/dev/null; then
printf " %-16s%s\n" "- Test Status:" "${GREEN}Successful${NC}"
printf " %-17s%s\n" "- Test Status:" "${GREEN}Successful${NC}"
elif [[ -f "$BACKUP_LOG" ]]; then
printf " %-16s%s\n" "- Test Status:" "Failed (check $BACKUP_LOG)"
printf " %-17s%s\n" "- Test Status:" "Failed (check $BACKUP_LOG)"
else
printf " %-16s%s\n" "- Test Status:" "Not run"
printf " %-17s%s\n" "- Test Status:" "Not run"
fi
else
echo -e " Remote Backup: ${RED}Not configured${NC}"
echo -e " Remote Backup: ${RED}Not configured${NC}"
fi
# --- Tailscale Summary ---
if command -v tailscale >/dev/null 2>&1; then
local TS_CONFIGURED=false
if [[ -f /tmp/tailscale_ips.txt ]] && grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' /tmp/tailscale_ips.txt 2>/dev/null; then
TS_CONFIGURED=true
fi
if $TS_CONFIGURED; then
local TS_SERVER=$(cat /tmp/tailscale_server 2>/dev/null || echo "https://controlplane.tailscale.com")
local TS_IPS_RAW=$(cat /tmp/tailscale_ips.txt 2>/dev/null || echo "Not connected")
local TS_IPS=$(echo "$TS_IPS_RAW" | paste -sd ", " -)
local TS_FLAGS=$(cat /tmp/tailscale_flags 2>/dev/null || echo "None")
echo -e " Tailscale: ${GREEN}Configured and connected${NC}"
local TS_CONFIGURED=false
if [[ -f /tmp/tailscale_ips.txt ]] && grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' /tmp/tailscale_ips.txt 2>/dev/null; then
TS_CONFIGURED=true
fi
if $TS_CONFIGURED; then
local TS_SERVER=$(cat /tmp/tailscale_server 2>/dev/null || echo "https://controlplane.tailscale.com")
local TS_IPS_RAW=$(cat /tmp/tailscale_ips.txt 2>/dev/null || echo "Not connected")
local TS_IPS=$(echo "$TS_IPS_RAW" | paste -sd ", " -)
local TS_FLAGS=$(cat /tmp/tailscale_flags 2>/dev/null || echo "None")
echo -e " Tailscale: ${GREEN}Configured and connected${NC}"
printf " %-17s%s\n" "- Server:" "${TS_SERVER:-Not set}"
printf " %-17s%s\n" "- Tailscale IPs:" "${TS_IPS:-Not connected}"
printf " %-17s%s\n" "- Flags:" "${TS_FLAGS:-None}"
else
echo -e " Tailscale: ${YELLOW}Installed but not configured${NC}"
fi
else
echo -e " Tailscale: ${YELLOW}Installed but not configured${NC}"
print_info "You can configure Tailscale later by running: sudo tailscale up"
print_info "For custom servers, use: sudo tailscale up --login-server=<your_server_url>"
fi
printf " %-16s%s\n" "- Server:" "${TS_SERVER:-Not set}"
printf " %-16s%s\n" "- Tailscale IPs:" "${TS_IPS:-Not connected}"
printf " %-16s%s\n" "- Flags:" "${TS_FLAGS:-None}"
else
echo -e " Tailscale: ${RED}Not installed${NC}"
echo -e " Tailscale: ${RED}Not installed${NC}"
fi
# --- Security Audit Summary ---
if [[ "$AUDIT_RAN" == true ]]; then
echo -e " Security Audit: ${GREEN}Performed${NC}"
printf " %-16s%s\n" "- Audit Log:" "$AUDIT_LOG"
printf " %-16s%s\n" "- Hardening Index:" "${HARDENING_INDEX:-Unknown}"
printf " %-16s%s\n" "- Vulnerabilities:" "$DEBSECAN_VULNS"
echo -e " Security Audit: ${GREEN}Performed${NC}"
printf " %-17s%s\n" "- Audit Log:" "$AUDIT_LOG"
printf " %-17s%s\n" "- Hardening Index:" "${HARDENING_INDEX:-Unknown}"
printf " %-17s%s\n" "- Vulnerabilities:" "$DEBSECAN_VULNS"
else
echo -e " Security Audit: ${RED}Not run${NC}"
echo -e " Security Audit: ${RED}Not run${NC}"
fi
echo
printf "${PURPLE}%-16s%s${NC}\n" "Log File:" "$LOG_FILE"
printf "${PURPLE}%-16s%s${NC}\n" "Backups:" "$BACKUP_DIR"
echo
# --- Post-Reboot Verification ---
echo -e "${YELLOW}Post-Reboot Verification Steps:${NC}"
printf " %-20s${CYAN}%s${NC}\n" "- SSH access:" "ssh -p $SSH_PORT $USERNAME@$SERVER_IP"
printf " %-20s${CYAN}%s${NC}\n" "- Firewall rules:" "sudo ufw status verbose"
printf " %-20s${CYAN}%s${NC}\n" "- Time sync:" "chronyc tracking"
printf " %-20s${CYAN}%s${NC}\n" "- Fail2Ban ssh jail status:" "sudo fail2ban-client status sshd"
printf " %-20s${CYAN}%s${NC}\n" "- Fail2Ban ufw jail status:" "sudo fail2ban-client status ufw-probes"
printf " %-20s${CYAN}%s${NC}\n" "- Swap status:" "sudo swapon --show && free -h"
printf " %-20s${CYAN}%s${NC}\n" "- Hostname:" "hostnamectl"
printf " %-25s ${CYAN}%s${NC}\n" "- SSH access:" "ssh -p $SSH_PORT $USERNAME@$SERVER_IP"
printf " %-25s ${CYAN}%s${NC}\n" "- Firewall rules:" "sudo ufw status verbose"
printf " %-25s ${CYAN}%s${NC}\n" "- Time sync:" "chronyc tracking"
printf " %-25s ${CYAN}%s${NC}\n" "- Fail2Ban sshd jail:" "sudo fail2ban-client status sshd"
printf " %-25s ${CYAN}%s${NC}\n" "- Fail2Ban ufw jail:" "sudo fail2ban-client status ufw-probes"
printf " %-25s ${CYAN}%s${NC}\n" "- Swap status:" "sudo swapon --show && free -h"
printf " %-25s ${CYAN}%s${NC}\n" "- Kernel settings:" "sudo sysctl -a | grep 'du-hardening'"
if command -v docker >/dev/null 2>&1; then
printf " %-20s${CYAN}%s${NC}\n" "- Docker status:" "docker ps"
printf " %-25s ${CYAN}%s${NC}\n" "- Docker status:" "docker ps"
fi
if command -v tailscale >/dev/null 2>&1; then
printf " %-20s${CYAN}%s${NC}\n" "- Tailscale status:" "tailscale status"
printf " %-25s ${CYAN}%s${NC}\n" "- Tailscale status:" "tailscale status"
fi
if [[ -f /root/run_backup.sh ]]; then
echo -e " Remote Backup:"
printf " %-18s${CYAN}%s${NC}\n" "- Verify SSH key:" "sudo cat /root/.ssh/id_ed25519.pub"
printf " %-18s${CYAN}%s${NC}\n" "- Copy key if needed:" "ssh-copy-id -p $BACKUP_PORT -s $BACKUP_DEST"
printf " %-18s${CYAN}%s${NC}\n" "- Test backup:" "sudo /root/run_backup.sh"
printf " %-18s${CYAN}%s${NC}\n" "- Check logs:" "sudo less $BACKUP_LOG"
printf " %-23s ${CYAN}%s${NC}\n" "- Test backup:" "sudo /root/run_backup.sh"
printf " %-23s ${CYAN}%s${NC}\n" "- Check logs:" "sudo less $BACKUP_LOG"
fi
if [[ "$AUDIT_RAN" == true ]]; then
echo -e " Security Audit:"
printf " %-18s${CYAN}%s${NC}\n" "- Check results:" "sudo less $AUDIT_LOG"
printf " %-23s ${CYAN}%s${NC}\n" "- Check results:" "sudo less $AUDIT_LOG"
fi
echo
# --- Final Warnings and Actions ---
if [[ ${#FAILED_SERVICES[@]} -gt 0 ]]; then
print_warning "ACTION REQUIRED: The following services failed: ${FAILED_SERVICES[*]}. Verify with 'systemctl status <service>'."
fi
@@ -2211,10 +2299,10 @@ generate_summary() {
print_warning "ACTION REQUIRED: Tailscale connection failed. Run the following command to connect manually:"
echo -e "${CYAN} $TS_COMMAND${NC}"
fi
if [[ -f /root/run_backup.sh && "$KEY_COPY_CHOICE" == "2" ]]; then
print_warning "ACTION REQUIRED: Ensure the root SSH key (/root/.ssh/id_ed25519.pub) is copied to $BACKUP_DEST."
if [[ -f /root/run_backup.sh ]] && [[ "$KEY_COPY_CHOICE" != "1" ]]; then
print_warning "ACTION REQUIRED: Ensure the root SSH key (/root/.ssh/id_ed25519.pub) is copied to the backup destination."
fi
print_warning "ACTION REQUIRED: If remote backup is enabled, ensure the root SSH key is copied to the destination server."
print_warning "A reboot is required to apply all changes cleanly."
if [[ $VERBOSE == true ]]; then
if confirm "Reboot now?" "y"; then
@@ -2227,7 +2315,10 @@ generate_summary() {
else
print_warning "Quiet mode enabled. Please reboot manually with 'sudo reboot'."
fi
log "Script finished successfully."
) | tee -a "$REPORT_FILE"
log "Script finished successfully. Report generated at $REPORT_FILE"
}
handle_error() {
@@ -2266,6 +2357,7 @@ main() {
configure_fail2ban
configure_auto_updates
configure_time_sync
configure_kernel_hardening
install_docker
install_tailscale
setup_backup