Skip to content

docs(adr): ADR-0010 secure-by-default remote-control transport (v1alpha2) [Proposed] - #330

Open
thc1006 wants to merge 3 commits into
mainfrom
docs/adr-0010-secure-transport
Open

docs(adr): ADR-0010 secure-by-default remote-control transport (v1alpha2) [Proposed]#330
thc1006 wants to merge 3 commits into
mainfrom
docs/adr-0010-secure-transport

Conversation

@thc1006

@thc1006 thc1006 commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Status: Proposed — a design decision for review; no code lands with this ADR.

Fixes v1alpha1's implicit-plaintext flaw (an omitted tls block ⇒ ws://, the opposite of secure-by-default) by introducing v1alpha2 with a REQUIRED transport mode, riding on the v1alpha2 conversion/storage migration already planned for #214 / #315.

MUST (decided)

  • transport.mode required, no default → missing = schema rejection (fail-closed); plaintext must be written explicitly.
  • CEL structural rules (service XOR address; mode↔tls consistency; loopback-only raw plaintext).
  • Conversion webhook mapping v1alpha1 tls==nil → explicit mode: plaintext (never a default-upgraded TLS — conversion preserves semantics).
  • v1alpha1 admission ratcheting (grandfather unchanged legacy, deny new/widened plaintext) — else v1alpha1 is a full bypass.
  • A v1alpha2-specific credential VAP — verified that feat(chart): opt-in admission policy closing the remoteControl.tls confused deputy (#251) #309's policy pins matchConstraints.apiVersions: ["v1alpha1"], so a new version would otherwise bypass the Secret-authorization check.

DEFER (recorded; proportionality per ADR-0009)

Phased 8-PR rollout + explicit storage-migration sequence + a mutation-test matrix are in the ADR. Review the MUST/DEFER split before we open PR 2 (v1alpha2 types + conversion tests).

thc1006 and others added 3 commits July 31, 2026 15:00
…ha2) [Proposed]

Records the decision to fix v1alpha1's implicit-plaintext flaw (an omitted `tls` block means `ws://`)
by introducing v1alpha2 with a REQUIRED transport mode, riding on the v1alpha2 conversion/storage
migration already planned for #214/#315.

MUST (decided): required `transport.mode` (no default), explicit plaintext, CEL structural rules,
a lossless conversion webhook that maps `v1alpha1 tls==nil` to an explicit `mode: plaintext` (never a
default-upgraded TLS), v1alpha1 admission ratcheting, and a v1alpha2-specific credential VAP — the last
because the existing #309 policy pins `matchConstraints.apiVersions: ["v1alpha1"]` (verified), so a new
version would otherwise bypass the Secret-authorization check.

DEFER (recorded, proportionality per ADR-0009): express the admin transport allow-list as a VAP with a
ConfigMap paramKind rather than a new RemoteControlPolicy CRD (a new CRD repeats ADR-0009's
disproportionate new-CRD-subsystem cost for this minority feature); and add the ServiceReference target
as an additive v1alpha2 field later, since it has no lossless v1alpha1 down-conversion.

Phased 8-PR rollout + storage-migration sequence; no code lands with this ADR.

Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com>
Cross-checked every load-bearing decision against authoritative Kubernetes sources. None contradicted a
MUST; two changes result:

- STRENGTHENED: rejecting Service type=ExternalName is a documented confused-deputy/SSRF vector (Skipper
  GHSA-mxxc-p822-2hx9, Kyverno CVE-2026-4789, CVE-2020-8558), not a nicety — deny at admission + recheck
  at runtime; NetworkPolicy cannot even target an ExternalName Service.
- CORRECTED: the deferred admin transport allow-list is NOT "just a ConfigMap" (my earlier claim) — a
  structured allow-list is idiomatically a CRD (K8s guidance: ConfigMap paramKind = simple key-value, CRD
  = structured/validated). So defer the admission-time allow-list entirely (runtime flag already gates
  destinations); if built later it is a CRD-vs-flat-ConfigMap tradeoff, re-opening ADR-0009 proportionality.

Added: Gateway API BackendTLSPolicy (GEP-1897, "MUST NOT fall back to plaintext") as the authoritative
precedent for the no-implicit-plaintext rule; optionalOldSelf as the ratcheting mechanism (transition
rules aren't auto-ratcheted); StorageVersionMigration + storedVersions cleanup order; VAP type-checking
is best-effort (keep dry-run); alpha APIs have no required deprecation window (our window is a courtesy).
A References section records all sources.

Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com>
…opt-in as a flag

Review found three internal contradictions in the Proposed ADR:

- CEL/Testing required and tested ServiceReference while DEFER ships
  address-only first. v1 CEL is now address-only; the service XOR rule and the
  service-resolution / address<->service round-trip / ExternalName tests move
  to the additive service field where they belong.
- Rollout step 5 and a rationale bullet still said to build the ConfigMap-param
  transport allow-list, which DEFER drops entirely (runtime flag #251 already
  gates destinations). Removed both; the credential VAP needs no param.
- Loopback plaintext opt-in was only a principle. Now MUST 7: an
  --allow-loopback-plaintext manager flag (default off, runtime-checked, not a
  CR field a tenant could self-grant), gating only literal loopback IPs while
  CEL rejects DNS names that resolve to loopback.

Signed-off-by: thc1006 <hctsai@linux.com>
@thc1006
thc1006 force-pushed the docs/adr-0010-secure-transport branch from 42c89ca to d3c188c Compare July 31, 2026 07:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant