Update Linux/SSH/secure_ssh.sh

This commit is contained in:
2025-05-07 19:25:53 +00:00
parent dcff326574
commit 6d9348fc13

View File

@@ -1,182 +1,142 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# ────────────────────────────────────────────────────────────────────────────── # ──────────────────────────────────────────────────────────────────────────────
# SecureSSH Setup Modern Linux (2025edition, PAMaware) # Secure-SSH Hardened Setup (OpenSSH ≥9.x)
# ---------------------------------------------------------- # ----------------------------------------
# ✦ Generates hardened OpenSSH config (IPv4only) # ✦ Minimal Defaults + Explizite Härtung
# ✦ Installs / updates OpenSSHserver + creates host keys # ✦ Unterstützt:
# ✦ Creates users, adds SSH public keys, restricts login # - Benutzer/Gruppen-Whitelisting
# ✦ Removes deprecated directives fully OpenSSH ≥9.x compliant # - Auto-Logoff (Idle-Timeouts)
# ✦ Dynamically omits UsePAM if PAM isnt present (e.g. Alpine) # - Brute-Force-Rate-Limiting
# ✦ Adds postquantum KEX, minimal cipher suite, strict authflow, # - Kein Forwarding (Agent/TCP/X11)
# ratelimiting & root lockdown # ✦ Dynamisches PAM-Handling
# ────────────────────────────────────────────────────────────────────────────── # ──────────────────────────────────────────────────────────────────────────────
printf "\033c" # clear terminal printf "\033c" # Clear terminal
# ─── Konfigurationsvariablen ─────────────────────────────────────────────────
SSH_CONFIG_DIR="/etc/ssh/sshd_config.d" SSH_CONFIG_DIR="/etc/ssh/sshd_config.d"
SSH_MAIN_CONFIG="/etc/ssh/sshd_config" SSH_MAIN_CONFIG="/etc/ssh/sshd_config"
SSH_CONFIG_FILE="$SSH_CONFIG_DIR/secure.conf" SSH_CONFIG_FILE="$SSH_CONFIG_DIR/secure.conf"
ED25519_KEY="/etc/ssh/ssh_host_ed25519_key" ED25519_KEY="/etc/ssh/ssh_host_ed25519_key"
ECDSA_KEY="/etc/ssh/ssh_host_ecdsa_key"
# ─── ANSI colors ───────────────────────────────────────────────────────────── # ─── 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' 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}"; } log() { echo -e "${GREEN}[+] $1${RESET}"; }
warn() { echo -e "${YELLOW}$1${RESET}"; } warn() { echo -e "${YELLOW}[!] $1${RESET}"; }
error() { echo -e "${RED}$1${RESET}"; } error() { echo -e "${RED}[✗] $1${RESET}"; }
# ─── Servicemanager detection ────────────────────────────────────────────── # ─── Service Manager Detection ──────────────────────────────────────────────
detect_service_manager() { detect_service_manager() {
if command -v systemctl &>/dev/null; then echo systemd if command -v systemctl &>/dev/null; then echo "systemd"; return; fi
elif command -v rc-service &>/dev/null; then echo openrc # Alpine, Gentoo… command -v rc-service &>/dev/null && echo "openrc" || echo "sysvinit"
elif command -v service &>/dev/null; then echo sysvinit
else echo unknown; fi
}
# ─── SSH servicename detection ───────────────────────────────────────────────
detect_ssh_service() {
local manager=$1 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 ;;
openrc)
for s in "${services[@]}"; do rc-service -l | grep -q "^$s$" && { echo $s; return; }; done ;;
sysvinit)
for s in "${services[@]}"; do [ -x "/etc/init.d/$s" ] && { echo $s; return; }; done ;;
esac
[ -x /usr/sbin/sshd ] && echo sshd || echo unknown
} }
# ─── SSH Service Handling ──────────────────────────────────────────────────
restart_ssh_service() { restart_ssh_service() {
local manager=$1 service=$2; warn "Starte SSHDienst ($service) neu…" local service=$1
case $manager in case $(detect_service_manager) in
systemd) sudo systemctl restart "$service" && return 0 ;; systemd) sudo systemctl restart "$service" ;;
openrc) sudo rc-service "$service" restart && return 0 ;; openrc) sudo rc-service "$service" restart ;;
sysvinit) sudo "/etc/init.d/$service" restart 2>/dev/null && return 0 ;; sysvinit) sudo "/etc/init.d/$service" restart 2>/dev/null ;;
esac *) sudo killall -HUP sshd 2>/dev/null ;;
sudo killall -HUP sshd 2>/dev/null && return 0 esac || { error "Failed to restart SSH"; return 1; }
return 1
} }
# ─── Paketinstallation ──────────────────────────────────────────────────────
install_package() { install_package() {
local p=$1; warn "Installiere $p" local pkg=$1
if command -v apt &>/dev/null; then sudo apt update -qq && sudo apt install -y $p -qq warn "Installing $pkg..."
elif command -v dnf &>/dev/null; then sudo dnf install -y $p &>/dev/null if command -v apt &>/dev/null; then
elif command -v yum &>/dev/null; then sudo yum install -y $p &>/dev/null sudo apt update -qq && sudo apt install -y "$pkg" -qq
elif command -v apk &>/dev/null; then sudo apk add $p &>/dev/null elif command -v dnf &>/dev/null; then
elif command -v pacman &>/dev/null; then sudo pacman -Sy --noconfirm $p &>/dev/null sudo dnf install -y "$pkg" &>/dev/null
elif command -v zypper &>/dev/null; then sudo zypper install -y $p &>/dev/null elif command -v apk &>/dev/null; then
else error "Paketmanager nicht erkannt installiere $p manuell."; return 1; fi sudo apk add "$pkg" &>/dev/null
log "$p installiert." else
error "Package manager not found. Install $pkg manually."
return 1
fi || { error "Installation failed"; return 1; }
log "$pkg installed."
} }
# ─── Preparations ───────────────────────────────────────────────────────────── # ─── Hauptsetup ────────────────────────────────────────────────────────────
SERVICE_MANAGER=$(detect_service_manager); log "ServiceManager: $SERVICE_MANAGER" log "Starting Secure-SSH Setup..."
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 ──────────────────────────────────────────────────────────────── # ─── Voraussetzungen prüfen ────────────────────────────────────────────────
for entry in "$ED25519_KEY ed25519" "$ECDSA_KEY ecdsa -b 384"; do command -v sudo &>/dev/null || install_package sudo
set -- $entry; key=$1; shift; args=$* command -v sshd &>/dev/null || install_package openssh-server
[ -f "$key" ] || { warn "Generiere Host-Key $(basename $key)"; sudo ssh-keygen -t $args -f "$key" -N "" -q && sudo chmod 600 "$key" && log "Key erstellt."; } [ -d "$SSH_CONFIG_DIR" ] || { sudo mkdir -p "$SSH_CONFIG_DIR"; log "Created $SSH_CONFIG_DIR"; }
done
# ─── Replace main config with include only ──────────────────────────────────── # ─── Host Key (Ed25519) ────────────────────────────────────────────────────
warn "Setze $SSH_MAIN_CONFIG auf Include…" [ -f "$ED25519_KEY" ] || {
echo "Include $SSH_CONFIG_DIR/*.conf" | sudo tee "$SSH_MAIN_CONFIG" >/dev/null warn "Generating Ed25519 host key..."
sudo rm -f $SSH_CONFIG_DIR/* sudo ssh-keygen -t ed25519 -f "$ED25519_KEY" -N "" -q && sudo chmod 600 "$ED25519_KEY"
log "Host key generated."
}
# ─── User handling ──────────────────────────────────────────────────────────── # ─── Benutzer/Gruppen-Abfrage ──────────────────────────────────────────────
read -rp $'\e[1;34mWelche Benutzer dürfen sich per SSH anmelden? (Leerzeichen-getrennt): \e[0m' SSH_USERS read -rp $'\e[1;34mAllowed SSH users (space-separated): \e[0m' SSH_USERS
VALID_USERS="" read -rp $'\e[1;34mAllowed SSH group (leave empty if unused): \e[0m' SSH_GROUP
# distributionspecific 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 u in $SSH_USERS; do
if id "$u" &>/dev/null; then log "Benutzer $u existiert."; VALID_USERS+="$u "; continue; fi
read -rp $'\e[1;34mBenutzer '"$u"$' anlegen? [y/N]: \e[0m' create; [[ $create =~ ^[Yy]$ ]] || continue
read -rsp $'\e[1;34mPasswort für '"$u"$': \e[0m' pw; echo
sudo useradd -m -s /bin/bash "$u" && echo "$u:$pw" | sudo chpasswd
sudo usermod -aG "$SUDO_GROUP" "$u"
sudo install -d -m700 -o "$u" -g "$u" "/home/$u/.ssh"
sudo touch "/home/$u/.ssh/authorized_keys" && sudo chmod 600 "/home/$u/.ssh/authorized_keys" && sudo chown "$u":"$u" "/home/$u/.ssh/authorized_keys"
read -rp $'\e[1;34mSSH Public Key für '"$u"$' 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/$u/.ssh/authorized_keys" >/dev/null; fi
VALID_USERS+="$u "
done
# ─── SFTP binary discovery ───────────────────────────────────────────────────
for p in /usr/lib/openssh/sftp-server /usr/libexec/openssh/sftp-server /usr/lib/ssh/sftp-server; do [ -x "$p" ] && SFTP_PATH=$p && break; done
SFTP_PATH=${SFTP_PATH:-internal-sftp}; log "SFTP-Pfad: $SFTP_PATH"
# ─── PAM detection ────────────────────────────────────────────────────────────
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 ausgelassen."
# ─── Generate secure.conf ─────────────────────────────────────────────────────
warn "Erstelle $SSH_CONFIG_FILE (modern hardened)…"
# ─── Konfigurationsdatei erstellen ─────────────────────────────────────────
warn "Generating hardened SSH config..."
sudo tee "$SSH_CONFIG_FILE" >/dev/null <<EOF sudo tee "$SSH_CONFIG_FILE" >/dev/null <<EOF
# ───────────────────────────────────────────────────────────────────────────── # ───────────────────────────────────────────────────────────────────────────
# Generated $(date -u +'%Y-%m-%dT%H:%MZ') # Hardened SSH Config (generated $(date +%Y-%m-%d))
# ───────────────────────────────────────────────────────────────────────────── # OpenSSH ≥9.x | Auto-Logoff | Rate-Limiting | No Forwarding
# ───────────────────────────────────────────────────────────────────────────
AddressFamily inet # ─── Core Security ──────────────────────────────────────────────────────────
Port 22
HostKey $ED25519_KEY
HostKey $ECDSA_KEY
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
SyslogFacility AUTHPRIV
LogLevel VERBOSE
MaxStartups 10:30:100
LoginGraceTime 30s
PermitRootLogin no PermitRootLogin no
PermitEmptyPasswords no PermitEmptyPasswords no
IgnoreRhosts yes HostKey $ED25519_KEY
StrictModes yes
# ─── Access Control ───────────────────────────────────────────────────────
AllowUsers ${SSH_USERS}
${SSH_GROUP:+AllowGroups $SSH_GROUP} # Nur gesetzt, wenn Gruppe existiert
DenyUsers root admin administrator
# ─── Authentication ───────────────────────────────────────────────────────
PubkeyAuthentication yes PubkeyAuthentication yes
PasswordAuthentication no PasswordAuthentication no
KbdInteractiveAuthentication no
AuthenticationMethods publickey AuthenticationMethods publickey
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
# X11 & SFTP # ─── Session Hardening ────────────────────────────────────────────────────
X11Forwarding no
Subsystem sftp $SFTP_PATH
ClientAliveInterval 300 ClientAliveInterval 300
ClientAliveCountMax 2 ClientAliveCountMax 2
LoginGraceTime 30s
MaxAuthTries 3
MaxSessions 5
MaxStartups 10:30:60
AllowUsers ${VALID_USERS%% } # ─── Network Restrictions ──────────────────────────────────────────────────
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
GatewayPorts no
PermitTunnel no
# ─── Logging & Auditing ───────────────────────────────────────────────────
LogLevel VERBOSE
PrintLastLog yes
SyslogFacility AUTH
EOF EOF
# Append PAM directives only if available # ─── PAM Handling (dynamisch) ──────────────────────────────────────────────
if $PAM_AVAILABLE; then if [ -d /etc/pam.d ] && find / -name 'libpam.so*' -quit 2>/dev/null; then
printf '\nUsePAM yes\nPrintMotd no\n' | sudo tee -a "$SSH_CONFIG_FILE" >/dev/null echo -e "UsePAM yes\nPrintMotd no" | sudo tee -a "$SSH_CONFIG_FILE" >/dev/null
log "PAM support enabled."
fi fi
log "SecureConfig geschrieben." # ─── Konfiguration testen & neu starten ────────────────────────────────────
sudo sshd -t || { error "Invalid SSH config. Fix errors before restarting."; exit 1; }
restart_ssh_service $(basename "$(command -v sshd)") || exit 1
# ─── Validate & restart SSH ────────────────────────────────────────────────── log "Hardened SSH setup complete!"
[ -d /run/sshd ] || { sudo mkdir -p /run/sshd; sudo chmod 0755 /run/sshd; } echo -e "\n${WHITE}→ Allowed users: ${SSH_USERS}${RESET}"
[ -n "$SSH_GROUP" ] && echo -e "${WHITE}→ Allowed group: ${SSH_GROUP}${RESET}"
sudo sshd -t || { error "SSH-Konfiguration ungültig!"; exit 1; } echo -e "${WHITE}→ Active settings:${RESET}"
sudo sshd -T | grep -Ei "allowusers|allowgroups|permitroot|maxauthtries|clientalive"
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}"