Namen verwenden, die Informationen tragen
Wählen Sie ein Schema und halten Sie sich daran, zum Beispiel Rolle, Umgebung und Nummer:
web-prod-1
web-prod-2
db-staging-1
acme-web-prod-1
Ein solcher Name sagt Ihnen, was Sie gleich anfassen, und er funktioniert mit Mustern. Ein Name wie server3 oder eine nackte IP-Adresse leistet beides nicht. Ergänzen Sie ein Projekt- oder Kundenpräfix, wenn Sie mehr als eines betreuen.
Muster statt wiederholter Zeilen
Host *-prod-*
User deploy
IdentityFile ~/.ssh/prod_ed25519
IdentitiesOnly yes
Host web-prod-1
HostName 203.0.113.11
Host web-prod-2
HostName 203.0.113.12
Denken Sie daran, dass der erste Wert gewinnt und jeder passende Block angewendet wird, die Reihenfolge also zählt. Siehe die Anleitung zur ssh config. Prüfen Sie jeden Host mit ssh -G web-prod-1.
Lassen sich Ihre Namen im DNS auflösen, können Sie die Zeilen pro Host weglassen:
Host web-*
HostName %h.example.com
Eine Datei pro Projekt
# top of ~/.ssh/config
Include ~/.ssh/config.d/*
~/.ssh/config.d/
acme
internal
lab
Jede Datei enthält die Hosts eines Projekts, sodass Sie sie mit einem Teammitglied teilen, im Repository dieses Projekts aufbewahren oder löschen können, wenn das Projekt endet. Lassen Sie Include am Anfang der Hauptdatei stehen und die Host *-Standardwerte darunter.
Gruppen
ssh kennt keine Gruppen als solche. Muster sind der einfache Weg, die Benennung erledigt also die Arbeit. Tags, ab OpenSSH 9.4, fassen Hosts zusammen, deren Namen nicht zusammenpassen:
Host legacy-api billing-1
Tag prod
Match tagged prod
User deploy
Um einen reinen Lesebefehl über eine Gruppe auszuführen, reicht im kleinen Maßstab eine einfache Shell-Schleife:
for host in web-prod-1 web-prod-2; do
printf '%s: ' "$host"
ssh -n -o BatchMode=yes -o ConnectTimeout=5 "$host" uptime
done
-n hält ssh von der Standardeingabe fern, damit dieselbe Schleife auch funktioniert, wenn die Namen aus einer Datei kommen. BatchMode lässt den Aufruf scheitern, statt an einer Abfrage zu warten, und ConnectTimeout verhindert, dass ein toter Server alle anderen aufhält. Für parallele Läufe und vorsichtiges Ausrollen siehe Befehl per SSH auf mehreren Servern ausführen.
Ein Schlüssel pro Zweck
Ein Schlüssel pro Zweck, etwa Arbeit, ein Kunde oder Produktion, bedeutet: Geht einer verloren, öffnet er nicht alles. Außerdem können Sie den Zugang eines Kunden entziehen, indem Sie einen Schlüssel entfernen.
Host acme-*
IdentityFile ~/.ssh/acme_ed25519
IdentitiesOnly yes
Ohne IdentitiesOnly yes bietet ssh auch die Schlüssel in Ihrem Agent an, was zu Too many authentication failures führt. Setzen Sie IdentityFile nicht in Host *, wenn Sie diese Trennung wollen: Dieser Wert wird der Liste hinzugefügt und ersetzt sie nicht, der andere Schlüssel wird also ebenfalls versucht.
Ein Schlüssel pro Server ist meist mehr Aufwand, als es wert ist. Ändert sich die Liste der Personen und Server ständig, sehen Sie sich stattdessen SSH-Zertifikate an.
Gehashtes known_hosts: ein Kompromiss
HashKnownHosts yes speichert Hostnamen in ~/.ssh/known_hosts als Hashes, sodass jemand, der die Datei stiehlt, keine fertige Liste Ihrer Server bekommt. Debian und Ubuntu schalten es in /etc/ssh/ssh_config ein. Das ursprüngliche OpenSSH lässt es aus.
- Was Sie gewinnen: Eine gestohlene Datei listet Ihre Server nicht im Klartext auf. Hashes lassen sich weiterhin gegen eine Vermutung testen, das hält einen Angreifer also auf, stoppt ihn aber nicht.
- Was Sie verlieren: Sie können die Datei nicht mehr mit bloßem Auge lesen oder durchsuchen, und darauf basierende Shell-Vervollständigung funktioniert nicht mehr.
Die Werkzeuge funktionieren weiterhin mit gehashten Einträgen:
ssh-keygen -F web-prod-1 # find a host
ssh-keygen -R web-prod-1 # remove a host
ssh-keygen -H # hash an existing file
ssh-keygen -H behält das Original mit Klarnamen als known_hosts.old. Löschen Sie diese Datei, wenn Datenschutz der Grund war. Beachten Sie, dass auch Ihre ssh config, Ihr Shell-Verlauf und Ihr Inventar die Namen enthalten, Hashing allein verbirgt also weniger, als es scheint.
Ein Inventar führen
Ab etwa einem Dutzend Server brauchen Sie eine Liste, die sagt, was existiert: Name, Adresse, Rolle, Umgebung, Verantwortlicher. Eine Textdatei in einem privaten Git-Repository genügt. Halten Sie sie frei von Passwörtern und Schlüsseln. Diese Liste prüfen Sie, wenn jemand geht oder wenn Sie fragen, welche Server noch gebraucht werden.
Ein Ansible-Inventar ist dafür ein gutes Format, auch wenn Sie Ansible noch nicht nutzen:
[web]
web-prod-1
web-prod-2
[db]
db-prod-1 ansible_user=postgres
Haben Sie schon eine solche Liste, können Sie daraus die config.d-Dateien erzeugen, statt zwei Listen von Hand zu pflegen. Dieselben Dateien kann auch eine App lesen, die Hosts aus ~/.ssh/config importiert, samt der per Include eingebundenen Dateien.
Wann ein Werkzeug wie Ansible passt
ssh eignet sich, um einen Server zu erreichen. Es hält Server nicht gleich. Wechseln Sie zu Ansible oder einem ähnlichen Werkzeug, wenn Sie dieselbe Änderung auf mehr als ein paar Servern machen, ein Setup wiederholen müssen oder festhalten wollen, was sich geändert hat.
ansible all -i inventory.ini -m ping
ansible web -i inventory.ini -a 'uptime'
Ansible nutzt standardmäßig den Befehl ssh, Ihre Konfiguration, Jump-Hosts und Schlüssel funktionieren also weiter. Das Ziel braucht nur SSH und Python. Prüfen Sie mit --check, was ein Playbook tun wird, bevor Sie es auf Produktion ausführen, und lesen Sie wie Sie Fehler auf Produktionsservern vermeiden.
Fragen
Wie ordne ich viele Hosts in ~/.ssh/config?
Geben Sie Hosts Namen, die Rolle und Umgebung zeigen, legen Sie gemeinsame Einstellungen in Muster wie Host web-* und führen Sie eine Datei pro Projekt unter ~/.ssh/config.d/, eingebunden mit Include.
Wie führe ich einen Befehl auf vielen SSH-Servern aus?
Für wenige Server reicht eine Shell-Schleife mit ssh -n -o BatchMode=yes. Für wiederkehrende Änderungen nutzen Sie Ansible, das über Ihre vorhandene ssh-Konfiguration läuft.
Sollte ich einen SSH-Schlüssel für alle Server nutzen?
Nutzen Sie einen Schlüssel pro Zweck, etwa Arbeit, einen Kunden oder Produktion, mit IdentitiesOnly yes. Ein Schlüssel pro Server macht meist mehr Arbeit, als er bringt.