G. TLS + certificate lifecycle (public-CA direction, private-CA fallback) #139

Open
opened 2026-09-26 21:44:36 +00:00 by kilo · 3 comments
Member

Child G of #132. Stop making private-CA handling part of the normal end-user path; establish the recommended self-hosted production TLS direction and keep a supported private-CA fallback.

https://scarcity-router.creatidy.com:8787
srws://scarcity-router.creatidy.com:8790
  • Real FQDN, public-trusted certificate via ACME/Let's Encrypt with DNS-01; no application ports exposed publicly (split/internal DNS resolves the FQDN to the private host over LAN/VPN); one certificate usable by HTTPS 8787 and worker TLS 8790; automatic renewal with a safe deploy/reload hook; external clients use normal OS trust — no per-client CA configuration in the normal case.
  • Before implementing acquisition: inspect existing Creatidy ACME/Certbot/DNS mechanisms and REUSE proven infrastructure; do not assume the DNS provider; never expose DNS credentials; no large ACME implementation inside the routing core. Certificate lifecycle belongs in installer/service/deployment tooling; the core keeps accepting certificate/key paths.

Private-CA fallback (must not regress)

  • Explicit trust configuration: --ca-cert <path> for worker pair/run/service operations, persisted in worker-local configuration so all subsequent operations reuse it — no hand-written SSL_CERT_FILE environment hacks, and service units (child F) consume the persisted configuration.
  • Never: verify=false, insecure mode, trust-on-first-use, certificate-error suppression. CA export/trust guidance for external clients is documentation, never an automatic system-trust-store mutation.

Worker origin migration

Support moving srws://192.168.2.13:8790 → srws://scarcity-router.creatidy.com:8790 without destructive re-pairing when the existing worker identity remains valid. Before persisting a migrated origin: verify TLS to the new origin AND verify the existing device identity/authentication; only then commit the origin change.

Out of scope

No vendor control-plane/domain dependency; no ZCode-side changes (a concise reproducible report on the observed Custom-certificate propagation failure is prepared as an owner-review artifact only — not published without owner approval; Scarcity Router must not depend on any ZCode fix).

Tests

CA persistence across pair/run/service; origin migration verification order (verify-then-commit; refusal paths); unit/UX integration with child F; negative tests (no bypass modes reachable, credentials never persisted/logged); documentation of the recommended deployment path.

Security classification

Security-critical (TLS, credentials, identity migration): GLM-5.3-Flash review mandatory; Daybreak security review when available, else SECURITY_REVIEW_UNAVAILABLE with the gate open at the human decision point. UX assessment mandatory.

Complexity boundary

Worker config/store + worker_client.py flags + deployment tooling/docs; server CLI unchanged except doc guidance; ~3 test files. Budget: 120 min wall clock.

Child G of #132. Stop making private-CA handling part of the normal end-user path; establish the recommended self-hosted production TLS direction and keep a supported private-CA fallback. ## Recommended production direction (design + implement product support, not a vendor control plane) ``` https://scarcity-router.creatidy.com:8787 srws://scarcity-router.creatidy.com:8790 ``` - Real FQDN, public-trusted certificate via ACME/Let's Encrypt with DNS-01; no application ports exposed publicly (split/internal DNS resolves the FQDN to the private host over LAN/VPN); one certificate usable by HTTPS 8787 and worker TLS 8790; automatic renewal with a safe deploy/reload hook; external clients use normal OS trust — no per-client CA configuration in the normal case. - Before implementing acquisition: inspect existing Creatidy ACME/Certbot/DNS mechanisms and REUSE proven infrastructure; do not assume the DNS provider; never expose DNS credentials; no large ACME implementation inside the routing core. Certificate lifecycle belongs in installer/service/deployment tooling; the core keeps accepting certificate/key paths. ## Private-CA fallback (must not regress) - Explicit trust configuration: `--ca-cert <path>` for worker pair/run/service operations, persisted in worker-local configuration so all subsequent operations reuse it — no hand-written `SSL_CERT_FILE` environment hacks, and service units (child F) consume the persisted configuration. - Never: `verify=false`, insecure mode, trust-on-first-use, certificate-error suppression. CA export/trust guidance for external clients is documentation, never an automatic system-trust-store mutation. ## Worker origin migration Support moving `srws://192.168.2.13:8790` → `srws://scarcity-router.creatidy.com:8790` without destructive re-pairing when the existing worker identity remains valid. Before persisting a migrated origin: verify TLS to the new origin AND verify the existing device identity/authentication; only then commit the origin change. ## Out of scope No vendor control-plane/domain dependency; no ZCode-side changes (a concise reproducible report on the observed Custom-certificate propagation failure is prepared as an owner-review artifact only — not published without owner approval; Scarcity Router must not depend on any ZCode fix). ## Tests CA persistence across pair/run/service; origin migration verification order (verify-then-commit; refusal paths); unit/UX integration with child F; negative tests (no bypass modes reachable, credentials never persisted/logged); documentation of the recommended deployment path. ## Security classification Security-critical (TLS, credentials, identity migration): GLM-5.3-Flash review mandatory; **Daybreak security review** when available, else `SECURITY_REVIEW_UNAVAILABLE` with the gate open at the human decision point. UX assessment mandatory. ## Complexity boundary Worker config/store + `worker_client.py` flags + deployment tooling/docs; server CLI unchanged except doc guidance; ~3 test files. Budget: 120 min wall clock.
Author
Member

