Self-Update: ed25519-Signaturpflicht entfernen, Vertrauen auf TLS (https-Zwang + Hash-Check) — #113 Phase 2 Rückbau #187

Closed
opened 2026-06-26 14:31:00 +00:00 by chinux · 4 comments
Owner

Entscheidung / Begründung

#113 Phase 2 hat eine ed25519-Signatur fuer Self-Update eingefuehrt, mit dem Pubkey einkompiliert im Agent. Architektur-Entscheidung (Dev): Der Signing-Key wuerde ohnehin auf dem Backend liegen → die Signatur haengt dann am gleichen Vertrauensanker wie der Download (das Backend) und ist damit kryptografisch redundant zu https:///TLS, das die Quelle bereits authentifiziert. Echten Mehrwert haette nur ein Offline-Key (bewusst verworfen: "Backend kompromittiert = eh vorbei").

→ Signatur-Schicht entfernen, Vertrauen sauber auf TLS stuetzen. Self-Update ist dann wieder funktionsfaehig ohne Key-Management (aktuell fail-closed durch Pubkey-Platzhalter).

Wichtig — betrifft NICHT die Agent-Auth: Die Legitimitaet des Agents gegenueber dem Backend laeuft unveraendert ueber #185 (ed25519 Challenge-Response). Dieses Issue aendert nur die Update-Integritaet (Backend→Agent), nicht die Authentifizierung (Agent→Backend).

Umsetzung (Node-Agent/src/self_update.rs)

  • verify_update_signature + UPDATE_PUBKEY_B64-Const + base64/ed25519-Imports entfernen; den Aufruf bei :79 raus.
  • https://-Zwang fuer den Binary-Download: die Download-URL ({cfg.http_base}/node-agent-binary/{arch}, :63) muss https:// sein (Ausnahme localhost, analog zum wss-Zwang #113 Phase 1). Bei http:// zu Nicht-localhost → Update ablehnen (fail-closed gegen Klartext-Download). http_base wird aus server_url abgeleitet — Validierung dort wiederverwenden/spiegeln.
  • sha256-Hash-Check beibehalten als Integritaetspruefung (kaputter/abgebrochener Download): X-Binary-Hash-Header gegen lokalen sha256 vergleichen; Mismatch → ablehnen. (Das ist Integritaet, nicht Authentizitaet — die macht TLS.)
  • ureq nutzt System-/webpki-CAs → Server-Zert wird bei https:// verifiziert; sicherstellen, dass kein "accept invalid cert" gesetzt ist.

Backend (server/main.py)

  • X-Binary-Sig-Header + .sig-Datei-Logik (main.py:356) entfernen (wird nicht mehr gebraucht).
  • X-Binary-Hash (sha256) beibehalten.
  • scripts/sign-release.sh entfernen oder als "nur fuer optionalen Offline-Signing-Pfad (#zukunft)" markieren.

Doku

  • wiki/Deployment-Public.md Abschnitt 6 (Self-Update-Signatur) + wiki/Self-Update-Signing anpassen: Self-Update vertraut TLS, kein Key noetig. Hinweis: Offline-Key-Signatur ist ein optionales spaeteres Upgrade, falls theProx je als Produkt an Dritte ausgeliefert wird (schuetzt dann auch gegen kompromittiertes Backend).

