SSH · Automatisierung · Sicherheit · DevOps
SSH in der Automatisierung —
known_hosts, Agent, Keys und Sicherheit

SSH in Automatisierungs-Skripten richtig zu verwenden ist anspruchsvoller als es aussieht: StrictHostKeyChecking zu deaktivieren löst das Problem des ersten Verbindungsaufbaus — aber öffnet gleichzeitig Man-in-the-Middle-Angriffe. Dieser Artikel zeigt, wie SSH-Automatisierung ohne Sicherheitskompromisse funktioniert.

15 Min. Lesezeit StrictHostKeyChecking · ssh-agent · BatchMode · ProxyJump OpenSSH · Bash · Linux · macOS · CI/CD

1. Warum SSH-Automatisierung Sorgfalt erfordert

Die einfachste Lösung für das Problem "SSH fragt interaktiv nach Host-Bestätigung" ist -o StrictHostKeyChecking=no. Diese Option findet sich in unzähligen CI-Skripten, Tutorials und Deployment-Konfigurationen — und ist in den meisten Kontexten ein Sicherheitsproblem. Sie deaktiviert den Schutzmechanismus, der Man-in-the-Middle-Angriffe verhindert. In einer produktiven SSH-Automatisierung bedeutet das: Jeder, der den DNS-Namen oder die IP-Adresse des Zielservers kontrolliert oder umleiten kann, kann eine Verbindung abfangen, ohne dass das Skript es merkt. Credentials, Deployment-Artefakte und sensitive Konfigurationen werden an den Angreifer übertragen.

Das eigentliche Problem, das StrictHostKeyChecking=no lösen soll, ist ein Workflow-Problem: Die known_hosts-Datei des Automatisierungs-Accounts enthält den Fingerprint des Zielservers nicht. Die korrekte Lösung ist nicht, die Prüfung zu deaktivieren, sondern den Fingerprint vorab bereitzustellen. In der SSH-Automatisierung bedeutet das: ssh-keyscan beim Server-Provisioning aufrufen, den Fingerprint in die known_hosts des Automatisierungs-Accounts oder in ein projektspezifisches Known-Hosts-File schreiben und dieses in der CI-Konfiguration als Secret hinterlegen. Das löst das Workflow-Problem ohne Sicherheitskompromiss.

Ein weiterer häufiger Fehler in der SSH-Automatisierung: Private Keys werden als Klartextdateien in Repositories, Container-Images oder Environment-Variablen gespeichert, die in Logs erscheinen. Die korrekte Handhabung: Keys nur in geschützten Secret-Stores (GitHub Secrets, Vault, AWS Secrets Manager) hinterlegen, beim Build in temporäre Dateien mit eingeschränkten Berechtigungen (chmod 600) schreiben und nach Verwendung sicher löschen. Diese drei Grundsätze — kein StrictHostKeyChecking=no, keine Keys in Repositories, keine Keys in Logs — bilden das Fundament sicherer SSH-Automatisierung.

2. known_hosts: Fingerprints vorprovisionieren

Die known_hosts-Datei speichert den öffentlichen Host-Key jedes SSH-Servers, mit dem sich der Client verbunden hat. Bei der ersten Verbindung fragt SSH interaktiv, ob der Fingerprint akzeptiert werden soll — ein Mechanismus, der in der SSH-Automatisierung nicht funktioniert. Die Lösung ist ssh-keyscan: Dieses Tool fragt den öffentlichen Key eines Servers ab, ohne eine authentifizierte Verbindung aufzubauen, und gibt ihn im known_hosts-Format aus. Der Output kann direkt in die known_hosts-Datei geschrieben werden: ssh-keyscan -H hostname >> ~/.ssh/known_hosts. Das -H-Flag hashes den Hostnamen, was verhindert, dass die known_hosts-Datei als Netzwerk-Topologie-Leak verwendet werden kann.

Für die SSH-Automatisierung in CI-Pipelines empfiehlt sich ein projektspezifisches known_hosts-File anstelle der globalen ~/.ssh/known_hosts. Das File wird beim Server-Provisioning erstellt, als CI-Secret gespeichert und vor jeder SSH-Verbindung temporär in ~/.ssh/ oder in einen temporären Pfad geschrieben. In den SSH-Optionen wird es mit -o UserKnownHostsFile=/pfad/zu/known_hosts explizit referenziert. So bleibt die known_hosts-Verwaltung unabhängig vom CI-Runner-Environment und kann versioniert und auditiert werden. Das Server-seitige Rotieren von Host-Keys (nach einem Incident oder regulär) erfordert dann ein Update des CI-Secrets — das ist der erwünschte Prozess, der eine bewusste Entscheidung erfordert.


