diff --git a/setup.sh b/setup.sh index b7763c5..940c1ff 100755 --- a/setup.sh +++ b/setup.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Debian 12 Initial Setup Script with Git Integration +# Debian 12 Initial Setup Script # Run as root: bash setup.sh set -euo pipefail # Exit on error, undefined vars, pipe failures @@ -13,11 +13,9 @@ BLUE='\033[0;34m' NC='\033[0m' # No Color ### === SETTINGS === ### -GIT_SERVER="git.del-c.net" -USERNAME="" -SELECTED_REPO="" -SELECTED_DIR="" SYSADMIN_USER="sysadmin" +USE_UFW="" +USE_FAIL2BAN="" # Logging functions log() { @@ -47,6 +45,46 @@ check_debian() { fi } +# Ask user about firewall preferences +ask_firewall_preferences() { + echo "" + echo -e "${BLUE}=== Firewall Configuration ===${NC}" + echo "This script can configure UFW (Uncomplicated Firewall) or you can manage iptables manually." + echo "" + echo -e "${YELLOW}UFW vs iptables:${NC}" + echo "• UFW: Easy to use, good for basic setups" + echo "• Manual iptables: More control, better for complex setups (VPN servers, etc.)" + echo "" + read -p "Would you like to install and configure UFW? (y/N): " ufw_choice + + if [[ "$ufw_choice" =~ ^[Yy]$ ]]; then + USE_UFW="yes" + log "UFW will be installed and configured" + else + USE_UFW="no" + log "UFW will be skipped - you can configure iptables manually" + fi + + echo "" + echo -e "${BLUE}=== Fail2ban Configuration ===${NC}" + echo "Fail2ban protects against brute-force attacks by monitoring logs and banning IPs." + echo "" + echo -e "${YELLOW}Consider skipping fail2ban if:${NC}" + echo "• You're running a VPN server (WireGuard, OpenVPN, etc.)" + echo "• You have complex iptables rules" + echo "• You prefer managing IP banning manually" + echo "" + read -p "Would you like to install and configure fail2ban? (Y/n): " fail2ban_choice + + if [[ "$fail2ban_choice" =~ ^[Nn]$ ]]; then + USE_FAIL2BAN="no" + log "Fail2ban will be skipped" + else + USE_FAIL2BAN="yes" + log "Fail2ban will be installed and configured" + fi +} + ### === DEBIAN SYSTEM SETUP === ### setup_system() { log "Starting Debian 12 initial setup..." @@ -57,7 +95,20 @@ setup_system() { # Install essential packages log "Installing essential packages..." - apt install -y sudo ufw curl wget vim htop unzip fail2ban git openssh-server + + # Build package list based on user preferences + local packages="sudo curl wget vim htop unzip git openssh-server" + + if [[ "$USE_UFW" == "yes" ]]; then + packages="$packages ufw" + fi + + if [[ "$USE_FAIL2BAN" == "yes" ]]; then + packages="$packages fail2ban" + fi + + log "Installing packages: $packages" + apt install -y $packages } create_sysadmin_user() { @@ -104,54 +155,17 @@ configure_security() { log "Locking root password..." passwd -l root - # Configure UFW (Uncomplicated Firewall) - log "Configuring UFW firewall..." + # Configure firewall based on user choice + if [[ "$USE_UFW" == "yes" ]]; then + configure_ufw + else + configure_basic_iptables + fi - # 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 + # Configure fail2ban if requested + if [[ "$USE_FAIL2BAN" == "yes" ]]; then + configure_fail2ban + fi # Set up automatic security updates log "Configuring automatic security updates..." @@ -180,20 +194,131 @@ EOF echo "If you want to change timezone, run: timedatectl set-timezone Your/Timezone" } -### === GET USERNAME === ### -get_username() { - echo "[?] Enter your git username:" - read -p "Username: " USERNAME - if [ -z "$USERNAME" ]; then - echo "[!] Username cannot be empty. Please try again." - get_username - fi - echo "[*] Using username: $USERNAME" - echo +configure_ufw() { + 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 } -### === SSH KEY GENERATION FOR SYSADMIN === ### -generate_ssh_key() { +configure_basic_iptables() { + log "Setting up basic iptables rules..." + + # Create a simple script for basic iptables rules + cat > /etc/iptables-basic.sh << 'EOF' +#!/bin/bash +# Basic iptables rules for SSH, HTTP, HTTPS + +# Flush existing rules +iptables -F +iptables -X +iptables -t nat -F +iptables -t nat -X +iptables -t mangle -F +iptables -t mangle -X + +# Set default policies +iptables -P INPUT DROP +iptables -P FORWARD DROP +iptables -P OUTPUT ACCEPT + +# Allow loopback +iptables -A INPUT -i lo -j ACCEPT +iptables -A OUTPUT -o lo -j ACCEPT + +# Allow established and related connections +iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT + +# Allow SSH (port 22) +iptables -A INPUT -p tcp --dport 22 -j ACCEPT + +# Allow HTTP (port 80) +iptables -A INPUT -p tcp --dport 80 -j ACCEPT + +# Allow HTTPS (port 443) +iptables -A INPUT -p tcp --dport 443 -j ACCEPT + +# Save rules +iptables-save > /etc/iptables/rules.v4 +EOF + + chmod +x /etc/iptables-basic.sh + + # Create iptables directory if it doesn't exist + mkdir -p /etc/iptables + + # Run the basic rules script + /etc/iptables-basic.sh + + # Install iptables-persistent to make rules persistent + apt install -y iptables-persistent + + log "Basic iptables rules applied and saved" + warn "You can customize /etc/iptables-basic.sh and run it to update rules" + warn "Current rules are saved in /etc/iptables/rules.v4" +} + +configure_fail2ban() { + 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 + + log "Fail2ban configured and started" +} + + +### === SSH KEY GENERATION === ### +generate_ssh_keys() { + echo "[+] Please enter your email for the SSH keys:" + read -p "Enter your email: " user_email + + # Generate SSH key for sysadmin user + generate_sysadmin_ssh_key "$user_email" + + # Generate SSH key for root user + generate_root_ssh_key "$user_email" +} + +generate_sysadmin_ssh_key() { + local user_email="$1" local sysadmin_home="/home/$SYSADMIN_USER" local ssh_dir="$sysadmin_home/.ssh" local ssh_key="$ssh_dir/id_ed25519" @@ -208,8 +333,6 @@ generate_ssh_key() { 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 "" @@ -224,226 +347,65 @@ generate_ssh_key() { fi } -show_ssh_key() { +generate_root_ssh_key() { + local user_email="$1" + local root_ssh_dir="/root/.ssh" + local root_ssh_key="$root_ssh_dir/id_ed25519" + + log "Setting up SSH key for root user" + + # Create .ssh directory for root if it doesn't exist + if [ ! -d "$root_ssh_dir" ]; then + mkdir -p "$root_ssh_dir" + chmod 700 "$root_ssh_dir" + fi + + if [ ! -f "$root_ssh_key.pub" ]; then + log "Generating SSH key for root..." + + # Generate SSH key as root + ssh-keygen -t ed25519 -C "$user_email" -f "$root_ssh_key" -N "" + + # Set proper permissions + chmod 600 "$root_ssh_key" + chmod 644 "$root_ssh_key.pub" + + log "SSH key generated successfully for root" + else + warn "SSH key already exists for root" + fi +} + +show_ssh_keys() { local sysadmin_home="/home/$SYSADMIN_USER" - local ssh_key="$sysadmin_home/.ssh/id_ed25519.pub" + local sysadmin_ssh_key="$sysadmin_home/.ssh/id_ed25519.pub" + local root_ssh_key="/root/.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 -e "${BLUE}=== SSH PUBLIC KEYS ===${NC}" + echo "Add the following public keys to your Git server and any other systems:" + echo "" + + echo -e "${YELLOW}SYSADMIN USER ($SYSADMIN_USER) SSH KEY:${NC}" echo "----------------------------------------" - cat "$ssh_key" + cat "$sysadmin_ssh_key" echo "----------------------------------------" echo "" + + echo -e "${YELLOW}ROOT USER SSH KEY:${NC}" + echo "----------------------------------------" + cat "$root_ssh_key" + echo "----------------------------------------" + 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 "1. Copy both keys above" + echo "2. Add both keys to your git server and any other systems you need access to" + echo "3. You can now use these keys for SSH authentication" echo "" - read -p "Press Enter after you've added the key to continue..." + read -p "Press Enter to continue..." } -### === LIST AVAILABLE GIT PROJECTS === ### -list_git_projects() { - echo "[+] Fetching all accessible git projects..." - - local repo_count=1 - local found_repos=() - - # Try to use git server API if available (GitLab/Gitea style) - if command -v curl &> /dev/null; then - echo "[*] Attempting to fetch repositories via API..." - - # Try GitLab API format - local gitlab_repos=$(curl -s -H "Authorization: Bearer $(ssh-add -L 2>/dev/null || echo '')" \ - "https://$GIT_SERVER/api/v4/projects?membership=true&per_page=100" 2>/dev/null | \ - grep -o '"path_with_namespace":"[^"]*' | cut -d'"' -f4 2>/dev/null || echo "") - - # Try Gitea API format - if [ -z "$gitlab_repos" ]; then - local gitea_repos=$(curl -s "https://$GIT_SERVER/api/v1/user/repos" 2>/dev/null | \ - grep -o '"full_name":"[^"]*' | cut -d'"' -f4 2>/dev/null || echo "") - gitlab_repos="$gitea_repos" - fi - - if [ -n "$gitlab_repos" ]; then - echo "[*] Found repositories via API:" - while IFS= read -r repo; do - if [ -n "$repo" ]; then - echo "$repo_count. $repo" - found_repos+=("$repo") - ((repo_count++)) - fi - done <<< "$gitlab_repos" - fi - fi - - # Fallback: Check common patterns for multiple users and the current user - if [ ${#found_repos[@]} -eq 0 ]; then - echo "[*] API not available, scanning common repository patterns..." - - # Check user's own repositories first - for repo in "dotfiles" "scripts" "configs" "tools" "projects" "notes" "backup" "workspace"; do - local full_repo="$USERNAME/$repo" - if git ls-remote "git@$GIT_SERVER:$full_repo.git" &>/dev/null; then - echo "$repo_count. $full_repo (owner)" - found_repos+=("$full_repo") - ((repo_count++)) - fi - done - - # Check common shared repositories and other users' public repos - local common_users=("admin" "shared" "public" "team" "common" "devops" "infrastructure") - local common_repos=("dotfiles" "scripts" "configs" "tools" "projects" "notes" "backup" "workspace" "templates" "shared-configs" "common-tools") - - for user in "${common_users[@]}"; do - for repo in "${common_repos[@]}"; do - local full_repo="$user/$repo" - if [ "$user" != "$USERNAME" ] && git ls-remote "git@$GIT_SERVER:$full_repo.git" &>/dev/null; then - echo "$repo_count. $full_repo (shared)" - found_repos+=("$full_repo") - ((repo_count++)) - fi - done - done - - # Try to discover repositories by checking SSH access to common paths - echo "[*] Checking for additional accessible repositories..." - - # This is a more aggressive approach - try common project names - local project_names=("website" "api" "frontend" "backend" "database" "monitoring" "deployment" "ci-cd" "documentation") - for user in "${common_users[@]}" "$USERNAME"; do - for project in "${project_names[@]}"; do - local full_repo="$user/$project" - if git ls-remote "git@$GIT_SERVER:$full_repo.git" &>/dev/null 2>&1; then - # Check if we haven't already added this repo - local already_added=false - for existing_repo in "${found_repos[@]}"; do - if [ "$existing_repo" = "$full_repo" ]; then - already_added=true - break - fi - done - - if [ "$already_added" = false ]; then - local access_type="shared" - if [ "$user" = "$USERNAME" ]; then - access_type="owner" - fi - echo "$repo_count. $full_repo ($access_type)" - found_repos+=("$full_repo") - ((repo_count++)) - fi - fi - done - done - fi - - if [ ${#found_repos[@]} -eq 0 ]; then - echo "[!] No accessible repositories found" - echo "[*] You can still enter a custom repository path." - else - echo - echo "[*] Found ${#found_repos[@]} accessible repositories" - fi - - echo -} - -### === SELECT PROJECT TO DOWNLOAD === ### -select_project() { - list_git_projects - - echo "[?] Which project would you like to download?" - echo "Enter the number of the repository from the list above, or:" - echo "- Press Enter to use $USERNAME/dotfiles (if available)" - echo "- Type 'custom' to enter a custom repository path" - echo - - read -p "Enter your choice: " choice - - if [ -z "$choice" ]; then - # Default to dotfiles if it exists - if git ls-remote "git@$GIT_SERVER:$USERNAME/dotfiles.git" &>/dev/null; then - SELECTED_REPO="git@$GIT_SERVER:$USERNAME/dotfiles.git" - SELECTED_DIR="$HOME/.dotfiles" - else - echo "[!] $USERNAME/dotfiles not found. Please select a repository." - select_project - return - fi - elif [ "$choice" = "custom" ]; then - read -p "Enter repository path (e.g., $USERNAME/myproject): " custom_repo - SELECTED_REPO="git@$GIT_SERVER:$custom_repo.git" - SELECTED_DIR="$HOME/$(basename $custom_repo)" - elif [[ "$choice" =~ ^[0-9]+$ ]]; then - # User selected a number from the list - local repo_count=1 - local selected_repo="" - - for repo in "dotfiles" "scripts" "configs" "tools" "projects" "notes" "backup" "workspace"; do - local full_repo="$USERNAME/$repo" - if git ls-remote "git@$GIT_SERVER:$full_repo.git" &>/dev/null; then - if [ "$repo_count" -eq "$choice" ]; then - selected_repo="$full_repo" - break - fi - ((repo_count++)) - fi - done - - if [ -n "$selected_repo" ]; then - SELECTED_REPO="git@$GIT_SERVER:$selected_repo.git" - if [ "$(basename $selected_repo)" = "dotfiles" ]; then - SELECTED_DIR="$HOME/.dotfiles" - else - SELECTED_DIR="$HOME/$(basename $selected_repo)" - fi - else - echo "[!] Invalid choice. Please try again." - select_project - return - fi - else - echo "[!] Invalid choice. Please try again." - select_project - return - fi - - echo "[*] Selected repository: $SELECTED_REPO" - echo "[*] Download directory: $SELECTED_DIR" - echo -} - -### === 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 - log "Cloning selected repository as $SYSADMIN_USER..." - sudo -u "$SYSADMIN_USER" git clone "$SELECTED_REPO" "$SELECTED_DIR" - else - warn "Repository already cloned. Force pulling from remote (overwriting local changes)..." - cd "$SELECTED_DIR" - 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 - log "Launching dotfiles setup as $SYSADMIN_USER..." - sudo -u "$SYSADMIN_USER" bash "$SELECTED_DIR/setup.sh" - else - log "Repository cloned successfully to: $SELECTED_DIR" - log "Repository is owned by: $SYSADMIN_USER" - fi -} ### === CLEANUP AND FINALIZATION === ### finalize_setup() { @@ -459,12 +421,26 @@ finalize_setup() { # Final security check log "Final system status:" echo "================================" - echo "UFW Status:" - ufw status + + if [[ "$USE_UFW" == "yes" ]]; then + echo "UFW Status:" + ufw status + else + echo "Iptables Status:" + iptables -L -n | head -20 + fi + echo "================================" echo "SSH Configuration:" grep -E "PermitRootLogin|PasswordAuthentication|PubkeyAuthentication|AllowUsers" /etc/ssh/sshd_config echo "================================" + + if [[ "$USE_FAIL2BAN" == "yes" ]]; then + echo "Fail2ban Status:" + systemctl status fail2ban --no-pager -l + echo "================================" + fi + echo "Sudo users:" grep -E "sudo|wheel" /etc/group echo "================================" @@ -476,9 +452,27 @@ finalize_setup() { 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}" + + if [[ "$USE_UFW" == "yes" ]]; then + echo -e "${YELLOW}5. UFW firewall is active (SSH, HTTP, HTTPS allowed)${NC}" + else + echo -e "${YELLOW}5. Basic iptables rules are active (SSH, HTTP, HTTPS allowed)${NC}" + echo -e "${YELLOW} You can customize /etc/iptables-basic.sh for additional rules${NC}" + fi + + local note_number=6 + if [[ "$USE_FAIL2BAN" == "yes" ]]; then + echo -e "${YELLOW}$note_number. Fail2ban is protecting SSH${NC}" + ((note_number++)) + else + echo -e "${YELLOW}$note_number. Consider implementing IP banning manually if needed${NC}" + ((note_number++)) + fi + + echo -e "${YELLOW}$note_number. Automatic security updates are enabled${NC}" + ((note_number++)) + echo -e "${YELLOW}$note_number. SSH keys generated for both $SYSADMIN_USER and root users${NC}" + echo "" echo -e "${RED}REBOOT RECOMMENDED${NC}" echo "" @@ -491,11 +485,11 @@ main() { check_root check_debian - echo -e "${BLUE}=== Debian 12 Initial Setup with Git Integration ===${NC}" + echo -e "${BLUE}=== Debian 12 Initial Setup ===${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 "3. Generate SSH keys for both sysadmin and root users" echo "" read -p "Continue? (y/N): " confirm @@ -504,27 +498,17 @@ main() { exit 0 fi + # Ask for firewall preferences + ask_firewall_preferences + # 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 + generate_ssh_keys + show_ssh_keys # Finalize finalize_setup