Additive scope note (D-056, PR #147 remediation — the frozen scope text above is unchanged; this assigns newly accepted architecture into the existing deployment tooling/docs scope rather than creating a new issue):

This child now also implements the accepted same-host container plaintext transport tier from D-056 (docs/decisions.md):

  • Plain HTTP between containers on ONE physical host, only under deployment isolation that makes the transport host-local and non-routable from external networks (dedicated or internal: true Docker network, no externally published plaintext application port). This includes the currently unsupported Docker bridge + loopback-publish case (-p 127.0.0.1:8787:8787), which today fails because published traffic reaches the container on a non-loopback interface where plaintext binds are refused.
  • The tier is a property of the ENTIRE composed HTTP listener (execution, machine-interface, control and administration surfaces ride one listener, D-041) — never a per-surface plaintext/TLS mix, and never a global non-loopback 0.0.0.0 plaintext listener. An explicit deployment/local-transport mode is expected; it must be difficult to accidentally turn a LAN-facing endpoint into plaintext. Worker-protocol transport is unchanged.
  • Until this lands, non-loopback binds require TLS exactly as today; cross-host/LAN/VPN/remote stays TLS-required (VPN is not automatically local), and the TLS certificate lifecycle work above remains this child's primary direction.

Details: D-056 in docs/decisions.md, "Client-transport tiers (D-056)" in docs/security.md, PR #147.

Additive scope note (D-056, PR #147 remediation — the frozen scope text above is unchanged; this assigns newly accepted architecture into the existing deployment tooling/docs scope rather than creating a new issue): This child now also implements the accepted **same-host container plaintext transport tier** from D-056 (`docs/decisions.md`): - Plain HTTP between containers on ONE physical host, only under deployment isolation that makes the transport host-local and non-routable from external networks (dedicated or `internal: true` Docker network, no externally published plaintext application port). This includes the currently unsupported Docker bridge + loopback-publish case (`-p 127.0.0.1:8787:8787`), which today fails because published traffic reaches the container on a non-loopback interface where plaintext binds are refused. - The tier is a property of the ENTIRE composed HTTP listener (execution, machine-interface, control and administration surfaces ride one listener, D-041) — never a per-surface plaintext/TLS mix, and never a global non-loopback `0.0.0.0` plaintext listener. An explicit deployment/local-transport mode is expected; it must be difficult to accidentally turn a LAN-facing endpoint into plaintext. Worker-protocol transport is unchanged. - Until this lands, non-loopback binds require TLS exactly as today; cross-host/LAN/VPN/remote stays TLS-required (VPN is not automatically local), and the TLS certificate lifecycle work above remains this child's primary direction. Details: D-056 in `docs/decisions.md`, "Client-transport tiers (D-056)" in `docs/security.md`, PR #147.
Author
Member

Additive scope note #2 (D-056, PR #147 — complementing the same-host container-tier note above; frozen scope text unchanged):

D-056 also fixes the local-first normal path that this child's documentation and UX must present: plain-HTTP loopback (http://localhost:8787/v1) is a SUPPORTED local transport and a normal certificate-free configuration (D-056 pt 8A / pt 9). Local operation must not be documented or UX-framed as requiring certificate setup, and a private CA is never required for ordinary localhost operation. The remote normal UX stays public FQDN + publicly trusted certificate + automated renewal, with private CA as the advanced fallback (pt 8D — already this child's primary direction). These are documentation/UX consequences of D-056 only; no listener-behavior change beyond what the container-tier note above assigns.

Additive scope note #2 (D-056, PR #147 — complementing the same-host container-tier note above; frozen scope text unchanged): D-056 also fixes the local-first normal path that this child's documentation and UX must present: plain-HTTP loopback (`http://localhost:8787/v1`) is a SUPPORTED local transport and a normal certificate-free configuration (D-056 pt 8A / pt 9). Local operation must not be documented or UX-framed as requiring certificate setup, and a private CA is never required for ordinary localhost operation. The remote normal UX stays public FQDN + publicly trusted certificate + automated renewal, with private CA as the advanced fallback (pt 8D — already this child's primary direction). These are documentation/UX consequences of D-056 only; no listener-behavior change beyond what the container-tier note above assigns.
Author
Member

2026-10-27 owner backlog disposition (D-083, governance issue #228). This issue remains open with its wontfix label unchanged; history preserved. Its still-required obligations are re-homed to active successor #224 (same-host container tier B, persisted/validated CA trust, certificate lifecycle, origin migration — security-critical), which carries every retained invariant: no plaintext LAN/WAN exposure, whole-composed-listener property with proven deployment-boundary enforcement, no verify=false/TOFU/bypass, no TLS/CSRF/credential weakening. The former #186 → #139 native dependency was removed as stale. See D-083 in docs/decisions.md.

**2026-10-27 owner backlog disposition (D-083, governance issue #228).** This issue remains open with its `wontfix` label unchanged; history preserved. Its still-required obligations are re-homed to active successor **#224** (same-host container tier B, persisted/validated CA trust, certificate lifecycle, origin migration — security-critical), which carries every retained invariant: no plaintext LAN/WAN exposure, whole-composed-listener property with proven deployment-boundary enforcement, no `verify=false`/TOFU/bypass, no TLS/CSRF/credential weakening. The former #186 → #139 native dependency was removed as stale. See D-083 in `docs/decisions.md`.
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
Creatidy/scarcity-router#139
No description provided.