Einleitung
In diesem Tutorial werden wir einen neu erstellten Debian-Server (Debian 9 Stretch) mit einer sicheren Basiskonfiguration ausstatten und Docker installieren.
Wir werden ...
- einen unprivilegierten Sudo-Benutzer anlegen
- Passwort-Login verbieten
- den Root Benutzer sperren
- den SSH-Port ändern
- eine Firewall einrichten
- Docker und docker-compose installieren
- unserem Sudo-Benutzer Zugriff auf Docker gewähren
Wenn Docker nicht auf dem Server benötigt wird, kann dieser Schritt natürlich auch ausgelassen werden.
Ich habe außerdem eine Cloud-Init Konfiguration erstellt, mit welcher alle Schritte die wir in diesem Tutorial durchführen, automatisch beim erstellen eines Servers angewendet werden können.
Schritt 1 - Sudo-Benutzer erstellen
Da wir in einem der nächsten Schritte das Einloggen als Root unterbinden werden, benötigen wir zunächst einen neuen Nutzer, mit dem wir uns einloggen und den Server administrieren können.
Wir erstellen den Benutzer holu
mit folgendem Befehl:
adduser --disabled-password holu
Da wir den Login mit Passwörtern deaktivieren wollen, benötigen wir für unseren Benutzer auch kein Passwort und deaktivieren es daher mit dem Parameter --disabled-password
.
Der neu angelegte Benutzer 'holu' hat aktuell noch keine speziellen Berechtigungen. Da wir den Benutzer allerdings als Ersatz für 'root' verwenden wollen, werden wir holu Sudo-Berechtigungen erteilen, wodurch dieser Befehle als root ausführen kann.
Um dem Benutzer die Rechte zuzuweisen erstellen wir die Datei /etc/sudoers.d/90-holu
mit folgendem Inhalt:
holu ALL=(ALL) NOPASSWD:ALL
Schritt 2 - SSH konfigurieren
Schritt 2.1 - SSH-Serverkonfiguration
Für zusätzliche Sicherheit passen wir die Konfiguration des SSH-Servers an. Dazu öffnen wir /etc/ssh/sshd_config
mit einem Texteditor unserer Wahl (welche selbstverständlich auf vim fallen sollte), löschen den Inhalt der Datei und fügen stattdessen die unten stehende Konfiguration ein. Auf die wichtigsten Einstellungen gehe ich weiter unten noch gesondert ein.
Protocol 2
Port 44933
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
UsePrivilegeSeparation yes
KeyRegenerationInterval 3600
SyslogFacility AUTH
LogLevel INFO
PermitRootLogin no
StrictModes yes
IgnoreRhosts yes
RhostsRSAAuthentication no
HostbasedAuthentication no
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding no
PrintMotd no
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
AllowUsers holu
Protocol 2
Stellt sicher, dass der Server nur Verbindungen über die sichere Protokollversion 2 akzeptiert.
Port 44933
Das ändern des Ports erhöht zwar nicht die Sicherheit, allerdings können wir so die meisten automatisierten Login versuche umgehen, da diese meist nur den Standardport verwenden.
PermitRootLogin no
Verbietet den Login als Root über SSH.
PasswordAuthentication no
Verbietet den Login mit Passwörtern. Wir deaktivieren diese Möglichkeit, da der Login mit einem öffentlichen Schlüssel sicherer ist.
PubkeyAuthentication yes
Aktiviert die Authentifizierung mittels SSH-Schlüsselpaaren.
StrictModes yes
Verhindert den Start des SSH-Servers wenn bestimmte Dateien zu lockere Berechtigungen haben.
AllowUsers holu
Diese Option stellt eine Whitelist für alle Benutzer die sich per SSH einloggen dürfen da. Wir erlauben nur unseren 'holu' Benutzer.
Wichtig: Der Server oder der SSH-Dienst darf auf keinen Fall neu gestartet werden bevor die nächsten Schritte abgeschlossen sind, da sonst die neue Konfiguration aktiv wird, welche uns vom Server aussperrt.
Schritt 2.2 - Erstellen eines SSH-Schlüsselpaars
Im vorherigen Schritt haben wir den Login mit Passwörtern deaktiviert, also müssen wir uns nun auf die einzige verbleibende Möglichkeit, der Authentifizierung mit einem SSH-Schlüsselpaar, einstellen.
Zunächst müssen wir auf unserem lokalen Rechner ein Schlüsselpaar generieren. Wenn bereits ein Schlüsselpaar vorliegt, kann dieser Schritt natürlich übersprungen werden.
Nutzer die von Windows heimgesucht werden, können z.B. das Programm PuTTYgen verwenden.
Unter GNU/Linux können wir ein Schlüsselpaar mit dem folgendem Befehl erzeugen.
ssh-keygen \
-o \
-a 100 \
-t ed25519 \
-f ~/.ssh/id_ed25519 \
-C "$(whoami)@$(hostname)"
Das Schlüsselpaar (bestehend aus den Dateien id_ed25519
und id_ed25519.pub
) sollte sich nun im Home-Verzeichnis des lokalen Benutzers unter ~/.ssh
befinden. Der private Schlüssel (die Datei ohne .pub) sollte, ähnlich wie ein Passwort, sicher aufbewahrt und nicht weitergegeben werden.
Schritt 2.3 - Hinterlegen des öffentlichen Schlüssels
Damit wir uns mit dem unserem privaten Schlüssel authentifizieren können, muss der dazugehörige öffentliche Schlüssel auf dem Server hinterlegt werden. Dazu erstellen wir im SSH-Verzeichnis des Benutzers 'holu' die Datei authorized_keys
und fügen dort unseren öffentlichen Schlüssel (den Inhalt von id_ed25519.pub) ein und passen die Dateirechte so an, dass niemand außer dem Benutzer 'holu' auf diese Datei zugreifen kann (andernfalls würde der SSH-Service auf Grund des aktivierten 'StrictMode' nicht starten).
mkdir -p /home/holu/.ssh
vim /home/holu/.ssh/authorized_keys
chmod 600 /home/holu/.ssh/authorized_keys
chown holu:holu /home/holu/.ssh/authorized_keys
Schritt 2.4 - Aktivieren der neuen Konfiguration
Jetzt, da unser Schlüssel auf dem Server hinterlegt ist, können wir die neue Konfiguration des SSH-Servers aktivieren indem wir den SSH-Server neu starten.
systemctl restart sshd
Wir sollten uns nun mit dem Benutzer 'holu' über den neuen SSH-Port mit dem Server verbinden, und mithilfe unseres SSH-Schlüsselpaares authentifizieren können.
ssh -p 44933 holu@<your_host>
Ab hier werden alle Schritte mit dem Benutzer 'holu' durchgeführt.
Schritt 3 - Einrichtung der Firewall
Zum Einrichten einer Firewall werden wir das Programm 'ufw' (eine Abstraktion von iptables) verwenden, da die Regeln so deutlich einfacher und komfortabler als mit iptables direkt verwaltet werden können.
Das Paket 'ufw' ist nicht in der Standardinstallation von Debian enthalten und kann über die Paketverwaltung nachinstalliert werden.
sudo apt install ufw
Wir legen nun eine Regel an, die alle eingehenden Verbindungen, die nicht explizit erlaubt wurden, blockiert.
sudo ufw default deny incoming
Bevor wir die Firewall aktivieren müssen wir selbstverständlich unseren SSH-Port freigeben, da wir uns sonst vom Server aussperren.
sudo ufw allow 44933/tcp
Wir können die Firewall nun mit folgendem Befehl aktivieren.
sudo ufw enable
Mithilfe des Befehls ufw status
können alle angelegten Regeln aufgelistet werden. Dieser Befehl muss ebenfalls als root ausgeführt werden.
Schritt 4 - Docker Installation (Optional)
Schritt 4.1 - Hinzufügen der Paketquellen
Da Debian keine aktuelle Version von Docker in den offiziellen Paketquellen bereitstellt, werden zum Download über die Paketverwaltung die Paketquellen von Docker benötigt. Die Offizielle Dokumentation beschreibt wie diese eingebunden werden können.
Schritt 4.2 - Installation
Wenn die Paketquellen eingebunden sind, kann Docker ganz normal über die Paketverwaltung installiert werden.
sudo apt install \
docker-ce \
docker-ce-cli \
containerd.io \
docker-compose
Schritt 4.3 - Zugriff auf Docker
Standardmäßig kann Docker nur als root verwendet werden. Damit der Benutzer 'holu' Docker selbst (ohne sudo) verwenden kann, muss dieser zur Gruppe 'docker' hinzugefügt werden.
sudo usermod -aG docker holu
Achtung: Nutzer in der Docker-Gruppe haben effektiv Root-Rechte. Weitere Informationen gibt es hier: Docker security | Docker Documentation.
Schritt 5 - Cloud Init
Einige Anbieter, darunter auch Hetzner Cloud, unterstützen Cloud-Init zur Konfiguration von Servern direkt nach der Erstellung. Die Nachfolgende Cloud-Init-Konfiguration führt alle in diesem Artikel gezeigten Schritte automatisch durch.
Variablen (durch <>
gekennzeichnet) müssen vor der Verwendung der Konfiguration ersetzt werden.
#cloud-config
users:
- name: <username>
ssh-authorized_keys:
- <your ssh public key here>
sudo: ['ALL=(ALL) NOPASSWD:ALL']
groups:
- sudo
- docker
shell: /bin/bash
package_upgrade: true
packages:
- ufw
- vim
- apt-transport-https
- ca-certificates
- curl
- gnupg2
- software-properties-common
runcmd:
- curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
- add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"
- apt-get update -y
- apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose
- ufw default deny incoming
- ufw allow <ssh_port>/tcp
- echo "y" | ufw enable
write_files:
- path: /etc/ssh/sshd_config
content: |
Protocol 2
Port <ssh_port>
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
UsePrivilegeSeparation yes
KeyRegenerationInterval 3600
SyslogFacility AUTH
LogLevel INFO
PermitRootLogin no
StrictModes yes
IgnoreRhosts yes
RhostsRSAAuthentication no
HostbasedAuthentication no
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding no
PrintMotd no
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
AllowUsers <username>
Fazit
Fertig! Wir haben nun einen Debian-Server mit solider Basiskonfiguration.