Akzeptanz

  • Self-Update funktioniert ohne jeden Key (kein Pubkey-Platzhalter, kein fail-closed mehr).
  • Binary-Download nur ueber https:// (http:// zu Nicht-localhost = abgelehnt); Server-Zert verifiziert.
  • sha256-Integritaetspruefung aktiv; Mismatch lehnt ab.
  • Keine Signatur-/Key-Reste im Agent oder Backend.
  • Agent-Auth (#185) unveraendert.

Bezug

Baut #113 Phase 2 gezielt zurueck (Phase 1 wss-Zwang bleibt). Kein Konflikt mit #185/#115/#114.

Branch

refactor/self-update-tls-trust-no-signature

## Entscheidung / Begründung #113 Phase 2 hat eine **ed25519-Signatur** fuer Self-Update eingefuehrt, mit dem Pubkey **einkompiliert** im Agent. Architektur-Entscheidung (Dev): Der Signing-Key wuerde ohnehin **auf dem Backend** liegen → die Signatur haengt dann am **gleichen Vertrauensanker** wie der Download (das Backend) und ist damit **kryptografisch redundant zu `https://`/TLS**, das die Quelle bereits authentifiziert. Echten Mehrwert haette nur ein **Offline-Key** (bewusst verworfen: "Backend kompromittiert = eh vorbei"). → Signatur-Schicht **entfernen**, Vertrauen sauber auf TLS stuetzen. Self-Update ist dann wieder funktionsfaehig **ohne** Key-Management (aktuell fail-closed durch Pubkey-Platzhalter). **Wichtig — betrifft NICHT die Agent-Auth:** Die Legitimitaet des Agents gegenueber dem Backend laeuft unveraendert ueber #185 (ed25519 Challenge-Response). Dieses Issue aendert nur die *Update-Integritaet* (Backend→Agent), nicht die *Authentifizierung* (Agent→Backend). ## Umsetzung (`Node-Agent/src/self_update.rs`) - `verify_update_signature` + `UPDATE_PUBKEY_B64`-Const + base64/ed25519-Imports **entfernen**; den Aufruf bei :79 raus. - **`https://`-Zwang fuer den Binary-Download**: die Download-URL (`{cfg.http_base}/node-agent-binary/{arch}`, :63) muss `https://` sein (Ausnahme localhost, analog zum wss-Zwang #113 Phase 1). Bei `http://` zu Nicht-localhost → Update **ablehnen** (fail-closed gegen Klartext-Download). `http_base` wird aus `server_url` abgeleitet — Validierung dort wiederverwenden/spiegeln. - **sha256-Hash-Check beibehalten** als Integritaetspruefung (kaputter/abgebrochener Download): `X-Binary-Hash`-Header gegen lokalen sha256 vergleichen; Mismatch → ablehnen. (Das ist Integritaet, nicht Authentizitaet — die macht TLS.) - `ureq` nutzt System-/webpki-CAs → Server-Zert wird bei `https://` verifiziert; sicherstellen, dass kein "accept invalid cert" gesetzt ist. ## Backend (`server/main.py`) - `X-Binary-Sig`-Header + `.sig`-Datei-Logik (main.py:356) **entfernen** (wird nicht mehr gebraucht). - `X-Binary-Hash` (sha256) **beibehalten**. - `scripts/sign-release.sh` entfernen oder als "nur fuer optionalen Offline-Signing-Pfad (#zukunft)" markieren. ## Doku - `wiki/Deployment-Public.md` Abschnitt 6 (Self-Update-Signatur) + `wiki/Self-Update-Signing` anpassen: Self-Update vertraut TLS, kein Key noetig. Hinweis: Offline-Key-Signatur ist ein **optionales spaeteres Upgrade**, falls theProx je als Produkt an Dritte ausgeliefert wird (schuetzt dann auch gegen kompromittiertes Backend). ## Akzeptanz - Self-Update funktioniert ohne jeden Key (kein Pubkey-Platzhalter, kein fail-closed mehr). - Binary-Download nur ueber `https://` (http:// zu Nicht-localhost = abgelehnt); Server-Zert verifiziert. - sha256-Integritaetspruefung aktiv; Mismatch lehnt ab. - Keine Signatur-/Key-Reste im Agent oder Backend. - Agent-Auth (#185) unveraendert. ## Bezug Baut #113 Phase 2 gezielt zurueck (Phase 1 wss-Zwang bleibt). Kein Konflikt mit #185/#115/#114. ## Branch `refactor/self-update-tls-trust-no-signature`
Author
Owner

ERWEITERUNG — VPN-Hosts: Opt-in statt hartem Zwang

Entscheidung: Der https://-Zwang (und der wss://-Zwang aus #113 Phase 1) bleibt Default, ist aber pro Host abschaltbar fuer VPN-Hosts (Transport ist dort durch WireGuard/NetBird bereits verschluesselt+authentifiziert → Klartext-Link unkritisch).

Statt Klartext-Default oder manuellem Config-Edit: UI-gesteuert (siehe neues Issue, das den UI/Backend-Teil traegt). Dieses Issue (#187) deckt den Agent-Teil:

  • Neuer agent.conf-Schalter, z. B. TRUSTED_TRANSPORT=vpn (oder ALLOW_INSECURE_TRANSPORT=1), via pick(...) in config.rs gelesen.
  • validate_server_url (config.rs:36) erlaubt ws:///(implizit) http NUR, wenn dieser Schalter gesetzt ist ODER Host=localhost. Sonst weiterhin harter Reject (Default).
  • Im Self-Update denselben Schalter beachten: http://-Binary-Download nur erlaubt, wenn TRUSTED_TRANSPORT gesetzt; sonst https-Zwang. sha256-Check bleibt immer (auch ueber VPN — Integritaet).
  • WICHTIG: ws/http-Klartext NIE still — nur bei explizit gesetztem Flag (das die UI beim Install setzt). Der Default ohne Flag bleibt der scharfe https/wss-Zwang.

Gilt fuer beide Strecken (WS-Verbindung #113 Phase 1 + Binary-Download #187) — EIN gemeinsamer Schalter.

## ERWEITERUNG — VPN-Hosts: Opt-in statt hartem Zwang Entscheidung: Der `https://`-Zwang (und der `wss://`-Zwang aus #113 Phase 1) bleibt **Default**, ist aber **pro Host abschaltbar** fuer VPN-Hosts (Transport ist dort durch WireGuard/NetBird bereits verschluesselt+authentifiziert → Klartext-Link unkritisch). **Statt Klartext-Default oder manuellem Config-Edit: UI-gesteuert** (siehe neues Issue, das den UI/Backend-Teil traegt). Dieses Issue (#187) deckt den **Agent-Teil**: - Neuer agent.conf-Schalter, z. B. `TRUSTED_TRANSPORT=vpn` (oder `ALLOW_INSECURE_TRANSPORT=1`), via `pick(...)` in config.rs gelesen. - `validate_server_url` (config.rs:36) erlaubt `ws://`/(implizit) http NUR, wenn dieser Schalter gesetzt ist ODER Host=localhost. Sonst weiterhin harter Reject (Default). - Im Self-Update denselben Schalter beachten: `http://`-Binary-Download nur erlaubt, wenn `TRUSTED_TRANSPORT` gesetzt; sonst https-Zwang. **sha256-Check bleibt immer** (auch ueber VPN — Integritaet). - WICHTIG: ws/http-Klartext NIE still — nur bei explizit gesetztem Flag (das die UI beim Install setzt). Der Default ohne Flag bleibt der scharfe https/wss-Zwang. Gilt fuer **beide Strecken** (WS-Verbindung #113 Phase 1 + Binary-Download #187) — EIN gemeinsamer Schalter.
Author
Owner

UI/Backend/Install-Script-Teil + Modellfeld: siehe #189. #187 = Agent-Teil (config.rs/validate_server_url/self_update liest den Schalter).

UI/Backend/Install-Script-Teil + Modellfeld: siehe #189. #187 = Agent-Teil (config.rs/validate_server_url/self_update liest den Schalter).
Author
Owner

Bearbeitet zusammen mit #189 (gemeinsamer TRUSTED_TRANSPORT-Vertrag). Issue bleibt offen.

Commits: Agent `0416d9f` · Backend `198f8b5` · Doku `727f25f`

  • Agent 2.16.0 → 2.17.0 (self_update.rs): ed25519-Self-Update-Signatur entfernt — `UPDATE_PUBKEY_B64`, `verify_update_signature` + Aufruf, `X-Binary-Sig`-Read, base64/ed25519-Imports. ed25519-dalek bleibt Crate-Dep (#185). Integritäts-Gate jetzt sha256 über `X-Binary-Hash`: Header fehlt oder Mismatch → Update verweigert, laufende Binary bleibt. Größencheck bleibt.
  • Backend (main.py): `/node-agent-binary/{arch}` liefert nur noch `X-Binary-Hash`; `X-Binary-Sig`/`.sig`-Logik raus. `scripts/sign-release.sh` + `scripts/gen-update-key.sh` gelöscht.
  • Doku: Self-Update-Signing.md auf „TLS-Vertrauen, kein Key" umgeschrieben.

Akzeptanz: Self-Update ohne Key funktionsfähig; sha256-Check aktiv (fehlend/Mismatch → verweigert); keine Signatur-/sig-Reste; #185-Auth unverändert.

⚠️ Deploy: Node-Agent lokal neu bauen + ausrollen (kein cargo im Container). Backend-Rebuild liefert die neuen Header. Hinweis: der Crate baut im CI-Container aktuell nicht durch (pre-existing `identity.rs` `send_json` aus #185 — separat, nicht von diesem Change).

Bearbeitet zusammen mit #189 (gemeinsamer TRUSTED_TRANSPORT-Vertrag). Issue bleibt offen. **Commits:** Agent \`0416d9f\` · Backend \`198f8b5\` · Doku \`727f25f\` - **Agent 2.16.0 → 2.17.0** ([self_update.rs](Node-Agent/src/self_update.rs)): ed25519-Self-Update-Signatur entfernt — \`UPDATE_PUBKEY_B64\`, \`verify_update_signature\` + Aufruf, \`X-Binary-Sig\`-Read, base64/ed25519-Imports. ed25519-dalek bleibt Crate-Dep (#185). Integritäts-Gate jetzt **sha256 über \`X-Binary-Hash\`**: Header fehlt oder Mismatch → Update verweigert, laufende Binary bleibt. Größencheck bleibt. - **Backend** ([main.py](server/main.py)): \`/node-agent-binary/{arch}\` liefert nur noch \`X-Binary-Hash\`; \`X-Binary-Sig\`/\`.sig\`-Logik raus. \`scripts/sign-release.sh\` + \`scripts/gen-update-key.sh\` gelöscht. - **Doku**: [Self-Update-Signing.md](wiki/Self-Update-Signing.md) auf „TLS-Vertrauen, kein Key" umgeschrieben. **Akzeptanz:** Self-Update ohne Key funktionsfähig; sha256-Check aktiv (fehlend/Mismatch → verweigert); keine Signatur-/sig-Reste; #185-Auth unverändert. ⚠️ **Deploy:** Node-Agent lokal neu bauen + ausrollen (kein cargo im Container). Backend-Rebuild liefert die neuen Header. Hinweis: der Crate baut im CI-Container aktuell nicht durch (pre-existing \`identity.rs\` \`send_json\` aus #185 — separat, nicht von diesem Change).
Author
Owner

Verifiziert @ 727f25f (+ Build-Fix 903ea4f) → erfüllt, wird geschlossen.

  • Self-Update-Signatur entfernt (kein UPDATE_PUBKEY/verify_update_signature/X-Binary-Sig); sha256 über X-Binary-Hash bleibt (Integrität) — self_update.rs ✓
  • http-Download nur bei trusted_transport oder localhost (self_update.rs:30) — sonst verweigert, gleicher Riegel wie die WS-Verbindung ✓
  • TRUSTED_TRANSPORT=vpn-Schalter in config.rs (v.trim()=="vpn", :39-40), validate_server_url(url, trusted_transport): wss immer, ws nur localhost||VPN, sonst Fehler ✓
  • ureq nutzt webpki-CAs, keine accept-invalid-Pfade ✓
  • #185-Auth unberührt ✓

Backend-Build-Fix (903ea4f): identity.rs:87 enroll() nutzt ureq::send_json, aber ureq war ohne json-Feature gebaut (features=["tls"]) → Agent-Build gebrochen (latenter #185-Rest, nicht von diesem Batch). Behoben → features=["tls","json"].

**Verifiziert @ 727f25f (+ Build-Fix 903ea4f) → erfüllt, wird geschlossen.** - Self-Update-Signatur **entfernt** (kein UPDATE_PUBKEY/verify_update_signature/X-Binary-Sig); **sha256 über X-Binary-Hash bleibt** (Integrität) — self_update.rs ✓ - **http-Download nur bei `trusted_transport` oder localhost** (self_update.rs:30) — sonst verweigert, gleicher Riegel wie die WS-Verbindung ✓ - `TRUSTED_TRANSPORT=vpn`-Schalter in config.rs (`v.trim()=="vpn"`, :39-40), `validate_server_url(url, trusted_transport)`: wss immer, ws nur localhost||VPN, sonst Fehler ✓ - ureq nutzt webpki-CAs, keine accept-invalid-Pfade ✓ - #185-Auth unberührt ✓ **Backend-Build-Fix (903ea4f):** `identity.rs:87` enroll() nutzt `ureq::send_json`, aber `ureq` war ohne `json`-Feature gebaut (`features=["tls"]`) → Agent-Build gebrochen (latenter #185-Rest, nicht von diesem Batch). Behoben → `features=["tls","json"]`.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
chinux/theProx#187
No description provided.