[Bug] Agent enrollt bei unbekanntem Pubkey nicht neu → Dauerschleife type=challenge + Rate-Limit (Re-Enroll-Sackgasse) #195
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Bug — Re-Enroll-Sackgasse (live reproduziert an ITD-PROX01)
Wenn der Backend-Pubkey eines Nodes geleert wird (via
regenerate-token, #185) ODER aus anderem Grund nicht (mehr) zur lokalen Identity passt, läuft der Agent in eine Endlosschleife statt neu zu enrollen:/etc/theprox-agent/identity_ed25519) →freshly_created=false→ kein Enroll-Versuch (identity.rs:21, main.rs:105).auth rejected (type=challenge)(Backend kennt den Pubkey nicht).auth rejected (type=auth_fail): Rate limit.Kernproblem: "Backend kennt meinen Pubkey nicht" (type=challenge) wird wie ein normaler Auth-Fehler behandelt — der Agent versucht es stur mit demselben (im Backend unbekannten) Key erneut, statt neu zu enrollen. Der Enroll-Pfad wird nur bei
freshly_createdbetreten.Verschärfend
regenerate-token, neu installieren. Das ist nicht zumutbar für normalen Betrieb.Gewünschtes Verhalten
Bei
type=challenge-Ablehnung (= "Pubkey unbekannt/passt nicht") soll der Agent automatisch einen Re-Enroll versuchen, statt in den Rate-Limit zu laufen:type=challenge(klar abgrenzbar von "falsche Signatur" und von Rate-Limit), und liegt ein gültiger Enroll-Token in der Config vor → Identity-Datei verwerfen + neues Keypair erzeugen +/enroll/{token}aufrufen + mit neuem Key verbinden. (Nicht beitype=auth_fail/Rate-Limit — da nur warten.)Reproduktion
ITD-PROX01 (VPN-Node): nach
regenerate-token+ gelöschter Identity-Datei + altem Token in agent.conf → Dauerschleife austype=challenge+Rate limit, kein Enroll-Log (enrollment failedtaucht NICHT auf, weil freshly_created=false war / Token verbrannt).Akzeptanz
Bezug
#185 (Challenge-Response/Enroll), #181 (Rate-Limit), #193/#194 (regenerate-token URL/UI). Kein Public-Blocker, aber macht das Neu-Ausrollen/Re-Enrollen von Nodes aktuell praktisch kaputt.
Branch
fix/agent-reenroll-on-unknown-pubkeyEntscheidung: VARIANTE 1 — single-use bleibt, Agent hört auf zu hämmern
Re-Enroll bleibt ein bewusster Betreiber-Akt (regenerate-token). Der Enroll-Token bleibt single-use (#185/#182-Härte unverändert). Der Fix behebt nur die Dauerschleife + Rate-Limit-Self-DoS, nicht die Token-Semantik.
Verifizierte Code-Stellen
auth.rs:77wertettypeaus;:107loggt generischauth rejected (type={other}). Der Typ (challengevsauth_fail) ist also bereits unterscheidbar — wird nur nicht unterschiedlich behandelt.main.rs:139-147Reconnect-Loop mit festemreconnect_delay→ konstantes Hämmern, kein Backoff./enrollist hart single-use (main.py:390-396:enroll_used_at+node.token=None, sonst 403). Self-Re-Enroll ist konstruktiv unmöglich → "nicht hämmern" ist die korrekte Antwort.Gewünschtes Verhalten (Variante 1)
type=challenge→ Backend kennt den Pubkey nicht / Signatur passt nicht zum registrierten Key. Nicht als transienten Fehler behandeln.type=auth_fail(Rate-Limit) → transient, normal weiter.type=challenge: in einen langsamen Backoff + klare Logmeldung gehen, statt im festenreconnect_delayweiterzuhämmern:type=challengedarf der Node sich nicht mehr selbst in den Rate-Limit treiben. (Optional, falls einfach: erfolgreicher Handshake setzt den Fail-Zähler dieser IP zurück.)Ausdrücklich NICHT in Variante 1
Begleitend (klein, sinnvoll mitnehmen)
rm -f /etc/theprox-agent/identity_ed25519), damit ein bewusstes Re-Install (nach regenerate-token) sauber neu enrollt. Das ist der vorgesehene Re-Enroll-Weg und soll reibungslos funktionieren.Akzeptanz
type=challenge/type=auth_fail/ Transport-Fehler werden im Agent klar unterschieden.Branch
fix/agent-challenge-backoff-no-selfddosUmgesetzt in zwei Commits auf
main:Teil A — Agent Backoff + Fehlertypen (
d5dc082, Crate 2.17.0 → 2.18.0):enum AuthReject { Challenge, RateLimited, Other }(auth_reject.rs).ws.rs: WS-Upgrade HTTP 403 →Challenge.auth.rs:auth_failVOR Challenge →RateLimited(#181-Block);auth_failNACH Challenge →Challenge(Pubkey unbekannt/Sig ungültig).main.rsReconnect-Loop: Challenge → exponentieller Backoff abreconnect_delay, Deckel 10 min, EINMAL prägnanter WARN (Re-Enroll-Anweisung), danach knapp; RateLimited → Warten bis Block-Ablauf; Transport/sauberes Ende → Reset.Teil B — Install-Script räumt Identity (
5e0a9e2): generiertes Script entfernt/etc/theprox-agent/identity_ed25519vor Service-Start → Re-Install mit frischem Token enrollt sauber neu (freshly_created=true).Verifiziert:
cargo check+cargo build --release --target x86_64-unknown-linux-muslgrün; Binary 2.18.0 neu gebaut + committed (= advertised latest-version, kein Self-Update-Loop). Bleibt offen für deinen Build/Test auf echtem Node.Verifiziert → erfüllt (Variante 1), wird geschlossen.
AuthReject-Enum + challenge/auth_fail-Unterscheidung (auth.rs:41-48) ✓challenge_logged) + exponentieller Backoff*2 .min(BACKOFF_CAP); RateLimited → wartet BACKOFF_CAP; clean → reset. Kein Rate-Limit-Self-DoS mehr ✓rm -f "$CONF_DIR/identity_ed25519", main.py:922) → Re-Install mit frischem Token enrollt sauber ✓