From df883b42bb15bcded91712449b8c3b4c68d3cc27 Mon Sep 17 00:00:00 2001 From: Ali Date: Mon, 30 Jun 2025 22:44:28 +0100 Subject: [PATCH] add guide --- guide.md | 378 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100644 guide.md diff --git a/guide.md b/guide.md new file mode 100644 index 0000000..18f19cf --- /dev/null +++ b/guide.md @@ -0,0 +1,378 @@ +### **Setup** +- **Environment**: A fresh VM running **Ubuntu 22.04 LTS** (a supported OS) with: + - Root privileges (`sudo` or direct root access). + - Internet connectivity (for package downloads and Tailscale). + - At least 2GB free disk space (for swap and temporary files). + - Minimal installation (no prior SSH hardening, UFW, or Fail2Ban configured). +- **Script Version**: v0.52 +- **Execution Mode**: Interactive (not `--quiet`), to capture user prompts and verify decision points. +- **Inputs**: I’ll provide sample inputs for prompts (e.g., username, hostname, SSH port) to simulate a realistic run. +- **Verification**: I’ll check each function’s logic, validate outputs against the README, and highlight any potential runtime errors or edge cases. + +--- + +### **Walkthrough** + +#### **1. Preparation** +- **Download and Permissions**: + - The README instructs downloading with `wget https://raw.githubusercontent.com/buildplan/du_setup/refs/heads/main/du_setup.sh` and setting `chmod +x du_setup.sh`. + - Assumed command: `sudo ./du_setup.sh`. + - The script starts with `#!/bin/bash` and `set -euo pipefail`, ensuring strict error handling. + +- **Log File Creation**: + - The script creates `/var/log/du_setup_$(date +%Y%m%d_%H%M%S).log` (e.g., `/var/log/du_setup_20250630_222800.log`) with `chmod 600`. + - Backup directory `/root/setup_harden_backup_20250630_222800` is created with `chmod 700`. + +#### **2. Main Function Execution** + +##### **check_dependencies** +- **Logic**: Checks for `curl`, `sudo`, and `gpg`. Installs missing dependencies via `apt-get`. +- **Simulation**: + - On a fresh Ubuntu 22.04 VM, `sudo` and `curl` are typically present, but `gpg` might be missing in minimal installs. + - The script runs `apt-get install -y -qq gpg` if needed, which should succeed given internet access. +- **Expected Output**: `✓ All essential dependencies are installed.` (or installs `gpg` if missing). +- **Potential Issues**: None likely, as `apt-get update` and `install` are robust, and internet is assumed available. + +##### **check_system** +- **Logic**: Verifies root privileges, OS compatibility (Ubuntu 22.04), internet connectivity, SSH service, and `/var/log` writability. +- **Simulation**: + - Root check: `id -u` returns 0 (root), passes. + - OS check: `/etc/os-release` confirms `ID=ubuntu`, `VERSION_ID=22.04`, passes. + - Container check: No container detected (`/proc/1/cgroup` lacks docker/lxc/kubepod), so `IS_CONTAINER=false`. + - SSH check: Assumes `openssh-server` is installed (common in Ubuntu server). Detects `ssh.service` or `sshd.service`. + - Internet check: `curl -s --head https://archive.ubuntu.com` succeeds. + - `/var/log` and `/etc/shadow` checks: Permissions are correct (640 for `/etc/shadow`, writable `/var/log`). +- **Expected Output**: + ``` + ✓ Running with root privileges. + ✓ Compatible OS detected: Ubuntu 22.04 LTS + ✓ Internet connectivity confirmed. + ``` +- **Potential Issues**: If `openssh-server` is missing, the script installs it later in `install_packages`. No issues expected. + +##### **collect_config** +- **Logic**: Prompts for username, hostname, pretty hostname, and SSH port. Validates inputs. +- **Simulation Inputs**: + - Username: `adminuser` (valid, passes `validate_username`). + - Hostname: `myserver` (valid, passes `validate_hostname`). + - Pretty hostname: `My Server` (optional, accepted). + - SSH port: `2222` (default, passes `validate_port`). + - Server IP: Detected via `curl -s https://ifconfig.me` (e.g., `192.0.2.1`). + - Confirmation: User confirms the configuration. +- **Expected Output**: + ``` + Configuration Summary: + Username: adminuser + Hostname: myserver + SSH Port: 2222 + Server IP: 192.0.2.1 + Continue with this configuration? [Y/n]: y + ``` +- **Log Entry**: `Configuration collected: USER=adminuser, HOST=myserver, PORT=2222` +- **Potential Issues**: Invalid inputs (e.g., username with spaces) prompt re-entry, which is robust. No issues expected. + +##### **install_packages** +- **Logic**: Updates and upgrades packages, installs essentials (`ufw`, `fail2ban`, `chrony`, `rsync`, etc.). +- **Simulation**: + - `apt-get update` and `apt-get upgrade -y` run silently. + - Installs packages like `ufw`, `fail2ban`, `chrony`, `rsync`, `openssh-server`, etc. + - Assumes sufficient disk space and internet access. +- **Expected Output**: `✓ Essential packages installed.` +- **Potential Issues**: Rare chance of `apt-get` failures due to repository issues, but `set -e` ensures the script exits on error. No issues expected in a fresh VM. + +##### **setup_user** +- **Logic**: Creates `adminuser` if it doesn’t exist, sets a password (or skips for key-only), adds to `sudo` group, and configures SSH keys. +- **Simulation**: + - User `adminuser` doesn’t exist, so `adduser --disabled-password --gecos "" adminuser` runs. + - Password prompt: User enters `securepassword123` twice, set via `chpasswd`. + - SSH key prompt: User pastes a valid key (`ssh-ed25519 AAAAC3Nza... user@local`). + - Key is added to `/home/adminuser/.ssh/authorized_keys` with `chmod 600` and `chown adminuser:adminuser`. + - Adds `adminuser` to `sudo` group with `usermod -aG sudo adminuser`. +- **Expected Output**: + ``` + ✓ User 'adminuser' created. + ✓ SSH public key added. + ✓ User added to sudo group. + ✓ Sudo group membership confirmed for 'adminuser'. + ``` +- **Potential Issues**: Password mismatch prompts re-entry. If key is invalid, user is prompted again. Robust validation prevents issues. + +##### **configure_system** +- **Logic**: Sets timezone, hostname, and optionally configures locales. Backs up `/etc/hosts`, `/etc/fstab`, `/etc/sysctl.conf`. +- **Simulation**: + - Timezone: User enters `America/New_York`, validated via `/usr/share/zoneinfo`. + - Locale configuration: User skips (`dpkg-reconfigure locales` not run). + - Hostname: Sets `myserver` and pretty name `My Server` via `hostnamectl`. + - Updates `/etc/hosts` with `127.0.1.1 myserver`. +- **Expected Output**: + ``` + ✓ Timezone set to America/New_York. + ✓ Hostname configured: myserver + ``` +- **Potential Issues**: Invalid timezone prompts re-entry. No issues expected. + +##### **configure_ssh** +- **Logic**: Hardens SSH by setting a custom port (2222), disabling root login, enforcing key-based auth, and creating `/etc/issue.net`. Includes rollback on failure. +- **Simulation**: + - Detects `ssh.service` (Ubuntu 22.04). + - Current port: 22 (default). + - Backs up `/etc/ssh/sshd_config` to `/root/setup_harden_backup_20250630_222800/sshd_config.backup_*`. + - Sets port 2222 in `/etc/ssh/sshd_config` (Ubuntu 22.04 uses direct config). + - Creates `/etc/ssh/sshd_config.d/99-hardening.conf` with: + ``` + PermitRootLogin no + PasswordAuthentication no + PubkeyAuthentication yes + MaxAuthTries 3 + ClientAliveInterval 300 + X11Forwarding no + PrintMotd no + Banner /etc/issue.net + ``` + - Creates `/etc/issue.net` with a warning banner. + - Restarts `ssh.service` and verifies port 2222 with `ss -tuln`. + - User tests SSH: `ssh -p 2222 adminuser@192.0.2.1` (assumed successful). + - Verifies root login is disabled with `ssh -p 2222 root@localhost` (fails, as expected). +- **Expected Output**: + ``` + ✓ SSH service restarted on port 2222. + ✓ Confirmed: Root SSH login is disabled. + ✓ SSH hardening confirmed and finalized. + ``` +- **Potential Issues**: If the user fails to test SSH on port 2222, the script rolls back to port 22. The `trap` ensures rollback on errors. No issues expected with correct user input. + +##### **configure_firewall** +- **Logic**: Configures UFW with deny incoming, allow outgoing, and specific ports (2222/tcp, optional 80/tcp, 443/tcp, 41641/udp). +- **Simulation**: + - UFW is inactive initially. + - Sets `ufw default deny incoming`, `ufw default allow outgoing`. + - Allows `2222/tcp` (SSH). + - User allows HTTP (80/tcp) and HTTPS (443/tcp), skips Tailscale (41641/udp) and custom ports. + - Enables UFW with `ufw --force enable`. +- **Expected Output**: + ``` + ✓ HTTP traffic allowed. + ✓ HTTPS traffic allowed. + ✓ Firewall is active. + Status: active + To Action From + -- ------ ---- + 2222/tcp (Custom SSH) ALLOW Anywhere + 80/tcp (HTTP) ALLOW Anywhere + 443/tcp (HTTPS) ALLOW Anywhere + ``` +- **Potential Issues**: If the VPS provider’s firewall blocks port 2222, the user is warned to check. UFW enable failure is caught by `set -e`. No issues expected. + +##### **configure_fail2ban** +- **Logic**: Configures Fail2Ban to monitor SSH on port 2222 with `bantime=1h`, `findtime=10m`, `maxretry=3`. +- **Simulation**: + - Creates `/etc/fail2ban/jail.local` with: + ``` + [DEFAULT] + bantime = 1h + findtime = 10m + maxretry = 3 + backend = auto + [sshd] + enabled = true + port = 2222 + logpath = %(sshd_log)s + backend = %(sshd_backend)s + ``` + - Enables and restarts `fail2ban`. +- **Expected Output**: + ``` + ✓ Fail2Ban is active and monitoring port(s) 2222. + Status: sshd + ``` +- **Potential Issues**: Fail2Ban service failure is caught and exits the script. No issues expected. + +##### **configure_auto_updates** +- **Logic**: Configures `unattended-upgrades` for automatic security updates. +- **Simulation**: + - User confirms enabling auto-updates. + - Sets `unattended-upgrades/enable_auto_updates` to `true` and runs `dpkg-reconfigure`. +- **Expected Output**: `✓ Automatic security updates enabled.` +- **Potential Issues**: Package is already installed via `install_packages`. No issues expected. + +##### **configure_time_sync** +- **Logic**: Enables and verifies `chrony` for time synchronization. +- **Simulation**: + - `systemctl enable --now chrony` runs. + - `chronyc tracking` confirms synchronization. +- **Expected Output**: + ``` + ✓ Chrony is active for time synchronization. + Reference ID : 192.168.1.1 (time.example.com) + Stratum : 2 + ... + ``` +- **Potential Issues**: Chrony failure is caught and exits. No issues expected. + +##### **install_docker** +- **Logic**: Installs Docker if user confirms, adds `adminuser` to `docker` group, and runs a `hello-world` test. +- **Simulation**: + - User confirms Docker installation. + - Removes old runtimes, adds Docker GPG key and repository, installs `docker-ce`, `docker-ce-cli`, etc. + - Configures `/etc/docker/daemon.json` with log settings. + - Adds `adminuser` to `docker` group. + - Runs `docker run --rm hello-world` as `adminuser`. +- **Expected Output**: + ``` + ✓ Docker sanity check passed. + NOTE: 'adminuser' must log out and back in to use Docker without sudo. + ``` +- **Potential Issues**: Docker repository issues are caught by `set -e`. No issues expected with internet access. + +##### **install_tailscale** +- **Logic**: Installs Tailscale if confirmed, connects using a pre-auth key, and applies optional flags. +- **Simulation**: + - User confirms Tailscale installation. + - Chooses standard Tailscale (option 1). + - Enters key: `tskey-auth-xyz123`. + - Skips additional flags ( `--ssh`, `--advertise-exit-node`, etc.). + - Runs `tailscale up --auth-key=tskey-auth-xyz123 --operator=adminuser`. + - Verifies connection with `tailscale ip` (e.g., `100.64.0.1`). +- **Expected Output**: + ``` + ✓ Tailscale connected successfully. Node IPv4 in tailnet: 100.64.0.1 + ``` +- **Potential Issues**: Invalid key or network issues are logged to `/tmp/tailscale_status.txt`. Retries (3x) mitigate transient failures. Assumed success for simulation. + +##### **setup_backup** +- **Logic**: Configures rsync backups over SSH with optional notifications and a test backup. +- **Simulation**: + - User confirms backup setup. + - Backup destination: `u12345@u12345.your-storagebox.de`. + - Port: `23` (Hetzner). + - Remote path: `/home/backups/`. + - Hetzner mode: Enabled (uses `-s` for `ssh-copy-id`). + - Key copy: Manual (user runs `ssh-copy-id -p 23 -i /root/.ssh/id_ed25519.pub -s u12345@u12345.your-storagebox.de`). + - Creates `/root/.ssh/id_ed25519` if missing. + - Creates `/root/rsync_exclude.txt` with defaults. + - Cron schedule: `5 3 * * *` (daily at 3:05 AM). + - Notifications: Skipped. + - Test backup: User confirms, creates `/root/test_backup_*`, runs `rsync` to `u12345@u12345.your-storagebox.de:/home/backups/test_backup/`. +- **Expected Output**: + ``` + ✓ Root SSH key generated at /root/.ssh/id_ed25519 + ACTION REQUIRED: Copy the root SSH key to the backup destination. + The root user's public key is: ssh-ed25519 AAAAC3Nza... root@myserver + Run the following command: ssh-copy-id -p "23" -i "/root/.ssh/id_ed25519.pub" -s "u12345@u12345.your-storagebox.de" + ✓ Rsync exclude file created. + ✓ Test backup successful! Check /var/log/backup_rsync.log for details. + ✓ Backup cron job scheduled: 5 3 * * * + ``` +- **Potential Issues**: If the SSH key isn’t copied, the test backup fails, logged to `/var/log/backup_rsync.log`. Manual copy instructions are clear. No issues expected with correct setup. + +##### **configure_swap** +- **Logic**: Configures a swap file if confirmed, with default size 2G. +- **Simulation**: + - User confirms swap creation. + - Size: `2G`. + - Disk space check: Assumes >2GB available. + - Creates `/swapfile` with `fallocate`, `chmod 600`, `mkswap`, `swapon`. + - Adds `/swapfile none swap sw 0 0` to `/etc/fstab`. + - Sets `vm.swappiness=10`, `vm.vfs_cache_pressure=50` in `/etc/sysctl.d/99-swap.conf`. +- **Expected Output**: + ``` + ✓ Swap file created: 2G + ✓ Swap entry added to /etc/fstab. + ✓ Swap settings applied to /etc/sysctl.d/99-swap.conf. + NAME TYPE SIZE USED PRIO + /swapfile file 2G 0B -2 + ``` +- **Potential Issues**: Insufficient disk space exits the script. No issues expected. + +##### **configure_security_audit** +- **Logic**: Runs Lynis and (on Debian) debsecan if confirmed. +- **Simulation**: + - User confirms audit. + - Installs `lynis`, runs `lynis audit system --quick`. + - Skips debsecan (Ubuntu 22.04, not supported). + - Logs to `/var/log/setup_harden_security_audit_20250630_222800.log`. + - Extracts hardening index (e.g., `75`). +- **Expected Output**: + ``` + ✓ Lynis audit completed. Check /var/log/setup_harden_security_audit_20250630_222800.log for details. + ℹ debsecan is not supported on Ubuntu. Skipping debsecan audit. + ``` +- **Potential Issues**: Lynis failure is logged and doesn’t exit the script. No issues expected. + +##### **final_cleanup** +- **Logic**: Runs `apt-get update`, `upgrade`, `autoremove`, `autoclean`, and reloads daemons. +- **Simulation**: All commands succeed. +- **Expected Output**: `✓ Final system update and cleanup complete.` +- **Potential Issues**: Repository issues are logged as warnings, not fatal. No issues expected. + +##### **generate_summary** +- **Logic**: Summarizes configuration, checks service status, and provides verification steps. +- **Simulation**: + - Services (`ssh.service`, `fail2ban`, `chrony`, `ufw`, `docker`, `tailscaled`) are active. + - Backup is configured, test successful. + - Tailscale is connected (IP: `100.64.0.1`). + - Audit ran, hardening index: `75`, debsecan: `Not supported on Ubuntu`. +- **Expected Output**: + ``` + Setup Complete! + ✓ Service ssh.service is active. + ✓ Service fail2ban is active. + ✓ Service chrony is active. + ✓ Service ufw is active. + ✓ Service docker is active. + ✓ Service tailscaled is active and connected. + ✓ Security audit performed. + Configuration Summary: + Admin User: adminuser + Hostname: myserver + SSH Port: 2222 + Server IP: 192.0.2.1 + Remote Backup: Enabled + - Backup Script: /root/run_backup.sh + - Destination: u12345@u12345.your-storagebox.de + - SSH Port: 23 + - Remote Path: /home/backups/ + - Cron Schedule: 5 3 * * * + - Notifications: None + - Test Status: Successful + Tailscale: Enabled + - Server: https://controlplane.tailscale.com + - Tailscale IPs: 100.64.0.1 + - Flags: None + Security Audit: Performed + - Audit Log: /var/log/setup_harden_security_audit_20250630_222800.log + - Hardening Index: 75 + - Vulnerabilities: Not supported on Ubuntu + Log File: /var/log/du_setup_20250630_222800.log + Backups: /root/setup_harden_backup_20250630_222800 + Post-Reboot Verification Steps: + - SSH access: ssh -p 2222 adminuser@192.0.2.1 + - Firewall rules: sudo ufw status verbose + - Time sync: chronyc tracking + - Fail2Ban status: sudo fail2ban-client status sshd + - Swap status: sudo swapon --show && free -h + - Hostname: hostnamectl + - Docker status: docker ps + - Tailscale status: tailscale status + - Remote Backup: + - Verify SSH key: sudo cat /root/.ssh/id_ed25519.pub + - Copy key if needed: ssh-copy-id -p 23 -s u12345@u12345.your-storagebox.de + - Test backup: sudo /root/run_backup.sh + - Check logs: sudo less /var/log/backup_rsync.log + - Security Audit: + - Check results: sudo less /var/log/setup_harden_security_audit_20250630_222800.log + ⚠ ACTION REQUIRED: Ensure the root SSH key (/root/.ssh/id_ed25519.pub) is copied to u12345@u12345.your-storagebox.de. + ⚠ A reboot is required to apply all changes cleanly. + Reboot now? [Y/n]: n + ⚠ Please reboot manually with 'sudo reboot'. + ``` +- **Potential Issues**: If services fail, they’re listed in `FAILED_SERVICES`. Backup key copy warning is appropriate for manual mode. No issues expected. + +--- + +### **Potential Runtime Issues** +- **SSH Lockout**: If the user fails to test SSH on port 2222, the script rolls back to port 22, preventing lockout. The warning to test in a separate terminal is clear. +- **Backup Failure**: If the root SSH key isn’t copied to the backup server, the test backup fails, and logs provide clear troubleshooting steps (e.g., `ssh-copy-id`, `nc -zv`). +- **Tailscale**: Invalid keys or network issues (e.g., UDP 41641 blocked) are caught with retries and logged to `/tmp/tailscale_status.txt`. +- **Disk Space**: Swap creation checks available space, exiting if insufficient. Assumed 2GB available in the VM. +- **Package Installation**: Repository failures are caught by `set -e`, and the script exits cleanly.