#!/usr/bin/env bash set -euo pipefail # ============================================================================= # ssh_context.sh # Wird von den Deploy-Skripten gesourced. # Stellt Target-Aufloesung und SSH-Setup bereit. # # Targets werden NICHT mehr hartkodiert, sondern aus Konfigurationsdateien unter # targets/.env geladen. Neue Targets legt man interaktiv mit ./init.sh an. # # Der SSH-Key (id_ed25519_forgejo) ist mit einer Passphrase verschluesselt. # setup_ssh() laedt ihn in einen temporaeren ssh-agent; dabei wird die # Passphrase einmalig abgefragt (Quelle: VaultWarden). Eine falsche Passphrase # kann den Key nicht entschluesseln -> Abbruch, keine SSH/SFTP-Verbindung. # Ein separates Passwort-Secret ist dadurch nicht mehr noetig. # ============================================================================= # --- Pfade --- CONTEXT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" TARGETS_DIR="${CONTEXT_DIR}/targets" # --- Hilfsfunktion: verfuegbare Targets auflisten --- # Eine einzige Quelle fuer die Target-Liste (keine duplizierten Strings mehr). list_targets() { local found="" local f name if [ -d "${TARGETS_DIR}" ]; then for f in "${TARGETS_DIR}"/*.env; do [ -e "$f" ] || continue name="$(basename "$f" .env)" # 'example' ist nur eine Vorlage und kein echtes Target. [ "$name" = "example" ] && continue found="${found:+${found}, }${name}" done fi if [ -n "$found" ]; then echo "Verfuegbare Targets: ${found}" else echo "Keine Targets konfiguriert. Lege eines mit ./init.sh an." fi } # --- Target-Validierung --- TARGET="${1:-}" if [ -z "$TARGET" ]; then echo "FEHLER: Target ist erforderlich." echo "Verwendung: $0 " list_targets exit 1 fi # Target-Name auf sichere Zeichen beschraenken, bevor daraus ein Pfad gebaut # wird (verhindert Path-Traversal wie '../' und das Laden beliebiger Dateien). if ! printf '%s' "$TARGET" | grep -Eq '^[A-Za-z0-9._-]+$'; then echo "FEHLER: Ungueltiger Target-Name '${TARGET}'." echo "Erlaubt sind nur Buchstaben, Zahlen sowie '.', '_' und '-'." list_targets exit 1 fi # --- Target-Aufloesung (Config aus targets/.env laden) --- TARGET_FILE="${TARGETS_DIR}/${TARGET}.env" if [ ! -f "${TARGET_FILE}" ]; then echo "FEHLER: Unbekanntes Target '${TARGET}'." list_targets exit 1 fi # shellcheck disable=SC1090 source "${TARGET_FILE}" # Pflichtfelder pruefen, damit kaputte Configs frueh auffallen. for _var in SSH_HOST SFTP_HOST DB_NAME GIT_REMOTE DOMAIN; do if [ -z "${!_var:-}" ]; then echo "FEHLER: '${_var}' fehlt oder ist leer in ${TARGET_FILE}." exit 1 fi done unset _var export TARGET SSH_HOST SFTP_HOST DB_NAME GIT_REMOTE DOMAIN echo "Target: ${TARGET} (${DOMAIN})" # --- SSH-Setup --- setup_ssh() { WORKSPACE_SSH_DIR="/home/runner/workspace/.ssh" KEY_PATH="${WORKSPACE_SSH_DIR}/id_ed25519_forgejo" local FORGEJO_SSH_PORT="2222" SFTP_PORT="2022" mkdir -p "${WORKSPACE_SSH_DIR}" # SSH-Config fuer den aktuellen Host erstellen/aktualisieren local TEMP_CONFIG TEMP_CONFIG=$(mktemp) if [ -f "${WORKSPACE_SSH_DIR}/config" ]; then # Bestehende Eintraege fuer diesen Host entfernen awk -v host="${SSH_HOST}" ' /^Host / { skip = ($2 == host); } !skip { print; } ' "${WORKSPACE_SSH_DIR}/config" > "${TEMP_CONFIG}" else touch "${TEMP_CONFIG}" fi cat >> "${TEMP_CONFIG}" < nach Checkout/Reset liegt der Key auf 0644, # was ssh-add ablehnt. Rechte hier korrigieren und Fehler sichtbar machen. if ! chmod 600 "${KEY_PATH}"; then echo "FEHLER: Konnte Rechte auf ${KEY_PATH} nicht auf 600 setzen." exit 1 fi chmod 644 "${WORKSPACE_SSH_DIR}/config" # Symlinks ins Home-Verzeichnis mkdir -p ~/.ssh ln -sf "${WORKSPACE_SSH_DIR}/config" ~/.ssh/config ln -sf "${KEY_PATH}" ~/.ssh/id_ed25519_forgejo ln -sf "${KEY_PATH}.pub" ~/.ssh/id_ed25519_forgejo.pub # --- Verschluesselten Key in ssh-agent laden (Passphrase-Abfrage) --- if [ ! -f "${KEY_PATH}" ]; then echo "FEHLER: SSH-Key nicht gefunden: ${KEY_PATH}" exit 1 fi # ssh-add fragt die Passphrase ueber das Terminal ab. if [ ! -t 0 ]; then echo "FEHLER: Kein interaktives Terminal. Skript muss manuell ausgefuehrt werden." exit 1 fi # Frischen ssh-agent starten und beim Script-Ende automatisch beenden, # damit der entschluesselte Key nur waehrend der Laufzeit im Speicher liegt. eval "$(ssh-agent -s)" >/dev/null trap 'ssh-agent -k >/dev/null 2>&1 || true' EXIT echo "Lade SSH-Key in den Agent (Passphrase erforderlich; siehe VaultWarden)..." if ! ssh-add "${KEY_PATH}"; then echo "FEHLER: SSH-Key konnte nicht geladen werden (falsche Passphrase?)." exit 1 fi echo "SSH-Key geladen." echo "SSH-Setup fuer ${SSH_HOST} abgeschlossen." # Exportiere Pfade fuer andere Skripte export WORKSPACE_SSH_DIR KEY_PATH SFTP_PORT }