stalwart/bulwark: CORS als Chart-Werte - die Gateway-API hat einen CORS-Filter, aber nur Extended #129

Closed
opened 2026-10-13 13:25:49 +02:00 by jlab-bot · 0 comments
Member

Im Gateway-Modus verliert stalwart seine CORS-Konfiguration still, und die Gateway-API hat dafür ein Gegenstück. Ob wir es rendern wollen, ist offen — der Blocker ist nicht das Fehlen eines Feldes, sondern seine Support-Stufe.

Der Verlust, gemessen

Die laufende stalwart-Ingress trägt vier vom Betreiber gesetzte Annotationen, die der Chart selbst nicht setzt:

enable-cors:        true
cors-allow-origin:  https://webmail.bekemeyer-klein.de
cors-allow-methods: GET, POST, OPTIONS
cors-allow-headers: Authorization, Content-Type

Der Ursprung ist benannt: es ist die Verbindung zum bulwark-Webmail, also zu einem anderen Chart dieses Repositories. Im Gateway-Modus fallen ingress.annotations weg und damit alle vier — PR #120 benennt das im Gateway-Zweig von NOTES.txt, behebt es aber nicht.

Das Gegenstück existiert, und meine frühere Behauptung dazu war falsch

Ich hatte geschrieben, es gebe keines und responseHeaderModifier sei der einzige Hebel. Das stimmt nicht. In kubernetes-sigs/gateway-api v1.6.3, Standard-Channel, den dieses Repository pinnt:

  • HTTPRouteFilterCORS = "CORS" steht im Filter-Enum (httproute_types.go:859)
  • HTTPCORSFilter ist ein vollwertiger Typ mit AllowOrigins, AllowMethods, AllowHeaders, AllowCredentials und mehr (GEP-1767)
  • CEL-Regel: „CORS filter cannot be repeated"
  • Support: Extended

Warum trotzdem nichts gerendert wird — die Gründe stehen im Style-Guide

Der Chart-Style-Guide protokolliert zwei, und sie sind beide stärker als „es gibt kein Feld":

both Support: Extended, neither Core … Extended is not promisable — a rejected route is rejected whole, and the observed failure is quieter still (Cilium accepts filters.type: CORS and forwards the preflight upstream anyway).

And half a feature is worse than none: a responseHeaderModifier can add the Access-Control-Allow-* headers but cannot answer the preflight, which the gateway rather than the backend must do — and with Authorization in the allowed headers every request is preflighted, so the expressible half is exactly the useless one.

Der zweite Punkt trifft diesen Fall direkt: cors-allow-headers enthält Authorization, also ist jede Webmail-Anfrage preflight-pflichtig, und die Hälfte, die responseHeaderModifier ausdrücken kann, ist die nutzlose.

Der erste ist der eigentliche Blocker, und er ist unangenehm asymmetrisch: ein nicht unterstützter Filter setzt nach der Spezifikation Accepted: False auf die ganze Route — bei stalwart also auch das Routing des Mail-Hosts. Und das wäre der laute Fehlerfall. Der leise ist der dokumentierte Cilium-Fall: Filter akzeptiert, Preflight trotzdem nach oben durchgereicht — CORS kaputt, Route grün, nichts meldet etwas.

Was wahr sein müsste, damit das umsetzbar wird

Die eingesetzte Gateway-Implementierung müsste bekannt und ihre CORS-Unterstützung belegt sein. Das ist derzeit nicht feststellbar: httproutes und gatewayclasses sind für die lesende Identität im Cluster RBAC-gesperrt (system:serviceaccount:coder-workspaces:claude-readonly), und jede HTTP-Messung dieses Clusters läuft über den Frontproxy proxy.jk-dev.de. Die Implementierung ist also von hier aus nicht benennbar — in keinem der sieben PRs dieses Sweeps war sie es.

Das ist die erste Aufgabe dieses Issues, und sie ist keine Chart-Arbeit: feststellen, welcher Controller läuft, und ob er filters.type: CORS unterstützt oder nur annimmt. Beides ist in cluster-config zu beantworten, nicht hier.