#!/usr/bin/env bash
# ssh-automation-setup.sh — provision known_hosts and agent for automation
set -euo pipefail
IFS=$'\n\t'

KNOWN_HOSTS_FILE="${1:?Usage: $0 <known_hosts_file> <host1> [host2...]}"
shift

# Collect host fingerprints securely (with hashed hostnames)
provision_known_hosts() {
  local hosts=("$@")
  local tmpfile
  tmpfile="$(mktemp)"
  trap 'rm -f -- "$tmpfile"' EXIT

  local host
  for host in "${hosts[@]}"; do
    echo "Scanning: $host" >&2
    # -T timeout, -H hash hostname, query ed25519 and rsa keys
    ssh-keyscan -T 10 -H -t ed25519,rsa "$host" >> "$tmpfile" 2>/dev/null || {
      echo "[WARN] Could not scan $host" >&2
    }
  done

  # Deduplicate and sort for stable output
  sort -u "$tmpfile" > "$KNOWN_HOSTS_FILE"
  chmod 600 "$KNOWN_HOSTS_FILE"
  echo "[OK] Written ${#hosts[@]} host(s) to $KNOWN_HOSTS_FILE" >&2
}

provision_known_hosts "$@"

# Verify: connect with strict checking enabled
verify_connection() {
  local host="$1"
  ssh -o StrictHostKeyChecking=yes \
      -o UserKnownHostsFile="$KNOWN_HOSTS_FILE" \
      -o BatchMode=yes \
      -o ConnectTimeout=10 \
      "$host" 'echo OK' 2>&1 | head -1
}

3. StrictHostKeyChecking richtig konfigurieren

Das SSH-Optionspaar StrictHostKeyChecking hat drei relevante Werte für die SSH-Automatisierung: yes (Standard in neueren OpenSSH-Versionen) verbietet die Verbindung, wenn der Host nicht in known_hosts ist oder der Key geändert hat. no akzeptiert jeden Host und jeden Key ohne Prüfung — nie in Produktion verwenden. accept-new (OpenSSH 7.6+) ist der sinnvolle Mittelweg für Szenarien, in denen neue Hosts im laufenden Betrieb hinzukommen: Neue Hosts werden akzeptiert und zur known_hosts-Datei hinzugefügt, aber geänderte Keys von bekannten Hosts werden weiterhin als Fehler behandelt. Das ist der empfohlene Wert für Dynamic Infrastructure, wo neue Server-Instanzen automatisch verbunden werden müssen.

Ein häufig übersehener Aspekt: Wenn ein Server seinen Host-Key ändert (nach Neuinstallation, Key-Rotation oder Migration), schlägt die SSH-Automatisierung mit einer Warnung fehl. Das ist beabsichtigt — aber in automatisierten Deployment-Pipelines ohne Monitoring erscheint die Warnung in Logs, die niemand liest, und das Skript schlägt mit einem kryptischen Fehler fehl. Die Lösung: Den bekannten alten Key explizit aus known_hosts entfernen (ssh-keygen -R hostname) und den neuen Key per ssh-keyscan hinzufügen, als Teil des Server-Reprovisioning-Prozesses. Das macht den Prozess explizit und nachvollziehbar statt still fehlschlagend.

4. ssh-agent in Shell-Skripten und CI

Der ssh-agent hält entschlüsselte Private Keys im Speicher und stellt sie über ein Unix-Socket dem SSH-Client zur Verfügung. In der SSH-Automatisierung eliminiert er die Notwendigkeit, den Key-Passphrase bei jeder Verbindung einzugeben. In interaktiven Shells ist der Agent oft vom Desktop-Environment oder von der Login-Session gestartet und über die Umgebungsvariable SSH_AUTH_SOCK zugänglich. In nicht-interaktiven Kontexten (Cron-Jobs, CI-Runners) muss der Agent explizit gestartet werden: eval "$(ssh-agent -s)" startet einen neuen Agent-Prozess und setzt die Umgebungsvariablen in der aktuellen Shell. Der Key wird dann mit ssh-add /pfad/zum/key geladen.

