From c14240d5bef0184e67bc725a8628e6ce74255174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Barbosa?= Date: Thu, 31 Jul 2025 16:56:02 +0100 Subject: [PATCH] Refactor Debian setup script to enhance security and user experience. Implement sysadmin user creation with SSH key generation, configure UFW and fail2ban, and streamline repository cloning process. --- setup.sh | 343 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 313 insertions(+), 30 deletions(-) diff --git a/setup.sh b/setup.sh index 569c30a..b7763c5 100755 --- a/setup.sh +++ b/setup.sh @@ -1,12 +1,184 @@ #!/bin/bash -set -e +# Debian 12 Initial Setup Script with Git Integration +# Run as root: bash setup.sh + +set -euo pipefail # Exit on error, undefined vars, pipe failures + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color ### === SETTINGS === ### GIT_SERVER="git.del-c.net" USERNAME="" SELECTED_REPO="" SELECTED_DIR="" +SYSADMIN_USER="sysadmin" + +# Logging functions +log() { + echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}" +} + +warn() { + echo -e "${YELLOW}[WARNING] $1${NC}" +} + +error() { + echo -e "${RED}[ERROR] $1${NC}" + exit 1 +} + +# Check if running as root +check_root() { + if [[ $EUID -ne 0 ]]; then + error "This script must be run as root" + fi +} + +# Check if running on Debian +check_debian() { + if ! grep -q "Debian" /etc/os-release; then + error "This script is designed for Debian systems" + fi +} + +### === DEBIAN SYSTEM SETUP === ### +setup_system() { + log "Starting Debian 12 initial setup..." + + # Update system packages + log "Updating system packages..." + apt update && apt upgrade -y + + # Install essential packages + log "Installing essential packages..." + apt install -y sudo ufw curl wget vim htop unzip fail2ban git openssh-server +} + +create_sysadmin_user() { + log "Creating user: $SYSADMIN_USER" + + if id "$SYSADMIN_USER" &>/dev/null; then + warn "User $SYSADMIN_USER already exists, skipping creation" + else + # Create user with home directory + useradd -m -s /bin/bash "$SYSADMIN_USER" + log "User $SYSADMIN_USER created successfully" + + # Set password for sysadmin user + echo "Please set a password for user $SYSADMIN_USER:" + passwd "$SYSADMIN_USER" + fi + + # Add sysadmin to sudo group + log "Adding $SYSADMIN_USER to sudo group..." + usermod -aG sudo "$SYSADMIN_USER" +} + +configure_security() { + # Disable root SSH login + log "Disabling root SSH login..." + sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config + sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config + + # Additional SSH hardening + log "Applying SSH security settings..." + { + echo "Protocol 2" + echo "PasswordAuthentication no" + echo "PubkeyAuthentication yes" + echo "PermitEmptyPasswords no" + echo "X11Forwarding no" + echo "MaxAuthTries 3" + echo "ClientAliveInterval 300" + echo "ClientAliveCountMax 2" + echo "AllowUsers $SYSADMIN_USER" + } >> /etc/ssh/sshd_config + + # Remove/lock root password + log "Locking root password..." + passwd -l root + + # Configure UFW (Uncomplicated Firewall) + log "Configuring UFW firewall..." + + # Reset UFW to defaults + ufw --force reset + + # Set default policies + ufw default deny incoming + ufw default allow outgoing + + # Allow SSH (port 22) + ufw allow ssh + ufw allow 22/tcp + + # Allow HTTP (port 80) + ufw allow http + ufw allow 80/tcp + + # Allow HTTPS (port 443) + ufw allow https + ufw allow 443/tcp + + # Enable UFW + ufw --force enable + + log "UFW status:" + ufw status verbose + + # Configure fail2ban for SSH protection + log "Configuring fail2ban..." + cat > /etc/fail2ban/jail.local << EOF +[DEFAULT] +bantime = 1h +findtime = 10m +maxretry = 3 + +[sshd] +enabled = true +port = ssh +filter = sshd +logpath = /var/log/auth.log +maxretry = 3 +bantime = 1h +EOF + + # Start and enable fail2ban + systemctl enable fail2ban + systemctl start fail2ban + + # Set up automatic security updates + log "Configuring automatic security updates..." + apt install -y unattended-upgrades apt-listchanges + + # Configure unattended upgrades + cat > /etc/apt/apt.conf.d/50unattended-upgrades << EOF +Unattended-Upgrade::Allowed-Origins { + "\${distro_id}:\${distro_codename}-security"; + "\${distro_id}ESMApps:\${distro_codename}-apps-security"; + "\${distro_id}ESM:\${distro_codename}-infra-security"; +}; + +Unattended-Upgrade::AutoFixInterruptedDpkg "true"; +Unattended-Upgrade::MinimalSteps "true"; +Unattended-Upgrade::Remove-Unused-Dependencies "true"; +Unattended-Upgrade::Automatic-Reboot "false"; +EOF + + # Enable automatic updates + echo 'APT::Periodic::Update-Package-Lists "1";' > /etc/apt/apt.conf.d/20auto-upgrades + echo 'APT::Periodic::Unattended-Upgrade "1";' >> /etc/apt/apt.conf.d/20auto-upgrades + + # Set timezone (optional) + log "Current timezone: $(timedatectl show --property=Timezone --value)" + echo "If you want to change timezone, run: timedatectl set-timezone Your/Timezone" +} ### === GET USERNAME === ### get_username() { @@ -20,28 +192,55 @@ get_username() { echo } -### === CHECK FOR SSH KEY === ### +### === SSH KEY GENERATION FOR SYSADMIN === ### generate_ssh_key() { - if [ ! -f "$HOME/.ssh/id_ed25519.pub" ]; then - echo "[+] No SSH key found. Need to generate a new SSH key..." - echo "[+] Are you using the correct system user?" - echo "[+] If not, please switch to the correct user and run this script again." - echo "[+] If you are using the correct user, please enter your email for the SSH key." - read -p "Enter your email for the SSH key: " user_email - ssh-keygen -t ed25519 -C "$user_email" -f "$HOME/.ssh/id_ed25519" -N "" + local sysadmin_home="/home/$SYSADMIN_USER" + local ssh_dir="$sysadmin_home/.ssh" + local ssh_key="$ssh_dir/id_ed25519" + + log "Setting up SSH key for user: $SYSADMIN_USER" + + # Create .ssh directory for sysadmin user if it doesn't exist + if [ ! -d "$ssh_dir" ]; then + sudo -u "$SYSADMIN_USER" mkdir -p "$ssh_dir" + sudo -u "$SYSADMIN_USER" chmod 700 "$ssh_dir" + fi + + if [ ! -f "$ssh_key.pub" ]; then + log "Generating SSH key for $SYSADMIN_USER..." + echo "[+] Please enter your email for the SSH key:" + read -p "Enter your email: " user_email + + # Generate SSH key as sysadmin user + sudo -u "$SYSADMIN_USER" ssh-keygen -t ed25519 -C "$user_email" -f "$ssh_key" -N "" + + # Set proper permissions + sudo -u "$SYSADMIN_USER" chmod 600 "$ssh_key" + sudo -u "$SYSADMIN_USER" chmod 644 "$ssh_key.pub" + + log "SSH key generated successfully for $SYSADMIN_USER" else - echo "[~] SSH key already exists." + warn "SSH key already exists for $SYSADMIN_USER" fi } show_ssh_key() { - echo "[*] Add the following public key to your GitHub account:" + local sysadmin_home="/home/$SYSADMIN_USER" + local ssh_key="$sysadmin_home/.ssh/id_ed25519.pub" + + echo "" + echo -e "${BLUE}=== SSH PUBLIC KEY ===${NC}" + echo "Add the following public key to your Git server and any other systems:" echo "----------------------------------------" - cat "$HOME/.ssh/id_ed25519.pub" + cat "$ssh_key" echo "----------------------------------------" - echo "[*] Go to your git site and add the key to your account." - echo - read -p "Press Enter after you've added the key..." + echo "" + echo -e "${YELLOW}Instructions:${NC}" + echo "1. Copy the key above" + echo "2. Go to your git server ($GIT_SERVER) and add it to your account" + echo "3. Add it to any other systems you need SSH access to" + echo "" + read -p "Press Enter after you've added the key to continue..." } ### === LIST AVAILABLE GIT PROJECTS === ### @@ -218,33 +417,117 @@ select_project() { ### === CLONE SELECTED REPO === ### clone_selected_repo() { + local sysadmin_home="/home/$SYSADMIN_USER" + + # Update selected directory to be relative to sysadmin user's home + if [[ "$SELECTED_DIR" == "$HOME/"* ]]; then + SELECTED_DIR="${SELECTED_DIR/$HOME/$sysadmin_home}" + fi + if [ ! -d "$SELECTED_DIR" ]; then - echo "[+] Cloning selected repository..." - git clone "$SELECTED_REPO" "$SELECTED_DIR" + log "Cloning selected repository as $SYSADMIN_USER..." + sudo -u "$SYSADMIN_USER" git clone "$SELECTED_REPO" "$SELECTED_DIR" else - echo "[~] Repository already cloned. Force pulling from remote (overwriting local changes)..." + warn "Repository already cloned. Force pulling from remote (overwriting local changes)..." cd "$SELECTED_DIR" - git fetch origin - git reset --hard origin/$(git symbolic-ref --short HEAD) - git clean -fd + sudo -u "$SYSADMIN_USER" git fetch origin + sudo -u "$SYSADMIN_USER" git reset --hard origin/$(sudo -u "$SYSADMIN_USER" git symbolic-ref --short HEAD) + sudo -u "$SYSADMIN_USER" git clean -fd fi # Only run setup if it's the dotfiles repository if [[ "$SELECTED_REPO" == *"dotfiles.git" && -f "$SELECTED_DIR/setup.sh" ]]; then - echo "[+] Launching dotfiles setup using Bash..." - bash "$SELECTED_DIR/setup.sh" + log "Launching dotfiles setup as $SYSADMIN_USER..." + sudo -u "$SYSADMIN_USER" bash "$SELECTED_DIR/setup.sh" else - echo "[*] Repository cloned successfully to: $SELECTED_DIR" + log "Repository cloned successfully to: $SELECTED_DIR" + log "Repository is owned by: $SYSADMIN_USER" fi } +### === CLEANUP AND FINALIZATION === ### +finalize_setup() { + # Restart SSH service + log "Restarting SSH service..." + systemctl restart sshd + + # Clean up + log "Cleaning up..." + apt autoremove -y + apt autoclean + + # Final security check + log "Final system status:" + echo "================================" + echo "UFW Status:" + ufw status + echo "================================" + echo "SSH Configuration:" + grep -E "PermitRootLogin|PasswordAuthentication|PubkeyAuthentication|AllowUsers" /etc/ssh/sshd_config + echo "================================" + echo "Sudo users:" + grep -E "sudo|wheel" /etc/group + echo "================================" + + log "Setup completed successfully!" + echo "" + echo -e "${BLUE}=== IMPORTANT NOTES ===${NC}" + echo -e "${YELLOW}1. Root SSH login is now DISABLED${NC}" + echo -e "${YELLOW}2. Root password is LOCKED${NC}" + echo -e "${YELLOW}3. SSH password authentication is DISABLED${NC}" + echo -e "${YELLOW}4. Use '$SYSADMIN_USER' user with SSH key to connect${NC}" + echo -e "${YELLOW}5. UFW firewall is active (SSH, HTTP, HTTPS allowed)${NC}" + echo -e "${YELLOW}6. Fail2ban is protecting SSH${NC}" + echo -e "${YELLOW}7. Automatic security updates are enabled${NC}" + echo "" + echo -e "${RED}REBOOT RECOMMENDED${NC}" + echo "" + echo "To connect: ssh $SYSADMIN_USER@$(hostname -I | awk '{print $1}')" +} + ### === MAIN === ### main() { - get_username - generate_ssh_key - show_ssh_key - select_project - clone_selected_repo + # Check prerequisites + check_root + check_debian + + echo -e "${BLUE}=== Debian 12 Initial Setup with Git Integration ===${NC}" + echo "This script will:" + echo "1. Set up a secure Debian 12 system" + echo "2. Create a sysadmin user with SSH key authentication" + echo "3. Optionally clone a git repository" + echo "" + read -p "Continue? (y/N): " confirm + + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "Setup cancelled." + exit 0 + fi + + # System setup + setup_system + create_sysadmin_user + configure_security + + # SSH key setup + generate_ssh_key + show_ssh_key + + # Optional git repository setup + echo "" + echo -e "${BLUE}=== Optional Git Repository Setup ===${NC}" + read -p "Would you like to clone a git repository? (y/N): " git_setup + + if [[ "$git_setup" =~ ^[Yy]$ ]]; then + get_username + select_project + clone_selected_repo + else + log "Skipping git repository setup" + fi + + # Finalize + finalize_setup } -main +main "$@"