Ein Datenpunkt dazu liegt schon vor und zeigt in die richtige Richtung: cert-manager läuft in diesem Cluster mit enableGatewayAPI: true (gemessen in seiner ControllerConfiguration), es gibt dort also eine ernstgenommene Gateway-Installation und nicht nur CRDs.

Umfang, falls die Unterstützung belegt ist

  • stalwart: Werte für die vier Felder, Vorgabe aus, gerendert als CORS-Filter nur im Gateway-Modus.
  • Und in beiden Modi, sonst ist es ein modus-asymmetrisches Feature. Im Ingress-Modus heißt das: die vier Annotationen aus Chart-Werten erzeugen statt sie dem Betreiber zu überlassen — eine Erweiterung, die heute niemand verlangt hat, und der eigentliche Preis dieses Issues.
  • values.schema.json, NOTES.txt, Wiki-Seite stalwart, und Chart-Style-Guide, weil die dort protokollierte Regel („ein Filter wird nur gerendert, wenn das Support-Level das Verhalten zusagbar macht") dann eine begründete Ausnahme bekommt.
  • Zu klären: ob bulwark das Gegenstück braucht. Es ist der andere Teilnehmer dieser CORS-Beziehung.

Umfang, falls sie nicht belegt ist

Dann wird dieses Issue mit dem Befund geschlossen, und der Befund ist der Wert: welche Implementierung läuft und was sie nicht kann steht dann im Wiki, statt bei jedem künftigen Filter neu gefragt zu werden. Die vier Annotationen bleiben Betreibersache — mit dem Zusatz, dass sie im Gateway-Modus nicht wirken, was NOTES.txt seit #120 sagt.

Herkunft

Vorgeschlagen vom Entwicklungs-Agenten von #120 (Gruppe 3 des Gateway-API-Sweeps), der den Filter beim Prüfen der pinned CRDs gefunden und bewusst nichts gerendert hat — mit den drei Gründen im PR-Rumpf, von denen der Preflight der entscheidende war. Er hat es als eigenes Issue vorgeschlagen, weil CORS-Werte ein echtes Feature sind und kein Nachtrag zu einer Routing-Umstellung.

Im Gateway-Modus verliert `stalwart` seine CORS-Konfiguration still, und die Gateway-API hat dafür ein Gegenstück. Ob wir es rendern wollen, ist offen — der Blocker ist nicht das Fehlen eines Feldes, sondern seine Support-Stufe. ## Der Verlust, gemessen Die laufende `stalwart`-Ingress trägt vier vom **Betreiber** gesetzte Annotationen, die der Chart selbst nicht setzt: ``` enable-cors: true cors-allow-origin: https://webmail.bekemeyer-klein.de cors-allow-methods: GET, POST, OPTIONS cors-allow-headers: Authorization, Content-Type ``` Der Ursprung ist benannt: es ist die Verbindung zum **`bulwark`-Webmail**, also zu einem anderen Chart dieses Repositories. Im Gateway-Modus fallen `ingress.annotations` weg und damit alle vier — PR #120 benennt das im Gateway-Zweig von `NOTES.txt`, behebt es aber nicht. ## Das Gegenstück existiert, und meine frühere Behauptung dazu war falsch Ich hatte geschrieben, es gebe keines und `responseHeaderModifier` sei der einzige Hebel. **Das stimmt nicht.** In `kubernetes-sigs/gateway-api` v1.6.3, Standard-Channel, den dieses Repository pinnt: - `HTTPRouteFilterCORS = "CORS"` steht im Filter-Enum (`httproute_types.go:859`) - `HTTPCORSFilter` ist ein vollwertiger Typ mit `AllowOrigins`, `AllowMethods`, `AllowHeaders`, `AllowCredentials` und mehr (GEP-1767) - CEL-Regel: *„CORS filter cannot be repeated"* - **`Support: Extended`** ## Warum trotzdem nichts gerendert wird — die Gründe stehen im Style-Guide Der `Chart-Style-Guide` protokolliert zwei, und sie sind beide stärker als „es gibt kein Feld": > both `Support: Extended`, neither Core … **Extended is not promisable** — a rejected route is rejected **whole**, and the observed failure is quieter still (Cilium accepts `filters.type: CORS` and forwards the preflight upstream anyway). > **And half a feature is worse than none**: a `responseHeaderModifier` can add the `Access-Control-Allow-*` headers but cannot answer the **preflight**, which the gateway rather than the backend must do — and with `Authorization` in the allowed headers every request is preflighted, so the expressible half is exactly the useless one. Der zweite Punkt trifft diesen Fall direkt: `cors-allow-headers` enthält `Authorization`, also ist **jede** Webmail-Anfrage preflight-pflichtig, und die Hälfte, die `responseHeaderModifier` ausdrücken kann, ist die nutzlose. Der erste ist der eigentliche Blocker, und er ist unangenehm asymmetrisch: ein nicht unterstützter Filter setzt nach der Spezifikation `Accepted: False` auf die **ganze** Route — bei `stalwart` also auch das Routing des Mail-Hosts. Und das wäre der *laute* Fehlerfall. Der leise ist der dokumentierte Cilium-Fall: Filter akzeptiert, Preflight trotzdem nach oben durchgereicht — CORS kaputt, Route grün, nichts meldet etwas. ## Was wahr sein müsste, damit das umsetzbar wird **Die eingesetzte Gateway-Implementierung müsste bekannt und ihre CORS-Unterstützung belegt sein.** Das ist derzeit **nicht feststellbar**: `httproutes` und `gatewayclasses` sind für die lesende Identität im Cluster RBAC-gesperrt (`system:serviceaccount:coder-workspaces:claude-readonly`), und jede HTTP-Messung dieses Clusters läuft über den Frontproxy `proxy.jk-dev.de`. Die Implementierung ist also von hier aus nicht benennbar — in keinem der sieben PRs dieses Sweeps war sie es. Das ist die erste Aufgabe dieses Issues, und sie ist keine Chart-Arbeit: **feststellen, welcher Controller läuft, und ob er `filters.type: CORS` unterstützt oder nur annimmt.** Beides ist in `cluster-config` zu beantworten, nicht hier. Ein Datenpunkt dazu liegt schon vor und zeigt in die richtige Richtung: cert-manager läuft in diesem Cluster mit **`enableGatewayAPI: true`** (gemessen in seiner `ControllerConfiguration`), es gibt dort also eine ernstgenommene Gateway-Installation und nicht nur CRDs. ## Umfang, falls die Unterstützung belegt ist - `stalwart`: Werte für die vier Felder, Vorgabe aus, gerendert als `CORS`-Filter **nur** im Gateway-Modus. - **Und in beiden Modi**, sonst ist es ein modus-asymmetrisches Feature. Im Ingress-Modus heißt das: die vier Annotationen aus Chart-Werten erzeugen statt sie dem Betreiber zu überlassen — eine Erweiterung, die heute niemand verlangt hat, und der eigentliche Preis dieses Issues. - `values.schema.json`, `NOTES.txt`, Wiki-Seite `stalwart`, und `Chart-Style-Guide`, weil die dort protokollierte Regel („ein Filter wird nur gerendert, wenn das Support-Level das Verhalten zusagbar macht") dann eine begründete Ausnahme bekommt. - Zu klären: ob `bulwark` das Gegenstück braucht. Es ist der andere Teilnehmer dieser CORS-Beziehung. ## Umfang, falls sie nicht belegt ist Dann wird dieses Issue mit dem Befund geschlossen, und der Befund ist der Wert: **welche Implementierung läuft und was sie nicht kann** steht dann im Wiki, statt bei jedem künftigen Filter neu gefragt zu werden. Die vier Annotationen bleiben Betreibersache — mit dem Zusatz, dass sie im Gateway-Modus nicht wirken, was `NOTES.txt` seit #120 sagt. ## Herkunft Vorgeschlagen vom Entwicklungs-Agenten von #120 (Gruppe 3 des Gateway-API-Sweeps), der den Filter beim Prüfen der pinned CRDs gefunden und bewusst **nichts** gerendert hat — mit den drei Gründen im PR-Rumpf, von denen der Preflight der entscheidende war. Er hat es als eigenes Issue vorgeschlagen, weil CORS-Werte ein echtes Feature sind und kein Nachtrag zu einer Routing-Umstellung.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jlab-cluster/helm-charts#129