Files
Boilerplates/Linux/SSH/secure_ssh.sh

183 lines
9.9 KiB
Bash
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
# ──────────────────────────────────────────────────────────────────────────────
# SecureSSH Setup Modern Linux (2025edition, PAMaware)
# ----------------------------------------------------------
# ✦ Generates hardened OpenSSH config (IPv4only)
# ✦ Installs / updates OpenSSHserver + creates host keys
# ✦ Creates users, adds SSH public keys, restricts login
# ✦ Removes deprecated directives fully OpenSSH ≥9.x compliant
# ✦ Dynamically omits UsePAM if PAM isnt present (e.g. Alpine)
# ✦ Adds postquantum KEX, minimal cipher suite, strict authflow,
# ratelimiting & 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}"; }
# ─── Servicemanager detection ───────────────────────────────────────────────
detect_service_manager() {
if command -v systemctl &>/dev/null; then echo systemd
elif command -v rc-service &>/dev/null; then echo openrc # Alpine, Gentoo…
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
}
restart_ssh_service() {
local manager=$1 service=$2; warn "Starte SSHDienst ($service) neu…"
case $manager in
systemd) sudo systemctl restart "$service" && return 0 ;;
openrc) sudo rc-service "$service" restart && return 0 ;;
sysvinit) sudo "/etc/init.d/$service" restart 2>/dev/null && return 0 ;;
esac
sudo killall -HUP sshd 2>/dev/null && return 0
return 1
}
install_package() {
local p=$1; warn "Installiere $p"
if command -v apt &>/dev/null; then sudo apt update -qq && sudo apt install -y $p -qq
elif command -v dnf &>/dev/null; then sudo dnf install -y $p &>/dev/null
elif command -v yum &>/dev/null; then sudo yum install -y $p &>/dev/null
elif command -v apk &>/dev/null; then sudo apk add $p &>/dev/null
elif command -v pacman &>/dev/null; then sudo pacman -Sy --noconfirm $p &>/dev/null
elif command -v zypper &>/dev/null; then sudo zypper install -y $p &>/dev/null
else error "Paketmanager nicht erkannt installiere $p manuell."; return 1; fi
log "$p installiert."
}
# ─── Preparations ─────────────────────────────────────────────────────────────
SERVICE_MANAGER=$(detect_service_manager); log "ServiceManager: $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 ────────────────────────────────────────────────────────────────
for entry in "$ED25519_KEY ed25519" "$ECDSA_KEY ecdsa -b 384"; do
set -- $entry; key=$1; shift; args=$*
[ -f "$key" ] || { warn "Generiere Host-Key $(basename $key)"; sudo ssh-keygen -t $args -f "$key" -N "" -q && sudo chmod 600 "$key" && log "Key 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
sudo rm -f $SSH_CONFIG_DIR/*
# ─── User handling ────────────────────────────────────────────────────────────
read -rp $'\e[1;34mWelche Benutzer dürfen sich per SSH anmelden? (Leerzeichen-getrennt): \e[0m' SSH_USERS
VALID_USERS=""
# 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)…"
sudo tee "$SSH_CONFIG_FILE" >/dev/null <<EOF
# ─────────────────────────────────────────────────────────────────────────────
# Generated $(date -u +'%Y-%m-%dT%H:%MZ')
# ─────────────────────────────────────────────────────────────────────────────
AddressFamily inet
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
PermitEmptyPasswords no
IgnoreRhosts yes
StrictModes yes
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
AuthenticationMethods publickey
# X11 & SFTP
X11Forwarding no
Subsystem sftp $SFTP_PATH
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers ${VALID_USERS%% }
EOF
# Append PAM directives only if available
if $PAM_AVAILABLE; then
printf '\nUsePAM yes\nPrintMotd no\n' | sudo tee -a "$SSH_CONFIG_FILE" >/dev/null
fi
log "SecureConfig 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}"