In CI-Pipelines für die SSH-Automatisierung gibt es eine wichtige Sicherheitsentscheidung: Soll der Private Key direkt als CI-Secret gespeichert werden, oder soll ein Key ohne Passphrase für CI verwendet werden? Für hohe Sicherheit: Keys mit Passphrase, die Passphrase separat als CI-Secret, Agent mit automatischem ssh-add. Für Praktikabilität: Dedizierte CI-Keys ohne Passphrase, mit eingeschränkten Berechtigungen auf dem Zielserver (command=-Einschränkung in authorized_keys). In beiden Fällen: Der Agent-Prozess muss am Ende des Skripts gestoppt werden (ssh-agent -k), und der Key-Inhalt darf nie in Logs erscheinen. Daher immer ssh-add - (aus stdin) statt echo "$key" | ssh-add — Letzteres könnte in Process-Listen sichtbar werden.


#!/usr/bin/env bash
# ssh-agent-ci.sh — start ssh-agent, load key, cleanup after use
set -euo pipefail
IFS=$'\n\t'

# Private key from CI secret (never echo to stdout/stderr)
SSH_PRIVATE_KEY="${SSH_PRIVATE_KEY:?SSH_PRIVATE_KEY must be set}"

# Start agent and ensure cleanup
start_agent() {
  # eval sets SSH_AGENT_PID and SSH_AUTH_SOCK in current shell
  eval "$(ssh-agent -s)" > /dev/null
  # Register agent kill in cleanup
  trap 'ssh-agent -k > /dev/null 2>&1 || true' EXIT
}

load_key() {
  local key_content="$1"
  # ssh-add from stdin: key never appears in ps output or shell history
  printf '%s\n' "$key_content" | ssh-add - 2>/dev/null
  echo "[OK] SSH key loaded ($(ssh-add -l | wc -l) key(s) in agent)" >&2
}

start_agent
load_key "$SSH_PRIVATE_KEY"

# Now SSH connections use the agent — no password prompts
ssh -o StrictHostKeyChecking=yes \
    -o BatchMode=yes \
    -o ConnectTimeout=15 \
    deploy@production.example.com \
    'bash -s' < deploy-commands.sh

# Agent is killed automatically via trap EXIT

5. BatchMode: non-interaktive SSH-Verbindungen

Die SSH-Option BatchMode=yes ist in der SSH-Automatisierung unverzichtbar. Sie deaktiviert alle interaktiven Prompts: keine Passwort-Eingabe, keine Fingerprint-Bestätigung, keine Passphrases. Wenn SSH in BatchMode fehlschlägt, gibt es einen klaren Nicht-Null-Exit-Code statt einer blockierenden Eingabeaufforderung. Ohne BatchMode kann ein nicht-interaktives Skript an einem SSH-Prompt hängen — potenziell für immer, bis ein externes Timeout eingreift. In CI-Pipelines führt das zu Jobs, die nie enden und Slots blockieren.

Ergänzend zu BatchMode empfiehlt sich ConnectTimeout für die SSH-Automatisierung: Ein expliziter Timeout verhindert, dass ein nicht erreichbarer Host das Skript für die TCP-Verbindungs-Timeout-Zeit blockiert (die auf manchen Systemen mehrere Minuten beträgt). ServerAliveInterval und ServerAliveCountMax erkennen verlorene Verbindungen zu laufenden Remote-Prozessen und ermöglichen sauberes Failover statt endlosem Hängen. Die Kombination BatchMode=yes ConnectTimeout=30 ServerAliveInterval=60 ServerAliveCountMax=3 ist ein guter Standard für robuste SSH-Automatisierung in Deployment-Skripten.

6. SSH-Key-Verwaltung für Automatisierung

Die Key-Verwaltung ist der kritischste Sicherheitsaspekt der SSH-Automatisierung. Die wichtigste Grundregel: Für Automatisierung dedizierte Keys erstellen, die keine weiteren Zugriffsrechte haben. Kein Teilen von privaten Schlüsseln zwischen Personen und Automatisierungs-Accounts, kein Teilen eines Automatisierungs-Keys zwischen verschiedenen Umgebungen (Staging und Production müssen verschiedene Keys haben). Der authorized_keys-Eintrag auf dem Zielserver kann mit Optionen eingeschränkt werden: command="nur-dieser-befehl" erlaubt nur einen einzigen spezifischen Befehl, no-pty verhindert Pseudo-Terminal-Zuweisung, no-agent-forwarding und no-port-forwarding beschränken weitere SSH-Features.

