Last active
August 15, 2025 16:21
-
-
Save amosbastian/8cc3efd809cc244b4213bfc46b5e74f3 to your computer and use it in GitHub Desktop.
Revisions
-
amosbastian revised this gist
Aug 15, 2025 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -245,7 +245,7 @@ EOF # Install Docker log "Installing Docker..." apt-get install ca-certificates curl install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc chmod a+r /etc/apt/keyrings/docker.asc @@ -256,7 +256,7 @@ echo \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ tee /etc/apt/sources.list.d/docker.list > /dev/null apt-get update apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # Add admin to docker group usermod -aG docker "$NEW_USER" -
amosbastian revised this gist
Jul 18, 2025 . 1 changed file with 42 additions and 23 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -35,7 +35,7 @@ log "Starting Hetzner server hardening for Debian 12..." # Update system and install essentials log "Updating system and installing essentials..." apt-get update && apt-get install -y fail2ban sudo ansible curl wget git vim htop unattended-upgrades ufw python3-systemd libpam-modules libpam-modules # Create admin user log "Creating user '$NEW_USER'..." @@ -61,6 +61,15 @@ else warn "No authorized_keys found in /root/.ssh/ - you'll need to add your public key manually" fi # Configure UFW before running Ansible log "Configuring UFW firewall..." ufw --force reset ufw default deny incoming ufw default allow outgoing ufw allow ssh ufw --force enable log "UFW configured and enabled with default deny policy" # Install DevSec hardening collection log "Installing DevSec hardening collection..." ansible-galaxy collection install devsec.hardening @@ -77,7 +86,7 @@ cat > hardening_playbook.yml << 'EOF' vars: ssh_allow_users: "admin" ssh_allow_groups: "admin" # Debian 12 specific SSH configuration with PAM enabled ssh_server_ports: ['22'] ssh_use_pam: true ssh_challenge_response_authentication: false @@ -90,21 +99,28 @@ cat > hardening_playbook.yml << 'EOF' ssh_use_dns: false ssh_permit_tunnel: "no" ssh_print_motd: false ssh_password_authentication: false ssh_permit_root_login: "no" ssh_permit_empty_passwords: false # Aggressive fail2ban configuration for better protection fail2ban_jail_local: | [DEFAULT] # Debian 12 uses systemd journal by default backend = systemd # Aggressive mode settings bantime = 86400 findtime = 300 maxretry = 2 [sshd] enabled = true port = {{ ssh_server_ports | first | default('22') }} filter = sshd backend = systemd maxretry = 2 findtime = 300 bantime = 86400 ignoreip = 127.0.0.1/8 ::1 pre_tasks: @@ -120,6 +136,7 @@ cat > hardening_playbook.yml << 'EOF' - ufw - unattended-upgrades - apt-listchanges - libpam-modules state: present - name: Ensure fail2ban directories exist @@ -138,7 +155,16 @@ cat > hardening_playbook.yml << 'EOF' - devsec.hardening.ssh_hardening tasks: - name: Ensure SSH uses PAM lineinfile: path: /etc/ssh/sshd_config regexp: '^#?UsePAM' line: 'UsePAM yes' backup: yes notify: - Restart SSH - name: Configure Fail2Ban with aggressive settings copy: dest: /etc/fail2ban/jail.local content: "{{ fail2ban_jail_local }}" @@ -162,21 +188,7 @@ cat > hardening_playbook.yml << 'EOF' enabled: yes daemon_reload: yes - name: Verify UFW is enabled and configured ufw: state: enabled @@ -223,6 +235,12 @@ cat > hardening_playbook.yml << 'EOF' name: fail2ban state: restarted daemon_reload: yes - name: Restart SSH systemd: name: ssh state: restarted daemon_reload: yes EOF # Install Docker @@ -251,7 +269,8 @@ ansible-playbook hardening_playbook.yml log "Checking services status..." systemctl status ssh --no-pager systemctl status fail2ban --no-pager ufw status verbose log "Server hardening completed successfully!" warn "IMPORTANT: Test SSH connection as '$NEW_USER' user before logging out!" log "Your server is now hardened with DevSec playbook, fail2ban (aggressive mode), UFW firewall, and Docker installed." -
amosbastian revised this gist
Jul 18, 2025 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -35,7 +35,7 @@ log "Starting Hetzner server hardening for Debian 12..." # Update system and install essentials log "Updating system and installing essentials..." apt-get update && apt-get install -y fail2ban sudo ansible curl wget git vim htop unattended-upgrades ufw python3-systemd # Create admin user log "Creating user '$NEW_USER'..." -
amosbastian revised this gist
Jul 18, 2025 . 1 changed file with 5 additions and 5 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -29,15 +29,15 @@ if [[ $EUID -ne 0 ]]; then error "This script must be run as root" fi NEW_USER="admin" log "Starting Hetzner server hardening for Debian 12..." # Update system and install essentials log "Updating system and installing essentials..." apt-get update && apt-get install -y fail2ban sudo ansible curl wget git vim htop unattended-upgrades ufw # Create admin user log "Creating user '$NEW_USER'..." if ! id "$NEW_USER" &>/dev/null; then useradd -m -s /bin/bash "$NEW_USER" @@ -75,8 +75,8 @@ cat > hardening_playbook.yml << 'EOF' collections: - devsec.hardening vars: ssh_allow_users: "admin" ssh_allow_groups: "admin" # Debian 12 specific SSH configuration ssh_server_ports: ['22'] ssh_use_pam: true @@ -240,7 +240,7 @@ echo \ apt-get update apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # Add admin to docker group usermod -aG docker "$NEW_USER" # Run the hardening playbook -
amosbastian revised this gist
Jul 18, 2025 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -88,7 +88,7 @@ cat > hardening_playbook.yml << 'EOF' ssh_client_alive_count_max: 3 ssh_compression: false ssh_use_dns: false ssh_permit_tunnel: "no" ssh_print_motd: false fail2ban_jail_local: | -
amosbastian revised this gist
Jul 18, 2025 . 1 changed file with 74 additions and 288 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,34 +1,26 @@ #!/bin/bash # Hetzner Server Hardening Script for Debian 12 # Run as root after SSH'ing in: ./harden.sh set -euo pipefail # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color log() { echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}" } warn() { echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: $1${NC}" } error() { echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}" exit 1 } @@ -37,114 +29,56 @@ if [[ $EUID -ne 0 ]]; then error "This script must be run as root" fi NEW_USER="amos" log "Starting Hetzner server hardening for Debian 12..." # Update system and install essentials log "Updating system and installing essentials..." apt-get update && apt-get install -y fail2ban sudo ansible curl wget git vim htop unattended-upgrades ufw # Create amos user log "Creating user '$NEW_USER'..." if ! id "$NEW_USER" &>/dev/null; then useradd -m -s /bin/bash "$NEW_USER" usermod -aG sudo "$NEW_USER" echo "$NEW_USER ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/$NEW_USER" log "User '$NEW_USER' created and added to sudo group" else log "User '$NEW_USER' already exists" fi # Copy SSH keys from root to new user log "Setting up SSH for $NEW_USER user..." mkdir -p "/home/$NEW_USER/.ssh" if [ -f /root/.ssh/authorized_keys ]; then cp /root/.ssh/authorized_keys "/home/$NEW_USER/.ssh/" chmod 700 "/home/$NEW_USER/.ssh" chmod 600 "/home/$NEW_USER/.ssh/authorized_keys" chown -R "$NEW_USER:$NEW_USER" "/home/$NEW_USER/.ssh" log "SSH keys copied from root to $NEW_USER" else warn "No authorized_keys found in /root/.ssh/ - you'll need to add your public key manually" fi # Install DevSec hardening collection log "Installing DevSec hardening collection..." ansible-galaxy collection install devsec.hardening # Create hardening playbook log "Creating hardening playbook..." cat > hardening_playbook.yml << 'EOF' --- - hosts: localhost connection: local become: yes collections: - devsec.hardening vars: ssh_allow_users: "amos" ssh_allow_groups: "amos" # Debian 12 specific SSH configuration ssh_server_ports: ['22'] ssh_use_pam: true ssh_challenge_response_authentication: false ssh_gss_api_authentication: false @@ -154,38 +88,24 @@ cat > "$PLAYBOOK_FILE" << EOF ssh_client_alive_count_max: 3 ssh_compression: false ssh_use_dns: false ssh_permit_tunnel: false ssh_print_motd: false fail2ban_jail_local: | [DEFAULT] # Debian 12 uses systemd journal by default backend = systemd [sshd] enabled = true port = {{ ssh_server_ports | first | default('22') }} filter = sshd # Debian 12 journal backend backend = systemd maxretry = 3 findtime = 600 bantime = 3600 ignoreip = 127.0.0.1/8 ::1 pre_tasks: - name: Update package cache @@ -200,11 +120,6 @@ cat > "$PLAYBOOK_FILE" << EOF - ufw - unattended-upgrades - apt-listchanges state: present - name: Ensure fail2ban directories exist @@ -223,7 +138,7 @@ cat > "$PLAYBOOK_FILE" << EOF - devsec.hardening.ssh_hardening tasks: - name: Configure Fail2Ban for SSH (Debian 12 compatible) copy: dest: /etc/fail2ban/jail.local content: "{{ fail2ban_jail_local }}" @@ -258,7 +173,7 @@ cat > "$PLAYBOOK_FILE" << EOF - name: Allow SSH through UFW ufw: rule: allow port: "{{ ssh_server_ports | first | default('22') }}" proto: tcp - name: Enable UFW @@ -270,10 +185,10 @@ cat > "$PLAYBOOK_FILE" << EOF dest: /etc/apt/apt.conf.d/50unattended-upgrades content: | Unattended-Upgrade::Allowed-Origins { "${distro_id}:${distro_codename}"; "${distro_id}:${distro_codename}-security"; "${distro_id}ESMApps:${distro_codename}-apps-security"; "${distro_id}ESM:${distro_codename}-infra-security"; }; Unattended-Upgrade::Package-Blacklist { }; @@ -282,8 +197,6 @@ cat > "$PLAYBOOK_FILE" << EOF Unattended-Upgrade::Remove-New-Unused-Dependencies "true"; Unattended-Upgrade::Remove-Unused-Dependencies "true"; Unattended-Upgrade::Automatic-Reboot "false"; owner: root group: root mode: '0644' @@ -294,70 +207,10 @@ cat > "$PLAYBOOK_FILE" << EOF content: | APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1"; owner: root group: root mode: '0644' - name: Reload SSH service systemd: name: ssh @@ -372,100 +225,33 @@ cat > "$PLAYBOOK_FILE" << EOF daemon_reload: yes EOF # Install Docker log "Installing Docker..." apt-get install -y ca-certificates curl install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc chmod a+r /etc/apt/keyrings/docker.asc # Add the repository to Apt sources: echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ tee /etc/apt/sources.list.d/docker.list > /dev/null apt-get update apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # Add amos to docker group usermod -aG docker "$NEW_USER" # Run the hardening playbook log "Running DevSec hardening playbook..." ansible-playbook hardening_playbook.yml # Check services status log "Checking services status..." systemctl status ssh --no-pager systemctl status fail2ban --no-pager log "Server hardening completed successfully!" warn "IMPORTANT: Test SSH connection as '$NEW_USER' user before logging out!" log "Your server is now hardened with DevSec playbook, fail2ban, UFW, and Docker installed." -
amosbastian revised this gist
Jul 18, 2025 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -154,9 +154,9 @@ cat > "$PLAYBOOK_FILE" << EOF ssh_client_alive_count_max: 3 ssh_compression: false ssh_use_dns: false ssh_permit_tunnel: "no" ssh_print_motd: false ssh_permit_root_login: "no" ssh_password_authentication: false ssh_permit_empty_passwords: false -
amosbastian revised this gist
Jul 18, 2025 . 1 changed file with 283 additions and 48 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -6,56 +6,145 @@ set -e # Exit on any error # Configuration NEW_USER="${1:-amos}" # Accept username as argument or default to 'amos' SSH_PORT="${2:-22}" # Accept SSH port as argument or default to 22 PLAYBOOK_FILE="hardening_playbook.yml" LOG_FILE="/var/log/server-hardening.log" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Logging function log() { echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE" } warn() { echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1" | tee -a "$LOG_FILE" } error() { echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1" | tee -a "$LOG_FILE" exit 1 } # Check if running as root if [[ $EUID -ne 0 ]]; then error "This script must be run as root" fi # Usage information if [[ "$1" == "-h" || "$1" == "--help" ]]; then echo "Usage: $0 [username] [ssh_port]" echo "Example: $0 myuser 2222" echo "Defaults: username=amos, ssh_port=22" exit 0 fi log "π Starting Hetzner server hardening setup..." log "π€ User: $NEW_USER" log "π SSH Port: $SSH_PORT" # System checks log "π Performing system checks..." if ! command -v systemctl &> /dev/null; then error "systemctl not found. This script requires systemd." fi # Check available disk space AVAILABLE_SPACE=$(df / | awk 'NR==2 {print $4}') if [[ $AVAILABLE_SPACE -lt 1000000 ]]; then # Less than 1GB warn "Low disk space detected. Consider upgrading your server." fi # Backup existing configs log "πΎ Creating configuration backup..." mkdir -p /root/backup-$(date +%Y%m%d) cp -r /etc/ssh /root/backup-$(date +%Y%m%d)/ 2>/dev/null || true cp /etc/sudoers /root/backup-$(date +%Y%m%d)/ 2>/dev/null || true # Update system and install essential packages log "π¦ Updating system and installing packages..." export DEBIAN_FRONTEND=noninteractive apt-get update -y apt-get upgrade -y apt-get install -y fail2ban sudo ansible python3-pip curl wget htop neofetch \ apt-transport-https ca-certificates software-properties-common \ vim nano git tree # Create new user log "π€ Creating user: $NEW_USER" if id "$NEW_USER" &>/dev/null; then warn "User $NEW_USER already exists, skipping creation" else useradd -m -s /bin/bash "$NEW_USER" usermod -aG sudo "$NEW_USER" echo "$NEW_USER ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/$NEW_USER" # Set up SSH for the new user log "π Setting up SSH access for $NEW_USER" mkdir -p "/home/$NEW_USER/.ssh" if [ -f "/root/.ssh/authorized_keys" ]; then cp /root/.ssh/authorized_keys "/home/$NEW_USER/.ssh/" chmod 700 "/home/$NEW_USER/.ssh" chmod 600 "/home/$NEW_USER/.ssh/authorized_keys" chown -R "$NEW_USER:$NEW_USER" "/home/$NEW_USER/.ssh" log "β SSH keys copied for $NEW_USER" else warn "No SSH keys found in /root/.ssh/authorized_keys" log "You'll need to set up SSH keys manually for $NEW_USER" fi # Create a basic bashrc with useful aliases cat > "/home/$NEW_USER/.bashrc" << 'BASHRC' # Basic bashrc with useful aliases export HISTSIZE=10000 export HISTFILESIZE=10000 export HISTCONTROL=ignoredups:erasedups alias ll='ls -alF' alias la='ls -A' alias l='ls -CF' alias grep='grep --color=auto' alias fgrep='fgrep --color=auto' alias egrep='egrep --color=auto' alias ..='cd ..' alias ...='cd ../..' alias ports='netstat -tuln' alias pscpu='ps auxf | sort -nr -k 3' alias psmem='ps auxf | sort -nr -k 4' alias logs='journalctl -f' alias sshstatus='sudo systemctl status ssh' alias f2bstatus='sudo systemctl status fail2ban' alias ufwstatus='sudo ufw status' # Show system info on login neofetch 2>/dev/null || echo "Welcome to $(hostname)!" BASHRC chown "$NEW_USER:$NEW_USER" "/home/$NEW_USER/.bashrc" fi # Install DevSec hardening collection log "π‘οΈ Installing DevSec hardening collection..." ansible-galaxy collection install devsec.hardening --force # Create the hardening playbook log "π Creating Ansible playbook..." cat > "$PLAYBOOK_FILE" << EOF --- - hosts: localhost connection: local become: yes collections: - devsec.hardening vars: ssh_allow_users: "$NEW_USER" ssh_allow_groups: "$NEW_USER" ssh_server_ports: ['$SSH_PORT'] ssh_use_pam: true ssh_challenge_response_authentication: false ssh_gss_api_authentication: false @@ -67,20 +156,36 @@ cat > "$PLAYBOOK_FILE" << 'EOF' ssh_use_dns: false ssh_permit_tunnel: false ssh_print_motd: false ssh_permit_root_login: false ssh_password_authentication: false ssh_permit_empty_passwords: false # OS hardening variables os_auditd_enabled: true os_auditd_max_log_file_action: rotate fail2ban_jail_local: | [DEFAULT] backend = systemd bantime = 3600 findtime = 600 maxretry = 3 ignoreip = 127.0.0.1/8 ::1 [sshd] enabled = true port = $SSH_PORT filter = sshd backend = systemd maxretry = 3 findtime = 600 bantime = 3600 [nginx-http-auth] enabled = false [nginx-limit-req] enabled = false pre_tasks: - name: Update package cache @@ -95,6 +200,11 @@ cat > "$PLAYBOOK_FILE" << 'EOF' - ufw - unattended-upgrades - apt-listchanges - logwatch - rkhunter - chkrootkit - aide - auditd state: present - name: Ensure fail2ban directories exist @@ -148,7 +258,7 @@ cat > "$PLAYBOOK_FILE" << 'EOF' - name: Allow SSH through UFW ufw: rule: allow port: "$SSH_PORT" proto: tcp - name: Enable UFW @@ -160,10 +270,10 @@ cat > "$PLAYBOOK_FILE" << 'EOF' dest: /etc/apt/apt.conf.d/50unattended-upgrades content: | Unattended-Upgrade::Allowed-Origins { "\${distro_id}:\${distro_codename}"; "\${distro_id}:\${distro_codename}-security"; "\${distro_id}ESMApps:\${distro_codename}-apps-security"; "\${distro_id}ESM:\${distro_codename}-infra-security"; }; Unattended-Upgrade::Package-Blacklist { }; @@ -172,6 +282,8 @@ cat > "$PLAYBOOK_FILE" << 'EOF' Unattended-Upgrade::Remove-New-Unused-Dependencies "true"; Unattended-Upgrade::Remove-Unused-Dependencies "true"; Unattended-Upgrade::Automatic-Reboot "false"; Unattended-Upgrade::Mail "root"; Unattended-Upgrade::MailOnlyOnError "true"; owner: root group: root mode: '0644' @@ -182,10 +294,70 @@ cat > "$PLAYBOOK_FILE" << 'EOF' content: | APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1"; APT::Periodic::Download-Upgradeable-Packages "1"; APT::Periodic::AutocleanInterval "7"; owner: root group: root mode: '0644' - name: Configure logwatch copy: dest: /etc/logwatch/conf/logwatch.conf content: | LogDir = /var/log TmpDir = /var/cache/logwatch MailTo = root MailFrom = logwatch@$(hostname -f) Print = No Save = /tmp/logwatch Range = yesterday Detail = Med Service = All Service = "-zz-network" Service = "-zz-sys" mailer = "/usr/sbin/sendmail -t" owner: root group: root mode: '0644' - name: Initialize AIDE database command: aideinit args: creates: /var/lib/aide/aide.db - name: Move AIDE database command: mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db args: creates: /var/lib/aide/aide.db removes: /var/lib/aide/aide.db.new - name: Create daily security check script copy: dest: /usr/local/bin/daily-security-check.sh content: | #!/bin/bash echo "=== Daily Security Check - $(date) ===" >> /var/log/security-check.log echo "--- Fail2Ban Status ---" >> /var/log/security-check.log fail2ban-client status >> /var/log/security-check.log 2>&1 echo "--- UFW Status ---" >> /var/log/security-check.log ufw status >> /var/log/security-check.log 2>&1 echo "--- Last 10 SSH logins ---" >> /var/log/security-check.log last -n 10 >> /var/log/security-check.log 2>&1 echo "--- Failed login attempts ---" >> /var/log/security-check.log grep "Failed password" /var/log/auth.log | tail -10 >> /var/log/security-check.log 2>&1 echo "=========================" >> /var/log/security-check.log owner: root group: root mode: '0755' - name: Add daily security check to cron cron: name: "Daily security check" minute: "0" hour: "2" job: "/usr/local/bin/daily-security-check.sh" user: root - name: Reload SSH service systemd: name: ssh @@ -200,37 +372,100 @@ cat > "$PLAYBOOK_FILE" << 'EOF' daemon_reload: yes EOF log "β Playbook created: $PLAYBOOK_FILE" # Run the hardening playbook log "π Running hardening playbook..." if ansible-playbook "$PLAYBOOK_FILE" | tee -a "$LOG_FILE"; then log "β Hardening playbook completed successfully" else error "β Hardening playbook failed" fi # Check service status log "π Checking service status..." systemctl is-active --quiet ssh && log "β SSH service is running" || warn "β SSH service is not running" systemctl is-active --quiet fail2ban && log "β Fail2Ban service is running" || warn "β Fail2Ban service is not running" systemctl is-active --quiet ufw && log "β UFW service is running" || warn "β UFW service is not running" # Generate connection test script log "π Creating connection test script..." cat > "/home/$NEW_USER/test-connection.sh" << TESTSCRIPT #!/bin/bash echo "Testing SSH connection to this server..." echo "Run this from your local machine:" echo "ssh -p $SSH_PORT $NEW_USER@\$(curl -s ifconfig.me)" echo "" echo "If connection fails, check:" echo "1. UFW status: sudo ufw status" echo "2. SSH service: sudo systemctl status ssh" echo "3. Fail2Ban logs: sudo journalctl -u fail2ban -f" TESTSCRIPT chmod +x "/home/$NEW_USER/test-connection.sh" chown "$NEW_USER:$NEW_USER" "/home/$NEW_USER/test-connection.sh" # Create security status script cat > "/home/$NEW_USER/security-status.sh" << SECSCRIPT #!/bin/bash echo "=== Security Status ===" echo "SSH Service:" && sudo systemctl status ssh --no-pager -l echo "" echo "Fail2Ban Status:" && sudo fail2ban-client status echo "" echo "UFW Status:" && sudo ufw status echo "" echo "Last 10 SSH connections:" && last -n 10 echo "" echo "Failed login attempts today:" && sudo grep "Failed password" /var/log/auth.log | grep "\$(date +%b\ %d)" | wc -l SECSCRIPT chmod +x "/home/$NEW_USER/security-status.sh" chown "$NEW_USER:$NEW_USER" "/home/$NEW_USER/security-status.sh" # Final security recommendations SERVER_IP=$(curl -s ifconfig.me 2>/dev/null || hostname -I | awk '{print $1}') log "" log "π Server hardening complete!" log "" log "π Summary:" log " β’ Created user: $NEW_USER" log " β’ SSH port: $SSH_PORT" log " β’ Configured SSH hardening (root login disabled)" log " β’ Enabled Fail2Ban with intrusion detection" log " β’ Configured UFW firewall" log " β’ Enabled automatic security updates" log " β’ Added system monitoring (AIDE, logwatch, auditd)" log " β’ Created daily security check script" log "" log "π Security features enabled:" log " β’ SSH key-only authentication" log " β’ Failed login monitoring" log " β’ File integrity monitoring (AIDE)" log " β’ System auditing (auditd)" log " β’ Rootkit detection (rkhunter, chkrootkit)" log " β’ Log monitoring (logwatch)" log "" log "π οΈ Useful commands for $NEW_USER:" log " β’ Check security status: ./security-status.sh" log " β’ Test SSH connection: ./test-connection.sh" log " β’ View logs: sudo journalctl -f" log " β’ Check fail2ban: sudo fail2ban-client status sshd" log " β’ Run file integrity check: sudo aide --check" log "" log "π Connection details:" log " β’ SSH command: ssh -p $SSH_PORT $NEW_USER@$SERVER_IP" log " β’ Make sure to test this connection before logging out!" log "" log "π Next steps:" log " β’ Test SSH access with new user" log " β’ Consider setting up monitoring alerts" log " β’ Review security logs regularly" log " β’ Keep system updated" log "" warn "β οΈ CRITICAL: Test SSH access as $NEW_USER before closing this session!" warn "β οΈ Root SSH login has been disabled for security" # Final connection test prompt read -p "Press Enter to continue after testing SSH connection as $NEW_USER..." log "π Server hardening setup completed successfully!" log "π Full log available at: $LOG_FILE" -
amosbastian created this gist
Jul 18, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,236 @@ #!/bin/bash # Hetzner Server Hardening Setup Script # Run this script as root after initial SSH connection set -e # Exit on any error # Configuration NEW_USER="amos" # Change this to your desired username PLAYBOOK_FILE="hardening_playbook.yml" echo "π Starting Hetzner server hardening setup..." # Update system and install essential packages echo "π¦ Updating system and installing packages..." apt-get update -y apt-get install -y fail2ban sudo ansible python3-pip # Create new user echo "π€ Creating user: $NEW_USER" if id "$NEW_USER" &>/dev/null; then echo "User $NEW_USER already exists, skipping creation" else useradd -m -s /bin/bash "$NEW_USER" usermod -aG sudo "$NEW_USER" echo "$NEW_USER ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/$NEW_USER" # Set up SSH for the new user echo "π Setting up SSH access for $NEW_USER" mkdir -p "/home/$NEW_USER/.ssh" if [ -f "/root/.ssh/authorized_keys" ]; then cp /root/.ssh/authorized_keys "/home/$NEW_USER/.ssh/" chmod 700 "/home/$NEW_USER/.ssh" chmod 600 "/home/$NEW_USER/.ssh/authorized_keys" chown -R "$NEW_USER:$NEW_USER" "/home/$NEW_USER/.ssh" echo "β SSH keys copied for $NEW_USER" else echo "β οΈ No SSH keys found in /root/.ssh/authorized_keys" fi fi # Install DevSec hardening collection echo "π‘οΈ Installing DevSec hardening collection..." ansible-galaxy collection install devsec.hardening # Create the hardening playbook echo "π Creating Ansible playbook..." cat > "$PLAYBOOK_FILE" << 'EOF' --- - hosts: localhost connection: local become: yes collections: - devsec.hardening vars: ssh_allow_users: "amos" # Change this to your username ssh_allow_groups: "amos" # Change this to your username ssh_server_ports: ['22'] ssh_use_pam: true ssh_challenge_response_authentication: false ssh_gss_api_authentication: false ssh_x11_forwarding: false ssh_max_auth_tries: 3 ssh_client_alive_interval: 600 ssh_client_alive_count_max: 3 ssh_compression: false ssh_use_dns: false ssh_permit_tunnel: false ssh_print_motd: false fail2ban_jail_local: | [DEFAULT] backend = systemd [sshd] enabled = true port = {{ ssh_server_ports | first | default('22') }} filter = sshd backend = systemd maxretry = 3 findtime = 600 bantime = 3600 ignoreip = 127.0.0.1/8 ::1 pre_tasks: - name: Update package cache apt: update_cache: yes cache_valid_time: 3600 - name: Install required packages apt: name: - fail2ban - ufw - unattended-upgrades - apt-listchanges state: present - name: Ensure fail2ban directories exist file: path: "{{ item }}" state: directory owner: root group: root mode: '0755' loop: - /etc/fail2ban - /etc/fail2ban/jail.d roles: - devsec.hardening.os_hardening - devsec.hardening.ssh_hardening tasks: - name: Configure Fail2Ban for SSH copy: dest: /etc/fail2ban/jail.local content: "{{ fail2ban_jail_local }}" owner: root group: root mode: '0644' notify: - Restart Fail2Ban - name: Enable and start Fail2Ban service systemd: name: fail2ban state: started enabled: yes daemon_reload: yes - name: Ensure SSH service is enabled and running systemd: name: ssh state: started enabled: yes daemon_reload: yes - name: Configure UFW default policies ufw: direction: "{{ item.direction }}" policy: "{{ item.policy }}" loop: - { direction: 'incoming', policy: 'deny' } - { direction: 'outgoing', policy: 'allow' } - name: Allow SSH through UFW ufw: rule: allow port: "{{ ssh_server_ports | first | default('22') }}" proto: tcp - name: Enable UFW ufw: state: enabled - name: Configure automatic security updates copy: dest: /etc/apt/apt.conf.d/50unattended-upgrades content: | Unattended-Upgrade::Allowed-Origins { "${distro_id}:${distro_codename}"; "${distro_id}:${distro_codename}-security"; "${distro_id}ESMApps:${distro_codename}-apps-security"; "${distro_id}ESM:${distro_codename}-infra-security"; }; Unattended-Upgrade::Package-Blacklist { }; Unattended-Upgrade::DevRelease "false"; Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; Unattended-Upgrade::Remove-New-Unused-Dependencies "true"; Unattended-Upgrade::Remove-Unused-Dependencies "true"; Unattended-Upgrade::Automatic-Reboot "false"; owner: root group: root mode: '0644' - name: Enable automatic updates copy: dest: /etc/apt/apt.conf.d/20auto-upgrades content: | APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1"; owner: root group: root mode: '0644' - name: Reload SSH service systemd: name: ssh state: reloaded daemon_reload: yes handlers: - name: Restart Fail2Ban systemd: name: fail2ban state: restarted daemon_reload: yes EOF # Update the playbook with the correct username sed -i "s/ssh_allow_users: \"amos\"/ssh_allow_users: \"$NEW_USER\"/" "$PLAYBOOK_FILE" sed -i "s/ssh_allow_groups: \"amos\"/ssh_allow_groups: \"$NEW_USER\"/" "$PLAYBOOK_FILE" echo "β Playbook created: $PLAYBOOK_FILE" # Run the hardening playbook echo "π Running hardening playbook..." ansible-playbook "$PLAYBOOK_FILE" # Check service status echo "π Checking service status..." systemctl status ssh --no-pager -l systemctl status fail2ban --no-pager -l systemctl status ufw --no-pager -l echo "" echo "π Server hardening complete!" echo "" echo "π Summary:" echo " β’ Created user: $NEW_USER" echo " β’ Configured SSH hardening" echo " β’ Enabled Fail2Ban" echo " β’ Configured UFW firewall" echo " β’ Enabled automatic security updates" echo "" echo "π Security recommendations:" echo " β’ Test SSH access with: ssh $NEW_USER@$(hostname -I | awk '{print $1}')" echo " β’ Disable root SSH login after confirming user access works" echo " β’ Consider changing SSH port from default 22" echo " β’ Review UFW rules: sudo ufw status" echo " β’ Monitor logs: sudo journalctl -u fail2ban -f" echo "" echo "β οΈ IMPORTANT: Test SSH access before logging out!"