Task · SKT-0014.04

Support Gateway API HTTPRoute in the chart, and reconcile exposure with it

Description

The chart ships templates/ingress.yaml and nothing else for inbound traffic. Every real cluster this has been deployed to routes with Gateway API instead, so the control-plane UI cannot be reached without hand-writing a route outside the chart.

The lab deployment is the worked example: applications/otel-demo/httproutes/frontend.yaml and the k8s-monitoring route set in rkps-awsinfra are all gateway.networking.k8s.io/v1 HTTPRoute objects with parentRefs naming a shared gateway and a sectionName, not Ingress. That cluster explicitly disables the k8s-monitoring chart’s Ingress so a default flip cannot quietly create Ingress objects alongside the routes.

So the chart needs an HTTPRoute template alongside the Ingress one, with the two mutually exclusive: enabling both for the same host publishes the UI twice through different data paths, which is a misconfiguration rather than a choice. Fail the render rather than letting it happen, in the same style as the credential-group guard.

The HTTPRoute surface actually needed, from the real manifests: parentRefs (name, namespace, optional sectionName), hostnames, and path-prefix rules to the control-plane Service. Filters and multiple backendRefs are not needed for a single-service UI and should not be invented.

Exposing the UI changes the exposure acknowledgement, and the chart must enforce that. controlPlane.exposure.ack: trusted-network means plaintext HTTP on an isolated path. A route through a TLS-terminating gateway is tls-proxy. Publishing a hostname while the value still says trusted-network is exactly the state the acknowledgement exists to prevent, so the render should reject it.

Audit the existing Ingress template in the same pass: it has never been deployed anywhere, so its hosts/tls shape is unverified against a real controller.

The chart’s NetworkPolicy is default-deny ingress to the pod. A route or Ingress that publishes the UI without a matching networkPolicy.ingressFrom peer produces a working route to a blocked pod, which reads as a broken gateway rather than a policy decision. Reconcile the two.

Acceptance Criteria

Definition of Done

Implementation Plan

Lane D owns charts/synthkit/ only: add the schema-backed HTTPRoute values/template and render tests for equivalence, mutual exclusion, tls-proxy acknowledgement, and ingress peer guards. Root later owns the live-controller route switch and acceptance evidence.

Implementation Notes

2026-08-29, decided with Rob: the chart renders the HTTPRoute AND the lab switches to it. The hand-written applications/synthkit/httproutes/synthkit.yaml in rkps-awsinfra is deleted and the chart-rendered route replaces it, which is what satisfies acceptance criterion #5 — verified against a real controller rather than assumed.

Sequence matters, because the UI route is live at synthkit.k8s.m7kni.io: land the chart template, render it into the lab values, confirm the rendered route is equivalent to the hand-written one, and only then remove the hand-written one. Do not delete first.

The hand-written route is the specification to match: parentRefs naming the tailscale gateway in envoy-gateway-system with sectionName: https, hostname synthkit.k8s.m7kni.io, backend the control-plane Service on 8088. The lab values already set controlPlane.exposure.ack: "tls-proxy" and carry a networkPolicy.ingressFrom peer for envoy-gateway-system, so criteria #3 and #4 have a working reference to check the guards against.

Note the chart is at 0.2.0 with a values.schema.json that sets additionalProperties: false throughout. New values keys must be added to the schema or the lab install fails — which is the schema working, not a bug.

Final verification 2026-08-29: chart render tests cover HTTPRoute shape, Ingress/HTTPRoute mutual exclusion, tls-proxy acknowledgement, and ingress peer guards. The rendered lab route had an empty canonical spec diff against the working hand-written route before replacement. Live Envoy Gateway reports Accepted=True and ResolvedRefs=True; the public readiness endpoint and authenticated UI return HTTP 200. just check, just dump, just e2e, local kubeconform with the Gateway API schema, and exact-SHA helm validation passed. No blueprint field or construct/workload config struct changed, so the conditional blueprint-schema DoD item was not applicable.

Final Summary

Added a schema-backed HTTPRoute surface with fail-closed exposure guards, then replaced the lab’s hand-written route only after proving equivalence. Render tests and live-controller HTTP 200 evidence passed.

View the source file on GitHub