In modernen Setups für die SSH-Automatisierung werden Private Keys nicht statisch gespeichert, sondern von einem Secret-Manager dynamisch generiert und zeitlich befristet ausgestellt. Vault von HashiCorp hat eine SSH-Secrets-Engine, die für jede Verbindung ein kurzlebiges Zertifikat ausstellt, das nach wenigen Minuten oder Stunden abläuft. Das eliminiert das Problem der Key-Rotation vollständig: Es gibt keine langlebigen Private Keys mehr, die gestohlen werden könnten. Für Umgebungen ohne Vault ist das Minimum: Keys mit ssh-keygen -t ed25519 (moderne, sichere Algorithmuswahl), regelmäßige Rotation (mindestens jährlich) und sofortige Revokation bei Verdacht auf Kompromittierung.

7. Jump-Hosts und Bastion-Proxies

In vielen Produktionsumgebungen sind Zielserver nicht direkt aus dem Internet oder dem CI-Runner erreichbar, sondern nur über einen Bastion-Host (Jump-Host). Die klassische, unsichere Lösung: Den Private Key auf den Bastion-Host kopieren und von dort aus auf Zielserver verbinden (-A Agent-Forwarding). Das ist problematisch: Ein Angreifer, der den Bastion-Host kompromittiert, kann den weitergeleiteten Agent-Socket nutzen, um sich mit beliebigen Zielservern zu verbinden, solange die Agent-Session aktiv ist. Für die SSH-Automatisierung ist die sichere Alternative ProxyJump (oder die ältere ProxyCommand-Variante): Alle Verbindungen werden durch den Bastion-Host getunnelt, aber der Agent-Socket bleibt auf dem ursprünglichen Client.

Die OpenSSH-Option -J user@bastion oder in der ~/.ssh/config als ProxyJump konfiguriert, erstellt einen direkten TCP-Tunnel über den Bastion-Host. Das Kryptographie-Material (Private Keys) verlässt nie den CI-Runner — der Bastion-Host sieht nur den verschlüsselten Datenstream. Für komplexe Topologien können mehrere Jump-Hosts in einer Kette angegeben werden: -J bastion1,bastion2. In der ssh_config kann die Jump-Host-Konfiguration für verschiedene Hostnamen-Pattern unterschiedlich konfiguriert werden, was verschiedene Umgebungen (Staging über Bastion A, Production über Bastion B) sauber trennt.


#!/usr/bin/env bash
# ssh-jump-deployment.sh — deploy through bastion with ProxyJump
set -euo pipefail
IFS=$'\n\t'

readonly BASTION="${BASTION_HOST:?BASTION_HOST must be set}"
readonly TARGET="${TARGET_HOST:?TARGET_HOST must be set}"
readonly DEPLOY_USER="${DEPLOY_USER:-deploy}"
readonly KNOWN_HOSTS_FILE="${KNOWN_HOSTS_FILE:?KNOWN_HOSTS_FILE must be set}"

# Build common SSH options (no agent forwarding, strict host checking)
SSH_OPTS=(
  -o "StrictHostKeyChecking=yes"
  -o "UserKnownHostsFile=${KNOWN_HOSTS_FILE}"
  -o "BatchMode=yes"
  -o "ConnectTimeout=30"
  -o "ServerAliveInterval=60"
  -o "ServerAliveCountMax=3"
  -o "ForwardAgent=no"       # Never forward agent — security risk
  -o "LogLevel=ERROR"        # Suppress banner noise in CI output
)

# Connect to target through bastion via ProxyJump
# Private key never touches the bastion host
run_remote() {
  local cmd="$1"
  ssh "${SSH_OPTS[@]}" \
      -J "${DEPLOY_USER}@${BASTION}" \
      "${DEPLOY_USER}@${TARGET}" \
      "$cmd"
}

# Copy deployment artifact through bastion
deploy_artifact() {
  local local_file="$1"
  local remote_path="$2"
  scp -o "StrictHostKeyChecking=yes" \
      -o "UserKnownHostsFile=${KNOWN_HOSTS_FILE}" \
      -o "BatchMode=yes" \
      -o "ForwardAgent=no" \
      -J "${DEPLOY_USER}@${BASTION}" \
      "$local_file" \
      "${DEPLOY_USER}@${TARGET}:${remote_path}"
}

