Fehlerbild aus dem echten Betrieb: "mkdir: cannot create directory '/gegenbuch/schluessel': Permission denied", Container in der Neustart-Schleife. Ursache: Das Datenverzeichnis kommt als Bind-Mount vom Host; der Betreiber hatte das Projekt als root geklont, der Container lief aber direkt als UID 1000 und durfte dort nichts anlegen. Der .gitkeep-Ansatz hatte stillschweigend angenommen, dass als normaler Benutzer geklont wird - auf einem Server ist root der Normalfall. Fix: Der Container startet als root, setzt /gegenbuch per chown auf den Arbeitsbenutzer (PUID/PGID, Standard 1000) und startet sich per setpriv als dieser neu. Die eigentliche Arbeit laeuft weiterhin unprivilegiert. Schlaegt das chown fehl (rootless Docker), gibt es einen Hinweis mit dem passenden Host-Befehl statt eines stummen Abbruchs. Verifiziert mit exakt der Ausgangslage: Datenverzeichnis auf root:root gesetzt, Container gestartet -> laeuft durch, erzeugte Dateien gehoeren 1000:1000, der private Schluessel liegt mit 0600. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
88 lines
3.6 KiB
Bash
Executable File
88 lines
3.6 KiB
Bash
Executable File
#!/bin/bash
|
||
# Gegenbuch-Schleife: einrichten, dann in festem Takt beglaubigen.
|
||
set -uo pipefail
|
||
|
||
: "${INSTANZ:?INSTANZ fehlt (z. B. prod oder staging)}"
|
||
: "${CRM_URL:?CRM_URL fehlt – von welcher OpenCRM-Instanz soll geholt werden?}"
|
||
: "${CRM_EMAIL:?CRM_EMAIL fehlt – Dienstkonto im CRM mit dem Recht audit:read}"
|
||
: "${CRM_PASSWORD:?CRM_PASSWORD fehlt – Passwort dieses Dienstkontos}"
|
||
|
||
INTERVALL="${NOTARY_INTERVAL:-3600}"
|
||
BUCH=/gegenbuch/buch
|
||
SCHLUESSEL=/gegenbuch/schluessel
|
||
export NOTARY_STATE_FILE=/gegenbuch/beobachtungen.jsonl
|
||
export NOTARY_ALLOW_LOCAL=true # Buch liegt auf dieser Maschine
|
||
export NOTARY_PUSH=false # es gibt kein Ziel zum Pushen
|
||
|
||
# --- Rechte geraderuecken, dann Privilegien abgeben ------------------------
|
||
# Laeuft der Container als root, gehoert das Bind-Mount-Verzeichnis vermutlich
|
||
# ebenfalls root (typisch, wenn das Projekt als root geklont wurde). Wir setzen
|
||
# es auf den Arbeitsbenutzer um und starten uns selbst als dieser neu.
|
||
BENUTZER_UID="${PUID:-1000}"
|
||
BENUTZER_GID="${PGID:-1000}"
|
||
if [ "$(id -u)" = "0" ]; then
|
||
if ! chown -R "$BENUTZER_UID:$BENUTZER_GID" /gegenbuch 2>/dev/null; then
|
||
echo "[$INSTANZ] HINWEIS: Rechte auf /gegenbuch liessen sich nicht setzen." >&2
|
||
echo "[$INSTANZ] Falls es gleich an fehlenden Schreibrechten scheitert, auf dem Host:" >&2
|
||
echo "[$INSTANZ] chown -R $BENUTZER_UID:$BENUTZER_GID <datenverzeichnis>" >&2
|
||
fi
|
||
exec setpriv --reuid="$BENUTZER_UID" --regid="$BENUTZER_GID" --init-groups \
|
||
--inh-caps=-all "$0" "$@"
|
||
fi
|
||
|
||
echo "[$INSTANZ] Gegenbuch startet – Quelle: $CRM_URL, Takt: ${INTERVALL}s"
|
||
|
||
# --- Signaturschlüssel: einmalig auf DIESER Maschine erzeugen ---------------
|
||
# Er verlässt den Rechner nie. OpenCRM kennt ihn nicht.
|
||
mkdir -p "$SCHLUESSEL"
|
||
if [ ! -f "$SCHLUESSEL/id_ed25519" ]; then
|
||
echo "[$INSTANZ] Erzeuge Signaturschlüssel..."
|
||
ssh-keygen -t ed25519 -f "$SCHLUESSEL/id_ed25519" -N "" -C "gegenbuch-$INSTANZ" -q
|
||
fi
|
||
chmod 600 "$SCHLUESSEL/id_ed25519"
|
||
if [ ! -f "$SCHLUESSEL/allowed_signers" ]; then
|
||
echo "gegenbuch-$INSTANZ namespaces=\"git\" $(cat "$SCHLUESSEL/id_ed25519.pub")" \
|
||
> "$SCHLUESSEL/allowed_signers"
|
||
fi
|
||
|
||
# --- Buch anlegen, falls noch nicht vorhanden ------------------------------
|
||
if [ ! -d "$BUCH/.git" ]; then
|
||
echo "[$INSTANZ] Lege Gegenbuch an..."
|
||
mkdir -p "$BUCH"
|
||
git -C "$BUCH" init -q -b main
|
||
fi
|
||
cd "$BUCH" || exit 1
|
||
|
||
git config user.email "${NOTAR_EMAIL:-gegenbuch@localhost}"
|
||
git config user.name "Gegenbuch $INSTANZ"
|
||
git config gpg.format ssh
|
||
git config user.signingkey "$SCHLUESSEL/id_ed25519.pub"
|
||
git config gpg.ssh.allowedSignersFile "$SCHLUESSEL/allowed_signers"
|
||
|
||
# Ein erster Commit, damit es eine Historie gibt, an die angehängt werden kann.
|
||
if ! git rev-parse HEAD >/dev/null 2>&1; then
|
||
git commit -q -S --allow-empty -m "Gegenbuch $INSTANZ angelegt"
|
||
fi
|
||
|
||
# --- Schleife ---------------------------------------------------------------
|
||
# Jeder Rückgabecode außer 0 gehört angesehen. Der letzte Stand steht
|
||
# zusätzlich in status.txt, damit eine Überwachung ihn abgreifen kann, ohne
|
||
# Logs zu durchsuchen.
|
||
while true; do
|
||
ZEIT=$(date -Iseconds)
|
||
node /opt/notary/notary.mjs
|
||
CODE=$?
|
||
case $CODE in
|
||
0) LAGE="in Ordnung" ;;
|
||
1) LAGE="Betriebsfehler (Konfiguration, CRM nicht erreichbar, Commit)" ;;
|
||
2) LAGE="BEFUND – Widerspruch zwischen CRM und Gegenbuch" ;;
|
||
3) LAGE="nicht abschliessend feststellbar (u. a. erster Lauf)" ;;
|
||
4) LAGE="Gedaechtnis fehlt – Bestaetigung noetig, siehe README" ;;
|
||
5) LAGE="Anker unvollstaendig" ;;
|
||
*) LAGE="unbekannter Code" ;;
|
||
esac
|
||
echo "[$INSTANZ] $ZEIT exit=$CODE ($LAGE)"
|
||
printf '%s exit=%s %s\n' "$ZEIT" "$CODE" "$LAGE" > /gegenbuch/status.txt
|
||
sleep "$INTERVALL"
|
||
done
|