Files
Boilerplates/Linux/SSH/secure_ssh.sh

596 lines
19 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.
#!/bin/bash
printf "\033c"
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"
# Farben für bessere Lesbarkeit
RED='\033[1;31m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;34m'
WHITE='\033[1;37m'
RESET='\033[0m'
# Logging-Funktionen
log() {
echo -e "${GREEN}$1${RESET}"
}
warn() {
echo -e "${YELLOW}$1${RESET}"
}
error() {
echo -e "${RED}$1${RESET}"
}
# Funktion zur Erkennung des Service-Managers (systemd, init, etc.)
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
}
# Funktion zur Erkennung des SSH-Dienstnamens
detect_ssh_service() {
local service_manager=$1
# Liste möglicher SSH-Dienstnamen
local ssh_services=("sshd" "ssh" "openssh-server" "openssh")
case "$service_manager" in
systemd)
for service in "${ssh_services[@]}"; do
if systemctl list-units --type=service | grep -q "$service"; then
echo "$service"
return 0
fi
done
;;
sysvinit)
for service in "${ssh_services[@]}"; do
if service --status-all 2>&1 | grep -q "$service"; then
echo "$service"
return 0
fi
done
;;
openrc)
for service in "${ssh_services[@]}"; do
if rc-service -l | grep -q "$service"; then
echo "$service"
return 0
fi
done
;;
esac
# Fallback: Prüfe die üblichen Verzeichnisse auf ausführbare SSHd-Dateien
if [ -x /usr/sbin/sshd ]; then
echo "sshd"
elif [ -x /usr/bin/sshd ]; then
echo "sshd"
else
echo "unknown"
fi
}
# Funktion zum Neustart des SSH-Dienstes
restart_ssh_service() {
local service_manager=$1
local service_name=$2
warn "Starte SSH-Dienst ($service_name) neu..."
case "$service_manager" in
systemd)
if sudo systemctl restart "$service_name"; then
log "SSH-Dienst erfolgreich neu gestartet."
return 0
fi
;;
sysvinit)
if sudo service "$service_name" restart; then
log "SSH-Dienst erfolgreich neu gestartet."
return 0
fi
;;
openrc)
if sudo rc-service "$service_name" restart; then
log "SSH-Dienst erfolgreich neu gestartet."
return 0
fi
;;
*)
# Direkter Neustart als letzter Ausweg
if sudo killall -HUP sshd 2>/dev/null; then
log "SSH-Dienst durch Signal neu gestartet."
return 0
fi
;;
esac
error "Fehler beim Neustart des SSH-Dienstes."
return 1
}
# Funktion zur Paketinstallation basierend auf dem Paketmanager
install_package() {
local package=$1
warn "Installiere $package..."
# Erkennung des Paketmanagers
if command -v apt &> /dev/null; then
# Debian/Ubuntu
if sudo apt update &> /dev/null && sudo apt install -y "$package" &> /dev/null; then
log "$package wurde erfolgreich installiert."
return 0
fi
elif command -v dnf &> /dev/null; then
# RHEL 8+/Fedora
if sudo dnf install -y "$package" &> /dev/null; then
log "$package wurde erfolgreich installiert."
return 0
fi
elif command -v yum &> /dev/null; then
# Ältere RHEL/CentOS
if sudo yum install -y "$package" &> /dev/null; then
log "$package wurde erfolgreich installiert."
return 0
fi
elif command -v apk &> /dev/null; then
# Alpine Linux
if sudo apk add "$package" &> /dev/null; then
log "$package wurde erfolgreich installiert."
return 0
fi
elif command -v pacman &> /dev/null; then
# Arch Linux
if sudo pacman -Sy --noconfirm "$package" &> /dev/null; then
log "$package wurde erfolgreich installiert."
return 0
fi
elif command -v zypper &> /dev/null; then
# openSUSE
if sudo zypper install -y "$package" &> /dev/null; then
log "$package wurde erfolgreich installiert."
return 0
fi
else
error "Nicht unterstütztes System. Bitte $package manuell installieren."
return 1
fi
error "Fehler bei der Installation von $package."
return 1
}
# Erkennung des Service-Managers
SERVICE_MANAGER=$(detect_service_manager)
log "Erkannter Service-Manager: $SERVICE_MANAGER"
# Prüfe, ob sudo installiert ist
if ! command -v sudo &> /dev/null; then
warn "sudo ist nicht installiert. Versuche, sudo zu installieren..."
# Installiere sudo basierend auf dem erkannten Paketmanager
if command -v apt &> /dev/null; then
apt update && apt install -y sudo
elif command -v dnf &> /dev/null; then
dnf install -y sudo
elif command -v yum &> /dev/null; then
yum install -y sudo
elif command -v apk &> /dev/null; then
apk add sudo
elif command -v pacman &> /dev/null; then
pacman -Sy --noconfirm sudo
elif command -v zypper &> /dev/null; then
zypper install -y sudo
else
error "Nicht unterstütztes System. Bitte sudo manuell installieren."
exit 1
fi
if command -v sudo &> /dev/null; then
log "sudo wurde erfolgreich installiert."
else
error "Fehler bei der Installation von sudo."
exit 1
fi
else
log "sudo ist bereits installiert."
fi
# Prüfe und installiere OpenSSH-Server
if ! command -v sshd &> /dev/null; then
warn "OpenSSH-Server wird installiert..."
if command -v apt &> /dev/null; then
install_package "openssh-server"
elif command -v dnf &> /dev/null || command -v yum &> /dev/null; then
install_package "openssh-server"
elif command -v apk &> /dev/null; then
install_package "openssh"
elif command -v pacman &> /dev/null; then
install_package "openssh"
elif command -v zypper &> /dev/null; then
install_package "openssh"
else
error "Nicht unterstütztes System. Bitte OpenSSH manuell installieren."
exit 1
fi
else
log "OpenSSH-Server ist bereits installiert."
fi
# Stelle sicher, dass das Konfigurationsverzeichnis existiert
if [ ! -d "$SSH_CONFIG_DIR" ]; then
warn "SSH Konfigurationsverzeichnis existiert nicht. Es wird erstellt..."
sudo mkdir -p "$SSH_CONFIG_DIR"
log "SSH Konfigurationsverzeichnis erstellt."
fi
# Generiere fehlende Schlüssel
if [ ! -f "$ED25519_KEY" ]; then
warn "Host-Schlüssel fehlt. Generiere ssh_host_ed25519_key..."
if sudo ssh-keygen -t ed25519 -f "$ED25519_KEY" -N "" &> /dev/null; then
sudo chown root:root "$ED25519_KEY"
sudo chmod 600 "$ED25519_KEY"
log "Host-Schlüssel ssh_host_ed25519_key wurde erstellt."
else
error "Fehler beim Erstellen des Host-Schlüssels."
exit 1
fi
else
log "Host-Schlüssel ssh_host_ed25519_key ist bereits vorhanden."
fi
if [ ! -f "$ECDSA_KEY" ]; then
warn "Host-Schlüssel fehlt. Generiere ssh_host_ecdsa_key..."
if sudo ssh-keygen -t ecdsa -b 384 -f "$ECDSA_KEY" -N "" &> /dev/null; then
sudo chown root:root "$ECDSA_KEY"
sudo chmod 600 "$ECDSA_KEY"
log "Host-Schlüssel ssh_host_ecdsa_key wurde erstellt."
else
error "Fehler beim Erstellen des Host-Schlüssels."
exit 1
fi
else
log "Host-Schlüssel ssh_host_ecdsa_key ist bereits vorhanden."
fi
# Konfiguriere SSH für die Include-Direktive
warn "Setze /etc/ssh/sshd_config zurück auf Include-Direktive..."
sudo tee "$SSH_MAIN_CONFIG" > /dev/null <<EOF
Include $SSH_CONFIG_DIR/*.conf
EOF
log "/etc/ssh/sshd_config enthält jetzt nur noch die Include-Direktive."
# Bereinige alte Konfigurationsdateien im SSH_CONFIG_DIR
sudo rm -f $SSH_CONFIG_DIR/*
echo -en "${BLUE}Welche Benutzer dürfen sich per SSH anmelden? (Benutzer durch ${WHITE}Leerzeichen${BLUE} trennen): ${RESET}"
read SSH_USERS
VALID_USERS=""
# Bestimme die sudo-Gruppe abhängig von der Distribution
SUDO_GROUP="sudo" # Standard-Wert
# Erkennung der korrekten sudo-Gruppe
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian|raspbian)
SUDO_GROUP="sudo"
;;
centos|fedora|rhel|almalinux|rocky|ol)
SUDO_GROUP="wheel"
;;
arch|manjaro)
SUDO_GROUP="wheel"
;;
alpine)
SUDO_GROUP="wheel"
;;
opensuse*|sles)
SUDO_GROUP="wheel"
;;
*)
# Prüfe, ob die Gruppe wheel existiert
if getent group wheel &>/dev/null; then
SUDO_GROUP="wheel"
fi
;;
esac
fi
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 "
else
echo -en "${BLUE}Benutzer ${WHITE}$user${BLUE} existiert nicht. Soll dieser erstellt werden? ${YELLOW}[${WHITE}y/n${YELLOW}]${RESET}: "
read CREATE_USER
if [ "$CREATE_USER" == "y" ]; then
echo -en "${BLUE}Gib ein Passwort für ${WHITE}$user${BLUE} ein: ${RESET}"
read -s USER_PASSWORD
echo
# Benutzer erstellen basierend auf der Distribution
if command -v useradd &> /dev/null; then
# Linux-Standard
if sudo useradd -m -s /bin/bash "$user" &>/dev/null && echo "$user:$USER_PASSWORD" | sudo chpasswd &>/dev/null; then
log "Benutzer $user wurde erstellt."
# Füge Benutzer zur sudo-Gruppe hinzu
if getent group "$SUDO_GROUP" &>/dev/null; then
sudo usermod -aG "$SUDO_GROUP" "$user" &>/dev/null
log "Benutzer $user wurde zur $SUDO_GROUP-Gruppe hinzugefügt."
else
warn "Gruppe $SUDO_GROUP existiert nicht. Der Benutzer erhält keine sudo-Rechte."
fi
else
error "Fehler bei der Erstellung von Benutzer $user."
continue
fi
elif command -v adduser &> /dev/null; then
# Debian/Ubuntu-spezifisch
if sudo adduser --disabled-password --gecos "" "$user" &>/dev/null && echo "$user:$USER_PASSWORD" | sudo chpasswd &>/dev/null; then
log "Benutzer $user wurde erstellt."
# Füge Benutzer zur sudo-Gruppe hinzu
if getent group "$SUDO_GROUP" &>/dev/null; then
sudo usermod -aG "$SUDO_GROUP" "$user" &>/dev/null
log "Benutzer $user wurde zur $SUDO_GROUP-Gruppe hinzugefügt."
else
warn "Gruppe $SUDO_GROUP existiert nicht. Der Benutzer erhält keine sudo-Rechte."
fi
else
error "Fehler bei der Erstellung von Benutzer $user."
continue
fi
else
error "Kein Befehl zum Erstellen von Benutzern gefunden."
continue
fi
# SSH-Verzeichnis und Schlüsseldatei erstellen
sudo mkdir -p "/home/$user/.ssh"
sudo touch "/home/$user/.ssh/authorized_keys"
sudo chown -R "$user":"$user" "/home/$user/.ssh"
sudo chmod 700 "/home/$user/.ssh"
sudo chmod 600 "/home/$user/.ssh/authorized_keys"
echo -en "${BLUE}Möchtest du einen SSH Public Key für ${WHITE}$user${BLUE} hinzufügen? ${YELLOW}[${WHITE}y/n${YELLOW}]${RESET}: "
read ADD_KEY
if [ "$ADD_KEY" == "y" ]; then
echo -en "${BLUE}Füge den SSH Public Key hier ein: ${RESET}"
read SSH_KEY
echo "$SSH_KEY" | sudo tee -a "/home/$user/.ssh/authorized_keys" &> /dev/null
fi
VALID_USERS+="$user "
fi
fi
done
# Erstelle SSH-Konfigurationsdatei
warn "Erstelle SSH-Konfigurationsdatei..."
# Bestimme den Pfad zum SFTP-Server basierend auf der Distribution
SFTP_PATH="/usr/lib/openssh/sftp-server" # Standard für Debian/Ubuntu
# Finde den tatsächlichen Pfad des SFTP-Servers
if [ -f /usr/lib/openssh/sftp-server ]; then
SFTP_PATH="/usr/lib/openssh/sftp-server"
elif [ -f /usr/libexec/openssh/sftp-server ]; then
SFTP_PATH="/usr/libexec/openssh/sftp-server"
elif [ -f /usr/lib/ssh/sftp-server ]; then
SFTP_PATH="/usr/lib/ssh/sftp-server"
else
# Suche nach der sftp-server-Binärdatei im System
SFTP_PATH_FIND=$(find /usr -name sftp-server -type f 2>/dev/null | head -1)
if [ -n "$SFTP_PATH_FIND" ]; then
SFTP_PATH="$SFTP_PATH_FIND"
else
SFTP_PATH="internal-sftp" # Fallback auf internen SFTP-Server
fi
fi
log "Verwende SFTP-Server-Pfad: $SFTP_PATH"
# Prüfe, ob PAM verfügbar ist
PAM_AVAILABLE=false
if [ -d "/etc/pam.d" ] && (command -v pam &>/dev/null || ls /lib*/*/libpam.so* &>/dev/null || ls /lib/*/libpam.so* &>/dev/null || ls /usr/lib*/*/libpam.so* &>/dev/null || ls /usr/lib/*/libpam.so* &>/dev/null); then
PAM_AVAILABLE=true
log "PAM ist auf diesem System verfügbar."
else
warn "PAM scheint auf diesem System nicht verfügbar zu sein."
fi
# Prüfe, ob ModuliFile existiert und ob es ersetzt werden soll
MODULI_FILE="/etc/ssh/moduli"
if [ -f "$MODULI_FILE" ]; then
# Prüfe, ob eine Optimierung der moduli-Datei erwünscht ist
echo -en "${BLUE}Möchtest du die Diffie-Hellman-Parameter optimieren? Dies kann die SSH-Sicherheit erhöhen, benötigt aber etwas Zeit. ${YELLOW}[${WHITE}y/n${YELLOW}]${RESET}: "
read OPTIMIZE_MODULI
if [ "$OPTIMIZE_MODULI" == "y" ]; then
warn "Optimiere Diffie-Hellman-Parameter (Dies kann einige Minuten dauern)..."
# Sichere die Original-Datei
sudo cp "$MODULI_FILE" "${MODULI_FILE}.bak"
# Behalte nur starke Moduli (3072 Bit oder mehr)
sudo awk '$5 >= 3071' "$MODULI_FILE" | sudo tee "${MODULI_FILE}.tmp" > /dev/null
sudo mv "${MODULI_FILE}.tmp" "$MODULI_FILE"
log "Diffie-Hellman-Parameter wurden optimiert."
fi
fi
# Erstelle die Konfigurationsdatei mit dynamischen Einstellungen je nach System
sudo tee "$SSH_CONFIG_FILE" > /dev/null <<EOL
# SSHD Config - maximale Sicherheit (IPv4)
# Nur IPv4-Verbindungen
AddressFamily inet
# Standardport (22), kann bei Bedarf geändert werden
Port 22
# Nur Protokoll 2 zulassen (Protokoll 1 ist unsicher)
Protocol 2
# Host-Schlüssel (nur moderne Schlüssel)
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_ecdsa_key
# Sichere Key Exchange-Algorithmen (Kex)
KexAlgorithms curve25519-sha256,ecdh-sha2-nistp256,ecdh-sha2-nistp384,diffie-hellman-group14-sha256
# Sichere Ciphers (Chiffren)
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr
# Sichere MAC-Algorithmen
MACs hmac-sha2-512,hmac-sha2-256
# Log-Einstellungen
SyslogFacility AUTHPRIV
LogLevel VERBOSE
# Maximale Login-Wartezeit
LoginGraceTime 30s
# Root-Login verbieten
PermitRootLogin no
# Nur Schlüssel-Authentifizierung erlauben
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication no
EOL
# Füge PAM-Konfiguration hinzu, wenn verfügbar
if $PAM_AVAILABLE; then
cat <<EOL | sudo tee -a "$SSH_CONFIG_FILE" > /dev/null
# PAM für zusätzliche Sicherheitsmodule verwenden
UsePAM yes
# Kein MOTD durch SSH (über PAM regeln)
PrintMotd no
EOL
else
cat <<EOL | sudo tee -a "$SSH_CONFIG_FILE" > /dev/null
# PAM ist nicht verfügbar auf diesem System
# Basic-Auth-Einstellungen
UsePrivilegeSeparation sandbox
StrictModes yes
MaxAuthTries 3
MaxSessions 5
EOL
fi
# Füge den Rest der Konfiguration hinzu
cat <<EOL | sudo tee -a "$SSH_CONFIG_FILE" > /dev/null
# X11-Weiterleitung deaktivieren (falls nicht benötigt)
X11Forwarding no
# Pfad zur Authorized Keys-Datei
AuthorizedKeysFile .ssh/authorized_keys
# SFTP-Subsystem
Subsystem sftp $SFTP_PATH
# Inaktive SSH-Sitzungen überwachen und beenden
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers $VALID_USERS
EOL
log "Prüfe SSH-Konfiguration..."
# Stelle sicher, dass das PrivilegeSeparationVerzeichnis existiert
if [ ! -d /run/sshd ]; then
warn "/run/sshd fehlt - erstelle Verzeichnis..."
sudo mkdir -p /run/sshd
sudo chown root:sys /run/sshd || sudo chown root:root /run/sshd
sudo chmod 0755 /run/sshd
log "/run/sshd wurde erstellt."
fi
# Überprüfe, ob die Konfiguration gültig ist
if command -v sshd &> /dev/null; then
if ! sudo sshd -t &> /dev/null; then
error "Die SSH-Konfiguration enthält Fehler! Überprüfe die Konfiguration manuell."
exit 1
else
log "SSH-Konfiguration ist gültig."
fi
fi
# Erkenne den SSH-Dienst und starte ihn neu
SSH_SERVICE=$(detect_ssh_service "$SERVICE_MANAGER")
if [ "$SSH_SERVICE" == "unknown" ]; then
error "Kein SSH-Dienst gefunden. Bitte überprüfe deine Installation."
exit 1
fi
log "Erkannter SSH-Dienst: $SSH_SERVICE"
if ! restart_ssh_service "$SERVICE_MANAGER" "$SSH_SERVICE"; then
error "Fehler beim Neustart des SSH-Dienstes. Versuche einen alternativen Ansatz..."
# Fallback-Versuche für verschiedene Distributionen
if [ "$SERVICE_MANAGER" == "systemd" ]; then
# Versuche alle möglichen Dienste bei systemd
for service in sshd ssh openssh openssh-server; do
if sudo systemctl restart "$service" 2>/dev/null; then
log "SSH-Dienst ($service) erfolgreich neu gestartet."
exit 0
fi
done
elif [ "$SERVICE_MANAGER" == "sysvinit" ]; then
# Versuche alle möglichen Dienste bei sysvinit
for service in sshd ssh openssh openssh-server; do
if sudo service "$service" restart 2>/dev/null; then
log "SSH-Dienst ($service) erfolgreich neu gestartet."
exit 0
fi
done
elif [ "$SERVICE_MANAGER" == "openrc" ]; then
# Versuche alle möglichen Dienste bei OpenRC
for service in sshd ssh openssh openssh-server; do
if sudo rc-service "$service" restart 2>/dev/null; then
log "SSH-Dienst ($service) erfolgreich neu gestartet."
exit 0
fi
done
fi
# Als letzte Möglichkeit, versuche einen Kill/HUP-Signal an sshd zu senden
if pgrep sshd &>/dev/null && sudo killall -HUP sshd; then
log "SSH-Dienst durch Signal neu gestartet."
else
error "Konnte den SSH-Dienst nicht neu starten. Bitte starte den SSH-Dienst manuell neu."
exit 1
fi
fi
log "Setup abgeschlossen! Nur folgende Benutzer dürfen sich per SSH anmelden: ${WHITE}$VALID_USERS"
log "Die SSH-Konfiguration wurde für maximale Sicherheit optimiert."