echo "Deploying to $TARGET via $BASTION..."
deploy_artifact "app-release.tar.gz" "/tmp/app-release.tar.gz"
run_remote "bash /opt/deploy/install.sh /tmp/app-release.tar.gz"
echo "[OK] Deployment complete"

8. SSH in CI/CD-Pipelines sicher einrichten

Die SSH-Automatisierung in CI/CD-Pipelines hat spezifische Sicherheitsanforderungen, die über normale Shell-Skripte hinausgehen. Der Private Key wird als CI-Secret gespeichert (GitHub Secrets, GitLab CI Variables mit Masked und Protected), in einem Before-Step aus dem Secret in eine temporäre Datei mit chmod 600 geschrieben und nach dem Deployment-Step gelöscht. Das Known-Hosts-File wird ebenfalls als CI-Secret gespeichert — es enthält keine Geheimnisse, aber seine Integrität ist für die Sicherheit der Verbindung entscheidend. Wenn das Known-Hosts-File modifiziert werden kann, kann ein Angreifer die Host-Key-Prüfung umgehen.

Ein wichtiger Sicherheitsaspekt für die SSH-Automatisierung in Multi-Stage-Pipelines: Deploy-Keys sollten nur für den Deploy-Step zugänglich sein, nicht für alle Pipeline-Jobs. In GitHub Actions bedeutet das: Den Key als Environment-Secret für den spezifischen Job setzen, nicht als Repository-Secret, das für alle Workflows gilt. In GitLab CI: Environment-spezifische Variables mit Scope auf Production-Environment beschränken, sodass Feature-Branch-Pipelines keinen Zugriff auf Production-Deployment-Keys haben. Das Principle of Least Privilege — jeder Job bekommt nur die Credentials, die er tatsächlich braucht — ist die wichtigste Maßnahme gegen Credential-Leakage bei kompromittierten Supply-Chain-Komponenten.

9. SSH-Optionen im Sicherheitsvergleich

Für die SSH-Automatisierung gibt es für jede unsichere Abkürzung eine sichere Alternative, die denselben Workflow-Bedarf erfüllt ohne Sicherheitskompromisse.

Option / Praxis Unsicher Sicher Risiko
Host-Überprüfung StrictHostKeyChecking=no yes + Known-Hosts-Secret Man-in-the-Middle-Angriff
Key-Zugriff Key in Repository / Image CI-Secret + chmod 600 tmpfile Credential-Leakage
Jump-Host-Zugang Agent-Forwarding (-A) ProxyJump (-J) Agent-Hijacking auf Bastion
Interaktivität Kein BatchMode — hängt BatchMode=yes + ConnectTimeout Pipeline hängt endlos
Key-Berechtigung Voller Shell-Zugriff command= in authorized_keys Voller Server-Zugriff bei Key-Kompromittierung

Die Tabelle zeigt: Jede unsichere Praxis in der SSH-Automatisierung hat eine direkte, sichere Alternative. Der häufigste Einwand — "aber das ist komplizierter einzurichten" — stimmt für den ersten Setup. Danach ist der Betrieb einer sicheren SSH-Automatisierung nicht aufwändiger als eine unsichere, und das Risikoprofil ist fundamental besser. Besonders command=-Einschränkungen in authorized_keys sind hochwertig: Selbst wenn ein Deployment-Key kompromittiert wird, kann der Angreifer damit nur den einen konfigurierten Befehl ausführen — keinen freien Shell-Zugriff.

Mironsoft

Shell-Automatisierung, DevOps-Tooling und Deployment-Infrastruktur

SSH-Automatisierung ohne Sicherheitsabkürzungen?

Wir überprüfen bestehende SSH-Automatisierungen auf Sicherheitslücken, ersetzen unsichere StrictHostKeyChecking=no-Konfigurationen durch korrekte Known-Hosts-Provisioning und richten sichere CI/CD-SSH-Pipelines mit ProxyJump und beschränkten Keys ein.

Security-Audit

Analyse bestehender SSH-Konfigurationen auf StrictHostKeyChecking=no und Key-Leakage

CI-Setup

Known-Hosts-Provisioning, ssh-agent und BatchMode für CI/CD-Pipelines

Jump-Host-Setup

ProxyJump-Konfiguration für Bastion-Hosts ohne Agent-Forwarding-Risiko

10. Zusammenfassung

