mirror of
https://github.com/buildplan/du_setup.git
synced 2025-12-17 09:45:26 +00:00
commit
e72b648fe9
@ -1,6 +1,6 @@
|
||||
# Debian & Ubuntu Server Setup & Hardening Script
|
||||
|
||||
**Version:** v0.51
|
||||
**Version:** v0.52
|
||||
|
||||
**Last Updated:** 2025-06-30
|
||||
|
||||
@ -75,7 +75,7 @@ sha256sum du_setup.sh
|
||||
|
||||
Compare the output hash to the one below. They must match exactly.
|
||||
|
||||
`fa2bbc20e5e658ed0a485d9bcb78f7c2f28501ed4363f759f1dd2bb75a395e58`
|
||||
`dbe2abf3dd0dee253988e8e53e7a91970a7c07ff97f9fa446f326667297c43de`
|
||||
|
||||
### 3\. Run the Script
|
||||
|
||||
|
||||
215
du_setup.sh
215
du_setup.sh
@ -1,8 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Debian 12 and Ubuntu Server Hardening Interactive Script
|
||||
# Version: 0.51 | 2025-06-30
|
||||
# Version: 0.52 | 2025-06-30
|
||||
# Changelog:
|
||||
# - v0.52: Roll-back SSH config on failure to configure SSH port, confirmed SSH config support for Ubuntu 24.10
|
||||
# - v0.51: corrected repo links
|
||||
# - v0.50: versioning format change and repo name change
|
||||
# - v4.3: Add SHA256 integrity verification
|
||||
@ -90,7 +91,7 @@ print_header() {
|
||||
echo -e "${CYAN}╔═════════════════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${CYAN}║ ║${NC}"
|
||||
echo -e "${CYAN}║ DEBIAN/UBUNTU SERVER SETUP AND HARDENING SCRIPT ║${NC}"
|
||||
echo -e "${CYAN}║ v0.51 | 2025-06-30 ║${NC}"
|
||||
echo -e "${CYAN}║ v0.52 | 2025-06-30 ║${NC}"
|
||||
echo -e "${CYAN}║ ║${NC}"
|
||||
echo -e "${CYAN}╚═════════════════════════════════════════════════════════════════╝${NC}"
|
||||
echo
|
||||
@ -503,17 +504,31 @@ configure_system() {
|
||||
log "System configuration completed."
|
||||
}
|
||||
|
||||
cleanup_and_exit() {
|
||||
local exit_code=$?
|
||||
if [[ $exit_code -ne 0 && $(type -t rollback_ssh_changes) == "function" ]]; then
|
||||
print_error "An error occurred. Rolling back SSH changes to port $PREVIOUS_SSH_PORT..."
|
||||
rollback_ssh_changes
|
||||
if [[ $? -ne 0 ]]; then
|
||||
print_error "Rollback failed. SSH may not be accessible. Please check 'systemctl status $SSH_SERVICE' and 'journalctl -u $SSH_SERVICE'."
|
||||
fi
|
||||
fi
|
||||
exit $exit_code
|
||||
}
|
||||
|
||||
configure_ssh() {
|
||||
trap cleanup_and_exit ERR
|
||||
|
||||
print_section "SSH Hardening"
|
||||
local CURRENT_SSH_PORT USER_HOME SSH_DIR SSH_KEY AUTH_KEYS NEW_SSH_CONFIG
|
||||
local CURRENT_SSH_PORT USER_HOME SSH_DIR SSH_KEY AUTH_KEYS NEW_SSH_CONFIG PREVIOUS_SSH_PORT
|
||||
|
||||
# Ensure openssh-server is installed
|
||||
if ! dpkg -l openssh-server | grep -q ^ii; then
|
||||
print_error "openssh-server package is not installed. Please ensure it is installed."
|
||||
exit 1
|
||||
print_error "openssh-server package is not installed."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Detect SSH service name, preserve socket activation on Ubuntu if active
|
||||
# Detect SSH service name
|
||||
if [[ $ID == "ubuntu" ]] && systemctl is-active ssh.socket >/dev/null 2>&1; then
|
||||
SSH_SERVICE="ssh.socket"
|
||||
print_info "Using SSH socket activation: $SSH_SERVICE"
|
||||
@ -521,105 +536,58 @@ configure_ssh() {
|
||||
SSH_SERVICE="ssh.service"
|
||||
elif systemctl is-enabled sshd.service >/dev/null 2>&1 || systemctl is-active sshd.service >/dev/null 2>&1; then
|
||||
SSH_SERVICE="sshd.service"
|
||||
elif ps aux | grep -q "[s]shd"; then
|
||||
print_warning "SSH daemon running but no standard service detected."
|
||||
SSH_SERVICE="ssh.service" # Default for Debian
|
||||
if ! systemctl enable --now "$SSH_SERVICE" >/dev/null 2>&1; then
|
||||
print_error "Failed to enable and start $SSH_SERVICE. Attempting manual start..."
|
||||
if ! /usr/sbin/sshd; then
|
||||
print_error "Failed to start SSH daemon manually."
|
||||
exit 1
|
||||
fi
|
||||
print_success "SSH daemon started manually."
|
||||
fi
|
||||
else
|
||||
print_error "No SSH service or daemon detected. Please verify openssh-server installation and daemon status."
|
||||
exit 1
|
||||
print_error "No SSH service or daemon detected."
|
||||
return 1
|
||||
fi
|
||||
print_info "Using SSH service: $SSH_SERVICE"
|
||||
log "Detected SSH service: $SSH_SERVICE"
|
||||
|
||||
# Ensure SSH service is enabled and running
|
||||
if ! systemctl is-enabled "$SSH_SERVICE" >/dev/null 2>&1; then
|
||||
if ! systemctl enable "$SSH_SERVICE" >/dev/null 2>&1; then
|
||||
print_error "Failed to enable $SSH_SERVICE. Please check service status."
|
||||
exit 1
|
||||
fi
|
||||
print_success "SSH service enabled: $SSH_SERVICE"
|
||||
fi
|
||||
if ! systemctl is-active "$SSH_SERVICE" >/dev/null 2>&1; then
|
||||
if ! systemctl start "$SSH_SERVICE" >/dev/null 2>&1; then
|
||||
print_error "Failed to start $SSH_SERVICE. Attempting manual start..."
|
||||
if ! /usr/sbin/sshd; then
|
||||
print_error "Failed to start SSH daemon manually."
|
||||
exit 1
|
||||
fi
|
||||
print_success "SSH daemon started manually."
|
||||
fi
|
||||
fi
|
||||
|
||||
CURRENT_SSH_PORT=$(ss -tuln | grep -E ":(22|.*$SSH_SERVICE.*)" | awk '{print $5}' | cut -d':' -f2 | head -n1 || echo "22")
|
||||
# Store the current active port as the previous port
|
||||
PREVIOUS_SSH_PORT=$(ss -tuln | grep -E ":(22|.*$SSH_SERVICE.*)" | awk '{print $5}' | cut -d':' -f2 | head -n1 || echo "22")
|
||||
CURRENT_SSH_PORT=$PREVIOUS_SSH_PORT
|
||||
USER_HOME=$(getent passwd "$USERNAME" | cut -d: -f6)
|
||||
SSH_DIR="$USER_HOME/.ssh"
|
||||
SSH_KEY="$SSH_DIR/id_ed25519"
|
||||
AUTH_KEYS="$SSH_DIR/authorized_keys"
|
||||
|
||||
if [[ $LOCAL_KEY_ADDED == false ]] && [[ ! -s "$AUTH_KEYS" ]]; then
|
||||
print_info "No local key provided and no existing keys found. Generating new SSH key..."
|
||||
mkdir -p "$SSH_DIR"
|
||||
chmod 700 "$SSH_DIR"
|
||||
sudo -u "$USERNAME" ssh-keygen -t ed25519 -f "$SSH_KEY" -N "" -q
|
||||
cat "$SSH_KEY.pub" >> "$AUTH_KEYS"
|
||||
chmod 600 "$AUTH_KEYS"
|
||||
chown -R "$USERNAME:$USERNAME" "$SSH_DIR"
|
||||
print_info "No local key provided. Generating new SSH key..."
|
||||
mkdir -p "$SSH_DIR"; chmod 700 "$SSH_DIR"
|
||||
sudo -u "$USERNAME" ssh-keygen -t ed25519 -f "$SSH_DIR/id_ed25519" -N "" -q
|
||||
cat "$SSH_DIR/id_ed25519.pub" >> "$AUTH_KEYS"
|
||||
chmod 600 "$AUTH_KEYS"; chown -R "$USERNAME:$USERNAME" "$SSH_DIR"
|
||||
print_success "SSH key generated."
|
||||
echo -e "${YELLOW}Public key for remote access:${NC}"
|
||||
cat "$SSH_KEY.pub" | tee -a "$LOG_FILE"
|
||||
echo -e "${YELLOW}Copy this key to your local ~/.ssh/authorized_keys or use 'ssh-copy-id -p $CURRENT_SSH_PORT $USERNAME@$SERVER_IP' from your local machine.${NC}"
|
||||
else
|
||||
print_info "SSH key(s) already present or added. Skipping key generation."
|
||||
echo -e "${YELLOW}Public key for remote access:${NC}"; cat "$SSH_DIR/id_ed25519.pub"
|
||||
fi
|
||||
|
||||
print_warning "SSH Key Authentication Required for Next Steps!"
|
||||
echo -e "${CYAN}Test SSH access from a SEPARATE terminal now: ssh -p $CURRENT_SSH_PORT $USERNAME@$SERVER_IP${NC}"
|
||||
|
||||
if ! confirm "Can you successfully log in using your SSH key?"; then
|
||||
print_error "SSH key authentication is mandatory to proceed. Please fix and re-run."
|
||||
exit 1
|
||||
print_error "SSH key authentication is mandatory to proceed."
|
||||
return 1
|
||||
fi
|
||||
|
||||
print_info "Backing up original SSH config..."
|
||||
SSHD_BACKUP_FILE="$BACKUP_DIR/sshd_config.backup_$(date +%Y%m%d_%H%M%S)"
|
||||
cp /etc/ssh/sshd_config "$SSHD_BACKUP_FILE"
|
||||
|
||||
# Apply port override based on SSH service type
|
||||
if [[ "$SSH_SERVICE" == "ssh.socket" ]]; then
|
||||
# Apply port override
|
||||
if [[ $ID == "ubuntu" ]] && dpkg --compare-versions "$(lsb_release -rs)" ge "24.04"; then
|
||||
print_info "Updating SSH port in /etc/ssh/sshd_config for Ubuntu 24.04+..."
|
||||
if ! grep -q "^Port" /etc/ssh/sshd_config; then echo "Port $SSH_PORT" >> /etc/ssh/sshd_config; else sed -i "s/^Port .*/Port $SSH_PORT/" /etc/ssh/sshd_config; fi
|
||||
elif [[ "$SSH_SERVICE" == "ssh.socket" ]]; then
|
||||
print_info "Configuring SSH socket to listen on port $SSH_PORT..."
|
||||
NEW_SSH_CONFIG=$(mktemp)
|
||||
tee "$NEW_SSH_CONFIG" > /dev/null <<EOF
|
||||
[Socket]
|
||||
ListenStream=
|
||||
ListenStream=$SSH_PORT
|
||||
EOF
|
||||
mkdir -p /etc/systemd/system/ssh.socket.d
|
||||
mv "$NEW_SSH_CONFIG" /etc/systemd/system/ssh.socket.d/override.conf
|
||||
chmod 644 /etc/systemd/system/ssh.socket.d/override.conf
|
||||
echo -e "[Socket]\nListenStream=\nListenStream=$SSH_PORT" > /etc/systemd/system/ssh.socket.d/override.conf
|
||||
else
|
||||
print_info "Configuring SSH service to listen on port $SSH_PORT..."
|
||||
NEW_SSH_CONFIG=$(mktemp)
|
||||
tee "$NEW_SSH_CONFIG" > /dev/null <<EOF
|
||||
[Service]
|
||||
ExecStart=
|
||||
ExecStart=/usr/sbin/sshd -D -p $SSH_PORT
|
||||
EOF
|
||||
mkdir -p /etc/systemd/system/ssh.service.d
|
||||
mv "$NEW_SSH_CONFIG" /etc/systemd/system/ssh.service.d/override.conf
|
||||
chmod 644 /etc/systemd/system/ssh.service.d/override.conf
|
||||
mkdir -p /etc/systemd/system/${SSH_SERVICE}.d
|
||||
echo -e "[Service]\nExecStart=\nExecStart=/usr/sbin/sshd -D -p $SSH_PORT" > /etc/systemd/system/${SSH_SERVICE}.d/override.conf
|
||||
fi
|
||||
|
||||
# Apply additional hardening via sshd_config.d
|
||||
NEW_SSH_CONFIG=$(mktemp)
|
||||
tee "$NEW_SSH_CONFIG" > /dev/null <<EOF
|
||||
# Apply additional hardening
|
||||
mkdir -p /etc/ssh/sshd_config.d
|
||||
tee /etc/ssh/sshd_config.d/99-hardening.conf > /dev/null <<EOF
|
||||
PermitRootLogin no
|
||||
PasswordAuthentication no
|
||||
PubkeyAuthentication yes
|
||||
@ -629,51 +597,28 @@ X11Forwarding no
|
||||
PrintMotd no
|
||||
Banner /etc/issue.net
|
||||
EOF
|
||||
if [[ -f /etc/ssh/sshd_config.d/99-hardening.conf ]] && cmp -s "$NEW_SSH_CONFIG" /etc/ssh/sshd_config.d/99-hardening.conf; then
|
||||
print_info "SSH configuration already hardened. Skipping."
|
||||
rm -f "$NEW_SSH_CONFIG"
|
||||
else
|
||||
print_info "Creating or updating hardened SSH configuration..."
|
||||
mkdir -p /etc/ssh/sshd_config.d
|
||||
mv "$NEW_SSH_CONFIG" /etc/ssh/sshd_config.d/99-hardening.conf
|
||||
chmod 644 /etc/ssh/sshd_config.d/99-hardening.conf
|
||||
tee /etc/issue.net > /dev/null <<'EOF'
|
||||
tee /etc/issue.net > /dev/null <<'EOF'
|
||||
******************************************************************************
|
||||
🔒AUTHORIZED ACCESS ONLY
|
||||
════ all attempts are logged and reviewed ════
|
||||
******************************************************************************
|
||||
EOF
|
||||
fi
|
||||
|
||||
print_info "Reloading systemd and restarting SSH service..."
|
||||
systemctl daemon-reload
|
||||
if ! systemctl restart "$SSH_SERVICE"; then
|
||||
print_error "SSH service failed to restart! Reverting changes..."
|
||||
rm -f /etc/systemd/system/ssh.service.d/override.conf
|
||||
cp "$SSHD_BACKUP_FILE" /etc/ssh/sshd_config
|
||||
rm -f /etc/ssh/sshd_config.d/99-hardening.conf
|
||||
systemctl daemon-reload
|
||||
systemctl restart "$SSH_SERVICE" || /usr/sbin/sshd || true
|
||||
exit 1
|
||||
fi
|
||||
# Wait and verify port binding
|
||||
systemctl restart "$SSH_SERVICE"
|
||||
sleep 5
|
||||
if ! ss -tuln | grep -q ":$SSH_PORT"; then
|
||||
print_error "SSH not listening on port $SSH_PORT after restart! Reverting changes..."
|
||||
rm -f /etc/systemd/system/ssh.service.d/override.conf
|
||||
cp "$SSHD_BACKUP_FILE" /etc/ssh/sshd_config
|
||||
rm -f /etc/ssh/sshd_config.d/99-hardening.conf
|
||||
systemctl daemon-reload
|
||||
systemctl restart "$SSH_SERVICE" || /usr/sbin/sshd || true
|
||||
exit 1
|
||||
print_error "SSH not listening on port $SSH_PORT after restart!"
|
||||
return 1
|
||||
fi
|
||||
print_success "SSH service restarted on port $SSH_PORT."
|
||||
|
||||
# Verify root SSH is disabled
|
||||
print_info "Verifying root SSH login is disabled..."
|
||||
if ssh -p "$SSH_PORT" -o BatchMode=yes -o ConnectTimeout=5 root@localhost true 2>/dev/null; then
|
||||
print_error "Root SSH login is still possible! Check SSH configuration."
|
||||
exit 1
|
||||
if ssh -p "$SSH_PORT" -o BatchMode=yes -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@localhost true 2>/dev/null; then
|
||||
print_error "Root SSH login is still possible! Check configuration."
|
||||
return 1
|
||||
else
|
||||
print_success "Confirmed: Root SSH login is disabled."
|
||||
fi
|
||||
@ -686,6 +631,7 @@ EOF
|
||||
local max_retries=3
|
||||
while (( retry_count < max_retries )); do
|
||||
if confirm "Was the new SSH connection successful?"; then
|
||||
print_success "SSH hardening confirmed and finalized."
|
||||
break
|
||||
else
|
||||
(( retry_count++ ))
|
||||
@ -693,19 +639,60 @@ EOF
|
||||
print_info "Retrying SSH connection test ($retry_count/$max_retries)..."
|
||||
sleep 5
|
||||
else
|
||||
print_error "Aborting. Restoring original SSH configuration."
|
||||
rm -f /etc/systemd/system/ssh.service.d/override.conf
|
||||
cp "$SSHD_BACKUP_FILE" /etc/ssh/sshd_config
|
||||
rm -f /etc/ssh/sshd_config.d/99-hardening.conf
|
||||
systemctl daemon-reload
|
||||
systemctl restart "$SSH_SERVICE" || /usr/sbin/sshd || true
|
||||
exit 1
|
||||
print_error "All retries failed. Initiating rollback to port $PREVIOUS_SSH_PORT..."
|
||||
rollback_ssh_changes
|
||||
if ! ss -tuln | grep -q ":$PREVIOUS_SSH_PORT"; then
|
||||
print_error "Rollback failed. SSH not restored on original port $PREVIOUS_SSH_PORT."
|
||||
else
|
||||
print_success "Rollback successful. SSH restored on original port $PREVIOUS_SSH_PORT."
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
trap - ERR
|
||||
log "SSH hardening completed."
|
||||
}
|
||||
|
||||
rollback_ssh_changes() {
|
||||
print_info "Rolling back SSH configuration changes to port $PREVIOUS_SSH_PORT..."
|
||||
rm -f /etc/systemd/system/ssh.service.d/override.conf
|
||||
rm -f /etc/systemd/system/ssh.socket.d/override.conf
|
||||
rm -f /etc/ssh/sshd_config.d/99-hardening.conf
|
||||
if [[ -f "$SSHD_BACKUP_FILE" ]]; then
|
||||
cp "$SSHD_BACKUP_FILE" /etc/ssh/sshd_config
|
||||
print_info "Restored original sshd_config from $SSHD_BACKUP_FILE."
|
||||
else
|
||||
print_error "Backup file not found. Could not restore sshd_config."
|
||||
return 1
|
||||
fi
|
||||
|
||||
print_info "Reloading systemd and restarting $SSH_SERVICE..."
|
||||
systemctl daemon-reload
|
||||
if ! systemctl restart "$SSH_SERVICE"; then
|
||||
print_warning "Failed to restart $SSH_SERVICE after rollback. Attempting manual start..."
|
||||
/usr/sbin/sshd || true
|
||||
fi
|
||||
|
||||
local rollback_verified=false
|
||||
print_info "Verifying SSH rollback to port $PREVIOUS_SSH_PORT..."
|
||||
for ((i=1; i<=10; i++)); do
|
||||
if ss -tuln | grep -q ":$PREVIOUS_SSH_PORT"; then
|
||||
print_success "Rollback successful. SSH is now listening on port $PREVIOUS_SSH_PORT."
|
||||
rollback_verified=true
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if [[ $rollback_verified == false ]]; then
|
||||
print_error "Rollback failed. SSH service is not listening on port $PREVIOUS_SSH_PORT."
|
||||
print_info "Please check service status manually with 'systemctl status $SSH_SERVICE' and 'journalctl -u $SSH_SERVICE'."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
configure_firewall() {
|
||||
print_section "Firewall Configuration (UFW)"
|
||||
if ufw status | grep -q "Status: active"; then
|
||||
|
||||
@ -1 +1 @@
|
||||
fa2bbc20e5e658ed0a485d9bcb78f7c2f28501ed4363f759f1dd2bb75a395e58 du_setup.sh
|
||||
dbe2abf3dd0dee253988e8e53e7a91970a7c07ff97f9fa446f326667297c43de du_setup.sh
|
||||
|
||||
376
guide.md
Normal file
376
guide.md
Normal file
@ -0,0 +1,376 @@
|
||||
### **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.
|
||||
|
||||
---
|
||||
|
||||
### **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`.\c
|
||||
|
||||
#### **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.
|
||||
|
||||
##### **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 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.
|
||||
Loading…
x
Reference in New Issue
Block a user