Files
Boilerplates/Linux/SSH/secure_ssh.sh

211 lines
10 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# ──────────────────────────────────────────────────────────────────────────────
# Secure-SSH Setup for Modern Linux (2025-edition)
# ------------------------------------------------
# * Generates hardened OpenSSH configuration (IPv4-only)
# * Installs/updates OpenSSH-server + creates host keys
# * Creates users, adds SSH public keys, restricts login
# * Removes all legacy / deprecated directives
# * Adds post-quantum KEX, rate-limiting, strict auth flow & root lockdown
# ──────────────────────────────────────────────────────────────────────────────
printf "\033c" # clear terminal
SSH_CONFIG_DIR="/etc/ssh/sshd_config.d"
SSH_MAIN_CONFIG="/etc/ssh/sshd_config"
SSH_CONFIG_FILE="$SSH_CONFIG_DIR/secure.conf"
ED25519_KEY="/etc/ssh/ssh_host_ed25519_key"
ECDSA_KEY="/etc/ssh/ssh_host_ecdsa_key"
# ─── ANSI colors ──────────────────────────────────────────────────────────────
RED='\033[1;31m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;34m'
WHITE='\033[1;37m'
RESET='\033[0m'
log() { echo -e "${GREEN}$1${RESET}"; }
warn() { echo -e "${YELLOW}$1${RESET}"; }
error() { echo -e "${RED}$1${RESET}"; }
# ─── Service-Manager detection (systemd │ sysvinit │ openrc) ───────────────────
detect_service_manager() {
if command -v systemctl &>/dev/null; then echo "systemd"
elif command -v service &>/dev/null; then echo "sysvinit"
elif [ -x /sbin/rc-service ]; then echo "openrc"
else echo "unknown"; fi
}
# ─── SSH service name detection ───────────────────────────────────────────────
detect_ssh_service() {
local manager=$1
local services=(sshd ssh openssh-server openssh)
case $manager in
systemd) for s in "${services[@]}"; do systemctl list-units --type=service | grep -q $s && echo $s && return; done ;;
sysvinit) for s in "${services[@]}"; do service --status-all | grep -q $s && echo $s && return; done ;;
openrc) for s in "${services[@]}"; do rc-service -l | grep -q $s && echo $s && return; done ;;
esac
[ -x /usr/sbin/sshd ] && echo sshd || echo unknown
}
restart_ssh_service() {
local manager=$1 service=$2
warn "Starte SSH-Dienst ($service) neu…"
case $manager in
systemd) sudo systemctl restart "$service" && return 0 ;;
sysvinit) sudo service "$service" restart && return 0 ;;
openrc) sudo rc-service "$service" restart && return 0 ;;
esac
sudo killall -HUP sshd 2>/dev/null && return 0
return 1
}
install_package() {
local pkg=$1
warn "Installiere $pkg"
if command -v apt &>/dev/null; then sudo apt update -qq && sudo apt install -y $pkg -qq ;
elif command -v dnf &>/dev/null; then sudo dnf install -y $pkg &>/dev/null ;
elif command -v yum &>/dev/null; then sudo yum install -y $pkg &>/dev/null ;
elif command -v apk &>/dev/null; then sudo apk add $pkg &>/dev/null ;
elif command -v pacman&>/dev/null; then sudo pacman -Sy --noconfirm $pkg &>/dev/null ;
elif command -v zypper&>/dev/null; then sudo zypper install -y $pkg &>/dev/null ;
else error "Kein unterstützter Paketmanager installiere $pkg manuell."; return 1; fi
log "$pkg wurde installiert."
}
# ─── Setup prerequisites ─────────────────────────────────────────────────────
SERVICE_MANAGER=$(detect_service_manager); log "Service-Manager: $SERVICE_MANAGER"
command -v sudo &>/dev/null || { warn "sudo fehlt Installation…"; install_package sudo; }
command -v sshd &>/dev/null || install_package openssh-server
[ -d "$SSH_CONFIG_DIR" ] || { warn "Erstelle $SSH_CONFIG_DIR"; sudo mkdir -p "$SSH_CONFIG_DIR"; }
# ─── Host keys (ed25519 & ecdsa-p384) ─────────────────────────────────────────
for key in "$ED25519_KEY ed25519" "$ECDSA_KEY ecdsa -b 384"; do
set -- $key; file=$1; shift; args=$*;
[ -f "$file" ] || {
warn "Generiere Host-Schlüssel $(basename $file)";
sudo ssh-keygen -t $args -f "$file" -N "" -q && sudo chmod 600 "$file" && log "Schlüssel $(basename $file) erstellt.";
}
done
# ─── Replace main config with include only ────────────────────────────────────
warn "Setze $SSH_MAIN_CONFIG auf Include…"
echo "Include $SSH_CONFIG_DIR/*.conf" | sudo tee "$SSH_MAIN_CONFIG" >/dev/null
# ─── Remove legacy configs ────────────────────────────────────────────────────
sudo rm -f $SSH_CONFIG_DIR/*
# ─── Collect allowed users + optional creation ───────────────────────────────
read -rp $'\e[1;34mWelche Benutzer dürfen sich per SSH anmelden? (Leerzeichen-getrennt): \e[0m' SSH_USERS
VALID_USERS=""
# distribution-specific sudo group
declare -A distro_sudo=( [ubuntu]=sudo [debian]=sudo [raspbian]=sudo [centos]=wheel [fedora]=wheel [rhel]=wheel [almalinux]=wheel [rocky]=wheel [ol]=wheel [arch]=wheel [manjaro]=wheel [alpine]=wheel )
SUDO_GROUP="sudo"
[ -f /etc/os-release ] && { . /etc/os-release; SUDO_GROUP=${distro_sudo[$ID]:-sudo}; }
log "Benutze sudo-Gruppe: $SUDO_GROUP"
for user in $SSH_USERS; do
if id "$user" &>/dev/null; then
log "Benutzer $user existiert."
VALID_USERS+="$user "
continue
fi
read -rp $'\e[1;34mBenutzer '"$user"$' existiert nicht. Anlegen? [y/N]: \e[0m' CREATE
[[ $CREATE =~ ^[Yy]$ ]] || continue
read -rsp $'\e[1;34mPasswort für '"$user"$': \e[0m' PW; echo
sudo useradd -m -s /bin/bash "$user" && echo "$user:$PW" | sudo chpasswd
sudo usermod -aG "$SUDO_GROUP" "$user"
sudo install -d -m700 -o "$user" -g "$user" "/home/$user/.ssh"
sudo touch "/home/$user/.ssh/authorized_keys" && sudo chmod 600 "/home/$user/.ssh/authorized_keys" && sudo chown "$user":"$user" "/home/$user/.ssh/authorized_keys"
read -rp $'\e[1;34mSSH Public Key für '"$user"$' hinzufügen? [y/N]: \e[0m' ADDKEY
if [[ $ADDKEY =~ ^[Yy]$ ]]; then
read -rp $'\e[1;34mPublic Key: \e[0m' KEY
echo "$KEY" | sudo tee -a "/home/$user/.ssh/authorized_keys" >/dev/null
fi
VALID_USERS+="$user "
done
# ─── Determine SFTP-server binary ─────────────────────────────────────────────
for path in /usr/lib/openssh/sftp-server /usr/libexec/openssh/sftp-server /usr/lib/ssh/sftp-server; do [ -x "$path" ] && SFTP_PATH=$path && break; done
SFTP_PATH=${SFTP_PATH:-internal-sftp}
log "SFTP-Pfad: $SFTP_PATH"
# ─── Check for PAM ────────────────────────────────────────────────────────────
PAM_AVAILABLE=false
[ -d /etc/pam.d ] && { find / -maxdepth 2 -name 'libpam.so*' -quit | grep -q libpam && PAM_AVAILABLE=true; }
$PAM_AVAILABLE && log "PAM verfügbar." || warn "PAM nicht gefunden UsePAM wird deaktiviert."
# ─── Generate modern, hardened secure.conf ────────────────────────────────────
warn "Erstelle $SSH_CONFIG_FILE (modern hardened)…"
sudo tee "$SSH_CONFIG_FILE" >/dev/null <<EOF
# ─────────────────────────────────────────────────────────────────────────────
# Generated $(date -u +'%Y-%m-%dT%H:%MZ')
# ─────────────────────────────────────────────────────────────────────────────
AddressFamily inet # IPv4 only
Port 22 # default port change if needed
# Modern host keys only
HostKey $ED25519_KEY
HostKey $ECDSA_KEY
# Post-quantum hybrid first
KexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,ecdh-sha2-nistp256,ecdh-sha2-nistp384,diffie-hellman-group14-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr
MACs hmac-sha2-512,hmac-sha2-256
# Logging & rate-limits
SyslogFacility AUTHPRIV
LogLevel VERBOSE
MaxStartups 10:30:100
# Login settings
LoginGraceTime 30s
PermitRootLogin no
PermitEmptyPasswords no
IgnoreRhosts yes
StrictModes yes
# Authentication flow publickey only (FIDO2/U2F etc.)
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
AuthenticationMethods publickey
# PAM (if available)
UsePAM $($PAM_AVAILABLE && echo yes || echo no)
PrintMotd no
# X11 forwarding disabled
X11Forwarding no
# SFTP subsystem
Subsystem sftp $SFTP_PATH
# Keepalive
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers ${VALID_USERS%% } # strip trailing space
EOF
log "Secure-Config geschrieben."
# ─── Validate & restart SSH ──────────────────────────────────────────────────
[ -d /run/sshd ] || { sudo mkdir -p /run/sshd; sudo chmod 0755 /run/sshd; }
sudo sshd -t || { error "SSH-Konfiguration ungültig!"; exit 1; }
SSH_SERVICE=$(detect_ssh_service "$SERVICE_MANAGER")
[ "$SSH_SERVICE" = unknown ] && { error "SSH-Dienst nicht gefunden."; exit 1; }
restart_ssh_service "$SERVICE_MANAGER" "$SSH_SERVICE" || { error "Neustart fehlgeschlagen manuell prüfen."; exit 1; }
log "Setup abgeschlossen. Zugelassene Benutzer: ${WHITE}${VALID_USERS}${RESET}"