Sichere SSH-Automatisierung in Shell-Skripten und CI/CD-Pipelines beruht auf wenigen, konsequent angewandten Prinzipien: Niemals StrictHostKeyChecking=no — stattdessen Known-Hosts-Files beim Server-Provisioning befüllen und als CI-Secret verwalten. Immer BatchMode=yes und ConnectTimeout für non-interaktive Verbindungen. Agent-Forwarding durch ProxyJump ersetzen, das Cryptographie-Material nie den Bastion-Host berühren lässt. Private Keys nur als CI-Secrets, nie in Repositories oder Container-Images. command=-Einschränkungen in authorized_keys begrenzen den Schaden bei Key-Kompromittierung.

Diese Maßnahmen erfordern beim ersten Einrichten etwas mehr Aufwand als die einfachen, unsicheren Alternativen. Aber der Betrieb ist danach nicht komplizierter — und das Risikoprofil ist fundamental besser. Gerade in Deployment-Pipelines, die mit Root-äquivalenten Berechtigungen auf Produktionsservern operieren, ist SSH-Automatisierung-Sicherheit kein optionales Feature, sondern eine Grundvoraussetzung für verantwortungsvolle Operations-Praxis.

SSH in der Automatisierung — Das Wichtigste auf einen Blick

Known-Hosts statt StrictHostKeyChecking=no

ssh-keyscan -H beim Server-Provisioning, Output als CI-Secret, -o UserKnownHostsFile beim SSH-Aufruf — kein Sicherheitskompromiss.

BatchMode + ConnectTimeout

BatchMode=yes verhindert blockierende Prompts. ConnectTimeout=30 verhindert endloses Hängen bei nicht erreichbaren Hosts.

ProxyJump statt Agent-Forwarding

-J bastion statt -A. Private Keys verlassen nie den CI-Runner, kein Agent-Hijacking-Risiko auf dem Bastion-Host.

command= in authorized_keys

Automation-Keys auf einen Befehl beschränken. Bei Key-Kompromittierung: nur dieser eine Befehl ausführbar, kein freier Shell-Zugriff.

11. FAQ: SSH in der Automatisierung — known_hosts, Agent, Keys und Sicherheit

1Warum ist StrictHostKeyChecking=no gefährlich?
Deaktiviert Man-in-the-Middle-Schutz. Angreifer mit DNS-Kontrolle können Verbindungen abfangen — Credentials und Daten werden übertragen ohne Warnung.
2Was ist accept-new?
OpenSSH 7.6+: neue Hosts automatisch akzeptieren, geänderte bekannte Keys ablehnen. Mittelweg für Dynamic Infrastructure.
3SSH-Keys sicher in CI/CD verwalten?
Als CI-Secret speichern, in chmod-600-Tmpfile schreiben, nach Verwendung löschen. Niemals in Repositories oder Logs. ssh-add - aus stdin.
4ProxyJump vs. Agent-Forwarding?
ProxyJump: Private Key bleibt auf dem Client. Agent-Forwarding: Agent-Socket auf Bastion-Host zugänglich — Agent-Hijacking-Risiko.
5Was bewirkt BatchMode=yes?
Deaktiviert alle interaktiven Prompts. Bei fehlendem Auth gibt SSH sofort Exit-Code 1 zurück statt zu blockieren.
6Automation-Key in authorized_keys einschränken?
command="/pfad/deploy.sh",no-pty,no-agent-forwarding vor dem Schlüssel. Bei Kompromittierung: nur dieser eine Befehl ausführbar.
7Fingerprints ohne interaktive Bestätigung hinzufügen?
ssh-keyscan -H -t ed25519,rsa hostname. Output als CI-Secret, bei Pipeline-Run in temporäre Datei schreiben.
8Host-Key ändert sich — was tun?
ssh-keygen -R hostname (alten Key entfernen), ssh-keyscan (neuen hinzufügen), CI-Secret mit Known-Hosts-File aktualisieren.
9Warum ssh-add - statt Datei?
stdin: erscheint nicht in ps aux oder Shell-History. Tmpfile: von Root lesbar, in Directory-Listings sichtbar. stdin minimiert Angriffsfläche.
10Verschiedene Bastions für Staging/Production?
~/.ssh/config mit Host-Pattern und ProxyJump pro Umgebung. Verschiedene Keys und Known-Hosts-Files pro Umgebung als separate CI-Secrets.