Update Debian setup script to include user-configurable firewall and fail2ban options. Refactor SSH key generation for both sysadmin and root users, and streamline the final setup process with improved logging and user feedback.

This commit is contained in:
2025-08-07 11:40:38 +01:00
parent c14240d5be
commit 1c3dbcfcd7

582
setup.sh
View File

@@ -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