From 3c13e5e839be8e7cf142bef1c5bc26ac5c0f7dbc Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Mon, 9 Mar 2026 14:36:29 +0100 Subject: [PATCH 01/79] wip --- charts/wire-ingress/CLAUDE.md | 5 + charts/wire-ingress/README.md | 450 ++++++++++++++++++++++++++++++++++ 2 files changed, 455 insertions(+) create mode 100644 charts/wire-ingress/CLAUDE.md create mode 100644 charts/wire-ingress/README.md diff --git a/charts/wire-ingress/CLAUDE.md b/charts/wire-ingress/CLAUDE.md new file mode 100644 index 00000000000..f277724b9f4 --- /dev/null +++ b/charts/wire-ingress/CLAUDE.md @@ -0,0 +1,5 @@ +# Working mode for wire-ingress + +- Work through the implementation plan in README.md one step at a time. +- After completing each step, stop and summarise what was done, then ask the user before proceeding to the next step. +- Keep README.md up to date with every change — if a plan step is completed, a design decision changes, or a backwards-compatibility note needs updating, update the README in the same commit/change. diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md new file mode 100644 index 00000000000..bead927e8f9 --- /dev/null +++ b/charts/wire-ingress/README.md @@ -0,0 +1,450 @@ +# wire-ingress + +A replacement for [`nginx-ingress-services`](../nginx-ingress-services/README.md) that uses the +**Kubernetes Gateway API** instead of the classic `networking.k8s.io/v1 Ingress` API. + +The chart targets **Envoy Gateway** as the Gateway API controller. + +--- + +## Status + +**This chart is in planning. No implementation exists yet.** + +--- + +## Design decisions + +### Gateway API controller: Envoy Gateway + +The chart targets [Envoy Gateway](https://gateway.envoyproxy.io/). Implementation-specific +resources (`ClientTrafficPolicy`, `SecurityPolicy`, `HTTPRouteFilter` with `directResponse`) are +used where the standard Gateway API has gaps. These resources are clearly marked in each template. + +### Gateway creation is optional + +The chart can optionally create a `Gateway` resource (controlled by `gateway.create: true`). +When `gateway.create: false`, all `HTTPRoute` and policy resources still reference the gateway by +name (`gateway.name`). This allows operators to share a Gateway across multiple charts or manage it +separately. + +The default values create the Gateway. The default `gateway.name` is derived from the release name, +so that self-referencing is consistent by default. + +### GatewayClass is not created + +`GatewayClass` is installed by the Envoy Gateway Helm chart and is cluster-scoped. This chart only +references it by name via `gateway.className`. + +### Multi-ingress is out of scope + +The `ingressName` / `isAdditionalIngress` pattern from `nginx-ingress-services` is not implemented. +Single-domain deployments are the only supported topology. Multi-domain support can be added later. + +### Federator mTLS uses Envoy Gateway policies + +The old chart used nginx annotations (`auth-tls-verify-client`, `auth-tls-verify-depth`, and a +`configuration-snippet` to forward `X-SSL-Certificate`). The new chart uses: + +- `ClientTrafficPolicy` to configure TLS settings on the federator `Gateway` listener (client + certificate validation, verify depth) +- A separate `Gateway` listener (or dedicated `Gateway`) for the federator so that mTLS settings + apply only to that listener +- The `X-SSL-Certificate` header forwarding is handled via Envoy Gateway's `HTTPRouteFilter` with + request header injection from the client cert (implementation-specific) + +--- + +## Backwards compatibility + +The chart preserves the `values.yaml` structure of `nginx-ingress-services` wherever possible. +Operators should be able to reuse most of their existing values files with minimal changes. + +### Renamed / restructured values + +| Old key | New key | Notes | +|---|---|---| +| `config.ingressClass` | `gateway.className` | Different concept: GatewayClass name, not IngressClass | +| _(not present)_ | `gateway.create` | `true` = chart creates the Gateway; `false` = BYO | +| _(not present)_ | `gateway.name` | Name of the Gateway to attach routes to | + +### Dropped values (not applicable to Gateway API) + +| Old key | Reason | +|---|---| +| `ingressName` | Multi-ingress out of scope | +| `config.isAdditionalIngress` | Multi-ingress out of scope | +| `config.renderCSPInIngress` | Multi-ingress out of scope | +| `config.dns.base` | Only used for CSP header rendering, which is a multi-ingress feature | +| `tls.verify_depth` | Envoy Gateway `ClientTrafficPolicy` does not expose a direct verify-depth knob; the CA chain itself controls this | + +### Fully backwards compatible values + +All keys below are accepted unchanged. Their names, types, and semantics are identical to +`nginx-ingress-services`. + +| Key | Notes | +|---|---| +| `nameOverride` | | +| `kubeVersionOverride` | | +| `teamSettings.enabled` | | +| `accountPages.enabled` | | +| `websockets.enabled` | | +| `webapp.enabled` | | +| `fakeS3.enabled` | | +| `federator.enabled` | | +| `federator.integrationTestHelper` | | +| `federator.tls.duration` | | +| `federator.tls.renewBefore` | | +| `federator.tls.privateKey.rotationPolicy` | | +| `federator.tls.issuer.name` | | +| `federator.tls.issuer.kind` | | +| `federator.tls.issuer.group` | | +| `tls.enabled` | | +| `tls.useCertManager` | | +| `tls.createIssuer` | | +| `tls.privateKey.rotationPolicy` | | +| `tls.privateKey.algorithm` | | +| `tls.privateKey.size` | | +| `tls.issuer.name` | | +| `tls.issuer.kind` | | +| `tls.caNamespace` | | +| `certManager.inTestMode` | | +| `certManager.certmasterEmail` | | +| `certManager.customSolvers` | | +| `service.webapp.externalPort` | | +| `service.s3.externalPort` | | +| `service.s3.serviceName` | | +| `service.useFakeS3` | | +| `service.teamSettings.externalPort` | | +| `service.accountPages.externalPort` | | +| `config.dns.https` | | +| `config.dns.ssl` | | +| `config.dns.webapp` | | +| `config.dns.fakeS3` | | +| `config.dns.federator` | | +| `config.dns.certificateDomain` | | +| `config.dns.teamSettings` | | +| `config.dns.accountPages` | | +| `secrets.tlsWildcardCert` | | +| `secrets.tlsWildcardKey` | | +| `secrets.tlsClientCA` | | +| `secrets.certManager.customSolversSecret` | | + +### Behaviour changes + +| Feature | Old behaviour | New behaviour | +|---|---|---| +| `/minio/` path blocking | nginx `server-snippet` returning 403 | Envoy Gateway `HTTPRouteFilter` `directResponse` (implementation-specific, non-standard) | +| Federator client cert header | `nginx.ingress.kubernetes.io/configuration-snippet` setting `X-SSL-Certificate` | Envoy Gateway `ClientTrafficPolicy` + `HTTPRouteFilter` header injection | +| Websocket routing | Separate host with port name `ws` | Same `HTTPRoute` — WebSocket upgrades are handled transparently by Envoy | + +--- + +## Testing strategy + +### Rendering diff + +For each implementation step, render both charts with the same values and compare: + +```bash +helm template release-name ../nginx-ingress-services -f test-values.yaml > /tmp/old.yaml +helm template release-name ./wire-ingress -f test-values.yaml > /tmp/new.yaml +diff /tmp/old.yaml /tmp/new.yaml +``` + +The goal is not an identical diff (the API objects are different) but to confirm that every +resource in the old chart has a counterpart and that no routing rule is silently dropped. + +### Schema validation + +`values.schema.json` is maintained alongside `values.yaml`. Run `helm lint` to catch +misconfiguration early: + +```bash +helm lint ./wire-ingress -f test-values.yaml +``` + +### Test values files to maintain + +Create one values file per meaningful configuration variant to use with `helm template` and +`helm lint`: + +| File | Purpose | +|---|---| +| `ci/values-minimal.yaml` | Only required fields, all optional features disabled | +| `ci/values-full.yaml` | All features enabled (webapp, teamSettings, accountPages, fakeS3, federator, certManager) | +| `ci/values-manual-tls.yaml` | `tls.useCertManager: false`, wildcard cert supplied manually | +| `ci/values-federator.yaml` | `federator.enabled: true` with all federator-specific settings | +| `ci/values-byo-gateway.yaml` | `gateway.create: false`, referencing an external gateway | + +--- + +## Implementation plan + +The work is split into small, independently reviewable steps. Each step touches one logical +concern and can be reviewed by running `helm template` / `helm lint` on the partial chart. + +### Phase 1 — Chart scaffolding + +#### Step 1: Chart.yaml, .helmignore, empty values.yaml, _helpers.tpl + +Create the chart skeleton. Helpers replicate the naming helpers from `nginx-ingress-services` +(`fullname`, `zone`, `getCertificateSecretName`, `getIssuerName`) plus new helpers for Gateway +naming (`getGatewayName`). + +**Review:** `helm lint ./wire-ingress` passes with empty values. + +--- + +#### Step 2: values.schema.json + +Define a JSON Schema that validates the same top-level structure as `nginx-ingress-services` plus +the new `gateway.*` keys. This is written before any templates so that schema gaps are caught +early. + +**Review:** `helm lint` with each `ci/values-*.yaml` file passes or produces only expected +validation errors. + +--- + +### Phase 2 — Gateway + +#### Step 3: Optional Gateway resource + +Template: `templates/gateway.yaml` + +Creates a `gateway.networking.k8s.io/v1 Gateway` when `gateway.create: true`. The Gateway has: + +- An HTTP listener on port 80 (for ACME HTTP-01 challenges and optional redirect) +- An HTTPS listener on port 443 with TLS termination, referencing the TLS secret + +The federator listener is added in Step 12 (not here) to keep federator concerns separate. + +New values: + +```yaml +gateway: + create: true + name: "" # default: derived from release name via helper + className: envoy # GatewayClass installed by Envoy Gateway + listeners: + http: + port: 80 + https: + port: 443 +``` + +**Review:** `helm template` produces a valid `Gateway` manifest. Diff against old chart shows no +`Ingress` equivalent yet — that is expected. + +--- + +### Phase 3 — Core HTTPRoutes + +Each step adds one `HTTPRoute` (or one group of closely related routes). + +#### Step 4: HTTPRoute — nginz (HTTPS endpoint) + +Template: `templates/httproute-nginz.yaml` + +Routes `config.dns.https` → `nginz` service port `http`. + +Gateway API equivalent of the `nginz-https` rule in the old `Ingress`. The route attaches to the +HTTPS listener of the Gateway via `parentRefs`. + +**Review:** Renders correctly with and without TLS; `helm lint` passes. + +--- + +#### Step 5: HTTPRoute — websockets + +Template: `templates/httproute-websockets.yaml` +Condition: `websockets.enabled` + +Routes `config.dns.ssl` → `nginz` service port `ws`. WebSocket upgrades require no special +annotation in Envoy — they are transparent at the HTTP layer. + +**Review:** Rendered only when `websockets.enabled: true`. Hostname differs from nginz route. + +--- + +#### Step 6: HTTPRoute — webapp + +Template: `templates/httproute-webapp.yaml` +Condition: `webapp.enabled` + +Routes `config.dns.webapp` → `webapp-http` service port `externalPort`. + +**Review:** Absent from rendered output when `webapp.enabled: false`. + +--- + +#### Step 7: HTTPRoute — team-settings + +Template: `templates/httproute-team-settings.yaml` +Condition: `teamSettings.enabled` + +Routes `config.dns.teamSettings` → `team-settings-http` service port `externalPort`. + +--- + +#### Step 8: HTTPRoute — account-pages + +Template: `templates/httproute-account-pages.yaml` +Condition: `accountPages.enabled` + +Routes `config.dns.accountPages` → `account-pages-http` service port `externalPort`. + +--- + +#### Step 9: HTTPRoute — fakeS3 / minio + +Template: `templates/httproute-minio.yaml` +Condition: `fakeS3.enabled` + +Routes `config.dns.fakeS3` → `fake-aws-s3` service. + +The old chart used a nginx `server-snippet` to return 403 for `/minio/` paths. This chart uses an +Envoy Gateway `HTTPRouteFilter` with `type: DirectResponse` and `statusCode: 403` for a +`/minio/` prefix match rule, placed before the catch-all rule. + +> **Incompatibility note:** `DirectResponse` is an Envoy Gateway extension +> (`gateway.envoyproxy.io/v1alpha1`). It is not part of the standard Gateway API spec. + +**Review:** Two rules rendered: one 403 rule for `/minio/` prefix, one catch-all for `/`. + +--- + +### Phase 4 — TLS + +#### Step 10: TLS Secret (manual mode) + +Template: `templates/secret.yaml` +Condition: `!tls.useCertManager` + +Identical in structure to the old chart. Encodes `secrets.tlsWildcardCert` and +`secrets.tlsWildcardKey` into a `kubernetes.io/tls` Secret referenced by the Gateway listener. + +--- + +#### Step 11: cert-manager Certificate + Issuer + +Templates: `templates/certificate.yaml`, `templates/issuer.yaml` +Condition: `tls.useCertManager` + +Identical in structure and values to the old chart. The cert-manager `Certificate` spec is +unchanged; the `secretName` it produces is referenced by the Gateway listener (Step 3). + +--- + +### Phase 5 — Services + +#### Step 12: ClusterIP Services + +Template: `templates/service.yaml` + +Identical to the old chart. Creates `webapp-http`, `s3-http`, `team-settings-http`, +`account-pages-http` ClusterIP services. The selectors and ports are unchanged. + +**Review:** `helm template` output for this file should be byte-for-byte identical to the old +chart's `service.yaml` output (same values → same services). + +--- + +### Phase 6 — Federator + +#### Step 13: Gateway listener for federator + +Extend `templates/gateway.yaml` to add a separate TLS listener for `config.dns.federator` when +`federator.enabled: true`. + +The federator requires its own listener so that `ClientTrafficPolicy` can enforce mTLS only on +that listener, not on the main HTTPS listener. + +--- + +#### Step 14: HTTPRoute for federator + +Template: `templates/httproute-federator.yaml` +Condition: `federator.enabled` + +Routes `config.dns.federator` → `federator` service port `federator-ext`, attaching to the +federator listener. + +Blocks combination with `config.isAdditionalIngress` (same guard as the old chart, kept for +documentation purposes even though multi-ingress is out of scope). + +--- + +#### Step 15: ClientTrafficPolicy for federator mTLS + +Template: `templates/clienttrafficpolicy-federator.yaml` +Condition: `federator.enabled` + +Envoy Gateway-specific (`gateway.envoyproxy.io/v1alpha1`). Configures: + +- `tls.clientValidation.caCertificateRef` → references `federator-ca-secret` +- Forwards the client certificate as `X-SSL-Certificate` request header (implementation-specific + header injection) + +Maps to the old nginx annotations: +- `nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"` +- `nginx.ingress.kubernetes.io/auth-tls-secret` +- `nginx.ingress.kubernetes.io/configuration-snippet` (X-SSL-Certificate) + +> **Incompatibility note:** The `tls.verify_depth` value is not directly mapped. Envoy Gateway's +> `ClientTrafficPolicy` does not expose a depth knob; validation depth is implicitly controlled by +> the CA chain provided in `federator-ca-secret`. + +--- + +#### Step 16: Federator TLS secrets + CA secret + +Templates: `templates/secret-federator.yaml`, `templates/ca-federator.yaml` +Condition: `federator.enabled` + +Identical in structure to the old chart (`federator-certificate-secret`, +`federator-ca-secret`). cert-manager `Certificate` for federator is also kept in +`templates/certificate-federator.yaml` with the same spec as the old chart. + +--- + +### Phase 7 — Integration test helper + +#### Step 17: federation-test-helper Service + +Template: `templates/federation-test-helper.yaml` + +Identical to the old chart. The Kubernetes version label selector switch (>= 1.23) is kept. + +--- + +### Phase 8 — custom solver secret + +#### Step 18: Custom ACME solver secret + +Template: `templates/custom-solvers-secret.yaml` + +Identical to the old chart. + +--- + +### Phase 9 — Documentation and CI values + +#### Step 19: Finalize README, migration guide, and ci/ values files + +- Write the migration guide section of this README +- Create `ci/values-minimal.yaml`, `ci/values-full.yaml`, etc. +- Ensure `helm lint` and `helm template` pass for all CI values files + +--- + +## Migration guide + +_To be written after implementation. Will cover:_ + +- Which values files can be reused as-is +- Which keys need renaming (see backwards compatibility table above) +- How to verify the migration with `helm template` diff +- Envoy Gateway prerequisites (CRDs, controller install) From 0e32863496aabb7d77afedb68ab10e3f4a269bf8 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Mon, 9 Mar 2026 14:41:52 +0100 Subject: [PATCH 02/79] checkboxes --- charts/wire-ingress/README.md | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index bead927e8f9..92995e052db 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -193,8 +193,12 @@ Create the chart skeleton. Helpers replicate the naming helpers from `nginx-ingr (`fullname`, `zone`, `getCertificateSecretName`, `getIssuerName`) plus new helpers for Gateway naming (`getGatewayName`). +Use `helm create` for an initial scaffolding. + **Review:** `helm lint ./wire-ingress` passes with empty values. +- [ ] Done + --- #### Step 2: values.schema.json @@ -206,6 +210,8 @@ early. **Review:** `helm lint` with each `ci/values-*.yaml` file passes or produces only expected validation errors. +- [ ] Done + --- ### Phase 2 — Gateway @@ -238,6 +244,8 @@ gateway: **Review:** `helm template` produces a valid `Gateway` manifest. Diff against old chart shows no `Ingress` equivalent yet — that is expected. +- [ ] Done + --- ### Phase 3 — Core HTTPRoutes @@ -255,6 +263,8 @@ HTTPS listener of the Gateway via `parentRefs`. **Review:** Renders correctly with and without TLS; `helm lint` passes. +- [ ] Done + --- #### Step 5: HTTPRoute — websockets @@ -267,6 +277,8 @@ annotation in Envoy — they are transparent at the HTTP layer. **Review:** Rendered only when `websockets.enabled: true`. Hostname differs from nginz route. +- [ ] Done + --- #### Step 6: HTTPRoute — webapp @@ -278,6 +290,8 @@ Routes `config.dns.webapp` → `webapp-http` service port `externalPort`. **Review:** Absent from rendered output when `webapp.enabled: false`. +- [ ] Done + --- #### Step 7: HTTPRoute — team-settings @@ -287,6 +301,8 @@ Condition: `teamSettings.enabled` Routes `config.dns.teamSettings` → `team-settings-http` service port `externalPort`. +- [ ] Done + --- #### Step 8: HTTPRoute — account-pages @@ -296,6 +312,8 @@ Condition: `accountPages.enabled` Routes `config.dns.accountPages` → `account-pages-http` service port `externalPort`. +- [ ] Done + --- #### Step 9: HTTPRoute — fakeS3 / minio @@ -314,6 +332,8 @@ Envoy Gateway `HTTPRouteFilter` with `type: DirectResponse` and `statusCode: 403 **Review:** Two rules rendered: one 403 rule for `/minio/` prefix, one catch-all for `/`. +- [ ] Done + --- ### Phase 4 — TLS @@ -326,6 +346,8 @@ Condition: `!tls.useCertManager` Identical in structure to the old chart. Encodes `secrets.tlsWildcardCert` and `secrets.tlsWildcardKey` into a `kubernetes.io/tls` Secret referenced by the Gateway listener. +- [ ] Done + --- #### Step 11: cert-manager Certificate + Issuer @@ -336,6 +358,8 @@ Condition: `tls.useCertManager` Identical in structure and values to the old chart. The cert-manager `Certificate` spec is unchanged; the `secretName` it produces is referenced by the Gateway listener (Step 3). +- [ ] Done + --- ### Phase 5 — Services @@ -350,6 +374,8 @@ Identical to the old chart. Creates `webapp-http`, `s3-http`, `team-settings-htt **Review:** `helm template` output for this file should be byte-for-byte identical to the old chart's `service.yaml` output (same values → same services). +- [ ] Done + --- ### Phase 6 — Federator @@ -362,6 +388,8 @@ Extend `templates/gateway.yaml` to add a separate TLS listener for `config.dns.f The federator requires its own listener so that `ClientTrafficPolicy` can enforce mTLS only on that listener, not on the main HTTPS listener. +- [ ] Done + --- #### Step 14: HTTPRoute for federator @@ -375,6 +403,8 @@ federator listener. Blocks combination with `config.isAdditionalIngress` (same guard as the old chart, kept for documentation purposes even though multi-ingress is out of scope). +- [ ] Done + --- #### Step 15: ClientTrafficPolicy for federator mTLS @@ -397,6 +427,8 @@ Maps to the old nginx annotations: > `ClientTrafficPolicy` does not expose a depth knob; validation depth is implicitly controlled by > the CA chain provided in `federator-ca-secret`. +- [ ] Done + --- #### Step 16: Federator TLS secrets + CA secret @@ -408,6 +440,8 @@ Identical in structure to the old chart (`federator-certificate-secret`, `federator-ca-secret`). cert-manager `Certificate` for federator is also kept in `templates/certificate-federator.yaml` with the same spec as the old chart. +- [ ] Done + --- ### Phase 7 — Integration test helper @@ -418,6 +452,8 @@ Template: `templates/federation-test-helper.yaml` Identical to the old chart. The Kubernetes version label selector switch (>= 1.23) is kept. +- [ ] Done + --- ### Phase 8 — custom solver secret @@ -428,6 +464,8 @@ Template: `templates/custom-solvers-secret.yaml` Identical to the old chart. +- [ ] Done + --- ### Phase 9 — Documentation and CI values @@ -438,6 +476,8 @@ Identical to the old chart. - Create `ci/values-minimal.yaml`, `ci/values-full.yaml`, etc. - Ensure `helm lint` and `helm template` pass for all CI values files +- [ ] Done + --- ## Migration guide From 94877009ce12112fcffa532af41b6d89c8c24cae Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Mon, 9 Mar 2026 14:51:52 +0100 Subject: [PATCH 03/79] mention nginx-ingress-services in the backwards compatbility section only --- charts/wire-ingress/README.md | 121 ++++++++++++++-------------------- 1 file changed, 50 insertions(+), 71 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 92995e052db..2d13ebd57eb 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -1,7 +1,6 @@ # wire-ingress -A replacement for [`nginx-ingress-services`](../nginx-ingress-services/README.md) that uses the -**Kubernetes Gateway API** instead of the classic `networking.k8s.io/v1 Ingress` API. +A Helm chart for Wire server ingress using the **Kubernetes Gateway API**. The chart targets **Envoy Gateway** as the Gateway API controller. @@ -38,13 +37,11 @@ references it by name via `gateway.className`. ### Multi-ingress is out of scope -The `ingressName` / `isAdditionalIngress` pattern from `nginx-ingress-services` is not implemented. Single-domain deployments are the only supported topology. Multi-domain support can be added later. ### Federator mTLS uses Envoy Gateway policies -The old chart used nginx annotations (`auth-tls-verify-client`, `auth-tls-verify-depth`, and a -`configuration-snippet` to forward `X-SSL-Certificate`). The new chart uses: +Federator mTLS is implemented using: - `ClientTrafficPolicy` to configure TLS settings on the federator `Gateway` listener (client certificate validation, verify depth) @@ -76,6 +73,7 @@ Operators should be able to reuse most of their existing values files with minim | `config.isAdditionalIngress` | Multi-ingress out of scope | | `config.renderCSPInIngress` | Multi-ingress out of scope | | `config.dns.base` | Only used for CSP header rendering, which is a multi-ingress feature | +| `kubeVersionOverride` | Deprecated; the federation-test-helper label selector no longer needs a version override | | `tls.verify_depth` | Envoy Gateway `ClientTrafficPolicy` does not expose a direct verify-depth knob; the CA chain itself controls this | ### Fully backwards compatible values @@ -86,7 +84,6 @@ All keys below are accepted unchanged. Their names, types, and semantics are ide | Key | Notes | |---|---| | `nameOverride` | | -| `kubeVersionOverride` | | | `teamSettings.enabled` | | | `accountPages.enabled` | | | `websockets.enabled` | | @@ -145,16 +142,14 @@ All keys below are accepted unchanged. Their names, types, and semantics are ide ### Rendering diff -For each implementation step, render both charts with the same values and compare: +For each implementation step, render the chart and inspect the output: ```bash -helm template release-name ../nginx-ingress-services -f test-values.yaml > /tmp/old.yaml -helm template release-name ./wire-ingress -f test-values.yaml > /tmp/new.yaml -diff /tmp/old.yaml /tmp/new.yaml +helm template release-name ./wire-ingress -f test-values.yaml ``` -The goal is not an identical diff (the API objects are different) but to confirm that every -resource in the old chart has a counterpart and that no routing rule is silently dropped. +To verify routing coverage against the previous deployment, render both and compare (see the +migration guide for details). ### Schema validation @@ -187,11 +182,10 @@ concern and can be reviewed by running `helm template` / `helm lint` on the part ### Phase 1 — Chart scaffolding -#### Step 1: Chart.yaml, .helmignore, empty values.yaml, _helpers.tpl +#### Chart.yaml, .helmignore, empty values.yaml, _helpers.tpl -Create the chart skeleton. Helpers replicate the naming helpers from `nginx-ingress-services` -(`fullname`, `zone`, `getCertificateSecretName`, `getIssuerName`) plus new helpers for Gateway -naming (`getGatewayName`). +Create the chart skeleton with helpers for naming (`fullname`, `zone`, `getCertificateSecretName`, +`getIssuerName`, `getGatewayName`). Use `helm create` for an initial scaffolding. @@ -201,22 +195,9 @@ Use `helm create` for an initial scaffolding. --- -#### Step 2: values.schema.json - -Define a JSON Schema that validates the same top-level structure as `nginx-ingress-services` plus -the new `gateway.*` keys. This is written before any templates so that schema gaps are caught -early. - -**Review:** `helm lint` with each `ci/values-*.yaml` file passes or produces only expected -validation errors. - -- [ ] Done - ---- - ### Phase 2 — Gateway -#### Step 3: Optional Gateway resource +#### Optional Gateway resource Template: `templates/gateway.yaml` @@ -225,7 +206,7 @@ Creates a `gateway.networking.k8s.io/v1 Gateway` when `gateway.create: true`. Th - An HTTP listener on port 80 (for ACME HTTP-01 challenges and optional redirect) - An HTTPS listener on port 443 with TLS termination, referencing the TLS secret -The federator listener is added in Step 12 (not here) to keep federator concerns separate. +The federator listener is added in the federator phase (not here) to keep federator concerns separate. New values: @@ -252,14 +233,13 @@ gateway: Each step adds one `HTTPRoute` (or one group of closely related routes). -#### Step 4: HTTPRoute — nginz (HTTPS endpoint) +#### HTTPRoute — nginz (HTTPS endpoint) Template: `templates/httproute-nginz.yaml` Routes `config.dns.https` → `nginz` service port `http`. -Gateway API equivalent of the `nginz-https` rule in the old `Ingress`. The route attaches to the -HTTPS listener of the Gateway via `parentRefs`. +The route attaches to the HTTPS listener of the Gateway via `parentRefs`. **Review:** Renders correctly with and without TLS; `helm lint` passes. @@ -267,7 +247,7 @@ HTTPS listener of the Gateway via `parentRefs`. --- -#### Step 5: HTTPRoute — websockets +#### HTTPRoute — websockets Template: `templates/httproute-websockets.yaml` Condition: `websockets.enabled` @@ -281,7 +261,7 @@ annotation in Envoy — they are transparent at the HTTP layer. --- -#### Step 6: HTTPRoute — webapp +#### HTTPRoute — webapp Template: `templates/httproute-webapp.yaml` Condition: `webapp.enabled` @@ -294,7 +274,7 @@ Routes `config.dns.webapp` → `webapp-http` service port `externalPort`. --- -#### Step 7: HTTPRoute — team-settings +#### HTTPRoute — team-settings Template: `templates/httproute-team-settings.yaml` Condition: `teamSettings.enabled` @@ -305,7 +285,7 @@ Routes `config.dns.teamSettings` → `team-settings-http` service port `external --- -#### Step 8: HTTPRoute — account-pages +#### HTTPRoute — account-pages Template: `templates/httproute-account-pages.yaml` Condition: `accountPages.enabled` @@ -316,16 +296,15 @@ Routes `config.dns.accountPages` → `account-pages-http` service port `external --- -#### Step 9: HTTPRoute — fakeS3 / minio +#### HTTPRoute — fakeS3 / minio Template: `templates/httproute-minio.yaml` Condition: `fakeS3.enabled` Routes `config.dns.fakeS3` → `fake-aws-s3` service. -The old chart used a nginx `server-snippet` to return 403 for `/minio/` paths. This chart uses an -Envoy Gateway `HTTPRouteFilter` with `type: DirectResponse` and `statusCode: 403` for a -`/minio/` prefix match rule, placed before the catch-all rule. +Access to `/minio/` paths is blocked with a 403 using an Envoy Gateway `HTTPRouteFilter` with +`type: DirectResponse` and `statusCode: 403`, placed as a prefix match rule before the catch-all. > **Incompatibility note:** `DirectResponse` is an Envoy Gateway extension > (`gateway.envoyproxy.io/v1alpha1`). It is not part of the standard Gateway API spec. @@ -338,25 +317,25 @@ Envoy Gateway `HTTPRouteFilter` with `type: DirectResponse` and `statusCode: 403 ### Phase 4 — TLS -#### Step 10: TLS Secret (manual mode) +#### TLS Secret (manual mode) Template: `templates/secret.yaml` Condition: `!tls.useCertManager` -Identical in structure to the old chart. Encodes `secrets.tlsWildcardCert` and -`secrets.tlsWildcardKey` into a `kubernetes.io/tls` Secret referenced by the Gateway listener. +Encodes `secrets.tlsWildcardCert` and `secrets.tlsWildcardKey` into a `kubernetes.io/tls` Secret +referenced by the Gateway listener. - [ ] Done --- -#### Step 11: cert-manager Certificate + Issuer +#### cert-manager Certificate + Issuer Templates: `templates/certificate.yaml`, `templates/issuer.yaml` Condition: `tls.useCertManager` -Identical in structure and values to the old chart. The cert-manager `Certificate` spec is -unchanged; the `secretName` it produces is referenced by the Gateway listener (Step 3). +A cert-manager `Certificate` and `Issuer`/`ClusterIssuer` for ACME HTTP-01 certificate issuance. +The `secretName` produced by the `Certificate` is referenced by the Gateway listener. - [ ] Done @@ -364,15 +343,14 @@ unchanged; the `secretName` it produces is referenced by the Gateway listener (S ### Phase 5 — Services -#### Step 12: ClusterIP Services +#### ClusterIP Services Template: `templates/service.yaml` -Identical to the old chart. Creates `webapp-http`, `s3-http`, `team-settings-http`, -`account-pages-http` ClusterIP services. The selectors and ports are unchanged. +Creates `webapp-http`, `s3-http`, `team-settings-http`, and `account-pages-http` ClusterIP +services with their respective selectors and ports. -**Review:** `helm template` output for this file should be byte-for-byte identical to the old -chart's `service.yaml` output (same values → same services). +**Review:** `helm template` produces the expected set of ClusterIP services for the enabled features. - [ ] Done @@ -380,7 +358,7 @@ chart's `service.yaml` output (same values → same services). ### Phase 6 — Federator -#### Step 13: Gateway listener for federator +#### Gateway listener for federator Extend `templates/gateway.yaml` to add a separate TLS listener for `config.dns.federator` when `federator.enabled: true`. @@ -392,7 +370,7 @@ that listener, not on the main HTTPS listener. --- -#### Step 14: HTTPRoute for federator +#### HTTPRoute for federator Template: `templates/httproute-federator.yaml` Condition: `federator.enabled` @@ -400,14 +378,14 @@ Condition: `federator.enabled` Routes `config.dns.federator` → `federator` service port `federator-ext`, attaching to the federator listener. -Blocks combination with `config.isAdditionalIngress` (same guard as the old chart, kept for -documentation purposes even though multi-ingress is out of scope). +Fails with an error if `config.isAdditionalIngress` is set, since federation and multi-ingress +cannot be combined. - [ ] Done --- -#### Step 15: ClientTrafficPolicy for federator mTLS +#### ClientTrafficPolicy for federator mTLS Template: `templates/clienttrafficpolicy-federator.yaml` Condition: `federator.enabled` @@ -418,10 +396,8 @@ Envoy Gateway-specific (`gateway.envoyproxy.io/v1alpha1`). Configures: - Forwards the client certificate as `X-SSL-Certificate` request header (implementation-specific header injection) -Maps to the old nginx annotations: -- `nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"` -- `nginx.ingress.kubernetes.io/auth-tls-secret` -- `nginx.ingress.kubernetes.io/configuration-snippet` (X-SSL-Certificate) +Enforces mTLS client certificate validation and forwards the client certificate as the +`X-SSL-Certificate` request header to the federator backend. > **Incompatibility note:** The `tls.verify_depth` value is not directly mapped. Envoy Gateway's > `ClientTrafficPolicy` does not expose a depth knob; validation depth is implicitly controlled by @@ -431,14 +407,14 @@ Maps to the old nginx annotations: --- -#### Step 16: Federator TLS secrets + CA secret +#### Federator TLS secrets + CA secret Templates: `templates/secret-federator.yaml`, `templates/ca-federator.yaml` Condition: `federator.enabled` -Identical in structure to the old chart (`federator-certificate-secret`, -`federator-ca-secret`). cert-manager `Certificate` for federator is also kept in -`templates/certificate-federator.yaml` with the same spec as the old chart. +Creates `federator-certificate-secret` and `federator-ca-secret`. When `tls.useCertManager` is +enabled, a cert-manager `Certificate` with both `server auth` and `client auth` EKUs is created +in `templates/certificate-federator.yaml`. - [ ] Done @@ -446,11 +422,13 @@ Identical in structure to the old chart (`federator-certificate-secret`, ### Phase 7 — Integration test helper -#### Step 17: federation-test-helper Service +#### federation-test-helper Service Template: `templates/federation-test-helper.yaml` -Identical to the old chart. The Kubernetes version label selector switch (>= 1.23) is kept. +A ClusterIP service targeting the ingress controller pod, used for SRV-based discovery in +integration tests. Uses `app.kubernetes.io/` labels on Kubernetes >= 1.23, legacy labels +otherwise. - [ ] Done @@ -458,11 +436,12 @@ Identical to the old chart. The Kubernetes version label selector switch (>= 1.2 ### Phase 8 — custom solver secret -#### Step 18: Custom ACME solver secret +#### Custom ACME solver secret Template: `templates/custom-solvers-secret.yaml` -Identical to the old chart. +An opaque Secret containing credentials for custom ACME challenge solvers, referenced by +`certManager.customSolvers`. - [ ] Done @@ -470,7 +449,7 @@ Identical to the old chart. ### Phase 9 — Documentation and CI values -#### Step 19: Finalize README, migration guide, and ci/ values files +#### Finalize README, migration guide, and ci/ values files - Write the migration guide section of this README - Create `ci/values-minimal.yaml`, `ci/values-full.yaml`, etc. From 466b51b57a145084a3e67c20fa2da4dcf92a9f3e Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Mon, 9 Mar 2026 15:01:56 +0100 Subject: [PATCH 04/79] scaffolding + helpers --- charts/wire-ingress/.helmignore | 21 +++++++ charts/wire-ingress/Chart.yaml | 4 ++ charts/wire-ingress/README.md | 2 +- charts/wire-ingress/templates/_helpers.tpl | 67 ++++++++++++++++++++++ charts/wire-ingress/values.yaml | 1 + 5 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 charts/wire-ingress/.helmignore create mode 100644 charts/wire-ingress/Chart.yaml create mode 100644 charts/wire-ingress/templates/_helpers.tpl create mode 100644 charts/wire-ingress/values.yaml diff --git a/charts/wire-ingress/.helmignore b/charts/wire-ingress/.helmignore new file mode 100644 index 00000000000..f0c13194444 --- /dev/null +++ b/charts/wire-ingress/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/charts/wire-ingress/Chart.yaml b/charts/wire-ingress/Chart.yaml new file mode 100644 index 00000000000..fabe75062d3 --- /dev/null +++ b/charts/wire-ingress/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +description: A Helm chart for Wire server ingress using the Kubernetes Gateway API +name: wire-ingress +version: 0.1.0 diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 2d13ebd57eb..504f40a9bd5 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -191,7 +191,7 @@ Use `helm create` for an initial scaffolding. **Review:** `helm lint ./wire-ingress` passes with empty values. -- [ ] Done +- [x] Done --- diff --git a/charts/wire-ingress/templates/_helpers.tpl b/charts/wire-ingress/templates/_helpers.tpl new file mode 100644 index 00000000000..95c9784c485 --- /dev/null +++ b/charts/wire-ingress/templates/_helpers.tpl @@ -0,0 +1,67 @@ +{{/* vim: set filetype=mustache: */}} + +{{- define "wire-ingress.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- define "wire-ingress.fullname" -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Determine DNS zone based on the HTTPS FQDN (e.g. "nginz-https.example.com" → "example.com") +*/}} +{{- define "wire-ingress.zone" -}} +{{- $zones := splitList "." .Values.config.dns.https -}} +{{- slice $zones 1 | join "." -}} +{{- end -}} + +{{/* +Name of the TLS certificate secret. Differs based on whether cert-manager is used. +*/}} +{{- define "wire-ingress.getCertificateSecretName" -}} +{{- $nameParts := list (include "wire-ingress.fullname" .) -}} +{{- if .Values.tls.useCertManager -}} + {{- $nameParts = append $nameParts "managed" -}} +{{- else -}} + {{- $nameParts = append $nameParts "wildcard" -}} +{{- end -}} +{{- $nameParts = append $nameParts "tls-certificate" -}} +{{- join "-" $nameParts -}} +{{- end -}} + +{{/* +Name of the custom ACME solver secret. +*/}} +{{- define "wire-ingress.getCustomSolversSecretName" -}} +{{- $nameParts := list (include "wire-ingress.fullname" .) -}} +{{- $nameParts = append $nameParts "cert-manager-custom-solvers" -}} +{{- join "-" $nameParts -}} +{{- end -}} + +{{/* +Name of the cert-manager Issuer / ClusterIssuer. +*/}} +{{- define "wire-ingress.getIssuerName" -}} +{{ .Values.tls.issuer.name }} +{{- end -}} + +{{/* +Name of the Gateway resource. Uses gateway.name if set, otherwise derives one from the release name. +*/}} +{{- define "wire-ingress.getGatewayName" -}} +{{- if and .Values.gateway .Values.gateway.name (not (eq .Values.gateway.name "")) -}} +{{ .Values.gateway.name }} +{{- else -}} +{{ include "wire-ingress.fullname" . }}-gateway +{{- end -}} +{{- end -}} + +{{/* +Whether to use new-style app.kubernetes.io labels for the federation-test-helper. +Kubernetes >= 1.23 uses app.kubernetes.io/*, older versions use app/component labels. +*/}} +{{- define "wire-ingress.integrationTestHelperNewLabels" -}} + {{- (semverCompare ">= 1.23-0" .Capabilities.KubeVersion.Version) -}} +{{- end -}} diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml new file mode 100644 index 00000000000..f0b138c506d --- /dev/null +++ b/charts/wire-ingress/values.yaml @@ -0,0 +1 @@ +# Default values for wire-ingress From c3fb3705817d03f011ec969000fac83c281f2642 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Mon, 9 Mar 2026 15:07:15 +0100 Subject: [PATCH 05/79] modify .envrc for development --- .envrc | 95 +++------------------------------------------------------- 1 file changed, 4 insertions(+), 91 deletions(-) diff --git a/.envrc b/.envrc index fbb67a797ad..4ae8d1476ec 100644 --- a/.envrc +++ b/.envrc @@ -1,95 +1,8 @@ -# Build a folder ./.env that contains the dev-shell which load all the right env -# vars. -# -# To speed up the nix evaluation, we only rebuild our environment when `./nix` -# or any of the `default.nix` files change. We do this by adding all these files -# to the nix store and using the store paths as a cache key. - -# FUTUREWORK: The speedhack saves only a couple of Seconds when cd'ing into the -# repo's directory. The price is some state we have to manage manually (e.g. -# `rm .direnv`) and a non-intuitive usage of flakes. -# -# The hack could be replaced by the line -# `use flake .\#` -# -# The env variable exports could then be added to the flake's devShell. - -nix_files=$(find . -name '*.nix' | grep -v '^./dist-newstyle') -for nix_file in $nix_files; do - watch_file "$nix_file" -done -watch_file ./services/nginz/third_party/nginx-zauth-module/* -watch_file ./libs/libzauth/**/* -store_paths=$(echo "$nix_files" ./services/nginz/third_party/nginx-zauth-module/ ./libs/libzauth/ | xargs nix-store --add ./nix) -layout_dir=$(direnv_layout_dir) -env_dir=./.env - -export NIX_CONFIG='extra-experimental-features = nix-command flakes' - -[[ -d "$layout_dir" ]] || mkdir -p "$layout_dir" - -if [[ ! -d "$env_dir" || ! -f "$layout_dir/nix-rebuild" || "$store_paths" != $(<"$layout_dir/nix-rebuild") ]]; then - bcmd=nix - if command -v nom &>/dev/null; then - if [[ "${USE_NOM}" != "0" ]]; then - bcmd=nom - fi - fi - echo "🔧 Building environment" - $bcmd build '.#wireServer.devEnv' -Lv --out-link ./.env --fallback - echo "$store_paths" >"$layout_dir/nix-rebuild" -fi - -PATH_add "./.env/bin" -PATH_add "./.env-hs-run/bin" -path_add "PKG_CONFIG_PATH" "./.env/lib/pkgconfig" -path_add "LIBRARY_PATH" "./.env/lib" -path_add "PYTHONPATH" "./hack/python" -PATH_add "./dist" - -# source .profile from `$env`. This sets NIX_PATH to pkgs defined in -# ./nix/default.nix. Tis is useful for nix tooling that runs inside this direnv, -# e.g. "nix-shell -p foo" will get "foo" for pkgs defined in ./nix/default.nix -[[ -f "./.env/.profile" ]] && source_env "./.env/.profile" - -# Locale -export LC_ALL=en_US.UTF-8 -export LANG=en_US.UTF-8 - -# RabbitMQ -export RABBITMQ_USERNAME=guest -export RABBITMQ_PASSWORD=alpaca-grapefruit - -export RABBITMQ_USERNAME_V0=guest -export RABBITMQ_PASSWORD_V0=alpaca-grapefruit - -export RABBITMQ_USERNAME_V1=guest -export RABBITMQ_PASSWORD_V1=alpaca-grapefruit - -# Redis -export REDIS_PASSWORD=very-secure-redis-cluster-password -export REDIS_ADDITIONAL_WRITE_PASSWORD=very-secure-redis-master-password - -# Integration tests -export INTEGRATION_DYNAMIC_BACKENDS_POOLSIZE=3 - -# AWS credentials for locally running services -# Keep these in sync with deploy/dockerephmeral/init.sh -export AWS_REGION="eu-west-1" -export AWS_ACCESS_KEY_ID="dummykey" -export AWS_SECRET_ACCESS_KEY="dummysecret" - -# integration test suite timeout -export TEST_TIMEOUT_SECONDS=2 - -# OTEL -OTEL_SEMCONV_STABILITY_OPT_IN=http - # uncomment if you plan to run the integration setup manually against kube-ci -# unset AWS_REGION -# unset AWS_ACCESS_KEY_ID -# unset AWS_SECRET_ACCESS_KEY -# source_env ../cailleach/.envrc +unset AWS_REGION +unset AWS_ACCESS_KEY_ID +unset AWS_SECRET_ACCESS_KEY +source_env ../cailleach/.envrc # allow local .envrc overrides [[ -f .envrc.local ]] && source_env .envrc.local From aa46978fda9717cbef8fab16f71d8440b883bf94 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 10 Mar 2026 17:20:00 +0100 Subject: [PATCH 06/79] update plan --- charts/wire-ingress/README.md | 58 +++++++++++++++++------------------ 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 504f40a9bd5..994a35dd9d8 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -8,7 +8,7 @@ The chart targets **Envoy Gateway** as the Gateway API controller. ## Status -**This chart is in planning. No implementation exists yet.** +**This chart is in development. Dont use it in production yet!** --- @@ -75,6 +75,7 @@ Operators should be able to reuse most of their existing values files with minim | `config.dns.base` | Only used for CSP header rendering, which is a multi-ingress feature | | `kubeVersionOverride` | Deprecated; the federation-test-helper label selector no longer needs a version override | | `tls.verify_depth` | Envoy Gateway `ClientTrafficPolicy` does not expose a direct verify-depth knob; the CA chain itself controls this | +| `tls.enabled` | This is removed since it didnt ahve any effect. All ingresses are always defined with TLS. | ### Fully backwards compatible values @@ -97,7 +98,6 @@ All keys below are accepted unchanged. Their names, types, and semantics are ide | `federator.tls.issuer.name` | | | `federator.tls.issuer.kind` | | | `federator.tls.issuer.group` | | -| `tls.enabled` | | | `tls.useCertManager` | | | `tls.createIssuer` | | | `tls.privateKey.rotationPolicy` | | @@ -195,7 +195,31 @@ Use `helm create` for an initial scaffolding. --- -### Phase 2 — Gateway +### Phase 2 — TLS + +#### TLS Secret (manual mode) + +Template: `templates/secret.yaml` +Condition: `!tls.useCertManager` + +Encodes `secrets.tlsWildcardCert` and `secrets.tlsWildcardKey` into a `kubernetes.io/tls` Secret +referenced by the Gateway listener. + +- [ ] Done + +--- + +#### cert-manager Certificate + Issuer + +Templates: `templates/certificate.yaml`, `templates/issuer.yaml` +Condition: `tls.useCertManager` + +A cert-manager `Certificate` and `Issuer`/`ClusterIssuer` for ACME HTTP-01 certificate issuance. +The `secretName` produced by the `Certificate` is referenced by the Gateway listener. + +- [ ] Done + +### Phase 3 — Gateway #### Optional Gateway resource @@ -203,7 +227,6 @@ Template: `templates/gateway.yaml` Creates a `gateway.networking.k8s.io/v1 Gateway` when `gateway.create: true`. The Gateway has: -- An HTTP listener on port 80 (for ACME HTTP-01 challenges and optional redirect) - An HTTPS listener on port 443 with TLS termination, referencing the TLS secret The federator listener is added in the federator phase (not here) to keep federator concerns separate. @@ -229,7 +252,7 @@ gateway: --- -### Phase 3 — Core HTTPRoutes +### Phase 4 — Core HTTPRoutes Each step adds one `HTTPRoute` (or one group of closely related routes). @@ -313,31 +336,6 @@ Access to `/minio/` paths is blocked with a 403 using an Envoy Gateway `HTTPRout - [ ] Done ---- - -### Phase 4 — TLS - -#### TLS Secret (manual mode) - -Template: `templates/secret.yaml` -Condition: `!tls.useCertManager` - -Encodes `secrets.tlsWildcardCert` and `secrets.tlsWildcardKey` into a `kubernetes.io/tls` Secret -referenced by the Gateway listener. - -- [ ] Done - ---- - -#### cert-manager Certificate + Issuer - -Templates: `templates/certificate.yaml`, `templates/issuer.yaml` -Condition: `tls.useCertManager` - -A cert-manager `Certificate` and `Issuer`/`ClusterIssuer` for ACME HTTP-01 certificate issuance. -The `secretName` produced by the `Certificate` is referenced by the Gateway listener. - -- [ ] Done --- From 9404385770f8353c43c46255e77df9be986466f1 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 10 Mar 2026 17:21:27 +0100 Subject: [PATCH 07/79] phase 2-3 --- charts/wire-ingress/README.md | 23 +++++ charts/wire-ingress/templates/_helpers.tpl | 14 ++- .../wire-ingress/templates/certificate.yaml | 45 +++++++++ .../clienttrafficpolicy-proxy-protocol.yaml | 18 ++++ charts/wire-ingress/templates/gateway.yaml | 34 +++++++ charts/wire-ingress/templates/issuer.yaml | 38 ++++++++ charts/wire-ingress/templates/secret.yaml | 19 ++++ charts/wire-ingress/values.yaml | 95 +++++++++++++++++++ 8 files changed, 285 insertions(+), 1 deletion(-) create mode 100644 charts/wire-ingress/templates/certificate.yaml create mode 100644 charts/wire-ingress/templates/clienttrafficpolicy-proxy-protocol.yaml create mode 100644 charts/wire-ingress/templates/gateway.yaml create mode 100644 charts/wire-ingress/templates/issuer.yaml create mode 100644 charts/wire-ingress/templates/secret.yaml diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 994a35dd9d8..a562c34da50 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -39,6 +39,23 @@ references it by name via `gateway.className`. Single-domain deployments are the only supported topology. Multi-domain support can be added later. +### HTTP01 certificate challenges + +cert-manager can complete ACME HTTP01 challenges through the Gateway using the `gatewayHTTPRoute` +solver (cert-manager >= 1.14). The **default solver** in this chart uses `gatewayHTTPRoute` — it +requires the HTTP listener to be enabled: + +```yaml +gateway: + listeners: + http: + enabled: true # required for HTTP01 challenges +``` + +If you cannot or do not want to open port 80, use a DNS01 solver instead by setting +`certManager.customSolvers`. DNS01 requires credentials for your DNS provider but does not need +port 80 to be open. + ### Federator mTLS uses Envoy Gateway policies Federator mTLS is implemented using: @@ -64,6 +81,8 @@ Operators should be able to reuse most of their existing values files with minim | `config.ingressClass` | `gateway.className` | Different concept: GatewayClass name, not IngressClass | | _(not present)_ | `gateway.create` | `true` = chart creates the Gateway; `false` = BYO | | _(not present)_ | `gateway.name` | Name of the Gateway to attach routes to | +| _(not present)_ | `gateway.infrastructure.annotations` | Annotations forwarded to the LoadBalancer Service provisioned by Envoy Gateway — see [Gateway API docs](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.GatewayInfrastructure) | +| _(not present)_ | `gateway.proxyProtocol.enabled` | Creates a `ClientTrafficPolicy` enabling PROXY protocol on all Gateway listeners — required when the load balancer is configured to send PROXY protocol headers | ### Dropped values (not applicable to Gateway API) @@ -132,6 +151,7 @@ All keys below are accepted unchanged. Their names, types, and semantics are ide | Feature | Old behaviour | New behaviour | |---|---|---| +| Default ACME solver | `http01.ingress.class: nginx` | `http01.gatewayHTTPRoute` targeting this chart's Gateway — requires `gateway.listeners.http.enabled: true` | | `/minio/` path blocking | nginx `server-snippet` returning 403 | Envoy Gateway `HTTPRouteFilter` `directResponse` (implementation-specific, non-standard) | | Federator client cert header | `nginx.ingress.kubernetes.io/configuration-snippet` setting `X-SSL-Certificate` | Envoy Gateway `ClientTrafficPolicy` + `HTTPRouteFilter` header injection | | Websocket routing | Separate host with port name `ws` | Same `HTTPRoute` — WebSocket upgrades are handled transparently by Envoy | @@ -206,6 +226,7 @@ Encodes `secrets.tlsWildcardCert` and `secrets.tlsWildcardKey` into a `kubernete referenced by the Gateway listener. - [ ] Done +- [ ] Manually tested --- @@ -218,6 +239,8 @@ A cert-manager `Certificate` and `Issuer`/`ClusterIssuer` for ACME HTTP-01 certi The `secretName` produced by the `Certificate` is referenced by the Gateway listener. - [ ] Done +- [x] Manually tested tested http01 challenge +- [ ] Manually tested tested dns01 challenge ### Phase 3 — Gateway diff --git a/charts/wire-ingress/templates/_helpers.tpl b/charts/wire-ingress/templates/_helpers.tpl index 95c9784c485..ee582201689 100644 --- a/charts/wire-ingress/templates/_helpers.tpl +++ b/charts/wire-ingress/templates/_helpers.tpl @@ -40,6 +40,18 @@ Name of the custom ACME solver secret. {{- join "-" $nameParts -}} {{- end -}} +{{/* +Returns the Letsencrypt ACME API server URL. +*/}} +{{- define "wire-ingress.certManagerAPIServerURL" -}} +{{- $hostnameParts := list "acme" -}} +{{- if .Values.certManager.inTestMode -}} + {{- $hostnameParts = append $hostnameParts "staging" -}} +{{- end -}} +{{- $hostnameParts = append $hostnameParts "v02" -}} +{{- join "-" $hostnameParts | printf "https://%s.api.letsencrypt.org/directory" -}} +{{- end -}} + {{/* Name of the cert-manager Issuer / ClusterIssuer. */}} @@ -51,7 +63,7 @@ Name of the cert-manager Issuer / ClusterIssuer. Name of the Gateway resource. Uses gateway.name if set, otherwise derives one from the release name. */}} {{- define "wire-ingress.getGatewayName" -}} -{{- if and .Values.gateway .Values.gateway.name (not (eq .Values.gateway.name "")) -}} +{{- if .Values.gateway.name -}} {{ .Values.gateway.name }} {{- else -}} {{ include "wire-ingress.fullname" . }}-gateway diff --git a/charts/wire-ingress/templates/certificate.yaml b/charts/wire-ingress/templates/certificate.yaml new file mode 100644 index 00000000000..907ed721cbc --- /dev/null +++ b/charts/wire-ingress/templates/certificate.yaml @@ -0,0 +1,45 @@ +{{- if .Values.tls.useCertManager -}} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: "{{ include "wire-ingress.zone" . | replace "." "-" }}-csr" + namespace: {{ .Release.Namespace }} + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + issuerRef: + name: {{ include "wire-ingress.getIssuerName" . | quote }} + kind: {{ .Values.tls.issuer.kind }} + usages: + - server auth + duration: 2160h # 90d, Letsencrypt default; NOTE: changes are ignored by Letsencrypt + renewBefore: 360h # 15d + isCA: false + secretName: {{ include "wire-ingress.getCertificateSecretName" . | quote }} + + privateKey: + algorithm: {{ .Values.tls.privateKey.algorithm }} + size: {{ .Values.tls.privateKey.size }} + encoding: PKCS1 + rotationPolicy: {{ .Values.tls.privateKey.rotationPolicy }} + + dnsNames: + - {{ .Values.config.dns.https }} + {{- if .Values.websockets.enabled }} + - {{ .Values.config.dns.ssl }} + {{- end }} + {{- if .Values.webapp.enabled }} + - {{ .Values.config.dns.webapp }} + {{- end }} + {{- if .Values.fakeS3.enabled }} + - {{ .Values.config.dns.fakeS3 }} + {{- end }} + {{- if .Values.teamSettings.enabled }} + - {{ .Values.config.dns.teamSettings }} + {{- end }} + {{- if .Values.accountPages.enabled }} + - {{ .Values.config.dns.accountPages }} + {{- end }} +{{- end -}} diff --git a/charts/wire-ingress/templates/clienttrafficpolicy-proxy-protocol.yaml b/charts/wire-ingress/templates/clienttrafficpolicy-proxy-protocol.yaml new file mode 100644 index 00000000000..4969d3fbf2e --- /dev/null +++ b/charts/wire-ingress/templates/clienttrafficpolicy-proxy-protocol.yaml @@ -0,0 +1,18 @@ +{{- if .Values.gateway.proxyProtocol.enabled }} +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: ClientTrafficPolicy +metadata: + name: {{ include "wire-ingress.getGatewayName" . }}-proxy-protocol + namespace: {{ .Release.Namespace }} + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: {{ include "wire-ingress.getGatewayName" . | quote }} + proxyProtocol: + optional: {{ .Values.gateway.proxyProtocol.optional | default false }} +{{- end }} diff --git a/charts/wire-ingress/templates/gateway.yaml b/charts/wire-ingress/templates/gateway.yaml new file mode 100644 index 00000000000..4969da4f76d --- /dev/null +++ b/charts/wire-ingress/templates/gateway.yaml @@ -0,0 +1,34 @@ +{{- if .Values.gateway.create }} +{{- if not .Values.gateway.className }} +{{- fail "gateway.className must be set when gateway.create is true (set it to the name of your GatewayClass, e.g. 'envoy')" }} +{{- end }} +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: {{ include "wire-ingress.getGatewayName" . | quote }} + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + gatewayClassName: {{ .Values.gateway.className | quote }} + {{- if .Values.gateway.infrastructure.annotations }} + infrastructure: + annotations: + {{- toYaml .Values.gateway.infrastructure.annotations | nindent 6 }} + {{- end }} + listeners: + - name: https + port: {{ .Values.gateway.listeners.https.port }} + protocol: HTTPS + tls: + mode: Terminate + certificateRefs: + - name: {{ include "wire-ingress.getCertificateSecretName" . | quote }} + kind: Secret + {{- if .Values.gateway.listeners.http.enabled }} + - name: http + port: {{ .Values.gateway.listeners.http.port }} + protocol: HTTP + {{- end }} +{{- end }} diff --git a/charts/wire-ingress/templates/issuer.yaml b/charts/wire-ingress/templates/issuer.yaml new file mode 100644 index 00000000000..a71c7f9f662 --- /dev/null +++ b/charts/wire-ingress/templates/issuer.yaml @@ -0,0 +1,38 @@ +{{- if and .Values.tls.useCertManager .Values.tls.createIssuer -}} +apiVersion: cert-manager.io/v1 +{{- if or (eq .Values.tls.issuer.kind "Issuer") (eq .Values.tls.issuer.kind "ClusterIssuer") }} +kind: "{{ .Values.tls.issuer.kind }}" +{{- else }} +{{- fail (cat ".tls.issuer.kind can only be one of Issuer or ClusterIssuer, got: " .Values.tls.issuer.kind) }} +{{- end }} +metadata: + name: {{ include "wire-ingress.getIssuerName" . | quote }} + {{- if eq .Values.tls.issuer.kind "Issuer" }} + namespace: {{ .Release.Namespace }} + {{- end }} + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + acme: + server: {{ include "wire-ingress.certManagerAPIServerURL" . | quote }} + email: {{ required "Missing value: certmasterEmail" .Values.certManager.certmasterEmail | quote }} + # NOTE: this secret doesn't need to be created manually, cert-manager manages it + privateKeySecretRef: + name: {{ include "wire-ingress.getIssuerName" . -}}-account-key + solvers: +{{- if .Values.certManager.customSolvers }} +{{ toYaml .Values.certManager.customSolvers | indent 6 }} +{{- else }} +{{- if not .Values.gateway.listeners.http.enabled }} +{{- fail "The default HTTP01 solver requires gateway.listeners.http.enabled=true. Either enable the HTTP listener or supply certManager.customSolvers with a DNS01 solver." }} +{{- end }} + - http01: + gatewayHTTPRoute: + parentRefs: + - name: {{ include "wire-ingress.getGatewayName" . | quote }} + namespace: {{ .Release.Namespace | quote }} + kind: Gateway +{{- end }} +{{- end -}} diff --git a/charts/wire-ingress/templates/secret.yaml b/charts/wire-ingress/templates/secret.yaml new file mode 100644 index 00000000000..699f419410c --- /dev/null +++ b/charts/wire-ingress/templates/secret.yaml @@ -0,0 +1,19 @@ +{{- if not .Values.tls.useCertManager }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "wire-ingress.getCertificateSecretName" . | quote }} + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +type: kubernetes.io/tls +data: + {{/* for_helm_linting is necessary only since the 'with' block below does not throw an error upon an empty .Values.secrets */}} + for_helm_linting: {{ required "No .secrets found in configuration. Did you forget to helm -f path/to/secrets.yaml ?" .Values.secrets | quote | b64enc | quote }} + + {{- with .Values.secrets }} + tls.crt: {{ .tlsWildcardCert | b64enc | quote }} + tls.key: {{ .tlsWildcardKey | b64enc | quote }} + {{- end -}} +{{- end -}} diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index f0b138c506d..3fa83da157f 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -1 +1,96 @@ # Default values for wire-ingress + +gateway: + # If true, a Gateway resource is created by this chart. + # If false, set gateway.name to reference an existing Gateway. + create: true + # Name of the Gateway. Defaults to -wire-ingress-gateway if empty. + name: "" + # Name of the GatewayClass installed by the Envoy Gateway controller. + className: "" + # Annotations to add to the LoadBalancer Service created by Envoy Gateway. + # Requires Gateway API CRDs v1.1+. + # Example for AWS NLB: + # infrastructure: + # annotations: + # service.beta.kubernetes.io/aws-load-balancer-type: external + # service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip + infrastructure: + annotations: {} + # Enable if your load balancer sends PROXY protocol headers (e.g. Hetzner with + # load-balancer.hetzner.cloud/uses-proxyprotocol: "true"). Creates a + # ClientTrafficPolicy targeting the Gateway. + proxyProtocol: + enabled: false + # If true, connections without a PROXY protocol header are also accepted. + # Use this only if some traffic bypasses the load balancer (e.g. direct node access). + # WARNING: breaks PROXY protocol spec compliance. + optional: false + listeners: + https: + port: 443 + # Enable the HTTP listener if you want to use HTTP01 challenges via cert-manager's + # gatewayHTTPRoute solver. Requires cert-manager >= 1.14. + # See the README for configuration details. + http: + enabled: false + port: 80 + +teamSettings: + enabled: false +accountPages: + enabled: false +websockets: + enabled: true +webapp: + enabled: true +fakeS3: + enabled: true + +tls: + useCertManager: false + createIssuer: true + privateKey: + rotationPolicy: Always + algorithm: ECDSA + size: 384 # 521 is not supported by Let's Encrypt + issuer: + name: letsencrypt-http01 + kind: Issuer # Issuer | ClusterIssuer + # caNamespace: wire-federation-v0 + +certManager: + # If true, uses the Let's Encrypt staging API (certificates are NOT trusted): + # https://acme-staging-v02.api.letsencrypt.org/directory + # If false (default), uses the production API (certificates are trusted): + # https://acme-v02.api.letsencrypt.org/directory + inTestMode: false + certmasterEmail: + customSolvers: + +# You will need to supply DNS names: +# config: +# dns: +# https: nginz-https. +# ssl: nginz-ssl. # ignored if websockets.enabled == false +# webapp: webapp. # ignored if webapp.enabled == false +# fakeS3: assets. # ignored if fakeS3.enabled == false +# federator: federator. # ignored unless federator.enabled == true +# certificateDomain: federator. # domain to use in the federator CSR +# teamSettings: teams. # ignored unless teamSettings.enabled == true +# accountPages: account. # ignored unless accountPages.enabled == true +# +# For TLS (manual mode, tls.useCertManager: false): +# secrets: +# tlsWildcardCert: | +# -----BEGIN CERTIFICATE----- +# ... +# -----END CERTIFICATE----- +# tlsWildcardKey: | +# -----BEGIN PRIVATE KEY----- +# ... +# -----END PRIVATE KEY----- +# tlsClientCA: | +# -----BEGIN CERTIFICATE----- +# ... +# -----END CERTIFICATE----- From 7c6c5d6a4a1b256f708cb989741c2854a1b5c0f8 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Thu, 12 Mar 2026 13:55:38 +0100 Subject: [PATCH 08/79] Allow for externally created secret --- charts/wire-ingress/README.md | 23 +++++++++++++++------- charts/wire-ingress/templates/_helpers.tpl | 16 +++++++++------ charts/wire-ingress/templates/secret.yaml | 5 +---- charts/wire-ingress/values.yaml | 6 ++++++ 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index a562c34da50..060ac9174c1 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -53,7 +53,15 @@ gateway: ``` If you cannot or do not want to open port 80, use a DNS01 solver instead by setting -`certManager.customSolvers`. DNS01 requires credentials for your DNS provider but does not need + +```yaml +certManager: + customSolvers: + - dns01: + # .. provider-specific settings +``` + +DNS01 requires credentials for your DNS provider but does not need port 80 to be open. ### Federator mTLS uses Envoy Gateway policies @@ -83,6 +91,8 @@ Operators should be able to reuse most of their existing values files with minim | _(not present)_ | `gateway.name` | Name of the Gateway to attach routes to | | _(not present)_ | `gateway.infrastructure.annotations` | Annotations forwarded to the LoadBalancer Service provisioned by Envoy Gateway — see [Gateway API docs](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.GatewayInfrastructure) | | _(not present)_ | `gateway.proxyProtocol.enabled` | Creates a `ClientTrafficPolicy` enabling PROXY protocol on all Gateway listeners — required when the load balancer is configured to send PROXY protocol headers | +| _(not present)_ | `tls.secret.create` | If `false`, the TLS Secret is not created by this chart — use when the secret is managed externally (e.g. by another chart or operator). `secrets.tlsWildcardCert` and `secrets.tlsWildcardKey` are ignored when `false`. | +| _(not present)_ | `tls.secret.nameOverride` | Override the name of the TLS Secret referenced by the Gateway listener. If not set, the name is derived from the release name. | ### Dropped values (not applicable to Gateway API) @@ -225,8 +235,8 @@ Condition: `!tls.useCertManager` Encodes `secrets.tlsWildcardCert` and `secrets.tlsWildcardKey` into a `kubernetes.io/tls` Secret referenced by the Gateway listener. -- [ ] Done -- [ ] Manually tested +- [x] Done +- [x] Manually tested deployment --- @@ -238,9 +248,8 @@ Condition: `tls.useCertManager` A cert-manager `Certificate` and `Issuer`/`ClusterIssuer` for ACME HTTP-01 certificate issuance. The `secretName` produced by the `Certificate` is referenced by the Gateway listener. -- [ ] Done -- [x] Manually tested tested http01 challenge -- [ ] Manually tested tested dns01 challenge +- [x] Done +- [x] Manually tested http01 challenge, via issuer ### Phase 3 — Gateway @@ -271,7 +280,7 @@ gateway: **Review:** `helm template` produces a valid `Gateway` manifest. Diff against old chart shows no `Ingress` equivalent yet — that is expected. -- [ ] Done +- [x] Done --- diff --git a/charts/wire-ingress/templates/_helpers.tpl b/charts/wire-ingress/templates/_helpers.tpl index ee582201689..4c5134addef 100644 --- a/charts/wire-ingress/templates/_helpers.tpl +++ b/charts/wire-ingress/templates/_helpers.tpl @@ -21,14 +21,18 @@ Determine DNS zone based on the HTTPS FQDN (e.g. "nginz-https.example.com" → " Name of the TLS certificate secret. Differs based on whether cert-manager is used. */}} {{- define "wire-ingress.getCertificateSecretName" -}} -{{- $nameParts := list (include "wire-ingress.fullname" .) -}} -{{- if .Values.tls.useCertManager -}} - {{- $nameParts = append $nameParts "managed" -}} +{{- if .Values.tls.secret.nameOverride -}} + {{- .Values.tls.secret.nameOverride -}} {{- else -}} - {{- $nameParts = append $nameParts "wildcard" -}} + {{- $nameParts := list (include "wire-ingress.fullname" .) -}} + {{- if .Values.tls.useCertManager -}} + {{- $nameParts = append $nameParts "managed" -}} + {{- else -}} + {{- $nameParts = append $nameParts "wildcard" -}} + {{- end -}} + {{- $nameParts = append $nameParts "tls-certificate" -}} + {{- join "-" $nameParts -}} {{- end -}} -{{- $nameParts = append $nameParts "tls-certificate" -}} -{{- join "-" $nameParts -}} {{- end -}} {{/* diff --git a/charts/wire-ingress/templates/secret.yaml b/charts/wire-ingress/templates/secret.yaml index 699f419410c..e0094ba1777 100644 --- a/charts/wire-ingress/templates/secret.yaml +++ b/charts/wire-ingress/templates/secret.yaml @@ -1,4 +1,4 @@ -{{- if not .Values.tls.useCertManager }} +{{- if and (not .Values.tls.useCertManager) .Values.tls.secret.create }} apiVersion: v1 kind: Secret metadata: @@ -9,9 +9,6 @@ metadata: heritage: "{{ .Release.Service }}" type: kubernetes.io/tls data: - {{/* for_helm_linting is necessary only since the 'with' block below does not throw an error upon an empty .Values.secrets */}} - for_helm_linting: {{ required "No .secrets found in configuration. Did you forget to helm -f path/to/secrets.yaml ?" .Values.secrets | quote | b64enc | quote }} - {{- with .Values.secrets }} tls.crt: {{ .tlsWildcardCert | b64enc | quote }} tls.key: {{ .tlsWildcardKey | b64enc | quote }} diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index 3fa83da157f..61977b6306c 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -48,6 +48,12 @@ fakeS3: enabled: true tls: + secret: + # If true, a kubernetes.io/tls Secret is created from secrets.tlsWildcardCert + # and secrets.tlsWildcardKey. Set to false if the secret is managed externally. + create: true + # Override the name of the Secret. If not set, the name is derived from the release name. + nameOverride: "" useCertManager: false createIssuer: true privateKey: From 357edd501e09afa034c1db4459465fdf2e88597d Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Thu, 12 Mar 2026 14:28:38 +0100 Subject: [PATCH 09/79] nginz routes --- charts/wire-ingress/README.md | 2 +- .../templates/httproute-nginz.yaml | 25 +++++++++++++++++ .../templates/httproute-websockets.yaml | 27 +++++++++++++++++++ charts/wire-ingress/values.yaml | 7 +++++ 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 charts/wire-ingress/templates/httproute-nginz.yaml create mode 100644 charts/wire-ingress/templates/httproute-websockets.yaml diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 060ac9174c1..02fde406b3c 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -298,7 +298,7 @@ The route attaches to the HTTPS listener of the Gateway via `parentRefs`. **Review:** Renders correctly with and without TLS; `helm lint` passes. -- [ ] Done +- [x] Done --- diff --git a/charts/wire-ingress/templates/httproute-nginz.yaml b/charts/wire-ingress/templates/httproute-nginz.yaml new file mode 100644 index 00000000000..14466c21331 --- /dev/null +++ b/charts/wire-ingress/templates/httproute-nginz.yaml @@ -0,0 +1,25 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "wire-ingress.fullname" . }}-nginz + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + parentRefs: + - name: {{ include "wire-ingress.getGatewayName" . | quote }} + namespace: {{ .Release.Namespace | quote }} + kind: Gateway + sectionName: https + hostnames: + - {{ required "config.dns.https is required" .Values.config.dns.https | quote }} + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: nginz + port: {{ .Values.services.nginz.httpPort }} + kind: Service diff --git a/charts/wire-ingress/templates/httproute-websockets.yaml b/charts/wire-ingress/templates/httproute-websockets.yaml new file mode 100644 index 00000000000..3000f2e0ce0 --- /dev/null +++ b/charts/wire-ingress/templates/httproute-websockets.yaml @@ -0,0 +1,27 @@ +{{- if .Values.websockets.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "wire-ingress.fullname" . }}-websockets + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + parentRefs: + - name: {{ include "wire-ingress.getGatewayName" . | quote }} + namespace: {{ .Release.Namespace | quote }} + kind: Gateway + sectionName: https + hostnames: + - {{ required "config.dns.ssl is required when websockets.enabled is true" .Values.config.dns.ssl | quote }} + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: nginz + port: {{ .Values.services.nginz.wsPort }} + kind: Service +{{- end }} diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index 61977b6306c..99637281417 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -47,6 +47,13 @@ webapp: fakeS3: enabled: true +services: + nginz: + # Update this if you've overwritten the default HTTP port in nginz. + httpPort: 8080 + # Update this if you've overwritten the default WebSocket port in nginz. + wsPort: 8081 + tls: secret: # If true, a kubernetes.io/tls Secret is created from secrets.tlsWildcardCert From ad89047c5e902bd190015c63c080cefa4c6edf63 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Fri, 13 Mar 2026 11:34:16 +0100 Subject: [PATCH 10/79] more routes --- charts/wire-ingress/README.md | 4 +-- ...s.yaml => httproute-nginz-websockets.yaml} | 4 +-- .../templates/httproute-nginz.yaml | 2 +- .../templates/httproute-webapp.yaml | 27 +++++++++++++++++++ .../templates/service-webapp.yaml | 14 ++++++++++ charts/wire-ingress/values.yaml | 4 ++- 6 files changed, 49 insertions(+), 6 deletions(-) rename charts/wire-ingress/templates/{httproute-websockets.yaml => httproute-nginz-websockets.yaml} (86%) create mode 100644 charts/wire-ingress/templates/httproute-webapp.yaml create mode 100644 charts/wire-ingress/templates/service-webapp.yaml diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 02fde406b3c..91c26991c3d 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -312,7 +312,7 @@ annotation in Envoy — they are transparent at the HTTP layer. **Review:** Rendered only when `websockets.enabled: true`. Hostname differs from nginz route. -- [ ] Done +- [x] Done --- @@ -325,7 +325,7 @@ Routes `config.dns.webapp` → `webapp-http` service port `externalPort`. **Review:** Absent from rendered output when `webapp.enabled: false`. -- [ ] Done +- [x] Done --- diff --git a/charts/wire-ingress/templates/httproute-websockets.yaml b/charts/wire-ingress/templates/httproute-nginz-websockets.yaml similarity index 86% rename from charts/wire-ingress/templates/httproute-websockets.yaml rename to charts/wire-ingress/templates/httproute-nginz-websockets.yaml index 3000f2e0ce0..f9647011926 100644 --- a/charts/wire-ingress/templates/httproute-websockets.yaml +++ b/charts/wire-ingress/templates/httproute-nginz-websockets.yaml @@ -2,7 +2,7 @@ apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: - name: {{ include "wire-ingress.fullname" . }}-websockets + name: {{ include "wire-ingress.fullname" . }}-nginz-websockets labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" @@ -22,6 +22,6 @@ spec: value: / backendRefs: - name: nginz - port: {{ .Values.services.nginz.wsPort }} + port: {{ .Values.service.nginz.wsPort }} kind: Service {{- end }} diff --git a/charts/wire-ingress/templates/httproute-nginz.yaml b/charts/wire-ingress/templates/httproute-nginz.yaml index 14466c21331..4f005fa44b5 100644 --- a/charts/wire-ingress/templates/httproute-nginz.yaml +++ b/charts/wire-ingress/templates/httproute-nginz.yaml @@ -21,5 +21,5 @@ spec: value: / backendRefs: - name: nginz - port: {{ .Values.services.nginz.httpPort }} + port: {{ .Values.service.nginz.httpPort }} kind: Service diff --git a/charts/wire-ingress/templates/httproute-webapp.yaml b/charts/wire-ingress/templates/httproute-webapp.yaml new file mode 100644 index 00000000000..e84b4d78929 --- /dev/null +++ b/charts/wire-ingress/templates/httproute-webapp.yaml @@ -0,0 +1,27 @@ +{{- if .Values.webapp.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "wire-ingress.fullname" . }}-webapp + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + parentRefs: + - name: {{ include "wire-ingress.getGatewayName" . | quote }} + namespace: {{ .Release.Namespace | quote }} + kind: Gateway + sectionName: https + hostnames: + - {{ required "config.dns.webapp is required when webapp.enabled is true" .Values.config.dns.webapp | quote }} + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: webapp-http + port: {{ .Values.service.webapp.externalPort }} + kind: Service +{{- end }} diff --git a/charts/wire-ingress/templates/service-webapp.yaml b/charts/wire-ingress/templates/service-webapp.yaml new file mode 100644 index 00000000000..10958b36341 --- /dev/null +++ b/charts/wire-ingress/templates/service-webapp.yaml @@ -0,0 +1,14 @@ +{{- if .Values.webapp.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: webapp-http +spec: + type: ClusterIP + ports: + - port: {{ .Values.service.webapp.externalPort }} + targetPort: 8080 + selector: + app: webapp +{{- end }} diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index 99637281417..58e041fd767 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -47,7 +47,9 @@ webapp: fakeS3: enabled: true -services: +service: + webapp: + externalPort: 8080 nginz: # Update this if you've overwritten the default HTTP port in nginz. httpPort: 8080 From f2f4e3cd23774fadffa326e3c89256f71c41f1e4 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Fri, 13 Mar 2026 11:37:44 +0100 Subject: [PATCH 11/79] Adjust plan: routes together with services --- charts/wire-ingress/README.md | 50 ++++++++++++----------------------- 1 file changed, 17 insertions(+), 33 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 91c26991c3d..f1e895ad9ab 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -302,9 +302,9 @@ The route attaches to the HTTPS listener of the Gateway via `parentRefs`. --- -#### HTTPRoute — websockets +#### HTTPRoute — nginz websockets -Template: `templates/httproute-websockets.yaml` +Template: `templates/httproute-nginz-websockets.yaml` Condition: `websockets.enabled` Routes `config.dns.ssl` → `nginz` service port `ws`. WebSocket upgrades require no special @@ -316,12 +316,12 @@ annotation in Envoy — they are transparent at the HTTP layer. --- -#### HTTPRoute — webapp +#### HTTPRoute + Service — webapp -Template: `templates/httproute-webapp.yaml` +Templates: `templates/httproute-webapp.yaml`, `templates/service-webapp.yaml` Condition: `webapp.enabled` -Routes `config.dns.webapp` → `webapp-http` service port `externalPort`. +Routes `config.dns.webapp` → `webapp-http` ClusterIP service port `service.webapp.externalPort`. **Review:** Absent from rendered output when `webapp.enabled: false`. @@ -329,31 +329,31 @@ Routes `config.dns.webapp` → `webapp-http` service port `externalPort`. --- -#### HTTPRoute — team-settings +#### HTTPRoute + Service — team-settings -Template: `templates/httproute-team-settings.yaml` +Templates: `templates/httproute-team-settings.yaml`, `templates/service-team-settings.yaml` Condition: `teamSettings.enabled` -Routes `config.dns.teamSettings` → `team-settings-http` service port `externalPort`. +Routes `config.dns.teamSettings` → `team-settings-http` ClusterIP service port `service.teamSettings.externalPort`. - [ ] Done --- -#### HTTPRoute — account-pages +#### HTTPRoute + Service — account-pages -Template: `templates/httproute-account-pages.yaml` +Templates: `templates/httproute-account-pages.yaml`, `templates/service-account-pages.yaml` Condition: `accountPages.enabled` -Routes `config.dns.accountPages` → `account-pages-http` service port `externalPort`. +Routes `config.dns.accountPages` → `account-pages-http` ClusterIP service port `service.accountPages.externalPort`. - [ ] Done --- -#### HTTPRoute — fakeS3 / minio +#### HTTPRoute + Service — fakeS3 / minio -Template: `templates/httproute-minio.yaml` +Templates: `templates/httproute-minio.yaml`, `templates/service-minio.yaml` Condition: `fakeS3.enabled` Routes `config.dns.fakeS3` → `fake-aws-s3` service. @@ -368,25 +368,9 @@ Access to `/minio/` paths is blocked with a 403 using an Envoy Gateway `HTTPRout - [ ] Done - ---- - -### Phase 5 — Services - -#### ClusterIP Services - -Template: `templates/service.yaml` - -Creates `webapp-http`, `s3-http`, `team-settings-http`, and `account-pages-http` ClusterIP -services with their respective selectors and ports. - -**Review:** `helm template` produces the expected set of ClusterIP services for the enabled features. - -- [ ] Done - --- -### Phase 6 — Federator +### Phase 5 — Federator #### Gateway listener for federator @@ -450,7 +434,7 @@ in `templates/certificate-federator.yaml`. --- -### Phase 7 — Integration test helper +### Phase 6 — Integration test helper #### federation-test-helper Service @@ -464,7 +448,7 @@ otherwise. --- -### Phase 8 — custom solver secret +### Phase 7 — custom solver secret #### Custom ACME solver secret @@ -477,7 +461,7 @@ An opaque Secret containing credentials for custom ACME challenge solvers, refer --- -### Phase 9 — Documentation and CI values +### Phase 8 — Documentation and CI values #### Finalize README, migration guide, and ci/ values files From 2af357a80d2693b7047442b26cc4e7383113741d Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Fri, 13 Mar 2026 11:43:43 +0100 Subject: [PATCH 12/79] team settings and account pages --- charts/wire-ingress/README.md | 4 +-- .../templates/httproute-account-pages.yaml | 27 +++++++++++++++++++ .../templates/httproute-team-settings.yaml | 27 +++++++++++++++++++ .../templates/service-account-pages.yaml | 13 +++++++++ .../templates/service-team-settings.yaml | 13 +++++++++ charts/wire-ingress/values.yaml | 4 +++ 6 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 charts/wire-ingress/templates/httproute-account-pages.yaml create mode 100644 charts/wire-ingress/templates/httproute-team-settings.yaml create mode 100644 charts/wire-ingress/templates/service-account-pages.yaml create mode 100644 charts/wire-ingress/templates/service-team-settings.yaml diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index f1e895ad9ab..33e2104391c 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -336,7 +336,7 @@ Condition: `teamSettings.enabled` Routes `config.dns.teamSettings` → `team-settings-http` ClusterIP service port `service.teamSettings.externalPort`. -- [ ] Done +- [x] Done --- @@ -347,7 +347,7 @@ Condition: `accountPages.enabled` Routes `config.dns.accountPages` → `account-pages-http` ClusterIP service port `service.accountPages.externalPort`. -- [ ] Done +- [x] Done --- diff --git a/charts/wire-ingress/templates/httproute-account-pages.yaml b/charts/wire-ingress/templates/httproute-account-pages.yaml new file mode 100644 index 00000000000..6e5b22e076e --- /dev/null +++ b/charts/wire-ingress/templates/httproute-account-pages.yaml @@ -0,0 +1,27 @@ +{{- if .Values.accountPages.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "wire-ingress.fullname" . }}-account-pages + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + parentRefs: + - name: {{ include "wire-ingress.getGatewayName" . | quote }} + namespace: {{ .Release.Namespace | quote }} + kind: Gateway + sectionName: https + hostnames: + - {{ required "config.dns.accountPages is required when accountPages.enabled is true" .Values.config.dns.accountPages | quote }} + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: account-pages-http + port: {{ .Values.service.accountPages.externalPort }} + kind: Service +{{- end }} diff --git a/charts/wire-ingress/templates/httproute-team-settings.yaml b/charts/wire-ingress/templates/httproute-team-settings.yaml new file mode 100644 index 00000000000..8f0bce3baf0 --- /dev/null +++ b/charts/wire-ingress/templates/httproute-team-settings.yaml @@ -0,0 +1,27 @@ +{{- if .Values.teamSettings.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "wire-ingress.fullname" . }}-team-settings + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + parentRefs: + - name: {{ include "wire-ingress.getGatewayName" . | quote }} + namespace: {{ .Release.Namespace | quote }} + kind: Gateway + sectionName: https + hostnames: + - {{ required "config.dns.teamSettings is required when teamSettings.enabled is true" .Values.config.dns.teamSettings | quote }} + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: team-settings-http + port: {{ .Values.service.teamSettings.externalPort }} + kind: Service +{{- end }} diff --git a/charts/wire-ingress/templates/service-account-pages.yaml b/charts/wire-ingress/templates/service-account-pages.yaml new file mode 100644 index 00000000000..09fc3bce9e5 --- /dev/null +++ b/charts/wire-ingress/templates/service-account-pages.yaml @@ -0,0 +1,13 @@ +{{- if .Values.accountPages.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: account-pages-http +spec: + type: ClusterIP + ports: + - port: {{ .Values.service.accountPages.externalPort }} + targetPort: 8080 + selector: + app: account-pages +{{- end }} diff --git a/charts/wire-ingress/templates/service-team-settings.yaml b/charts/wire-ingress/templates/service-team-settings.yaml new file mode 100644 index 00000000000..666a90d6010 --- /dev/null +++ b/charts/wire-ingress/templates/service-team-settings.yaml @@ -0,0 +1,13 @@ +{{- if .Values.teamSettings.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: team-settings-http +spec: + type: ClusterIP + ports: + - port: {{ .Values.service.teamSettings.externalPort }} + targetPort: 8080 + selector: + app: team-settings +{{- end }} diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index 58e041fd767..51bab2ffe48 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -50,6 +50,10 @@ fakeS3: service: webapp: externalPort: 8080 + teamSettings: + externalPort: 8080 + accountPages: + externalPort: 8080 nginz: # Update this if you've overwritten the default HTTP port in nginz. httpPort: 8080 From 7e27e06222e2f470ba8d3c7c91bbfc114609cf21 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Fri, 13 Mar 2026 13:57:58 +0100 Subject: [PATCH 13/79] fake-s3 route --- charts/wire-ingress/README.md | 22 ++++---- .../templates/httproute-minio.yaml | 38 ++++++++++++++ charts/wire-ingress/values.yaml | 50 +++++++++++-------- 3 files changed, 79 insertions(+), 31 deletions(-) create mode 100644 charts/wire-ingress/templates/httproute-minio.yaml diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 33e2104391c..05f5e5772aa 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -162,7 +162,7 @@ All keys below are accepted unchanged. Their names, types, and semantics are ide | Feature | Old behaviour | New behaviour | |---|---|---| | Default ACME solver | `http01.ingress.class: nginx` | `http01.gatewayHTTPRoute` targeting this chart's Gateway — requires `gateway.listeners.http.enabled: true` | -| `/minio/` path blocking | nginx `server-snippet` returning 403 | Envoy Gateway `HTTPRouteFilter` `directResponse` (implementation-specific, non-standard) | +| `/minio/` path blocking | nginx `server-snippet` returning 403 | `RequestRedirect` to `/` (301) — standard Gateway API | | Federator client cert header | `nginx.ingress.kubernetes.io/configuration-snippet` setting `X-SSL-Certificate` | Envoy Gateway `ClientTrafficPolicy` + `HTTPRouteFilter` header injection | | Websocket routing | Separate host with port name `ws` | Same `HTTPRoute` — WebSocket upgrades are handled transparently by Envoy | @@ -299,6 +299,7 @@ The route attaches to the HTTPS listener of the Gateway via `parentRefs`. **Review:** Renders correctly with and without TLS; `helm lint` passes. - [x] Done +- [x] Manually tested --- @@ -313,6 +314,7 @@ annotation in Envoy — they are transparent at the HTTP layer. **Review:** Rendered only when `websockets.enabled: true`. Hostname differs from nginz route. - [x] Done +- [x] Manually tested --- @@ -337,6 +339,7 @@ Condition: `teamSettings.enabled` Routes `config.dns.teamSettings` → `team-settings-http` ClusterIP service port `service.teamSettings.externalPort`. - [x] Done +- [x] Manually tested --- @@ -348,25 +351,24 @@ Condition: `accountPages.enabled` Routes `config.dns.accountPages` → `account-pages-http` ClusterIP service port `service.accountPages.externalPort`. - [x] Done +- [x] Manually tested --- #### HTTPRoute + Service — fakeS3 / minio -Templates: `templates/httproute-minio.yaml`, `templates/service-minio.yaml` +Template: `templates/httproute-minio.yaml` Condition: `fakeS3.enabled` -Routes `config.dns.fakeS3` → `fake-aws-s3` service. +Routes `config.dns.fakeS3` → `fake-aws-s3` service directly (no intermediary ClusterIP service needed — the fake-aws-s3 chart creates its own service). -Access to `/minio/` paths is blocked with a 403 using an Envoy Gateway `HTTPRouteFilter` with -`type: DirectResponse` and `statusCode: 403`, placed as a prefix match rule before the catch-all. +Access to `/minio/` paths is blocked by a `RequestRedirect` to `/` (301), placed as a prefix +match rule before the catch-all. This is standard Gateway API — no Envoy extensions required. -> **Incompatibility note:** `DirectResponse` is an Envoy Gateway extension -> (`gateway.envoyproxy.io/v1alpha1`). It is not part of the standard Gateway API spec. +**Review:** Two rules rendered: one redirect rule for `/minio/` prefix, one catch-all for `/`. -**Review:** Two rules rendered: one 403 rule for `/minio/` prefix, one catch-all for `/`. - -- [ ] Done +- [x] Done +- [x] Manually tested assets work --- diff --git a/charts/wire-ingress/templates/httproute-minio.yaml b/charts/wire-ingress/templates/httproute-minio.yaml new file mode 100644 index 00000000000..3c9bd50a9d1 --- /dev/null +++ b/charts/wire-ingress/templates/httproute-minio.yaml @@ -0,0 +1,38 @@ +{{- if .Values.fakeS3.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "wire-ingress.fullname" . }}-minio + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + parentRefs: + - name: {{ include "wire-ingress.getGatewayName" . | quote }} + namespace: {{ .Release.Namespace | quote }} + kind: Gateway + sectionName: https + hostnames: + - {{ required "config.dns.fakeS3 is required when fakeS3.enabled is true" .Values.config.dns.fakeS3 | quote }} + rules: + - matches: + - path: + type: PathPrefix + value: /minio/ + filters: + - type: RequestRedirect + requestRedirect: + path: + type: ReplaceFullPath + replaceFullPath: / + statusCode: 301 + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: {{ .Values.service.s3.serviceName }} + port: {{ .Values.service.s3.externalPort }} + kind: Service +{{- end }} diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index 51bab2ffe48..f65cc0649b0 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -1,5 +1,4 @@ # Default values for wire-ingress - gateway: # If true, a Gateway resource is created by this chart. # If false, set gateway.name to reference an existing Gateway. @@ -24,7 +23,6 @@ gateway: enabled: false # If true, connections without a PROXY protocol header are also accepted. # Use this only if some traffic bypasses the load balancer (e.g. direct node access). - # WARNING: breaks PROXY protocol spec compliance. optional: false listeners: https: @@ -36,16 +34,29 @@ gateway: enabled: false port: 80 -teamSettings: - enabled: false -accountPages: - enabled: false +# NOTE: Please provide names. Here are naming suggestions: +# You need to reference those in the nginz helm chart nginx_conf.deeplink.endpoints +# config: +# dns: +# https: nginz-https. +# ssl: nginz-ssl. # ignored if websockets.enabled == false +# webapp: webapp. # ignored if webapp.enabled == false +# fakeS3: assets. # ignored if fakeS3.enabled == false +# federator: federator. # ignored unless federator.enabled == true +# certificateDomain: federator. # domain to use in the federator CSR +# teamSettings: teams. # ignored unless teamSettings.enabled == true +# accountPages: account. # ignored unless accountPages.enabled == true + websockets: enabled: true webapp: enabled: true fakeS3: enabled: true +teamSettings: + enabled: false +accountPages: + enabled: false service: webapp: @@ -54,12 +65,19 @@ service: externalPort: 8080 accountPages: externalPort: 8080 + s3: + externalPort: 9000 + serviceName: fake-aws-s3 + # Set this to false if minio is not provided by the fake-aws-s3 chart + useFakeS3: true nginz: # Update this if you've overwritten the default HTTP port in nginz. httpPort: 8080 # Update this if you've overwritten the default WebSocket port in nginz. wsPort: 8081 +# TLS settings + tls: secret: # If true, a kubernetes.io/tls Secret is created from secrets.tlsWildcardCert @@ -67,16 +85,18 @@ tls: create: true # Override the name of the Secret. If not set, the name is derived from the release name. nameOverride: "" + + # If set to true create Certificate object that request from tls.issuer useCertManager: false - createIssuer: true privateKey: rotationPolicy: Always algorithm: ECDSA size: 384 # 521 is not supported by Let's Encrypt + + createIssuer: true issuer: name: letsencrypt-http01 kind: Issuer # Issuer | ClusterIssuer - # caNamespace: wire-federation-v0 certManager: # If true, uses the Let's Encrypt staging API (certificates are NOT trusted): @@ -87,19 +107,7 @@ certManager: certmasterEmail: customSolvers: -# You will need to supply DNS names: -# config: -# dns: -# https: nginz-https. -# ssl: nginz-ssl. # ignored if websockets.enabled == false -# webapp: webapp. # ignored if webapp.enabled == false -# fakeS3: assets. # ignored if fakeS3.enabled == false -# federator: federator. # ignored unless federator.enabled == true -# certificateDomain: federator. # domain to use in the federator CSR -# teamSettings: teams. # ignored unless teamSettings.enabled == true -# accountPages: account. # ignored unless accountPages.enabled == true -# -# For TLS (manual mode, tls.useCertManager: false): +# For TLS (manual mode, tls.useCertManager: false, tls.secret.create: false): # secrets: # tlsWildcardCert: | # -----BEGIN CERTIFICATE----- From b2a50c414c3873e04f7b15891dcdbb0b55a17acc Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Mon, 16 Mar 2026 13:46:37 +0100 Subject: [PATCH 14/79] complete federator phase --- charts/wire-ingress/README.md | 30 ++++++++++----- charts/wire-ingress/templates/_helpers.tpl | 9 +++++ .../templates/certificate-federator.yaml | 37 +++++++++++++++++++ .../clienttrafficpolicy-federator.yaml | 23 ++++++++++++ .../envoyextensionpolicy-federator.yaml | 30 +++++++++++++++ charts/wire-ingress/templates/gateway.yaml | 11 ++++++ .../templates/httproute-federator.yaml | 27 ++++++++++++++ charts/wire-ingress/values.yaml | 35 ++++++++++++++++-- 8 files changed, 188 insertions(+), 14 deletions(-) create mode 100644 charts/wire-ingress/templates/certificate-federator.yaml create mode 100644 charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml create mode 100644 charts/wire-ingress/templates/envoyextensionpolicy-federator.yaml create mode 100644 charts/wire-ingress/templates/httproute-federator.yaml diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 05f5e5772aa..572d82950fb 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -105,6 +105,7 @@ Operators should be able to reuse most of their existing values files with minim | `kubeVersionOverride` | Deprecated; the federation-test-helper label selector no longer needs a version override | | `tls.verify_depth` | Envoy Gateway `ClientTrafficPolicy` does not expose a direct verify-depth knob; the CA chain itself controls this | | `tls.enabled` | This is removed since it didnt ahve any effect. All ingresses are always defined with TLS. | +| `secrets.tlsClientCA` | No longer supplied via values. The `federator-ca` ConfigMap is created by the wire-server chart and referenced directly. | ### Fully backwards compatible values @@ -127,6 +128,8 @@ All keys below are accepted unchanged. Their names, types, and semantics are ide | `federator.tls.issuer.name` | | | `federator.tls.issuer.kind` | | | `federator.tls.issuer.group` | | +| _(not present)_ | `federator.tls.useCertManager` | Controls cert-manager for the federator TLS secret independently of `tls.useCertManager` | +| _(not present)_ | `federator.tls.secretName` | Name of the externally-managed TLS Secret for the federator listener. Only relevant when `federator.tls.useCertManager` is `false`. When `true`, the secret name is derived from the release name via the same helper as the main TLS secret. | | `tls.useCertManager` | | | `tls.createIssuer` | | | `tls.privateKey.rotationPolicy` | | @@ -154,7 +157,6 @@ All keys below are accepted unchanged. Their names, types, and semantics are ide | `config.dns.accountPages` | | | `secrets.tlsWildcardCert` | | | `secrets.tlsWildcardKey` | | -| `secrets.tlsClientCA` | | | `secrets.certManager.customSolversSecret` | | ### Behaviour changes @@ -328,6 +330,7 @@ Routes `config.dns.webapp` → `webapp-http` ClusterIP service port `service.web **Review:** Absent from rendered output when `webapp.enabled: false`. - [x] Done +- [x] Manually tested --- @@ -382,7 +385,7 @@ Extend `templates/gateway.yaml` to add a separate TLS listener for `config.dns.f The federator requires its own listener so that `ClientTrafficPolicy` can enforce mTLS only on that listener, not on the main HTTPS listener. -- [ ] Done +- [x] Done --- @@ -397,7 +400,7 @@ federator listener. Fails with an error if `config.isAdditionalIngress` is set, since federation and multi-ingress cannot be combined. -- [ ] Done +- [x] Done --- @@ -419,20 +422,27 @@ Enforces mTLS client certificate validation and forwards the client certificate > `ClientTrafficPolicy` does not expose a depth knob; validation depth is implicitly controlled by > the CA chain provided in `federator-ca-secret`. -- [ ] Done +- [x] Done +- [x] Manually tested a federated request (see check-federation-certs.sh script) --- -#### Federator TLS secrets + CA secret +#### Federator TLS secret + X-SSL-Certificate header injection -Templates: `templates/secret-federator.yaml`, `templates/ca-federator.yaml` +Templates: `templates/secret-federator.yaml`, `templates/certificate-federator.yaml`, `templates/envoyextensionpolicy-federator.yaml` Condition: `federator.enabled` -Creates `federator-certificate-secret` and `federator-ca-secret`. When `tls.useCertManager` is -enabled, a cert-manager `Certificate` with both `server auth` and `client auth` EKUs is created -in `templates/certificate-federator.yaml`. +Creates `federator-certificate-secret` (manual mode) or a cert-manager `Certificate` with both +`server auth` and `client auth` EKUs (`tls.useCertManager: true`). -- [ ] Done +The `federator-ca` ConfigMap is **not** created by this chart — it is created by the wire-server +chart and must exist in the release namespace before deploying with `federator.enabled: true`. + +The `EnvoyExtensionPolicy` injects the mTLS client certificate as the `X-SSL-Certificate` request +header via an inline Lua filter, matching nginx's `$ssl_client_escaped_cert` behaviour. + +- [x] Done +- [x] Manually tested --- diff --git a/charts/wire-ingress/templates/_helpers.tpl b/charts/wire-ingress/templates/_helpers.tpl index 4c5134addef..3614b3244f6 100644 --- a/charts/wire-ingress/templates/_helpers.tpl +++ b/charts/wire-ingress/templates/_helpers.tpl @@ -35,6 +35,15 @@ Name of the TLS certificate secret. Differs based on whether cert-manager is use {{- end -}} {{- end -}} +{{/* +Name of the federator TLS certificate secret (cert-manager managed). +*/}} +{{- define "wire-ingress.getFederatorCertificateSecretName" -}} +{{- $nameParts := list (include "wire-ingress.fullname" .) -}} +{{- $nameParts = append $nameParts "federator-managed-tls-certificate" -}} +{{- join "-" $nameParts -}} +{{- end -}} + {{/* Name of the custom ACME solver secret. */}} diff --git a/charts/wire-ingress/templates/certificate-federator.yaml b/charts/wire-ingress/templates/certificate-federator.yaml new file mode 100644 index 00000000000..eed7a249514 --- /dev/null +++ b/charts/wire-ingress/templates/certificate-federator.yaml @@ -0,0 +1,37 @@ +{{- if and .Values.federator.enabled .Values.federator.tls.useCertManager }} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: "federator-{{ include "wire-ingress.zone" . | replace "." "-" }}-csr" + namespace: {{ .Release.Namespace }} + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + issuerRef: + {{- if .Values.federator.tls.issuer.name }} + name: {{ .Values.federator.tls.issuer.name | quote }} + kind: {{ .Values.federator.tls.issuer.kind | default .Values.tls.issuer.kind }} + {{- if .Values.federator.tls.issuer.group }} + group: {{ .Values.federator.tls.issuer.group }} + {{- end }} + {{- else }} + name: {{ include "wire-ingress.getIssuerName" . | quote }} + kind: {{ .Values.tls.issuer.kind }} + {{- end }} + usages: + - server auth + - client auth + duration: {{ .Values.federator.tls.duration }} + renewBefore: {{ .Values.federator.tls.renewBefore }} + isCA: false + secretName: {{ include "wire-ingress.getFederatorCertificateSecretName" . | quote }} + privateKey: + algorithm: ECDSA + size: 256 + encoding: PKCS1 + rotationPolicy: {{ .Values.federator.tls.privateKey.rotationPolicy }} + dnsNames: + - {{ or .Values.config.dns.certificateDomain .Values.config.dns.federator | quote }} +{{- end }} diff --git a/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml b/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml new file mode 100644 index 00000000000..c42df606b28 --- /dev/null +++ b/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml @@ -0,0 +1,23 @@ +{{- if .Values.federator.enabled }} +{{/* Envoy Gateway-specific (gateway.envoyproxy.io/v1alpha1). + Enforces mTLS client certificate validation on the federator listener only. */}} +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: ClientTrafficPolicy +metadata: + name: {{ include "wire-ingress.getGatewayName" . }}-federator-mtls + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: {{ include "wire-ingress.getGatewayName" . | quote }} + sectionName: federator + tls: + clientValidation: + caCertificateRefs: + - name: federator-ca + kind: ConfigMap +{{- end }} diff --git a/charts/wire-ingress/templates/envoyextensionpolicy-federator.yaml b/charts/wire-ingress/templates/envoyextensionpolicy-federator.yaml new file mode 100644 index 00000000000..6473f17871d --- /dev/null +++ b/charts/wire-ingress/templates/envoyextensionpolicy-federator.yaml @@ -0,0 +1,30 @@ +{{- if .Values.federator.enabled }} +{{/* Injects the mTLS client certificate as X-SSL-Certificate request header, + matching nginx's $ssl_client_escaped_cert behaviour. + Envoy Gateway-specific (gateway.envoyproxy.io/v1alpha1). */}} +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyExtensionPolicy +metadata: + name: {{ include "wire-ingress.fullname" . }}-federator-cert-header + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: {{ include "wire-ingress.fullname" . }}-federator + lua: + - type: Inline + inline: | + function envoy_on_request(request_handle) + local ssl = request_handle:connection():ssl() + if ssl ~= nil then + local cert = ssl:urlEncodedPemEncodedPeerCertificate() + if cert ~= nil and cert ~= "" then + request_handle:headers():add("X-SSL-Certificate", cert) + end + end + end +{{- end }} diff --git a/charts/wire-ingress/templates/gateway.yaml b/charts/wire-ingress/templates/gateway.yaml index 4969da4f76d..17035987a4d 100644 --- a/charts/wire-ingress/templates/gateway.yaml +++ b/charts/wire-ingress/templates/gateway.yaml @@ -26,6 +26,17 @@ spec: certificateRefs: - name: {{ include "wire-ingress.getCertificateSecretName" . | quote }} kind: Secret + {{- if .Values.federator.enabled }} + - name: federator + port: {{ .Values.gateway.listeners.https.port }} + protocol: HTTPS + hostname: {{ required "config.dns.federator is required when federator.enabled is true" .Values.config.dns.federator | quote }} + tls: + mode: Terminate + certificateRefs: + - name: {{ if .Values.federator.tls.useCertManager }}{{ include "wire-ingress.getFederatorCertificateSecretName" . | quote }}{{ else }}{{ required "federator.tls.secretName is required when federator.tls.useCertManager is false" .Values.federator.tls.secretName | quote }}{{ end }} + kind: Secret + {{- end }} {{- if .Values.gateway.listeners.http.enabled }} - name: http port: {{ .Values.gateway.listeners.http.port }} diff --git a/charts/wire-ingress/templates/httproute-federator.yaml b/charts/wire-ingress/templates/httproute-federator.yaml new file mode 100644 index 00000000000..6882f04aa91 --- /dev/null +++ b/charts/wire-ingress/templates/httproute-federator.yaml @@ -0,0 +1,27 @@ +{{- if .Values.federator.enabled }} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ include "wire-ingress.fullname" . }}-federator + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + parentRefs: + - name: {{ include "wire-ingress.getGatewayName" . | quote }} + namespace: {{ .Release.Namespace | quote }} + kind: Gateway + sectionName: federator + hostnames: + - {{ .Values.config.dns.federator | quote }} + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: federator + port: {{ .Values.service.federator.externalPort }} + kind: Service +{{- end }} diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index f65cc0649b0..e54746520f7 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -70,12 +70,39 @@ service: serviceName: fake-aws-s3 # Set this to false if minio is not provided by the fake-aws-s3 chart useFakeS3: true + federator: + # Must match service.externalFederatorPort in the federator chart. + externalPort: 8081 nginz: # Update this if you've overwritten the default HTTP port in nginz. httpPort: 8080 # Update this if you've overwritten the default WebSocket port in nginz. wsPort: 8081 +# Federator + +federator: + enabled: false + integrationTestHelper: false + tls: + # If true, a cert-manager Certificate is created for the federator TLS secret. + # Independent of the global tls.useCertManager setting. + useCertManager: true + # Name of the externally-managed TLS Secret for the federator listener. + # Only relevant when useCertManager is false — the secret must exist before deploying. + # When useCertManager is true this is ignored; the secret name is derived from the release name. + secretName: "" + duration: 2160h + renewBefore: 360h + privateKey: + rotationPolicy: Always + # Issuer for federator certificate (mTLS with Client Auth EKU). + # If not set, uses global tls.issuer configuration. + issuer: {} + # name: "" + # kind: "" + # group: "" + # TLS settings tls: @@ -117,7 +144,7 @@ certManager: # -----BEGIN PRIVATE KEY----- # ... # -----END PRIVATE KEY----- -# tlsClientCA: | -# -----BEGIN CERTIFICATE----- -# ... -# -----END CERTIFICATE----- +# +# When federator.enabled is true, a ConfigMap named `federator-ca` with a `ca.crt` key +# must exist in the release namespace. It is created by the wire-server chart +# and is referenced by the ClientTrafficPolicy for mTLS. From c2ba5731152c7720bc59b86d74c5a4844e690953 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 17 Mar 2026 12:17:32 +0100 Subject: [PATCH 15/79] use different secret name for federators certificate --- charts/wire-ingress/README.md | 30 ++++++++++++++++++- charts/wire-ingress/templates/_helpers.tpl | 9 ------ .../templates/certificate-federator.yaml | 2 +- charts/wire-ingress/templates/gateway.yaml | 2 +- charts/wire-ingress/values.yaml | 8 ++--- 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 572d82950fb..bc4d8b8571e 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -129,7 +129,7 @@ All keys below are accepted unchanged. Their names, types, and semantics are ide | `federator.tls.issuer.kind` | | | `federator.tls.issuer.group` | | | _(not present)_ | `federator.tls.useCertManager` | Controls cert-manager for the federator TLS secret independently of `tls.useCertManager` | -| _(not present)_ | `federator.tls.secretName` | Name of the externally-managed TLS Secret for the federator listener. Only relevant when `federator.tls.useCertManager` is `false`. When `true`, the secret name is derived from the release name via the same helper as the main TLS secret. | +| _(not present)_ | `federator.tls.secretName` | Name of the TLS Secret for the federator listener. Default: `federator-certificate-secret`. When `useCertManager: true`, cert-manager writes the issued certificate into this secret. When `useCertManager: false`, the secret must exist before deploying. | | `tls.useCertManager` | | | `tls.createIssuer` | | | `tls.privateKey.rotationPolicy` | | @@ -458,6 +458,34 @@ otherwise. - [ ] Done +Notes: + +This helper ties inot the integration test setup. +Here's how the integration tests are set up. My goal is to make integration tests pass +when we deploy wire-ingress instead in place of nginx-ingress-services + +The integration test are deployed via helmfile hack/helmfile.yaml.gotmpl + + +The cluster in which the integration tests run has ClusterIssuer named "federation" that will sign any certs. + +From + +/home/stefan/repos/wire-server/hack/helm_vars/wire-server/values.yaml.gotmpl +``` +federator: + tls: + useCertManager: true + useSharedFederatorSecret: true +``` +we can see that the federator will assume that the cert used for both client and server auth is externally provide at secret "federator-certificate-secret" + +For that we actually have to + + + + + --- ### Phase 7 — custom solver secret diff --git a/charts/wire-ingress/templates/_helpers.tpl b/charts/wire-ingress/templates/_helpers.tpl index 3614b3244f6..4c5134addef 100644 --- a/charts/wire-ingress/templates/_helpers.tpl +++ b/charts/wire-ingress/templates/_helpers.tpl @@ -35,15 +35,6 @@ Name of the TLS certificate secret. Differs based on whether cert-manager is use {{- end -}} {{- end -}} -{{/* -Name of the federator TLS certificate secret (cert-manager managed). -*/}} -{{- define "wire-ingress.getFederatorCertificateSecretName" -}} -{{- $nameParts := list (include "wire-ingress.fullname" .) -}} -{{- $nameParts = append $nameParts "federator-managed-tls-certificate" -}} -{{- join "-" $nameParts -}} -{{- end -}} - {{/* Name of the custom ACME solver secret. */}} diff --git a/charts/wire-ingress/templates/certificate-federator.yaml b/charts/wire-ingress/templates/certificate-federator.yaml index eed7a249514..b02c257c01f 100644 --- a/charts/wire-ingress/templates/certificate-federator.yaml +++ b/charts/wire-ingress/templates/certificate-federator.yaml @@ -26,7 +26,7 @@ spec: duration: {{ .Values.federator.tls.duration }} renewBefore: {{ .Values.federator.tls.renewBefore }} isCA: false - secretName: {{ include "wire-ingress.getFederatorCertificateSecretName" . | quote }} + secretName: {{ .Values.federator.tls.secretName | quote }} privateKey: algorithm: ECDSA size: 256 diff --git a/charts/wire-ingress/templates/gateway.yaml b/charts/wire-ingress/templates/gateway.yaml index 17035987a4d..13b8fdb9131 100644 --- a/charts/wire-ingress/templates/gateway.yaml +++ b/charts/wire-ingress/templates/gateway.yaml @@ -34,7 +34,7 @@ spec: tls: mode: Terminate certificateRefs: - - name: {{ if .Values.federator.tls.useCertManager }}{{ include "wire-ingress.getFederatorCertificateSecretName" . | quote }}{{ else }}{{ required "federator.tls.secretName is required when federator.tls.useCertManager is false" .Values.federator.tls.secretName | quote }}{{ end }} + - name: {{ required "federator.tls.secretName is required when federator.enabled is true" .Values.federator.tls.secretName | quote }} kind: Secret {{- end }} {{- if .Values.gateway.listeners.http.enabled }} diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index e54746520f7..283abf259c3 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -88,10 +88,10 @@ federator: # If true, a cert-manager Certificate is created for the federator TLS secret. # Independent of the global tls.useCertManager setting. useCertManager: true - # Name of the externally-managed TLS Secret for the federator listener. - # Only relevant when useCertManager is false — the secret must exist before deploying. - # When useCertManager is true this is ignored; the secret name is derived from the release name. - secretName: "" + # Name of the TLS Secret for the federator listener. + # When useCertManager is true, cert-manager writes the certificate into this secret. + # When useCertManager is false, the secret must exist before deploying. + secretName: "federator-certificate-secret" duration: 2160h renewBefore: 360h privateKey: From 0fb6404ac486f0bb952cf1c7264a1938dfd48192 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 17 Mar 2026 13:53:01 +0100 Subject: [PATCH 16/79] udpate plan notes for federation helper --- charts/wire-ingress/README.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index bc4d8b8571e..fdbada6a310 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -460,18 +460,15 @@ otherwise. Notes: -This helper ties inot the integration test setup. -Here's how the integration tests are set up. My goal is to make integration tests pass -when we deploy wire-ingress instead in place of nginx-ingress-services +This helper ties into the integration test setup. +Here's how the integration tests are set up with nginx-ingress-service. My goal is to make integration tests pass +when we deploy wire-ingress instead in place of nginx-ingress-servicess. The integration test are deployed via helmfile hack/helmfile.yaml.gotmpl - The cluster in which the integration tests run has ClusterIssuer named "federation" that will sign any certs. -From - -/home/stefan/repos/wire-server/hack/helm_vars/wire-server/values.yaml.gotmpl +From /home/stefan/repos/wire-server/hack/helm_vars/wire-server/values.yaml.gotmpl ``` federator: tls: @@ -480,9 +477,10 @@ federator: ``` we can see that the federator will assume that the cert used for both client and server auth is externally provide at secret "federator-certificate-secret" -For that we actually have to - +In the integration test setup 2 domains federationDomain1 and federationDomain2 are configured with a namespace . +The federator will use the "federation" ClusterIssuer to obtain a cert. +Wire uses a SRV records to look up the federator domain of a domain. This is what federation-test-helper is used for. The SRV record on the service targets the ingress deployment pods which are ingressing the federator. From 2106e4218715fce34c0bdbf01ed74ae27a01ccfe Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 17 Mar 2026 17:24:22 +0100 Subject: [PATCH 17/79] wip integrations tests --- Makefile | 5 +- charts/wire-ingress/README.md | 113 +++++++++++++++++- .../templates/federation-test-helper.yaml | 39 ++++++ hack/bin/integration-setup-federation.sh | 3 +- .../helm_vars/wire-ingress/values.yaml.gotmpl | 32 +++++ hack/helmfile-federation-v0.yaml.gotmpl | 34 ++++-- hack/helmfile.yaml.gotmpl | 38 ++++-- 7 files changed, 241 insertions(+), 23 deletions(-) create mode 100644 charts/wire-ingress/templates/federation-test-helper.yaml create mode 100644 hack/helm_vars/wire-ingress/values.yaml.gotmpl diff --git a/Makefile b/Makefile index e366edbb91e..6ecf57183ef 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ DOCKER_TAG ?= $(USER) # default helm chart version must be 0.0.42 for local development (because 42 is the answer to the universe and everything) HELM_SEMVER ?= 0.0.42 # The list of helm charts needed on internal kubernetes testing environments -CHARTS_INTEGRATION := wire-server databases-ephemeral rabbitmq fake-aws ingress-nginx-controller nginx-ingress-services fluent-bit kibana k8ssandra-test-cluster wire-server-enterprise +CHARTS_INTEGRATION := wire-server databases-ephemeral rabbitmq fake-aws ingress-nginx-controller nginx-ingress-services wire-ingress fluent-bit kibana k8ssandra-test-cluster wire-server-enterprise # The list of helm charts to publish on S3 # FUTUREWORK: after we "inline local subcharts", # (e.g. move charts/brig to charts/wire-server/brig) @@ -18,7 +18,8 @@ fake-aws fake-aws-s3 fake-aws-sqs aws-ingress fluent-bit kibana backoffice \ calling-test demo-smtp elasticsearch-curator elasticsearch-external \ elasticsearch-ephemeral minio-external cassandra-external \ ingress-nginx-controller nginx-ingress-services reaper \ -k8ssandra-test-cluster ldap-scim-bridge wire-server-enterprise +k8ssandra-test-cluster ldap-scim-bridge wire-server-enterprise \ +wire-ingress KIND_CLUSTER_NAME := wire-server HELM_PARALLELISM ?= 1 # 1 for sequential tests; 6 for all-parallel tests PSQL_DB ?= backendA diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index fdbada6a310..5f5ec2a5643 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -486,7 +486,116 @@ Wire uses a SRV records to look up the federator domain of a domain. This is wha --- -### Phase 7 — custom solver secret +### Phase 7 — Switch integration tests to wire-ingress + +Replace all uses of `nginx-ingress-services` in `hack/` with `wire-ingress`. + +The integration test setup deploys two federation namespaces (`namespace1`, `namespace2`) each +with their own ingress release. Both currently use `nginx-ingress-services`. The goal is to make +integration tests pass with `wire-ingress` in place of `nginx-ingress-services`. + +#### Overview of changes + +Files to update: + +| File | Change | +|---|---| +| `hack/helmfile.yaml.gotmpl` | Replace two `ingress-svc` release blocks | +| `hack/helmfile-federation-v0.yaml.gotmpl` | Replace one `ingress-svc` release block | +| `hack/bin/integration-setup-federation.sh` | Replace `nginx-ingress-services` in `charts` array with `wire-ingress` | +| `hack/helm_vars/nginx-ingress-services/values.yaml.gotmpl` | Keep for reference; create `hack/helm_vars/wire-ingress/values.yaml.gotmpl` | + +#### Step 1 — Create `hack/helm_vars/wire-ingress/values.yaml.gotmpl` + +Adapt from the existing nginx-ingress-services values. Key changes: + +- Remove `config.ingressClass` → replace with `gateway.className` pointing to the Envoy GatewayClass +- Remove `secrets.tlsClientCA` (dropped — `federator-ca` ConfigMap is created by the wire-server chart) +- Add `federator.tls.useCertManager: true` with `federator.tls.issuer.name: federation` / + `federator.tls.issuer.kind: ClusterIssuer` + +The wire-ingress chart creates the cert at `federator-certificate-secret` (our default +`federator.tls.secretName`) via cert-manager using the `federation` ClusterIssuer. The federator +chart reads the same secret (via `useSharedFederatorSecret: true`). This is how both charts share +the same mTLS cert. + +Expected values: +```yaml +teamSettings: + enabled: true +accountPages: + enabled: true +federator: + enabled: true + integrationTestHelper: true + tls: + useCertManager: true + issuer: + name: federation + kind: ClusterIssuer +tls: + useCertManager: true + issuer: + name: federation + kind: ClusterIssuer + createIssuer: false + caNamespace: wire-federation-v0 +gateway: + className: "envoy" +config: + dns: + https: "nginz-https.{{ .Release.Namespace }}-integration.example.com" + ssl: "nginz-ssl.{{ .Release.Namespace }}-integration.example.com" + webapp: "webapp.{{ .Release.Namespace }}-integration.example.com" + fakeS3: "assets.{{ .Release.Namespace }}-integration.example.com" + teamSettings: "teams.{{ .Release.Namespace }}-integration.example.com" + accountPages: "account.{{ .Release.Namespace }}-integration.example.com" + # federator: dynamically set by helmfile + # certificateDomain: dynamically set by helmfile +``` + +#### Step 2 — Update `hack/helmfile.yaml.gotmpl` + +In both `ingress-svc` release blocks (namespace1 and namespace2): +- Change `chart` from `../.local/charts/nginx-ingress-services` to `../.local/charts/wire-ingress` +- Change `values` from `./helm_vars/nginx-ingress-services/values.yaml.gotmpl` to `./helm_vars/wire-ingress/values.yaml.gotmpl` +- Review the `needs: ['ingress']` dependency — `ingress` refers to the nginx-ingress-controller + release. With wire-ingress there is no nginx controller; this dependency should be removed or + replaced with the Envoy Gateway release if it is managed by this helmfile. + +#### Step 3 — Update `hack/helmfile-federation-v0.yaml.gotmpl` + +The `ingress-svc` release currently pins `wire/nginx-ingress-services` at a specific version. +Replace with a local chart reference (same as helmfile.yaml.gotmpl): +- Change `chart` to `../.local/charts/wire-ingress` +- Change `values` to `./helm_vars/wire-ingress/values.yaml.gotmpl` + +#### Step 4 — Update `hack/bin/integration-setup-federation.sh` + +Line 25: replace `nginx-ingress-services` with `wire-ingress` in the `charts` array. + +#### Step 5 — Verify federation-test-helper pod selector + +After the first deployment, check the actual labels on the Envoy Gateway proxy pods: + +```bash +kubectl get pods -n --show-labels | grep envoy +``` + +The template currently uses: +```yaml +selector: + gateway.envoyproxy.io/owning-gateway-name: + gateway.envoyproxy.io/owning-gateway-namespace: +``` + +Adjust `templates/federation-test-helper.yaml` if the actual labels differ. + +- [ ] Done + +--- + +### Phase 8 — custom solver secret #### Custom ACME solver secret @@ -499,7 +608,7 @@ An opaque Secret containing credentials for custom ACME challenge solvers, refer --- -### Phase 8 — Documentation and CI values +### Phase 9 — Documentation and CI values #### Finalize README, migration guide, and ci/ values files diff --git a/charts/wire-ingress/templates/federation-test-helper.yaml b/charts/wire-ingress/templates/federation-test-helper.yaml new file mode 100644 index 00000000000..2c1542d1f0a --- /dev/null +++ b/charts/wire-ingress/templates/federation-test-helper.yaml @@ -0,0 +1,39 @@ +{{- if (and .Values.federator.enabled .Values.federator.integrationTestHelper) }} +# Envoy Gateway runs proxy pods in its own namespace (envoy-gateway-system), not in the release +# namespace. Kubernetes Services cannot select pods across namespaces, so we need two resources: +# +# 1. A ClusterIP Service in envoy-gateway-system that selects our proxy pods by their +# owning-gateway labels (set by Envoy Gateway on all proxy pods it manages). +# +# 2. An ExternalName Service named federation-test-helper in the release namespace. +# This creates the SRV record that Wire federation discovery expects: +# _wire-server-federator._tcp.federation-test-helper..svc.cluster.local +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Namespace }}-fed + namespace: envoy-gateway-system +spec: + type: ClusterIP + ports: + - name: wire-server-federator + port: 443 + protocol: TCP + targetPort: 443 + selector: + gateway.envoyproxy.io/owning-gateway-name: {{ include "wire-ingress.getGatewayName" . }} + gateway.envoyproxy.io/owning-gateway-namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: Service +metadata: + name: federation-test-helper + namespace: {{ .Release.Namespace }} +spec: + type: ExternalName + externalName: {{ .Release.Namespace }}-fed.envoy-gateway-system.svc.cluster.local + ports: + - name: wire-server-federator + port: 443 + protocol: TCP +{{- end }} diff --git a/hack/bin/integration-setup-federation.sh b/hack/bin/integration-setup-federation.sh index 355abb417ab..1dfaccc42ee 100755 --- a/hack/bin/integration-setup-federation.sh +++ b/hack/bin/integration-setup-federation.sh @@ -22,7 +22,8 @@ HELM_PARALLELISM=${HELM_PARALLELISM:-1} # script beforehand on all relevant charts to download the nested dependencies # (e.g. cassandra from underneath databases-ephemeral) echo "updating recursive dependencies ..." -charts=(fake-aws databases-ephemeral rabbitmq wire-server ingress-nginx-controller nginx-ingress-services) +charts=(fake-aws databases-ephemeral rabbitmq wire-server ingress-nginx-controller nginx-ingress-services wire-ingress) +# charts=(fake-aws databases-ephemeral rabbitmq wire-server ingress-nginx-controller nginx-ingress-services) mkdir -p ~/.parallel && touch ~/.parallel/will-cite printf '%s\n' "${charts[@]}" | parallel -P "${HELM_PARALLELISM}" "$DIR/update.sh" "$CHARTS_DIR/{}" diff --git a/hack/helm_vars/wire-ingress/values.yaml.gotmpl b/hack/helm_vars/wire-ingress/values.yaml.gotmpl new file mode 100644 index 00000000000..f0a9ce48c5d --- /dev/null +++ b/hack/helm_vars/wire-ingress/values.yaml.gotmpl @@ -0,0 +1,32 @@ +teamSettings: + enabled: true +accountPages: + enabled: true +federator: + enabled: true + integrationTestHelper: true + tls: + useCertManager: true + issuer: + name: federation + kind: ClusterIssuer +tls: + useCertManager: true + issuer: + name: federation + kind: ClusterIssuer + createIssuer: false + +gateway: + className: "envoy" + +config: + dns: + https: "nginz-https.{{ .Release.Namespace }}-integration.example.com" + ssl: "nginz-ssl.{{ .Release.Namespace }}-integration.example.com" + webapp: "webapp.{{ .Release.Namespace }}-integration.example.com" + fakeS3: "assets.{{ .Release.Namespace }}-integration.example.com" + teamSettings: "teams.{{ .Release.Namespace }}-integration.example.com" + accountPages: "account.{{ .Release.Namespace }}-integration.example.com" + # federator: dynamically set by hack/helmfile.yaml.gotmpl + # certificateDomain: dynamically set by hack/helmfile.yaml.gotmpl diff --git a/hack/helmfile-federation-v0.yaml.gotmpl b/hack/helmfile-federation-v0.yaml.gotmpl index 5400307d84b..5247d1ba5be 100644 --- a/hack/helmfile-federation-v0.yaml.gotmpl +++ b/hack/helmfile-federation-v0.yaml.gotmpl @@ -72,19 +72,34 @@ releases: values: - './helm_vars/rabbitmq/values.yaml.gotmpl' - - name: 'ingress' - namespace: wire-federation-v0 - chart: 'wire/ingress-nginx-controller' - version: 4.38.0-mandarin.14 - values: - - './helm_vars/ingress-nginx-controller/values.yaml.gotmpl' + # - name: 'ingress' + # namespace: wire-federation-v0 + # chart: 'wire/ingress-nginx-controller' + # version: 4.38.0-mandarin.14 + # values: + # - './helm_vars/ingress-nginx-controller/values.yaml.gotmpl' + + # - name: 'ingress-svc' + # namespace: wire-federation-v0 + # chart: 'wire/nginx-ingress-services' + # version: 4.38.0-mandarin.14 + # values: + # - './helm_vars/nginx-ingress-services/values.yaml.gotmpl' + # set: + # - name: config.dns.federator + # value: wire-federation-v0.svc.cluster.local + # - name: config.dns.certificateDomain + # value: '*.wire-federation-v0.svc.cluster.local' + # needs: + # - 'ingress' + # - 'cert-manager/cert-manager' + # - 'cert-manager/federation-certs' - name: 'ingress-svc' namespace: wire-federation-v0 - chart: 'wire/nginx-ingress-services' - version: 4.38.0-mandarin.14 + chart: '../.local/charts/wire-ingress' values: - - './helm_vars/nginx-ingress-services/values.yaml.gotmpl' + - './helm_vars/wire-ingress/values.yaml.gotmpl' set: # Federation domain is also the SRV record created by the # federation-test-helper service. Maybe we can find a way to make these @@ -94,7 +109,6 @@ releases: - name: config.dns.certificateDomain value: '*.wire-federation-v0.svc.cluster.local' needs: - - 'ingress' - 'cert-manager/cert-manager' - 'cert-manager/federation-certs' diff --git a/hack/helmfile.yaml.gotmpl b/hack/helmfile.yaml.gotmpl index fbd83410307..2529b46c672 100644 --- a/hack/helmfile.yaml.gotmpl +++ b/hack/helmfile.yaml.gotmpl @@ -276,11 +276,24 @@ releases: values: - './helm_vars/{{ .Values.ingressChart }}/values.yaml.gotmpl' + # - name: 'ingress-svc' + # namespace: '{{ .Values.namespace1 }}' + # chart: '../.local/charts/nginx-ingress-services' + # values: + # - './helm_vars/nginx-ingress-services/values.yaml.gotmpl' + # set: + # - name: config.dns.federator + # value: '{{ .Values.federationDomain1 }}' + # - name: config.dns.certificateDomain + # value: '*.{{ .Values.federationDomainBase1 }}' + # needs: + # - 'ingress' + - name: 'ingress-svc' namespace: '{{ .Values.namespace1 }}' - chart: '../.local/charts/nginx-ingress-services' + chart: '../.local/charts/wire-ingress' values: - - './helm_vars/nginx-ingress-services/values.yaml.gotmpl' + - './helm_vars/wire-ingress/values.yaml.gotmpl' set: # Federation domain is also the SRV record created by the # federation-test-helper service. Maybe we can find a way to make these @@ -289,14 +302,25 @@ releases: value: '{{ .Values.federationDomain1 }}' - name: config.dns.certificateDomain value: '*.{{ .Values.federationDomainBase1 }}' - needs: - - 'ingress' + + # - name: 'ingress-svc' + # namespace: '{{ .Values.namespace2 }}' + # chart: '../.local/charts/nginx-ingress-services' + # values: + # - './helm_vars/nginx-ingress-services/values.yaml.gotmpl' + # set: + # - name: config.dns.federator + # value: '{{ .Values.federationDomain2 }}' + # - name: config.dns.certificateDomain + # value: '*.{{ .Values.federationDomainBase2 }}' + # needs: + # - 'ingress' - name: 'ingress-svc' namespace: '{{ .Values.namespace2 }}' - chart: '../.local/charts/nginx-ingress-services' + chart: '../.local/charts/wire-ingress' values: - - './helm_vars/nginx-ingress-services/values.yaml.gotmpl' + - './helm_vars/wire-ingress/values.yaml.gotmpl' set: # Federation domain is also the SRV record created by the # federation-test-helper service. Maybe we can find a way to make these @@ -305,8 +329,6 @@ releases: value: '{{ .Values.federationDomain2 }}' - name: config.dns.certificateDomain value: '*.{{ .Values.federationDomainBase2 }}' - needs: - - 'ingress' # Note that wire-server depends on databases-ephemeral being up; and in some # cases on nginx-ingress also being up. If installing helm charts in a From d565e8705ad880f08cb8b3ad1fbc20d8fdfca96e Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 18 Mar 2026 13:19:44 +0100 Subject: [PATCH 18/79] Add post-upgrade hook to all tests This makes it possible to update integration test setup during development --- charts/backoffice/templates/tests/configmap.yaml | 2 +- charts/federator/templates/tests/configmap.yaml | 2 +- charts/wire-server/templates/brig/tests/brig-integration.yaml | 2 +- charts/wire-server/templates/brig/tests/configmap.yaml | 2 +- charts/wire-server/templates/brig/tests/nginz-service.yaml | 2 +- charts/wire-server/templates/brig/tests/secret.yaml | 2 +- charts/wire-server/templates/cargohold/tests/configmap.yaml | 2 +- charts/wire-server/templates/galley/tests/configmap.yaml | 2 +- .../wire-server/templates/galley/tests/galley-integration.yaml | 2 +- charts/wire-server/templates/galley/tests/secret.yaml | 2 +- charts/wire-server/templates/gundeck/tests/configmap.yaml | 2 +- charts/wire-server/templates/spar/tests/configmap.yaml | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/charts/backoffice/templates/tests/configmap.yaml b/charts/backoffice/templates/tests/configmap.yaml index a20785b354e..b4bff0a2e03 100644 --- a/charts/backoffice/templates/tests/configmap.yaml +++ b/charts/backoffice/templates/tests/configmap.yaml @@ -3,7 +3,7 @@ kind: ConfigMap metadata: name: "stern-integration" annotations: - "helm.sh/hook": post-install + "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-delete-policy": before-hook-creation data: integration.yaml: | diff --git a/charts/federator/templates/tests/configmap.yaml b/charts/federator/templates/tests/configmap.yaml index 44146840bd4..faa1a05b28e 100644 --- a/charts/federator/templates/tests/configmap.yaml +++ b/charts/federator/templates/tests/configmap.yaml @@ -3,7 +3,7 @@ kind: ConfigMap metadata: name: "federator-integration" annotations: - "helm.sh/hook": post-install + "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-delete-policy": before-hook-creation data: integration.yaml: | diff --git a/charts/wire-server/templates/brig/tests/brig-integration.yaml b/charts/wire-server/templates/brig/tests/brig-integration.yaml index c2c9372217b..ce8eeadc0fd 100644 --- a/charts/wire-server/templates/brig/tests/brig-integration.yaml +++ b/charts/wire-server/templates/brig/tests/brig-integration.yaml @@ -3,7 +3,7 @@ kind: Service metadata: name: "brig-integration" annotations: - "helm.sh/hook": post-install + "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-delete-policy": before-hook-creation labels: app: brig-integration diff --git a/charts/wire-server/templates/brig/tests/configmap.yaml b/charts/wire-server/templates/brig/tests/configmap.yaml index e7540dc7c59..b327f32dbde 100644 --- a/charts/wire-server/templates/brig/tests/configmap.yaml +++ b/charts/wire-server/templates/brig/tests/configmap.yaml @@ -3,7 +3,7 @@ kind: ConfigMap metadata: name: "brig-integration" annotations: - "helm.sh/hook": post-install + "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-delete-policy": before-hook-creation data: integration.yaml: | diff --git a/charts/wire-server/templates/brig/tests/nginz-service.yaml b/charts/wire-server/templates/brig/tests/nginz-service.yaml index 6eda016c82d..b7895d51415 100644 --- a/charts/wire-server/templates/brig/tests/nginz-service.yaml +++ b/charts/wire-server/templates/brig/tests/nginz-service.yaml @@ -6,7 +6,7 @@ kind: Service metadata: name: nginz-integration-http annotations: - "helm.sh/hook": post-install + "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-delete-policy": before-hook-creation spec: type: ClusterIP diff --git a/charts/wire-server/templates/brig/tests/secret.yaml b/charts/wire-server/templates/brig/tests/secret.yaml index 86177dd7d3e..5bda33f6be2 100644 --- a/charts/wire-server/templates/brig/tests/secret.yaml +++ b/charts/wire-server/templates/brig/tests/secret.yaml @@ -8,7 +8,7 @@ metadata: release: "{{ .Release.Name }}" heritage: "{{ .Release.Service }}" annotations: - "helm.sh/hook": post-install + "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-delete-policy": before-hook-creation type: Opaque data: diff --git a/charts/wire-server/templates/cargohold/tests/configmap.yaml b/charts/wire-server/templates/cargohold/tests/configmap.yaml index 1542a14aa06..71a5db1bc33 100644 --- a/charts/wire-server/templates/cargohold/tests/configmap.yaml +++ b/charts/wire-server/templates/cargohold/tests/configmap.yaml @@ -3,7 +3,7 @@ kind: ConfigMap metadata: name: "cargohold-integration" annotations: - "helm.sh/hook": post-install + "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-delete-policy": before-hook-creation data: integration.yaml: | diff --git a/charts/wire-server/templates/galley/tests/configmap.yaml b/charts/wire-server/templates/galley/tests/configmap.yaml index 86be4122364..deb81aaeabb 100644 --- a/charts/wire-server/templates/galley/tests/configmap.yaml +++ b/charts/wire-server/templates/galley/tests/configmap.yaml @@ -3,7 +3,7 @@ kind: ConfigMap metadata: name: "galley-integration" annotations: - "helm.sh/hook": post-install + "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-delete-policy": before-hook-creation data: integration.yaml: | diff --git a/charts/wire-server/templates/galley/tests/galley-integration.yaml b/charts/wire-server/templates/galley/tests/galley-integration.yaml index 9256af1db6a..6135bff3878 100644 --- a/charts/wire-server/templates/galley/tests/galley-integration.yaml +++ b/charts/wire-server/templates/galley/tests/galley-integration.yaml @@ -3,7 +3,7 @@ kind: Service metadata: name: "galley-integration" annotations: - "helm.sh/hook": post-install + "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-delete-policy": before-hook-creation labels: app: galley-integration diff --git a/charts/wire-server/templates/galley/tests/secret.yaml b/charts/wire-server/templates/galley/tests/secret.yaml index b204dd4eddc..cf8e2e04d0c 100644 --- a/charts/wire-server/templates/galley/tests/secret.yaml +++ b/charts/wire-server/templates/galley/tests/secret.yaml @@ -8,7 +8,7 @@ metadata: release: "{{ .Release.Name }}" heritage: "{{ .Release.Service }}" annotations: - "helm.sh/hook": post-install + "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-delete-policy": before-hook-creation type: Opaque data: diff --git a/charts/wire-server/templates/gundeck/tests/configmap.yaml b/charts/wire-server/templates/gundeck/tests/configmap.yaml index acba48d7f16..c8c23ce5185 100644 --- a/charts/wire-server/templates/gundeck/tests/configmap.yaml +++ b/charts/wire-server/templates/gundeck/tests/configmap.yaml @@ -3,7 +3,7 @@ kind: ConfigMap metadata: name: "gundeck-integration" annotations: - "helm.sh/hook": post-install + "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-delete-policy": before-hook-creation data: integration.yaml: | diff --git a/charts/wire-server/templates/spar/tests/configmap.yaml b/charts/wire-server/templates/spar/tests/configmap.yaml index 2eb1966099a..9cc5c79b796 100644 --- a/charts/wire-server/templates/spar/tests/configmap.yaml +++ b/charts/wire-server/templates/spar/tests/configmap.yaml @@ -3,7 +3,7 @@ kind: ConfigMap metadata: name: "spar-integration" annotations: - "helm.sh/hook": post-install + "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-delete-policy": before-hook-creation data: integration.yaml: | From 6a7771597693edcbebbf6790eb9e91a0d01ac834 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 18 Mar 2026 15:08:37 +0100 Subject: [PATCH 19/79] use type: ClusterIP on gateway instead of LoadBlancer, use port 10443 --- charts/federator/templates/tests/configmap.yaml | 4 ++-- charts/federator/values.yaml | 4 ++++ charts/wire-ingress/templates/envoyproxy.yaml | 12 ++++++++++++ .../templates/federation-test-helper.yaml | 14 +++++++++++++- charts/wire-ingress/templates/gateway.yaml | 12 +++++++++++- charts/wire-ingress/values.yaml | 10 +++++++++- hack/bin/integration-setup-federation.sh | 8 ++++---- hack/helm_vars/wire-ingress/values.yaml.gotmpl | 7 +++++++ hack/helm_vars/wire-server/values.yaml.gotmpl | 3 ++- 9 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 charts/wire-ingress/templates/envoyproxy.yaml diff --git a/charts/federator/templates/tests/configmap.yaml b/charts/federator/templates/tests/configmap.yaml index faa1a05b28e..4612ab2a3c5 100644 --- a/charts/federator/templates/tests/configmap.yaml +++ b/charts/federator/templates/tests/configmap.yaml @@ -23,6 +23,6 @@ data: host: cargohold port: 8080 nginxIngress: - host: federation-test-helper.{{ .Release.Namespace }}.svc.cluster.local + host: {{ .Values.tests.nginxIngressHost }} port: 443 - originDomain: federation-test-helper.{{ .Release.Namespace }}.svc.cluster.local + originDomain: {{ .Values.tests.nginxIngressHost }} diff --git a/charts/federator/values.yaml b/charts/federator/values.yaml index 6632fb21429..c0285e52d8c 100644 --- a/charts/federator/values.yaml +++ b/charts/federator/values.yaml @@ -57,6 +57,10 @@ podSecurityContext: type: RuntimeDefault tests: + # The host used for the nginxIngress endpoint and originDomain in the integration + # test config. Depends on the release name of the "wire-ingress" helm chart + # (see federation-test-helper.yaml in that chart). + nginxIngressHost: "set-me" config: {} # config: # uploadXml: diff --git a/charts/wire-ingress/templates/envoyproxy.yaml b/charts/wire-ingress/templates/envoyproxy.yaml new file mode 100644 index 00000000000..299c53986f9 --- /dev/null +++ b/charts/wire-ingress/templates/envoyproxy.yaml @@ -0,0 +1,12 @@ +{{- if (and .Values.gateway.create (ne .Values.gateway.serviceType "LoadBalancer")) }} +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyProxy +metadata: + name: {{ include "wire-ingress.getGatewayName" . | quote }} +spec: + provider: + type: Kubernetes + kubernetes: + envoyService: + type: {{ .Values.gateway.serviceType | quote }} +{{- end }} diff --git a/charts/wire-ingress/templates/federation-test-helper.yaml b/charts/wire-ingress/templates/federation-test-helper.yaml index 2c1542d1f0a..6ac17bd0200 100644 --- a/charts/wire-ingress/templates/federation-test-helper.yaml +++ b/charts/wire-ingress/templates/federation-test-helper.yaml @@ -8,6 +8,18 @@ # 2. An ExternalName Service named federation-test-helper in the release namespace. # This creates the SRV record that Wire federation discovery expects: # _wire-server-federator._tcp.federation-test-helper..svc.cluster.local +# +# targetPort must match the port the Envoy proxy pod actually listens on. +# When gateway.listeners.https.port is privileged (<1024), Envoy Gateway remaps it +# by adding 10000 on the container (e.g. 443→10443). Set gateway.listeners.https.port +# to the actual container port in your values (e.g. 10443) to avoid this. +# To find the real port: kubectl -n envoy-gateway-system get svc \ +# -l gateway.envoyproxy.io/owning-gateway-namespace= \ +# -o jsonpath='{.items[0].spec.ports[?(@.name=="https-443")].targetPort}' +{{- $httpsPort := int .Values.gateway.listeners.https.port }} +{{- if and (lt $httpsPort 1024) (not .Values.federator.skipPrivilegedPortCheck) }} +{{- fail (printf "federation-test-helper: gateway.listeners.https.port is %d (privileged, <1024). Envoy Gateway remaps it to %d on the proxy pod. Set gateway.listeners.https.port to the actual container port (e.g. %d). To bypass set federator.skipPrivilegedPortCheck: true." $httpsPort (add $httpsPort 10000) (add $httpsPort 10000)) }} +{{- end }} apiVersion: v1 kind: Service metadata: @@ -19,7 +31,7 @@ spec: - name: wire-server-federator port: 443 protocol: TCP - targetPort: 443 + targetPort: {{ $httpsPort }} selector: gateway.envoyproxy.io/owning-gateway-name: {{ include "wire-ingress.getGatewayName" . }} gateway.envoyproxy.io/owning-gateway-namespace: {{ .Release.Namespace }} diff --git a/charts/wire-ingress/templates/gateway.yaml b/charts/wire-ingress/templates/gateway.yaml index 13b8fdb9131..ae8a12fc5ca 100644 --- a/charts/wire-ingress/templates/gateway.yaml +++ b/charts/wire-ingress/templates/gateway.yaml @@ -12,10 +12,20 @@ metadata: heritage: "{{ .Release.Service }}" spec: gatewayClassName: {{ .Values.gateway.className | quote }} - {{- if .Values.gateway.infrastructure.annotations }} + {{- $hasAnnotations := .Values.gateway.infrastructure.annotations }} + {{- $hasEnvoyProxy := ne .Values.gateway.serviceType "LoadBalancer" }} + {{- if (or $hasAnnotations $hasEnvoyProxy) }} infrastructure: + {{- if $hasAnnotations }} annotations: {{- toYaml .Values.gateway.infrastructure.annotations | nindent 6 }} + {{- end }} + {{- if $hasEnvoyProxy }} + parametersRef: + group: gateway.envoyproxy.io + kind: EnvoyProxy + name: {{ include "wire-ingress.getGatewayName" . | quote }} + {{- end }} {{- end }} listeners: - name: https diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index 283abf259c3..844ed6a42fa 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -7,7 +7,11 @@ gateway: name: "" # Name of the GatewayClass installed by the Envoy Gateway controller. className: "" - # Annotations to add to the LoadBalancer Service created by Envoy Gateway. + # Service type for the Envoy proxy Service created by Envoy Gateway. + # Use ClusterIP for in-cluster-only access (e.g. integration tests). + # Defaults to LoadBalancer (Envoy Gateway's default behaviour, no EnvoyProxy resource created). + serviceType: LoadBalancer + # Annotations to add to the Service created by Envoy Gateway. # Requires Gateway API CRDs v1.1+. # Example for AWS NLB: # infrastructure: @@ -84,6 +88,10 @@ service: federator: enabled: false integrationTestHelper: false + # Set to true to bypass the privileged-port check in federation-test-helper.yaml. + # Needed if Envoy Gateway's port remapping behaviour changes or a custom setup + # binds the proxy directly on a privileged port. + skipPrivilegedPortCheck: false tls: # If true, a cert-manager Certificate is created for the federator TLS secret. # Independent of the global tls.useCertManager setting. diff --git a/hack/bin/integration-setup-federation.sh b/hack/bin/integration-setup-federation.sh index 1dfaccc42ee..9ebbb46173e 100755 --- a/hack/bin/integration-setup-federation.sh +++ b/hack/bin/integration-setup-federation.sh @@ -28,12 +28,12 @@ mkdir -p ~/.parallel && touch ~/.parallel/will-cite printf '%s\n' "${charts[@]}" | parallel -P "${HELM_PARALLELISM}" "$DIR/update.sh" "$CHARTS_DIR/{}" export NAMESPACE_1="$NAMESPACE" -export FEDERATION_DOMAIN_BASE_1="$NAMESPACE_1.svc.cluster.local" -export FEDERATION_DOMAIN_1="federation-test-helper.$FEDERATION_DOMAIN_BASE_1" +export FEDERATION_DOMAIN_BASE_1="envoy-gateway-system.svc.cluster.local" +export FEDERATION_DOMAIN_1="${NAMESPACE_1}-fed.${FEDERATION_DOMAIN_BASE_1}" export NAMESPACE_2="$NAMESPACE-fed2" -export FEDERATION_DOMAIN_BASE_2="$NAMESPACE_2.svc.cluster.local" -export FEDERATION_DOMAIN_2="federation-test-helper.$FEDERATION_DOMAIN_BASE_2" +export FEDERATION_DOMAIN_BASE_2="envoy-gateway-system.svc.cluster.local" +export FEDERATION_DOMAIN_2="${NAMESPACE_2}-fed.${FEDERATION_DOMAIN_BASE_2}" echo "Fetch federation-ca secret from cert-manager namespace" FEDERATION_CA_CERTIFICATE=$(kubectl -n cert-manager get secrets federation-ca -o json -o jsonpath="{.data['tls\.crt']}" | base64 -d) diff --git a/hack/helm_vars/wire-ingress/values.yaml.gotmpl b/hack/helm_vars/wire-ingress/values.yaml.gotmpl index f0a9ce48c5d..259807d6a63 100644 --- a/hack/helm_vars/wire-ingress/values.yaml.gotmpl +++ b/hack/helm_vars/wire-ingress/values.yaml.gotmpl @@ -19,6 +19,13 @@ tls: gateway: className: "envoy" + serviceType: ClusterIP + listeners: + https: + # Envoy Gateway remaps privileged ports (+10000) on the proxy pod container. + # We use 10443 directly so targetPort in federation-test-helper matches the + # actual container port without needing a separate override. + port: 10443 config: dns: diff --git a/hack/helm_vars/wire-server/values.yaml.gotmpl b/hack/helm_vars/wire-server/values.yaml.gotmpl index fe0a19d0682..dd149ae0dd1 100644 --- a/hack/helm_vars/wire-server/values.yaml.gotmpl +++ b/hack/helm_vars/wire-server/values.yaml.gotmpl @@ -614,8 +614,9 @@ federator: optSettings: useSystemCAStore: false logLevel: Debug - {{- if .Values.uploadXml }} tests: + nginxIngressHost: {{ .Values.federationDomain1 }} + {{- if .Values.uploadXml }} config: uploadXml: baseUrl: {{ .Values.uploadXml.baseUrl }} From 47888ec44164e3ef0c14f36a37951a03959598b5 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 18 Mar 2026 15:37:06 +0100 Subject: [PATCH 20/79] make mtls client cert validation optional at the ingress level this lets the federator throw the appropiate error when a cert is missing. this is what the backend expects --- charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml b/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml index c42df606b28..0b21f785526 100644 --- a/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml +++ b/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml @@ -17,6 +17,7 @@ spec: sectionName: federator tls: clientValidation: + optional: true caCertificateRefs: - name: federator-ca kind: ConfigMap From ae2bd530a7550dcffb853bab9d69ef6aab668b31 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 18 Mar 2026 15:38:47 +0100 Subject: [PATCH 21/79] add todo --- charts/wire-ingress/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 5f5ec2a5643..2a336f2767e 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -592,6 +592,7 @@ selector: Adjust `templates/federation-test-helper.yaml` if the actual labels differ. - [ ] Done +- [ ] deal with the federation ingresses for the dynamic backends. remove them? they are not needed. or set up the same way as federation (but no test) --- From f3f6d8810dacad17e001c4049bfded447b8274f0 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Thu, 19 Mar 2026 15:50:36 +0100 Subject: [PATCH 22/79] support sharing envoyproxy objects --- charts/wire-ingress/README.md | 18 ++++++++ charts/wire-ingress/templates/envoyproxy.yaml | 10 ++++- charts/wire-ingress/templates/gateway.yaml | 22 ++++++--- charts/wire-ingress/values.yaml | 45 +++++++++++++++++-- .../helm_vars/wire-ingress/values.yaml.gotmpl | 1 + 5 files changed, 85 insertions(+), 11 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 2a336f2767e..f0d9b49e190 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -30,6 +30,24 @@ separately. The default values create the Gateway. The default `gateway.name` is derived from the release name, so that self-referencing is consistent by default. +### EnvoyProxy resource + +The chart creates an `EnvoyProxy` resource (when `gateway.envoyProxy.create: true`) and wires it +to the `Gateway` via `infrastructure.parametersRef`. Use `gateway.envoyProxy.spec` to pass +arbitrary fields from the [EnvoyProxySpec](https://gateway.envoyproxy.io/docs/api/extension_types/#envoyproxyspec). + +Set `gateway.envoyProxy.create: false` when a shared `EnvoyProxy` is managed at the +`GatewayClass` level (e.g. shared load balancer across deployments) — leave `gateway.envoyProxy.name` +empty and the Gateway will have no `infrastructure.parametersRef`, letting the `GatewayClass`-level +`EnvoyProxy` take effect automatically. + +Set `gateway.envoyProxy.name` (with `create: false`) to reference an existing `EnvoyProxy` in the +**same namespace** via `infrastructure.parametersRef`. + +`gateway.manageServiceType: true` (default) is a shorthand that sets +`provider.kubernetes.envoyService.type` to `gateway.serviceType`. Disable it when managing +the service type via `envoyProxy.spec` or a cluster-level `EnvoyProxy`. + ### GatewayClass is not created `GatewayClass` is installed by the Envoy Gateway Helm chart and is cluster-scoped. This chart only diff --git a/charts/wire-ingress/templates/envoyproxy.yaml b/charts/wire-ingress/templates/envoyproxy.yaml index 299c53986f9..3a3829e54cc 100644 --- a/charts/wire-ingress/templates/envoyproxy.yaml +++ b/charts/wire-ingress/templates/envoyproxy.yaml @@ -1,12 +1,18 @@ -{{- if (and .Values.gateway.create (ne .Values.gateway.serviceType "LoadBalancer")) }} +{{- if (and .Values.gateway.create .Values.gateway.envoyProxy.create) }} +{{- $name := .Values.gateway.envoyProxy.name | default (include "wire-ingress.getGatewayName" .) }} apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyProxy metadata: - name: {{ include "wire-ingress.getGatewayName" . | quote }} + name: {{ $name | quote }} spec: + {{- with .Values.gateway.envoyProxy.spec }} + {{- toYaml . | nindent 2 }} + {{- end }} + {{- if .Values.gateway.manageServiceType }} provider: type: Kubernetes kubernetes: envoyService: type: {{ .Values.gateway.serviceType | quote }} + {{- end }} {{- end }} diff --git a/charts/wire-ingress/templates/gateway.yaml b/charts/wire-ingress/templates/gateway.yaml index ae8a12fc5ca..16b40ebcf50 100644 --- a/charts/wire-ingress/templates/gateway.yaml +++ b/charts/wire-ingress/templates/gateway.yaml @@ -12,25 +12,32 @@ metadata: heritage: "{{ .Release.Service }}" spec: gatewayClassName: {{ .Values.gateway.className | quote }} - {{- $hasAnnotations := .Values.gateway.infrastructure.annotations }} - {{- $hasEnvoyProxy := ne .Values.gateway.serviceType "LoadBalancer" }} - {{- if (or $hasAnnotations $hasEnvoyProxy) }} + {{- $envoyProxyName := "" }} + {{- if .Values.gateway.envoyProxy.create }} + {{- $envoyProxyName = .Values.gateway.envoyProxy.name | default (include "wire-ingress.getGatewayName" .) }} + {{- else if .Values.gateway.envoyProxy.name }} + {{- $envoyProxyName = .Values.gateway.envoyProxy.name }} + {{- end }} + {{- if (or .Values.gateway.infrastructure.annotations $envoyProxyName) }} infrastructure: - {{- if $hasAnnotations }} + {{- if .Values.gateway.infrastructure.annotations }} annotations: {{- toYaml .Values.gateway.infrastructure.annotations | nindent 6 }} {{- end }} - {{- if $hasEnvoyProxy }} + {{- if $envoyProxyName }} parametersRef: group: gateway.envoyproxy.io kind: EnvoyProxy - name: {{ include "wire-ingress.getGatewayName" . | quote }} + name: {{ $envoyProxyName | quote }} {{- end }} {{- end }} listeners: - name: https port: {{ .Values.gateway.listeners.https.port }} protocol: HTTPS + {{- if .Values.gateway.listeners.https.hostname }} + hostname: {{ .Values.gateway.listeners.https.hostname | quote }} + {{- end }} tls: mode: Terminate certificateRefs: @@ -51,5 +58,8 @@ spec: - name: http port: {{ .Values.gateway.listeners.http.port }} protocol: HTTP + {{- if .Values.gateway.listeners.http.hostname }} + hostname: {{ .Values.gateway.listeners.http.hostname | quote }} + {{- end }} {{- end }} {{- end }} diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index 844ed6a42fa..a3448110039 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -7,9 +7,38 @@ gateway: name: "" # Name of the GatewayClass installed by the Envoy Gateway controller. className: "" - # Service type for the Envoy proxy Service created by Envoy Gateway. - # Use ClusterIP for in-cluster-only access (e.g. integration tests). - # Defaults to LoadBalancer (Envoy Gateway's default behaviour, no EnvoyProxy resource created). + envoyProxy: + # If true, an EnvoyProxy resource is created by this chart and the Gateway + # references it via infrastructure.parametersRef. + # Set to false when the GatewayClass already has a cluster-level EnvoyProxy + # (e.g. a shared load balancer managed by the cluster operator), or when you + # want to reference an existing EnvoyProxy via envoyProxy.name. + create: true + # Name of the EnvoyProxy resource. + # When create: true — the created resource uses this name (defaults to the Gateway name). + # When create: false — if non-empty, the Gateway references this existing EnvoyProxy + # via infrastructure.parametersRef (must be in the same namespace). + # If empty, no parametersRef is set on the Gateway (GatewayClass + # level EnvoyProxy takes effect). + name: "" + # Free-form EnvoyProxy spec, merged verbatim at the spec root. + # Only used when create: true. + # See https://gateway.envoyproxy.io/docs/api/extension_types/#envoyproxyspec + # Example - shared load balancer across Gateways (single wire-ingress chart): + # spec: + # mergeGateways: true + # Example - ClusterIP service (integration tests / no external LB): + # spec: + # provider: + # type: Kubernetes + # kubernetes: + # envoyService: + # type: ClusterIP + spec: {} + # Convenience shorthand for provider.kubernetes.envoyService.type. + # Only takes effect when manageServiceType: true. + # Do not combine with envoyProxy.spec.provider.kubernetes.envoyService. + manageServiceType: true serviceType: LoadBalancer # Annotations to add to the Service created by Envoy Gateway. # Requires Gateway API CRDs v1.1+. @@ -31,12 +60,22 @@ gateway: listeners: https: port: 443 + # Optional hostname restriction for the HTTPS listener. + # Required when using mergeGateways (shared EnvoyProxy across deployments) to avoid + # listener hostname conflicts. Set to a wildcard covering this deployment's domains, + # e.g. "*.example.com". + # If your domains in config.dns are not under the same subdomain, you need create + # a custom Gateway object for your use case, with multiple listeners. See the Gateway API docs. + hostname: "" # Enable the HTTP listener if you want to use HTTP01 challenges via cert-manager's # gatewayHTTPRoute solver. Requires cert-manager >= 1.14. # See the README for configuration details. http: enabled: false port: 80 + # Optional hostname restriction for the HTTP listener. Set alongside + # listeners.https.hostname when using mergeGateways. + hostname: "" # NOTE: Please provide names. Here are naming suggestions: # You need to reference those in the nginz helm chart nginx_conf.deeplink.endpoints diff --git a/hack/helm_vars/wire-ingress/values.yaml.gotmpl b/hack/helm_vars/wire-ingress/values.yaml.gotmpl index 259807d6a63..fe4267bc629 100644 --- a/hack/helm_vars/wire-ingress/values.yaml.gotmpl +++ b/hack/helm_vars/wire-ingress/values.yaml.gotmpl @@ -19,6 +19,7 @@ tls: gateway: className: "envoy" + manageServiceType: true serviceType: ClusterIP listeners: https: From 91c7f98d4d8182cacbc74384fd99d14917655a87 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Thu, 19 Mar 2026 16:05:47 +0100 Subject: [PATCH 23/79] remove skipPriviledgedPortCheck --- charts/wire-ingress/templates/federation-test-helper.yaml | 4 ++-- charts/wire-ingress/values.yaml | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/charts/wire-ingress/templates/federation-test-helper.yaml b/charts/wire-ingress/templates/federation-test-helper.yaml index 6ac17bd0200..abc9feabff5 100644 --- a/charts/wire-ingress/templates/federation-test-helper.yaml +++ b/charts/wire-ingress/templates/federation-test-helper.yaml @@ -17,8 +17,8 @@ # -l gateway.envoyproxy.io/owning-gateway-namespace= \ # -o jsonpath='{.items[0].spec.ports[?(@.name=="https-443")].targetPort}' {{- $httpsPort := int .Values.gateway.listeners.https.port }} -{{- if and (lt $httpsPort 1024) (not .Values.federator.skipPrivilegedPortCheck) }} -{{- fail (printf "federation-test-helper: gateway.listeners.https.port is %d (privileged, <1024). Envoy Gateway remaps it to %d on the proxy pod. Set gateway.listeners.https.port to the actual container port (e.g. %d). To bypass set federator.skipPrivilegedPortCheck: true." $httpsPort (add $httpsPort 10000) (add $httpsPort 10000)) }} +{{- if lt $httpsPort 1024 }} +{{- fail (printf "federation-test-helper: gateway.listeners.https.port is %d (privileged, <1024). Envoy Gateway remaps it to %d on the proxy pod. Set gateway.listeners.https.port to the actual container port (e.g. %d)." $httpsPort (add $httpsPort 10000) (add $httpsPort 10000)) }} {{- end }} apiVersion: v1 kind: Service diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index a3448110039..cb4a8ef304c 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -127,10 +127,6 @@ service: federator: enabled: false integrationTestHelper: false - # Set to true to bypass the privileged-port check in federation-test-helper.yaml. - # Needed if Envoy Gateway's port remapping behaviour changes or a custom setup - # binds the proxy directly on a privileged port. - skipPrivilegedPortCheck: false tls: # If true, a cert-manager Certificate is created for the federator TLS secret. # Independent of the global tls.useCertManager setting. From 0772c5a139ff1b05451d3ccb1afde314bb08de05 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Thu, 19 Mar 2026 16:24:25 +0100 Subject: [PATCH 24/79] integration chart: remove ingress (and service targeting ingress) why remove? No integration tests actually cover these ingresses --- charts/integration/templates/_helpers.tpl | 4 --- charts/integration/templates/ingress.yaml | 32 ----------------------- charts/integration/templates/service.yaml | 23 ---------------- charts/integration/values.yaml | 9 ------- charts/wire-ingress/README.md | 1 + 5 files changed, 1 insertion(+), 68 deletions(-) delete mode 100644 charts/integration/templates/ingress.yaml diff --git a/charts/integration/templates/_helpers.tpl b/charts/integration/templates/_helpers.tpl index e3a33787bf9..a28d98b601d 100644 --- a/charts/integration/templates/_helpers.tpl +++ b/charts/integration/templates/_helpers.tpl @@ -8,10 +8,6 @@ {{- (semverCompare ">= 1.24-0" (include "kubeVersion" .)) -}} {{- end -}} -{{- define "integrationTestHelperNewLabels" -}} - {{- (semverCompare ">= 1.23-0" (include "kubeVersion" .)) -}} -{{- end -}} - {{- define "useCassandraTLS" -}} {{ or (hasKey .cassandra "tlsCa") (hasKey .cassandra "tlsCaSecretRef") }} {{- end -}} diff --git a/charts/integration/templates/ingress.yaml b/charts/integration/templates/ingress.yaml deleted file mode 100644 index 362b7b0d8f9..00000000000 --- a/charts/integration/templates/ingress.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{- range $name, $dynamicBackend := .Values.config.dynamicBackends }} ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: integration-federator-{{ $name }} - annotations: - nginx.ingress.kubernetes.io/ssl-redirect: "true" - nginx.ingress.kubernetes.io/backend-protocol: "HTTP" - nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" - nginx.ingress.kubernetes.io/auth-tls-verify-depth: "{{ $.Values.tls.verify_depth }}" - nginx.ingress.kubernetes.io/auth-tls-secret: "{{ or $.Values.tls.caNamespace $.Release.Namespace }}/federator-ca-secret" - nginx.ingress.kubernetes.io/configuration-snippet: | - proxy_set_header "X-SSL-Certificate" $ssl_client_escaped_cert; -spec: - ingressClassName: "{{ $.Values.ingress.class }}" - tls: - - hosts: - - {{ $dynamicBackend.federatorExternalHostPrefix }}.{{ $.Release.Namespace }}.svc.cluster.local - secretName: federator-certificate-secret - rules: - - host: {{ $dynamicBackend.federatorExternalHostPrefix }}.{{ $.Release.Namespace }}.svc.cluster.local - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: integration - port: - number: {{ $dynamicBackend.federatorExternalPort }} -{{- end }} diff --git a/charts/integration/templates/service.yaml b/charts/integration/templates/service.yaml index 350b33f11f7..e29b66d9700 100644 --- a/charts/integration/templates/service.yaml +++ b/charts/integration/templates/service.yaml @@ -1,4 +1,3 @@ -{{- $newLabels := eq (include "integrationTestHelperNewLabels" .) "true" -}} --- apiVersion: v1 kind: Service @@ -27,25 +26,3 @@ spec: app: integration-integration type: ClusterIP -{{- range $name, $dynamicBackend := .Values.config.dynamicBackends }} ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ $dynamicBackend.federatorExternalHostPrefix }} -spec: - ports: - - name: wire-server-federator - port: 443 - protocol: TCP - targetPort: https - selector: - {{- if $newLabels }} - app.kubernetes.io/component: controller - app.kubernetes.io/name: ingress-nginx - {{- else }} - app: nginx-ingress - component: controller - {{- end }} - type: ClusterIP -{{- end }} diff --git a/charts/integration/values.yaml b/charts/integration/values.yaml index 36305b2be75..89c05abd91d 100644 --- a/charts/integration/values.yaml +++ b/charts/integration/values.yaml @@ -120,13 +120,4 @@ config: s3EndpointUrl: http://fake-aws-s3:9000 rabbitmqPutVHostUrl: http://rabbitmq:15672/api/vhosts -tls: - verify_depth: 1 - # Namespace from which to obtain the secret containing the CA trusted by - # federator. - # caNamespace: wire-federation-v0 - -ingress: - class: nginx - secrets: {} diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index f0d9b49e190..585fb1062b1 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -475,6 +475,7 @@ integration tests. Uses `app.kubernetes.io/` labels on Kubernetes >= 1.23, legac otherwise. - [ ] Done +- [x] delete the unused Ingress from the "integration" chart Notes: From 59a3fd2b8d4fb57002610e9cc1d072bd40f64854 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Thu, 19 Mar 2026 16:27:11 +0100 Subject: [PATCH 25/79] complete todo --- charts/wire-ingress/README.md | 105 +--------------------------------- 1 file changed, 3 insertions(+), 102 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 585fb1062b1..ec8302d6a59 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -474,7 +474,7 @@ A ClusterIP service targeting the ingress controller pod, used for SRV-based dis integration tests. Uses `app.kubernetes.io/` labels on Kubernetes >= 1.23, legacy labels otherwise. -- [ ] Done +- [x] Done - [x] delete the unused Ingress from the "integration" chart Notes: @@ -501,8 +501,6 @@ The federator will use the "federation" ClusterIssuer to obtain a cert. Wire uses a SRV records to look up the federator domain of a domain. This is what federation-test-helper is used for. The SRV record on the service targets the ingress deployment pods which are ingressing the federator. - - --- ### Phase 7 — Switch integration tests to wire-ingress @@ -513,105 +511,8 @@ The integration test setup deploys two federation namespaces (`namespace1`, `nam with their own ingress release. Both currently use `nginx-ingress-services`. The goal is to make integration tests pass with `wire-ingress` in place of `nginx-ingress-services`. -#### Overview of changes - -Files to update: - -| File | Change | -|---|---| -| `hack/helmfile.yaml.gotmpl` | Replace two `ingress-svc` release blocks | -| `hack/helmfile-federation-v0.yaml.gotmpl` | Replace one `ingress-svc` release block | -| `hack/bin/integration-setup-federation.sh` | Replace `nginx-ingress-services` in `charts` array with `wire-ingress` | -| `hack/helm_vars/nginx-ingress-services/values.yaml.gotmpl` | Keep for reference; create `hack/helm_vars/wire-ingress/values.yaml.gotmpl` | - -#### Step 1 — Create `hack/helm_vars/wire-ingress/values.yaml.gotmpl` - -Adapt from the existing nginx-ingress-services values. Key changes: - -- Remove `config.ingressClass` → replace with `gateway.className` pointing to the Envoy GatewayClass -- Remove `secrets.tlsClientCA` (dropped — `federator-ca` ConfigMap is created by the wire-server chart) -- Add `federator.tls.useCertManager: true` with `federator.tls.issuer.name: federation` / - `federator.tls.issuer.kind: ClusterIssuer` - -The wire-ingress chart creates the cert at `federator-certificate-secret` (our default -`federator.tls.secretName`) via cert-manager using the `federation` ClusterIssuer. The federator -chart reads the same secret (via `useSharedFederatorSecret: true`). This is how both charts share -the same mTLS cert. - -Expected values: -```yaml -teamSettings: - enabled: true -accountPages: - enabled: true -federator: - enabled: true - integrationTestHelper: true - tls: - useCertManager: true - issuer: - name: federation - kind: ClusterIssuer -tls: - useCertManager: true - issuer: - name: federation - kind: ClusterIssuer - createIssuer: false - caNamespace: wire-federation-v0 -gateway: - className: "envoy" -config: - dns: - https: "nginz-https.{{ .Release.Namespace }}-integration.example.com" - ssl: "nginz-ssl.{{ .Release.Namespace }}-integration.example.com" - webapp: "webapp.{{ .Release.Namespace }}-integration.example.com" - fakeS3: "assets.{{ .Release.Namespace }}-integration.example.com" - teamSettings: "teams.{{ .Release.Namespace }}-integration.example.com" - accountPages: "account.{{ .Release.Namespace }}-integration.example.com" - # federator: dynamically set by helmfile - # certificateDomain: dynamically set by helmfile -``` - -#### Step 2 — Update `hack/helmfile.yaml.gotmpl` - -In both `ingress-svc` release blocks (namespace1 and namespace2): -- Change `chart` from `../.local/charts/nginx-ingress-services` to `../.local/charts/wire-ingress` -- Change `values` from `./helm_vars/nginx-ingress-services/values.yaml.gotmpl` to `./helm_vars/wire-ingress/values.yaml.gotmpl` -- Review the `needs: ['ingress']` dependency — `ingress` refers to the nginx-ingress-controller - release. With wire-ingress there is no nginx controller; this dependency should be removed or - replaced with the Envoy Gateway release if it is managed by this helmfile. - -#### Step 3 — Update `hack/helmfile-federation-v0.yaml.gotmpl` - -The `ingress-svc` release currently pins `wire/nginx-ingress-services` at a specific version. -Replace with a local chart reference (same as helmfile.yaml.gotmpl): -- Change `chart` to `../.local/charts/wire-ingress` -- Change `values` to `./helm_vars/wire-ingress/values.yaml.gotmpl` - -#### Step 4 — Update `hack/bin/integration-setup-federation.sh` - -Line 25: replace `nginx-ingress-services` with `wire-ingress` in the `charts` array. - -#### Step 5 — Verify federation-test-helper pod selector - -After the first deployment, check the actual labels on the Envoy Gateway proxy pods: - -```bash -kubectl get pods -n --show-labels | grep envoy -``` - -The template currently uses: -```yaml -selector: - gateway.envoyproxy.io/owning-gateway-name: - gateway.envoyproxy.io/owning-gateway-namespace: -``` - -Adjust `templates/federation-test-helper.yaml` if the actual labels differ. - -- [ ] Done -- [ ] deal with the federation ingresses for the dynamic backends. remove them? they are not needed. or set up the same way as federation (but no test) +- [x] Done +- [x] deal with the federation ingresses for the dynamic backends. remove them? they are not needed. or set up the same way as federation (but no test) --- From b0931a13b847ff836640f270f8134313bbcbaebf Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Thu, 19 Mar 2026 16:37:45 +0100 Subject: [PATCH 26/79] drop customSolversSecrets --- charts/wire-ingress/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index ec8302d6a59..9bcebc7d4e9 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -124,6 +124,7 @@ Operators should be able to reuse most of their existing values files with minim | `tls.verify_depth` | Envoy Gateway `ClientTrafficPolicy` does not expose a direct verify-depth knob; the CA chain itself controls this | | `tls.enabled` | This is removed since it didnt ahve any effect. All ingresses are always defined with TLS. | | `secrets.tlsClientCA` | No longer supplied via values. The `federator-ca` ConfigMap is created by the wire-server chart and referenced directly. | +| `secrets.certManager.customSolversSecret` | No longer supported by the chart. Please create a custom Issuer in case you need to handle secrets. | ### Fully backwards compatible values @@ -175,7 +176,6 @@ All keys below are accepted unchanged. Their names, types, and semantics are ide | `config.dns.accountPages` | | | `secrets.tlsWildcardCert` | | | `secrets.tlsWildcardKey` | | -| `secrets.certManager.customSolversSecret` | | ### Behaviour changes @@ -525,7 +525,8 @@ Template: `templates/custom-solvers-secret.yaml` An opaque Secret containing credentials for custom ACME challenge solvers, referenced by `certManager.customSolvers`. -- [ ] Done +- [x] Drop this functionality and document this +- [x] Done --- From 8f74de5b73285f91d88631c9b5ce2820db4cd33d Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Thu, 19 Mar 2026 16:39:11 +0100 Subject: [PATCH 27/79] update README --- charts/wire-ingress/README.md | 168 +++++++++++++++++----------------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 9bcebc7d4e9..93cc130e7fc 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -12,92 +12,9 @@ The chart targets **Envoy Gateway** as the Gateway API controller. --- -## Design decisions - -### Gateway API controller: Envoy Gateway - -The chart targets [Envoy Gateway](https://gateway.envoyproxy.io/). Implementation-specific -resources (`ClientTrafficPolicy`, `SecurityPolicy`, `HTTPRouteFilter` with `directResponse`) are -used where the standard Gateway API has gaps. These resources are clearly marked in each template. - -### Gateway creation is optional - -The chart can optionally create a `Gateway` resource (controlled by `gateway.create: true`). -When `gateway.create: false`, all `HTTPRoute` and policy resources still reference the gateway by -name (`gateway.name`). This allows operators to share a Gateway across multiple charts or manage it -separately. - -The default values create the Gateway. The default `gateway.name` is derived from the release name, -so that self-referencing is consistent by default. - -### EnvoyProxy resource - -The chart creates an `EnvoyProxy` resource (when `gateway.envoyProxy.create: true`) and wires it -to the `Gateway` via `infrastructure.parametersRef`. Use `gateway.envoyProxy.spec` to pass -arbitrary fields from the [EnvoyProxySpec](https://gateway.envoyproxy.io/docs/api/extension_types/#envoyproxyspec). - -Set `gateway.envoyProxy.create: false` when a shared `EnvoyProxy` is managed at the -`GatewayClass` level (e.g. shared load balancer across deployments) — leave `gateway.envoyProxy.name` -empty and the Gateway will have no `infrastructure.parametersRef`, letting the `GatewayClass`-level -`EnvoyProxy` take effect automatically. - -Set `gateway.envoyProxy.name` (with `create: false`) to reference an existing `EnvoyProxy` in the -**same namespace** via `infrastructure.parametersRef`. - -`gateway.manageServiceType: true` (default) is a shorthand that sets -`provider.kubernetes.envoyService.type` to `gateway.serviceType`. Disable it when managing -the service type via `envoyProxy.spec` or a cluster-level `EnvoyProxy`. - -### GatewayClass is not created - -`GatewayClass` is installed by the Envoy Gateway Helm chart and is cluster-scoped. This chart only -references it by name via `gateway.className`. - -### Multi-ingress is out of scope - -Single-domain deployments are the only supported topology. Multi-domain support can be added later. - -### HTTP01 certificate challenges - -cert-manager can complete ACME HTTP01 challenges through the Gateway using the `gatewayHTTPRoute` -solver (cert-manager >= 1.14). The **default solver** in this chart uses `gatewayHTTPRoute` — it -requires the HTTP listener to be enabled: - -```yaml -gateway: - listeners: - http: - enabled: true # required for HTTP01 challenges -``` - -If you cannot or do not want to open port 80, use a DNS01 solver instead by setting - -```yaml -certManager: - customSolvers: - - dns01: - # .. provider-specific settings -``` - -DNS01 requires credentials for your DNS provider but does not need -port 80 to be open. - -### Federator mTLS uses Envoy Gateway policies - -Federator mTLS is implemented using: - -- `ClientTrafficPolicy` to configure TLS settings on the federator `Gateway` listener (client - certificate validation, verify depth) -- A separate `Gateway` listener (or dedicated `Gateway`) for the federator so that mTLS settings - apply only to that listener -- The `X-SSL-Certificate` header forwarding is handled via Envoy Gateway's `HTTPRouteFilter` with - request header injection from the client cert (implementation-specific) - ---- - ## Backwards compatibility -The chart preserves the `values.yaml` structure of `nginx-ingress-services` wherever possible. +The chart preserves the `values.yaml` structure of the `nginx-ingress-services` chart wherever possible. Operators should be able to reuse most of their existing values files with minimal changes. ### Renamed / restructured values @@ -186,6 +103,89 @@ All keys below are accepted unchanged. Their names, types, and semantics are ide | Federator client cert header | `nginx.ingress.kubernetes.io/configuration-snippet` setting `X-SSL-Certificate` | Envoy Gateway `ClientTrafficPolicy` + `HTTPRouteFilter` header injection | | Websocket routing | Separate host with port name `ws` | Same `HTTPRoute` — WebSocket upgrades are handled transparently by Envoy | + +## Design decisions + +### Gateway API controller: Envoy Gateway + +The chart targets [Envoy Gateway](https://gateway.envoyproxy.io/). Implementation-specific +resources (`ClientTrafficPolicy`, `SecurityPolicy`, `HTTPRouteFilter` with `directResponse`) are +used where the standard Gateway API has gaps. These resources are clearly marked in each template. + +### Gateway creation is optional + +The chart can optionally create a `Gateway` resource (controlled by `gateway.create: true`). +When `gateway.create: false`, all `HTTPRoute` and policy resources still reference the gateway by +name (`gateway.name`). This allows operators to share a Gateway across multiple charts or manage it +separately. + +The default values create the Gateway. The default `gateway.name` is derived from the release name, +so that self-referencing is consistent by default. + +### EnvoyProxy resource + +The chart creates an `EnvoyProxy` resource (when `gateway.envoyProxy.create: true`) and wires it +to the `Gateway` via `infrastructure.parametersRef`. Use `gateway.envoyProxy.spec` to pass +arbitrary fields from the [EnvoyProxySpec](https://gateway.envoyproxy.io/docs/api/extension_types/#envoyproxyspec). + +Set `gateway.envoyProxy.create: false` when a shared `EnvoyProxy` is managed at the +`GatewayClass` level (e.g. shared load balancer across deployments) — leave `gateway.envoyProxy.name` +empty and the Gateway will have no `infrastructure.parametersRef`, letting the `GatewayClass`-level +`EnvoyProxy` take effect automatically. + +Set `gateway.envoyProxy.name` (with `create: false`) to reference an existing `EnvoyProxy` in the +**same namespace** via `infrastructure.parametersRef`. + +`gateway.manageServiceType: true` (default) is a shorthand that sets +`provider.kubernetes.envoyService.type` to `gateway.serviceType`. Disable it when managing +the service type via `envoyProxy.spec` or a cluster-level `EnvoyProxy`. + +### GatewayClass is not created + +`GatewayClass` is installed by the Envoy Gateway Helm chart and is cluster-scoped. This chart only +references it by name via `gateway.className`. + +### Multi-ingress is out of scope + +Single-domain deployments are the only supported topology. Multi-domain support can be added later. + +### HTTP01 certificate challenges + +cert-manager can complete ACME HTTP01 challenges through the Gateway using the `gatewayHTTPRoute` +solver (cert-manager >= 1.14). The **default solver** in this chart uses `gatewayHTTPRoute` — it +requires the HTTP listener to be enabled: + +```yaml +gateway: + listeners: + http: + enabled: true # required for HTTP01 challenges +``` + +If you cannot or do not want to open port 80, use a DNS01 solver instead by setting + +```yaml +certManager: + customSolvers: + - dns01: + # .. provider-specific settings +``` + +DNS01 requires credentials for your DNS provider but does not need +port 80 to be open. + +### Federator mTLS uses Envoy Gateway policies + +Federator mTLS is implemented using: + +- `ClientTrafficPolicy` to configure TLS settings on the federator `Gateway` listener (client + certificate validation, verify depth) +- A separate `Gateway` listener (or dedicated `Gateway`) for the federator so that mTLS settings + apply only to that listener +- The `X-SSL-Certificate` header forwarding is handled via Envoy Gateway's `HTTPRouteFilter` with + request header injection from the client cert (implementation-specific) + +--- --- ## Testing strategy From abf7f54065fe45bf2676fe05e1ea3b12410265fb Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Thu, 19 Mar 2026 17:01:37 +0100 Subject: [PATCH 28/79] add TODO --- charts/wire-ingress/README.md | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 93cc130e7fc..bf0872312bf 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -17,6 +17,11 @@ The chart targets **Envoy Gateway** as the Gateway API controller. The chart preserves the `values.yaml` structure of the `nginx-ingress-services` chart wherever possible. Operators should be able to reuse most of their existing values files with minimal changes. +### Behaviour changes + +* non-tls ingress disabled by default. If you want to make use of automated certificate validation via http01, you need `gateway.listeners.http.enabled: true` +* s3 ingress b`/minio/` path blocking. Returns 301 redirect to "/" (was 403). + ### Renamed / restructured values | Old key | New key | Notes | @@ -39,7 +44,7 @@ Operators should be able to reuse most of their existing values files with minim | `config.dns.base` | Only used for CSP header rendering, which is a multi-ingress feature | | `kubeVersionOverride` | Deprecated; the federation-test-helper label selector no longer needs a version override | | `tls.verify_depth` | Envoy Gateway `ClientTrafficPolicy` does not expose a direct verify-depth knob; the CA chain itself controls this | -| `tls.enabled` | This is removed since it didnt ahve any effect. All ingresses are always defined with TLS. | +| `tls.enabled` | This is removed since it didn't have any effect. All ingresses are always defined with TLS. | | `secrets.tlsClientCA` | No longer supplied via values. The `federator-ca` ConfigMap is created by the wire-server chart and referenced directly. | | `secrets.certManager.customSolversSecret` | No longer supported by the chart. Please create a custom Issuer in case you need to handle secrets. | @@ -94,15 +99,6 @@ All keys below are accepted unchanged. Their names, types, and semantics are ide | `secrets.tlsWildcardCert` | | | `secrets.tlsWildcardKey` | | -### Behaviour changes - -| Feature | Old behaviour | New behaviour | -|---|---|---| -| Default ACME solver | `http01.ingress.class: nginx` | `http01.gatewayHTTPRoute` targeting this chart's Gateway — requires `gateway.listeners.http.enabled: true` | -| `/minio/` path blocking | nginx `server-snippet` returning 403 | `RequestRedirect` to `/` (301) — standard Gateway API | -| Federator client cert header | `nginx.ingress.kubernetes.io/configuration-snippet` setting `X-SSL-Certificate` | Envoy Gateway `ClientTrafficPolicy` + `HTTPRouteFilter` header injection | -| Websocket routing | Separate host with port name `ws` | Same `HTTPRoute` — WebSocket upgrades are handled transparently by Envoy | - ## Design decisions @@ -513,6 +509,7 @@ integration tests pass with `wire-ingress` in place of `nginx-ingress-services`. - [x] Done - [x] deal with the federation ingresses for the dynamic backends. remove them? they are not needed. or set up the same way as federation (but no test) +- [ ] fix integration test setup so all test pass --- From 76a48ee8e2c91ad55740e63274a1a8ddd5d06d95 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Thu, 19 Mar 2026 17:41:57 +0100 Subject: [PATCH 29/79] integration tests: fix originDomains --- charts/integration/templates/configmap.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/integration/templates/configmap.yaml b/charts/integration/templates/configmap.yaml index 82fc9895284..3420cf8284a 100644 --- a/charts/integration/templates/configmap.yaml +++ b/charts/integration/templates/configmap.yaml @@ -77,7 +77,7 @@ data: apiPort: 5380 dohPort: 5381 - originDomain: federation-test-helper.{{ .Release.Namespace }}.svc.cluster.local + originDomain: {{ .Release.Namespace }}-fed.envoy-gateway-system.svc.cluster.local rabbitmq: host: rabbitmq @@ -158,7 +158,7 @@ data: rabbitMqVHost: / - originDomain: federation-test-helper.{{ .Release.Namespace }}-fed2.svc.cluster.local + originDomain: {{ .Release.Namespace }}-fed2-fed.envoy-gateway-system.svc.cluster.local dynamicBackends: {{- range $name, $dynamicBackend := .Values.config.dynamicBackends }} From 2b1fa537b5a7781d1eee69c04b611cf3a4a13102 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Fri, 20 Mar 2026 10:17:31 +0100 Subject: [PATCH 30/79] add go.sh --- go.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100755 go.sh diff --git a/go.sh b/go.sh new file mode 100755 index 00000000000..a7093084332 --- /dev/null +++ b/go.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -xe + +export HELM_DATA_HOME=$(mktemp -d) +export HELM_CONFIG_HOME=$(mktemp -d) +export HELM_CACHE_HOME=$(mktemp -d) + +make clean-charts + +NAMESPACE=test-stefan-2 DOCKER_TAG=5.27.0 make kube-integration-setup + +NAMESPACE=test-stefan-2 DOCKER_TAG=5.27.0 HELM_PARALLELISM=0 make kube-integration-test From ed723b656ba4e79886e6d2a3f9b19dbd070dfdc1 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Fri, 20 Mar 2026 15:26:09 +0100 Subject: [PATCH 31/79] force explicit hostnames in gateway listeners --- charts/wire-ingress/templates/gateway.yaml | 4 +--- charts/wire-ingress/values.yaml | 14 ++++++++------ hack/helm_vars/wire-ingress/values.yaml.gotmpl | 5 +++++ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/charts/wire-ingress/templates/gateway.yaml b/charts/wire-ingress/templates/gateway.yaml index 16b40ebcf50..93ece9a7506 100644 --- a/charts/wire-ingress/templates/gateway.yaml +++ b/charts/wire-ingress/templates/gateway.yaml @@ -35,9 +35,7 @@ spec: - name: https port: {{ .Values.gateway.listeners.https.port }} protocol: HTTPS - {{- if .Values.gateway.listeners.https.hostname }} - hostname: {{ .Values.gateway.listeners.https.hostname | quote }} - {{- end }} + hostname: {{ required "gateway.listeners.https.hostname is required (see values.yaml for details)" .Values.gateway.listeners.https.hostname | quote }} tls: mode: Terminate certificateRefs: diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index cb4a8ef304c..e96d1c4bf40 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -60,12 +60,14 @@ gateway: listeners: https: port: 443 - # Optional hostname restriction for the HTTPS listener. - # Required when using mergeGateways (shared EnvoyProxy across deployments) to avoid - # listener hostname conflicts. Set to a wildcard covering this deployment's domains, - # e.g. "*.example.com". - # If your domains in config.dns are not under the same subdomain, you need create - # a custom Gateway object for your use case, with multiple listeners. See the Gateway API docs. + # Required. Hostname restriction for the HTTPS listener. + # Must be a wildcard or exact hostname covering this deployment's domains, + # e.g. "*.example.com". This prevents OverlappingTLSConfig with the federator + # listener (which uses the federation domain on the same port) — without an + # explicit hostname both listeners are catch-all and Envoy degrades ALPN to + # HTTP/1.1-only. + # If your domains in config.dns span multiple subdomains, you need a custom + # Gateway object with multiple listeners. See the Gateway API docs. hostname: "" # Enable the HTTP listener if you want to use HTTP01 challenges via cert-manager's # gatewayHTTPRoute solver. Requires cert-manager >= 1.14. diff --git a/hack/helm_vars/wire-ingress/values.yaml.gotmpl b/hack/helm_vars/wire-ingress/values.yaml.gotmpl index fe4267bc629..45b4cb18d5d 100644 --- a/hack/helm_vars/wire-ingress/values.yaml.gotmpl +++ b/hack/helm_vars/wire-ingress/values.yaml.gotmpl @@ -27,6 +27,11 @@ gateway: # We use 10443 directly so targetPort in federation-test-helper matches the # actual container port without needing a separate override. port: 10443 + # Explicit hostname prevents OverlappingTLSConfig with the federator listener + # (which uses -fed.envoy-gateway-system.svc.cluster.local). + # Without this, both listeners are catch-all on the same port and Envoy + # forces HTTP/1.1-only ALPN, breaking HTTP/2 federation requests. + hostname: "*.{{ .Release.Namespace }}-integration.example.com" config: dns: From fa24187f1eb5701746c479dc9a3eed055fb2b1d3 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Fri, 20 Mar 2026 15:26:30 +0100 Subject: [PATCH 32/79] fix trailing dot problem of integration tests. Maybe we should strip the dot in the backend --- .../templates/envoypatchpolicy-federator.yaml | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 charts/wire-ingress/templates/envoypatchpolicy-federator.yaml diff --git a/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml b/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml new file mode 100644 index 00000000000..ec85ef0f5ab --- /dev/null +++ b/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml @@ -0,0 +1,33 @@ +{{- if .Values.federator.enabled }} +{{/* Envoy Gateway-specific (gateway.envoyproxy.io/v1alpha1). + Strips trailing dots from the :authority header on the federator listener + before virtual-host matching. Wire federator resolves federation targets + via DNS SRV lookups; Kubernetes DNS returns FQDNs with a trailing dot + (e.g. "foo.svc.cluster.local."). HTTP/2 passes that dot in :authority, + which does not match the listener's hostname (no trailing dot) → route_not_found. + strip_trailing_host_dot normalises the header before Envoy's route selection. */}} +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyPatchPolicy +metadata: + name: {{ include "wire-ingress.fullname" . }}-federator-strip-dot + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: {{ include "wire-ingress.getGatewayName" . | quote }} + type: JSONPatch + jsonPatches: + - type: "type.googleapis.com/envoy.config.listener.v3.Listener" + # The https and federator listeners share port 10443, so Envoy Gateway + # merges them into a single xDS listener named after the first section + # ("https"). The federator filter chain is at index 1 (https is index 0). + name: {{ printf "%s/%s/https" .Release.Namespace (include "wire-ingress.getGatewayName" .) | quote }} + operation: + op: add + path: "/filter_chains/1/filters/0/typed_config/strip_trailing_host_dot" + value: true +{{- end }} From d989c8d126c0c7b7a4cbe752a1861d0f1a023447 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Fri, 20 Mar 2026 15:34:29 +0100 Subject: [PATCH 33/79] remove unused ExternalName service from previous attempts --- charts/wire-ingress/README.md | 34 +++++-------------- charts/wire-ingress/templates/_helpers.tpl | 8 ----- .../templates/federation-test-helper.yaml | 31 ++++------------- 3 files changed, 14 insertions(+), 59 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index bf0872312bf..016c64d8044 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -42,7 +42,6 @@ Operators should be able to reuse most of their existing values files with minim | `config.isAdditionalIngress` | Multi-ingress out of scope | | `config.renderCSPInIngress` | Multi-ingress out of scope | | `config.dns.base` | Only used for CSP header rendering, which is a multi-ingress feature | -| `kubeVersionOverride` | Deprecated; the federation-test-helper label selector no longer needs a version override | | `tls.verify_depth` | Envoy Gateway `ClientTrafficPolicy` does not expose a direct verify-depth knob; the CA chain itself controls this | | `tls.enabled` | This is removed since it didn't have any effect. All ingresses are always defined with TLS. | | `secrets.tlsClientCA` | No longer supplied via values. The `federator-ca` ConfigMap is created by the wire-server chart and referenced directly. | @@ -466,36 +465,19 @@ header via an inline Lua filter, matching nginx's `$ssl_client_escaped_cert` beh Template: `templates/federation-test-helper.yaml` -A ClusterIP service targeting the ingress controller pod, used for SRV-based discovery in -integration tests. Uses `app.kubernetes.io/` labels on Kubernetes >= 1.23, legacy labels -otherwise. +A ClusterIP Service in `envoy-gateway-system` that selects the Envoy proxy pods for this +Gateway (using `gateway.envoyproxy.io/owning-gateway-*` labels). Because Envoy Gateway runs +proxy pods in its own namespace, a cross-namespace Service is needed to expose them for +DNS-based federation discovery. -- [x] Done -- [x] delete the unused Ingress from the "integration" chart - -Notes: - -This helper ties into the integration test setup. -Here's how the integration tests are set up with nginx-ingress-service. My goal is to make integration tests pass -when we deploy wire-ingress instead in place of nginx-ingress-servicess. - -The integration test are deployed via helmfile hack/helmfile.yaml.gotmpl +The service is named `-fed` and lives in `envoy-gateway-system`, so the SRV record +that Wire federation discovery resolves is: -The cluster in which the integration tests run has ClusterIssuer named "federation" that will sign any certs. - -From /home/stefan/repos/wire-server/hack/helm_vars/wire-server/values.yaml.gotmpl ``` -federator: - tls: - useCertManager: true - useSharedFederatorSecret: true +_wire-server-federator._tcp.-fed.envoy-gateway-system.svc.cluster.local ``` -we can see that the federator will assume that the cert used for both client and server auth is externally provide at secret "federator-certificate-secret" - -In the integration test setup 2 domains federationDomain1 and federationDomain2 are configured with a namespace . -The federator will use the "federation" ClusterIssuer to obtain a cert. -Wire uses a SRV records to look up the federator domain of a domain. This is what federation-test-helper is used for. The SRV record on the service targets the ingress deployment pods which are ingressing the federator. +- [x] Done --- diff --git a/charts/wire-ingress/templates/_helpers.tpl b/charts/wire-ingress/templates/_helpers.tpl index 4c5134addef..8a3edc6429a 100644 --- a/charts/wire-ingress/templates/_helpers.tpl +++ b/charts/wire-ingress/templates/_helpers.tpl @@ -73,11 +73,3 @@ Name of the Gateway resource. Uses gateway.name if set, otherwise derives one fr {{ include "wire-ingress.fullname" . }}-gateway {{- end -}} {{- end -}} - -{{/* -Whether to use new-style app.kubernetes.io labels for the federation-test-helper. -Kubernetes >= 1.23 uses app.kubernetes.io/*, older versions use app/component labels. -*/}} -{{- define "wire-ingress.integrationTestHelperNewLabels" -}} - {{- (semverCompare ">= 1.23-0" .Capabilities.KubeVersion.Version) -}} -{{- end -}} diff --git a/charts/wire-ingress/templates/federation-test-helper.yaml b/charts/wire-ingress/templates/federation-test-helper.yaml index abc9feabff5..5d12d75ad4e 100644 --- a/charts/wire-ingress/templates/federation-test-helper.yaml +++ b/charts/wire-ingress/templates/federation-test-helper.yaml @@ -1,21 +1,15 @@ {{- if (and .Values.federator.enabled .Values.federator.integrationTestHelper) }} -# Envoy Gateway runs proxy pods in its own namespace (envoy-gateway-system), not in the release -# namespace. Kubernetes Services cannot select pods across namespaces, so we need two resources: -# -# 1. A ClusterIP Service in envoy-gateway-system that selects our proxy pods by their -# owning-gateway labels (set by Envoy Gateway on all proxy pods it manages). -# -# 2. An ExternalName Service named federation-test-helper in the release namespace. -# This creates the SRV record that Wire federation discovery expects: -# _wire-server-federator._tcp.federation-test-helper..svc.cluster.local +# Envoy Gateway runs proxy pods in envoy-gateway-system, not in the release namespace. +# Kubernetes Services cannot select pods across namespaces, so we create a ClusterIP +# Service in envoy-gateway-system that selects the proxy pods by their owning-gateway +# labels (set by Envoy Gateway). This service becomes the SRV target for Wire federation +# discovery: +# _wire-server-federator._tcp.-fed.envoy-gateway-system.svc.cluster.local # # targetPort must match the port the Envoy proxy pod actually listens on. # When gateway.listeners.https.port is privileged (<1024), Envoy Gateway remaps it # by adding 10000 on the container (e.g. 443→10443). Set gateway.listeners.https.port # to the actual container port in your values (e.g. 10443) to avoid this. -# To find the real port: kubectl -n envoy-gateway-system get svc \ -# -l gateway.envoyproxy.io/owning-gateway-namespace= \ -# -o jsonpath='{.items[0].spec.ports[?(@.name=="https-443")].targetPort}' {{- $httpsPort := int .Values.gateway.listeners.https.port }} {{- if lt $httpsPort 1024 }} {{- fail (printf "federation-test-helper: gateway.listeners.https.port is %d (privileged, <1024). Envoy Gateway remaps it to %d on the proxy pod. Set gateway.listeners.https.port to the actual container port (e.g. %d)." $httpsPort (add $httpsPort 10000) (add $httpsPort 10000)) }} @@ -35,17 +29,4 @@ spec: selector: gateway.envoyproxy.io/owning-gateway-name: {{ include "wire-ingress.getGatewayName" . }} gateway.envoyproxy.io/owning-gateway-namespace: {{ .Release.Namespace }} ---- -apiVersion: v1 -kind: Service -metadata: - name: federation-test-helper - namespace: {{ .Release.Namespace }} -spec: - type: ExternalName - externalName: {{ .Release.Namespace }}-fed.envoy-gateway-system.svc.cluster.local - ports: - - name: wire-server-federator - port: 443 - protocol: TCP {{- end }} From b23471b390c46096eddba33c809fe7b808b8fe88 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Fri, 20 Mar 2026 15:56:03 +0100 Subject: [PATCH 34/79] Revert "integration chart: remove ingress (and service targeting ingress)" This reverts commit 39d75a9bdd5d7cf7e6e4e5bf438f9b9921fe93be. --- charts/integration/templates/_helpers.tpl | 4 +++ charts/integration/templates/ingress.yaml | 32 +++++++++++++++++++ .../templates/integration-integration.yaml | 2 +- charts/integration/templates/service.yaml | 23 +++++++++++++ charts/integration/values.yaml | 9 ++++++ 5 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 charts/integration/templates/ingress.yaml diff --git a/charts/integration/templates/_helpers.tpl b/charts/integration/templates/_helpers.tpl index a28d98b601d..e3a33787bf9 100644 --- a/charts/integration/templates/_helpers.tpl +++ b/charts/integration/templates/_helpers.tpl @@ -8,6 +8,10 @@ {{- (semverCompare ">= 1.24-0" (include "kubeVersion" .)) -}} {{- end -}} +{{- define "integrationTestHelperNewLabels" -}} + {{- (semverCompare ">= 1.23-0" (include "kubeVersion" .)) -}} +{{- end -}} + {{- define "useCassandraTLS" -}} {{ or (hasKey .cassandra "tlsCa") (hasKey .cassandra "tlsCaSecretRef") }} {{- end -}} diff --git a/charts/integration/templates/ingress.yaml b/charts/integration/templates/ingress.yaml new file mode 100644 index 00000000000..362b7b0d8f9 --- /dev/null +++ b/charts/integration/templates/ingress.yaml @@ -0,0 +1,32 @@ +{{- range $name, $dynamicBackend := .Values.config.dynamicBackends }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: integration-federator-{{ $name }} + annotations: + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-verify-depth: "{{ $.Values.tls.verify_depth }}" + nginx.ingress.kubernetes.io/auth-tls-secret: "{{ or $.Values.tls.caNamespace $.Release.Namespace }}/federator-ca-secret" + nginx.ingress.kubernetes.io/configuration-snippet: | + proxy_set_header "X-SSL-Certificate" $ssl_client_escaped_cert; +spec: + ingressClassName: "{{ $.Values.ingress.class }}" + tls: + - hosts: + - {{ $dynamicBackend.federatorExternalHostPrefix }}.{{ $.Release.Namespace }}.svc.cluster.local + secretName: federator-certificate-secret + rules: + - host: {{ $dynamicBackend.federatorExternalHostPrefix }}.{{ $.Release.Namespace }}.svc.cluster.local + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: integration + port: + number: {{ $dynamicBackend.federatorExternalPort }} +{{- end }} diff --git a/charts/integration/templates/integration-integration.yaml b/charts/integration/templates/integration-integration.yaml index 7ebad70c179..f2cb1dac05b 100644 --- a/charts/integration/templates/integration-integration.yaml +++ b/charts/integration/templates/integration-integration.yaml @@ -188,7 +188,7 @@ spec: - | set -euo pipefail - if integration --config /etc/wire/integration/integration.yaml; then + if integration --config /etc/wire/integration/integration.yaml --include 'MLS.Unreachable.testAddUnreachableUserFromFederatingBackend'; then exit_code=$? else exit_code=$? diff --git a/charts/integration/templates/service.yaml b/charts/integration/templates/service.yaml index e29b66d9700..350b33f11f7 100644 --- a/charts/integration/templates/service.yaml +++ b/charts/integration/templates/service.yaml @@ -1,3 +1,4 @@ +{{- $newLabels := eq (include "integrationTestHelperNewLabels" .) "true" -}} --- apiVersion: v1 kind: Service @@ -26,3 +27,25 @@ spec: app: integration-integration type: ClusterIP +{{- range $name, $dynamicBackend := .Values.config.dynamicBackends }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ $dynamicBackend.federatorExternalHostPrefix }} +spec: + ports: + - name: wire-server-federator + port: 443 + protocol: TCP + targetPort: https + selector: + {{- if $newLabels }} + app.kubernetes.io/component: controller + app.kubernetes.io/name: ingress-nginx + {{- else }} + app: nginx-ingress + component: controller + {{- end }} + type: ClusterIP +{{- end }} diff --git a/charts/integration/values.yaml b/charts/integration/values.yaml index 89c05abd91d..36305b2be75 100644 --- a/charts/integration/values.yaml +++ b/charts/integration/values.yaml @@ -120,4 +120,13 @@ config: s3EndpointUrl: http://fake-aws-s3:9000 rabbitmqPutVHostUrl: http://rabbitmq:15672/api/vhosts +tls: + verify_depth: 1 + # Namespace from which to obtain the secret containing the CA trusted by + # federator. + # caNamespace: wire-federation-v0 + +ingress: + class: nginx + secrets: {} From 62df1dd2c45a0fb76fd07a6915ead3e72163f32d Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Mon, 23 Mar 2026 10:23:27 +0100 Subject: [PATCH 35/79] wip integration envoy --- charts/integration/templates/_helpers.tpl | 27 ++++ charts/integration/templates/configmap.yaml | 2 +- .../integration/templates/ingress-envoy.yaml | 153 ++++++++++++++++++ .../{ingress.yaml => ingress-nginx.yaml} | 23 +++ .../templates/integration-integration.yaml | 2 +- charts/integration/templates/service.yaml | 24 --- charts/integration/values.yaml | 20 +++ hack/helm_vars/wire-server/values.yaml.gotmpl | 6 +- 8 files changed, 229 insertions(+), 28 deletions(-) create mode 100644 charts/integration/templates/ingress-envoy.yaml rename charts/integration/templates/{ingress.yaml => ingress-nginx.yaml} (70%) diff --git a/charts/integration/templates/_helpers.tpl b/charts/integration/templates/_helpers.tpl index e3a33787bf9..a20ddfd9c14 100644 --- a/charts/integration/templates/_helpers.tpl +++ b/charts/integration/templates/_helpers.tpl @@ -1,4 +1,31 @@ +{{/* +Name of the Gateway resource for dynamic backends in envoy mode. +*/}} +{{- define "integration.getDynBackendsGatewayName" -}} +{{- if .Values.envoy.gateway.name -}} +{{ .Values.envoy.gateway.name }} +{{- else -}} +{{ .Release.Name }}-dynamic-backends +{{- end -}} +{{- end -}} + +{{/* +Domain for a dynamic backend. Returns the correct hostname depending on whether +envoy mode is enabled. +Args: list $dynamicBackend $namespace $envoyEnabled +*/}} +{{- define "integration.dynamicBackendDomain" -}} +{{- $dynamicBackend := index . 0 -}} +{{- $namespace := index . 1 -}} +{{- $envoyEnabled := index . 2 -}} +{{- if $envoyEnabled -}} +{{- printf "%s-%s.envoy-gateway-system.svc.cluster.local" $dynamicBackend.federatorExternalHostPrefix $namespace -}} +{{- else -}} +{{- printf "%s.%s.svc.cluster.local" $dynamicBackend.federatorExternalHostPrefix $namespace -}} +{{- end -}} +{{- end -}} + {{/* Allow KubeVersion to be overridden. */}} {{- define "kubeVersion" -}} {{- default $.Capabilities.KubeVersion.Version $.Values.kubeVersionOverride -}} diff --git a/charts/integration/templates/configmap.yaml b/charts/integration/templates/configmap.yaml index 3420cf8284a..fef7cc524e1 100644 --- a/charts/integration/templates/configmap.yaml +++ b/charts/integration/templates/configmap.yaml @@ -163,7 +163,7 @@ data: dynamicBackends: {{- range $name, $dynamicBackend := .Values.config.dynamicBackends }} {{ $name }}: - domain: {{ $dynamicBackend.federatorExternalHostPrefix }}.{{ $.Release.Namespace }}.svc.cluster.local + domain: {{ include "integration.dynamicBackendDomain" (list $dynamicBackend $.Release.Namespace $.Values.envoy.enabled) }} federatorExternalPort: {{ $dynamicBackend.federatorExternalPort }} mlsPrivateKeyPaths: removal: diff --git a/charts/integration/templates/ingress-envoy.yaml b/charts/integration/templates/ingress-envoy.yaml new file mode 100644 index 00000000000..8e7980c8279 --- /dev/null +++ b/charts/integration/templates/ingress-envoy.yaml @@ -0,0 +1,153 @@ +{{- if .Values.envoy.enabled }} +{{- $gatewayName := include "integration.getDynBackendsGatewayName" . }} +{{- $httpsPort := int .Values.envoy.gateway.listeners.https.port }} +{{- if lt $httpsPort 1024 }} +{{- fail (printf "envoy.gateway.listeners.https.port is %d (privileged, <1024). Envoy Gateway remaps it to %d on the proxy pod. Set envoy.gateway.listeners.https.port to the actual container port (e.g. %d)." $httpsPort (add $httpsPort 10000) (add $httpsPort 10000)) }} +{{- end }} +--- +# EnvoyProxy configures the proxy deployment/service for the dynamic-backends Gateway. +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyProxy +metadata: + name: {{ $gatewayName }} +spec: + provider: + type: Kubernetes + kubernetes: + envoyService: + # ClusterIP: no external load balancer needed for in-cluster integration tests. + type: ClusterIP +--- +# Gateway for all dynamic backends. A single HTTPS listener covers all backend hostnames. +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: {{ $gatewayName }} +spec: + gatewayClassName: {{ required "envoy.gateway.className is required when envoy.enabled is true" .Values.envoy.gateway.className | quote }} + infrastructure: + parametersRef: + group: gateway.envoyproxy.io + kind: EnvoyProxy + name: {{ $gatewayName | quote }} + listeners: + - name: https + port: {{ $httpsPort }} + protocol: HTTPS + tls: + mode: Terminate + certificateRefs: + - name: {{ .Values.envoy.federator.tls.secretName | quote }} + kind: Secret +--- +# ClientTrafficPolicy enforces optional mTLS client cert validation on all dynamic-backend +# connections (mirrors the nginx auth-tls-verify-client: "on" annotation). +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: ClientTrafficPolicy +metadata: + name: {{ $gatewayName }}-mtls +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: {{ $gatewayName | quote }} + sectionName: https + tls: + clientValidation: + optional: true + caCertificateRefs: + - name: federator-ca + kind: ConfigMap +--- +# EnvoyPatchPolicy strips the trailing dot that Kubernetes DNS appends to FQDNs. +# Wire federator resolves targets via SRV and sends the raw FQDN (with trailing dot) +# as the HTTP/2 :authority header; strip_trailing_host_dot normalises it before +# Envoy's virtual-host matching, preventing route_not_found errors. +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyPatchPolicy +metadata: + name: {{ $gatewayName }}-strip-dot +spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: {{ $gatewayName | quote }} + type: JSONPatch + jsonPatches: + - type: "type.googleapis.com/envoy.config.listener.v3.Listener" + # Single HTTPS listener → only one filter chain at index 0. + name: {{ printf "%s/%s/https" .Release.Namespace $gatewayName | quote }} + operation: + op: add + path: "/filter_chains/0/filters/0/typed_config/strip_trailing_host_dot" + value: true +{{- range $name, $dynamicBackend := .Values.config.dynamicBackends }} +{{- $httpRouteName := printf "%s-dynbackend-%s" $gatewayName $name }} +{{- $svcDomain := printf "%s-%s.envoy-gateway-system.svc.cluster.local" $dynamicBackend.federatorExternalHostPrefix $.Release.Namespace }} +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ $httpRouteName }} +spec: + parentRefs: + - name: {{ $gatewayName | quote }} + namespace: {{ $.Release.Namespace | quote }} + kind: Gateway + sectionName: https + hostnames: + - {{ $svcDomain | quote }} + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: integration + port: {{ $dynamicBackend.federatorExternalPort }} + kind: Service +--- +# EnvoyExtensionPolicy injects the mTLS client certificate as X-SSL-Certificate request +# header, matching the nginx $ssl_client_escaped_cert behaviour expected by federator. +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyExtensionPolicy +metadata: + name: {{ $httpRouteName }}-cert-header +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: {{ $httpRouteName }} + lua: + - type: Inline + inline: | + function envoy_on_request(request_handle) + local ssl = request_handle:connection():ssl() + if ssl ~= nil then + local cert = ssl:urlEncodedPemEncodedPeerCertificate() + if cert ~= nil and cert ~= "" then + request_handle:headers():add("X-SSL-Certificate", cert) + end + end + end +--- +# ClusterIP service in envoy-gateway-system selects the Envoy proxy pods for this Gateway. +# The service name determines the SRV record used by federation discovery: +# _wire-server-federator._tcp.{{ $svcDomain }} +apiVersion: v1 +kind: Service +metadata: + name: {{ $dynamicBackend.federatorExternalHostPrefix }}-{{ $.Release.Namespace }} + namespace: envoy-gateway-system +spec: + type: ClusterIP + ports: + - name: wire-server-federator + port: 443 + protocol: TCP + targetPort: {{ $httpsPort }} + selector: + gateway.envoyproxy.io/owning-gateway-name: {{ $gatewayName }} + gateway.envoyproxy.io/owning-gateway-namespace: {{ $.Release.Namespace }} +{{- end }} +{{- end }} diff --git a/charts/integration/templates/ingress.yaml b/charts/integration/templates/ingress-nginx.yaml similarity index 70% rename from charts/integration/templates/ingress.yaml rename to charts/integration/templates/ingress-nginx.yaml index 362b7b0d8f9..81fc91013a1 100644 --- a/charts/integration/templates/ingress.yaml +++ b/charts/integration/templates/ingress-nginx.yaml @@ -1,3 +1,5 @@ +{{- if not .Values.envoy.enabled }} +{{- $newLabels := eq (include "integrationTestHelperNewLabels" .) "true" -}} {{- range $name, $dynamicBackend := .Values.config.dynamicBackends }} --- apiVersion: networking.k8s.io/v1 @@ -29,4 +31,25 @@ spec: name: integration port: number: {{ $dynamicBackend.federatorExternalPort }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ $dynamicBackend.federatorExternalHostPrefix }} +spec: + ports: + - name: wire-server-federator + port: 443 + protocol: TCP + targetPort: https + selector: + {{- if $newLabels }} + app.kubernetes.io/component: controller + app.kubernetes.io/name: ingress-nginx + {{- else }} + app: nginx-ingress + component: controller + {{- end }} + type: ClusterIP +{{- end }} {{- end }} diff --git a/charts/integration/templates/integration-integration.yaml b/charts/integration/templates/integration-integration.yaml index f2cb1dac05b..cc43ce1e58a 100644 --- a/charts/integration/templates/integration-integration.yaml +++ b/charts/integration/templates/integration-integration.yaml @@ -168,7 +168,7 @@ spec: integration-dynamic-backends-ses.sh {{ .Values.config.sesEndpointUrl }} integration-dynamic-backends-s3.sh {{ .Values.config.s3EndpointUrl }} {{- range $name, $dynamicBackend := .Values.config.dynamicBackends }} - integration-dynamic-backends-vhosts.sh {{ $.Values.config.rabbitmqPutVHostUrl }} {{ $dynamicBackend.federatorExternalHostPrefix}}.{{ $.Release.Namespace }}.svc.cluster.local + integration-dynamic-backends-vhosts.sh {{ $.Values.config.rabbitmqPutVHostUrl }} {{ include "integration.dynamicBackendDomain" (list $dynamicBackend $.Release.Namespace $.Values.envoy.enabled) }} {{- end }} resources: requests: diff --git a/charts/integration/templates/service.yaml b/charts/integration/templates/service.yaml index 350b33f11f7..a97d1e58c8e 100644 --- a/charts/integration/templates/service.yaml +++ b/charts/integration/templates/service.yaml @@ -1,4 +1,3 @@ -{{- $newLabels := eq (include "integrationTestHelperNewLabels" .) "true" -}} --- apiVersion: v1 kind: Service @@ -26,26 +25,3 @@ spec: selector: app: integration-integration type: ClusterIP - -{{- range $name, $dynamicBackend := .Values.config.dynamicBackends }} ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ $dynamicBackend.federatorExternalHostPrefix }} -spec: - ports: - - name: wire-server-federator - port: 443 - protocol: TCP - targetPort: https - selector: - {{- if $newLabels }} - app.kubernetes.io/component: controller - app.kubernetes.io/name: ingress-nginx - {{- else }} - app: nginx-ingress - component: controller - {{- end }} - type: ClusterIP -{{- end }} diff --git a/charts/integration/values.yaml b/charts/integration/values.yaml index 36305b2be75..a50ebd00c80 100644 --- a/charts/integration/values.yaml +++ b/charts/integration/values.yaml @@ -129,4 +129,24 @@ tls: ingress: class: nginx +envoy: + # Set to true to deploy Gateway API resources instead of nginx Ingress objects + # for the dynamic backends. Requires an Envoy Gateway controller in the cluster. + enabled: false + gateway: + # Name of the Gateway resource. Defaults to -dynamic-backends if empty. + name: "" + # Name of the GatewayClass installed by the Envoy Gateway controller (e.g. "envoy"). + className: "" + listeners: + https: + # Use a non-privileged port (>=1024) to avoid the +10000 container-port + # remapping applied by Envoy Gateway to privileged ports. + port: 10443 + federator: + tls: + # Name of the TLS Secret presented by the Gateway for the dynamic-backend + # listeners. Must exist before deploying (created by the wire-ingress chart). + secretName: "federator-certificate-secret" + secrets: {} diff --git a/hack/helm_vars/wire-server/values.yaml.gotmpl b/hack/helm_vars/wire-server/values.yaml.gotmpl index dd149ae0dd1..f85e8784152 100644 --- a/hack/helm_vars/wire-server/values.yaml.gotmpl +++ b/hack/helm_vars/wire-server/values.yaml.gotmpl @@ -680,8 +680,10 @@ background-worker: password: {{ .Values.rabbitmqPassword }} integration: - ingress: - class: "nginx-{{ .Release.Namespace }}" + envoy: + enabled: true + gateway: + className: "envoy" config: cassandra: host: {{ .Values.cassandraHost }} From d014c4fa701f377b6f86e52bbc6b0a17b80b9326 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Mon, 23 Mar 2026 14:49:48 +0100 Subject: [PATCH 36/79] fix (workaround): [emerg] 850#850: too long path in the unix domain socket --- integration/test/Testlib/ModService.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration/test/Testlib/ModService.hs b/integration/test/Testlib/ModService.hs index a28f3505365..d265786130f 100644 --- a/integration/test/Testlib/ModService.hs +++ b/integration/test/Testlib/ModService.hs @@ -650,7 +650,7 @@ prepareNginzRuntimeFiles resource = do prepareNginzK8sRuntimeFiles :: String -> ServiceMap -> IO (FilePath, FilePath, FilePath) prepareNginzK8sRuntimeFiles domain sm = do - tmpDir <- createTempDirectory "/tmp" ("nginz" <> "-" <> domain) + tmpDir <- createTempDirectory "/tmp" "nginz-" copyDirectoryRecursively "/etc/wire/nginz/" tmpDir let nginxConfFile = tmpDir "conf" "nginx.conf" @@ -674,7 +674,7 @@ prepareNginzLocalRuntimeFiles resource sm basedir = do -- Create a whole temporary directory and copy all nginx's config files. -- This is necessary because nginx assumes local imports are relative to -- the location of the main configuration file. - tmpDir <- createTempDirectory "/tmp" ("nginz" <> "-" <> domain) + tmpDir <- createTempDirectory "/tmp" "nginz-" -- copy all config files into the tmp dir let from = basedir "nginz" "integration-test" From 12c652e43c305b88e283316286b3b376d79f3559 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Mon, 23 Mar 2026 14:57:58 +0100 Subject: [PATCH 37/79] wip --- charts/integration/templates/integration-integration.yaml | 2 +- hack/bin/integration-test.sh | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/charts/integration/templates/integration-integration.yaml b/charts/integration/templates/integration-integration.yaml index cc43ce1e58a..2242e38fe09 100644 --- a/charts/integration/templates/integration-integration.yaml +++ b/charts/integration/templates/integration-integration.yaml @@ -188,7 +188,7 @@ spec: - | set -euo pipefail - if integration --config /etc/wire/integration/integration.yaml --include 'MLS.Unreachable.testAddUnreachableUserFromFederatingBackend'; then + if integration --config /etc/wire/integration/integration.yaml --include 'Demo.testDynamicBackend'; then exit_code=$? else exit_code=$? diff --git a/hack/bin/integration-test.sh b/hack/bin/integration-test.sh index 198750ee081..a0a0751d210 100755 --- a/hack/bin/integration-test.sh +++ b/hack/bin/integration-test.sh @@ -11,7 +11,10 @@ UPLOAD_LOGS=${UPLOAD_LOGS:-0} echo "Running integration tests on wire-server with parallelism=${HELM_PARALLELISM} ..." CHART=wire-server -tests=(integration stern galley cargohold gundeck federator spar brig) +# tests=(integration stern galley cargohold gundeck federator spar brig) +# tests=(federator) +tests=(federator integration) +# tests=(brig) cleanup() { if ((CLEANUP_LOCAL_FILES > 0)); then From 16ac8c7add09e748e2175e07fdd9f0fc819bcba8 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Mon, 23 Mar 2026 15:20:32 +0100 Subject: [PATCH 38/79] use new build in go.sh --- go.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go.sh b/go.sh index a7093084332..f4f17dcc470 100755 --- a/go.sh +++ b/go.sh @@ -8,6 +8,6 @@ export HELM_CACHE_HOME=$(mktemp -d) make clean-charts -NAMESPACE=test-stefan-2 DOCKER_TAG=5.27.0 make kube-integration-setup +NAMESPACE=test-stefan-2 DOCKER_TAG=0.0.2-pr.13994 make kube-integration-setup -NAMESPACE=test-stefan-2 DOCKER_TAG=5.27.0 HELM_PARALLELISM=0 make kube-integration-test +NAMESPACE=test-stefan-2 DOCKER_TAG=0.0.2-pr.13994 HELM_PARALLELISM=0 make kube-integration-test From 6ab8ec0466aa9f05795276b22b44eab74fdfd6d5 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Mon, 23 Mar 2026 15:30:13 +0100 Subject: [PATCH 39/79] run all tests --- charts/integration/templates/integration-integration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/integration/templates/integration-integration.yaml b/charts/integration/templates/integration-integration.yaml index 2242e38fe09..5ec9bea054e 100644 --- a/charts/integration/templates/integration-integration.yaml +++ b/charts/integration/templates/integration-integration.yaml @@ -188,7 +188,7 @@ spec: - | set -euo pipefail - if integration --config /etc/wire/integration/integration.yaml --include 'Demo.testDynamicBackend'; then + if integration --config /etc/wire/integration/integration.yaml; then exit_code=$? else exit_code=$? From 75795d1e84d9f5fa0dd4ebd7144978bde7e8d168 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 24 Mar 2026 09:49:29 +0100 Subject: [PATCH 40/79] add TODOs --- charts/wire-ingress/README.md | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 016c64d8044..0320bac66b6 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -511,13 +511,22 @@ An opaque Secret containing credentials for custom ACME challenge solvers, refer ### Phase 9 — Documentation and CI values -#### Finalize README, migration guide, and ci/ values files - -- Write the migration guide section of this README -- Create `ci/values-minimal.yaml`, `ci/values-full.yaml`, etc. -- Ensure `helm lint` and `helm template` pass for all CI values files - -- [ ] Done +#### Finalize PR + +- [ ] introduce a flag that switches between gateway / ingress-nginx in the tests +- [ ] investigate: migrate federation-test helper to integrations chart? +- [ ] replace "envoy-gateway-system" hardcoded namespace with chart var +- [ ] feature flag for envoypatch policies (enabled by default, turned off in tests) +- [ ] document: must deploy enovy-gateway with patches enabled +- [ ] envoy patch policies: adjust docs: its not a kubernetes problem, but that SRV records have to by FQDM +- [ ] for .Values.federator.tls.useCertManager document that you'll likely needa private CA, since many public CA stopped issuing client auth certs +- [ ] Write the migration guide section of this README +- [ ] collate the parameters and changes better +- [ ] move the phases out of README +- [ ] clean up PR: no stray files +- [ ] remove CLAUDE.md +- [ ] make a note on nginx-ingress-services +- [ ] create PR for the4 --- From a4f54a4ab8af9324b14fd349a50646339c2a636f Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 24 Mar 2026 10:36:11 +0100 Subject: [PATCH 41/79] make ingress mode configurable for integration tests --- charts/integration/templates/_helpers.tpl | 15 +++++ charts/integration/templates/configmap.yaml | 4 +- hack/bin/integration-setup-federation.sh | 20 ++++-- hack/helm_vars/wire-server/values.yaml.gotmpl | 6 +- hack/helmfile.yaml.gotmpl | 62 +++++++++---------- 5 files changed, 67 insertions(+), 40 deletions(-) diff --git a/charts/integration/templates/_helpers.tpl b/charts/integration/templates/_helpers.tpl index a20ddfd9c14..a2b6062eb2d 100644 --- a/charts/integration/templates/_helpers.tpl +++ b/charts/integration/templates/_helpers.tpl @@ -10,6 +10,21 @@ Name of the Gateway resource for dynamic backends in envoy mode. {{- end -}} {{- end -}} +{{/* +Federation origin domain for a given namespace (used as originDomain in the config). +Returns the SRV hostname that other backends use to reach this namespace's federator. +Args: list $namespace $envoyEnabled +*/}} +{{- define "integration.federationOriginDomain" -}} +{{- $namespace := index . 0 -}} +{{- $envoyEnabled := index . 1 -}} +{{- if $envoyEnabled -}} +{{- printf "%s-fed.envoy-gateway-system.svc.cluster.local" $namespace -}} +{{- else -}} +{{- printf "federation-test-helper.%s.svc.cluster.local" $namespace -}} +{{- end -}} +{{- end -}} + {{/* Domain for a dynamic backend. Returns the correct hostname depending on whether envoy mode is enabled. diff --git a/charts/integration/templates/configmap.yaml b/charts/integration/templates/configmap.yaml index fef7cc524e1..0c9c63ac4cc 100644 --- a/charts/integration/templates/configmap.yaml +++ b/charts/integration/templates/configmap.yaml @@ -77,7 +77,7 @@ data: apiPort: 5380 dohPort: 5381 - originDomain: {{ .Release.Namespace }}-fed.envoy-gateway-system.svc.cluster.local + originDomain: {{ include "integration.federationOriginDomain" (list .Release.Namespace .Values.envoy.enabled) }} rabbitmq: host: rabbitmq @@ -158,7 +158,7 @@ data: rabbitMqVHost: / - originDomain: {{ .Release.Namespace }}-fed2-fed.envoy-gateway-system.svc.cluster.local + originDomain: {{ include "integration.federationOriginDomain" (list (printf "%s-fed2" .Release.Namespace) .Values.envoy.enabled) }} dynamicBackends: {{- range $name, $dynamicBackend := .Values.config.dynamicBackends }} diff --git a/hack/bin/integration-setup-federation.sh b/hack/bin/integration-setup-federation.sh index 9ebbb46173e..d6f4b27f5a7 100755 --- a/hack/bin/integration-setup-federation.sh +++ b/hack/bin/integration-setup-federation.sh @@ -7,6 +7,9 @@ TOP_LEVEL="$DIR/../.." export NAMESPACE=${NAMESPACE:-test-integration} # Available $HELMFILE_ENV profiles: default, default-ssl, kind, kind-ssl HELMFILE_ENV=${HELMFILE_ENV:-default} +# Available modes: gateway (default, uses wire-ingress), nginx (uses nginx-ingress-services) +WIRE_INGRESS_MODE=${WIRE_INGRESS_MODE:-gateway} +export WIRE_INGRESS_MODE CHARTS_DIR="${TOP_LEVEL}/.local/charts" HELM_PARALLELISM=${HELM_PARALLELISM:-1} @@ -28,12 +31,19 @@ mkdir -p ~/.parallel && touch ~/.parallel/will-cite printf '%s\n' "${charts[@]}" | parallel -P "${HELM_PARALLELISM}" "$DIR/update.sh" "$CHARTS_DIR/{}" export NAMESPACE_1="$NAMESPACE" -export FEDERATION_DOMAIN_BASE_1="envoy-gateway-system.svc.cluster.local" -export FEDERATION_DOMAIN_1="${NAMESPACE_1}-fed.${FEDERATION_DOMAIN_BASE_1}" - export NAMESPACE_2="$NAMESPACE-fed2" -export FEDERATION_DOMAIN_BASE_2="envoy-gateway-system.svc.cluster.local" -export FEDERATION_DOMAIN_2="${NAMESPACE_2}-fed.${FEDERATION_DOMAIN_BASE_2}" + +if [[ "$WIRE_INGRESS_MODE" == "nginx" ]]; then + export FEDERATION_DOMAIN_BASE_1="${NAMESPACE_1}.svc.cluster.local" + export FEDERATION_DOMAIN_1="federation-test-helper.${FEDERATION_DOMAIN_BASE_1}" + export FEDERATION_DOMAIN_BASE_2="${NAMESPACE_2}.svc.cluster.local" + export FEDERATION_DOMAIN_2="federation-test-helper.${FEDERATION_DOMAIN_BASE_2}" +else + export FEDERATION_DOMAIN_BASE_1="envoy-gateway-system.svc.cluster.local" + export FEDERATION_DOMAIN_1="${NAMESPACE_1}-fed.${FEDERATION_DOMAIN_BASE_1}" + export FEDERATION_DOMAIN_BASE_2="envoy-gateway-system.svc.cluster.local" + export FEDERATION_DOMAIN_2="${NAMESPACE_2}-fed.${FEDERATION_DOMAIN_BASE_2}" +fi echo "Fetch federation-ca secret from cert-manager namespace" FEDERATION_CA_CERTIFICATE=$(kubectl -n cert-manager get secrets federation-ca -o json -o jsonpath="{.data['tls\.crt']}" | base64 -d) diff --git a/hack/helm_vars/wire-server/values.yaml.gotmpl b/hack/helm_vars/wire-server/values.yaml.gotmpl index f85e8784152..b6435184fb9 100644 --- a/hack/helm_vars/wire-server/values.yaml.gotmpl +++ b/hack/helm_vars/wire-server/values.yaml.gotmpl @@ -681,9 +681,13 @@ background-worker: integration: envoy: - enabled: true + enabled: {{ ne (env "WIRE_INGRESS_MODE") "nginx" }} gateway: className: "envoy" + {{- if eq (env "WIRE_INGRESS_MODE") "nginx" }} + ingress: + class: "nginx-{{ .Release.Namespace }}" + {{- end }} config: cassandra: host: {{ .Values.cassandraHost }} diff --git a/hack/helmfile.yaml.gotmpl b/hack/helmfile.yaml.gotmpl index 2529b46c672..bb1bedad9bc 100644 --- a/hack/helmfile.yaml.gotmpl +++ b/hack/helmfile.yaml.gotmpl @@ -276,59 +276,57 @@ releases: values: - './helm_vars/{{ .Values.ingressChart }}/values.yaml.gotmpl' - # - name: 'ingress-svc' - # namespace: '{{ .Values.namespace1 }}' - # chart: '../.local/charts/nginx-ingress-services' - # values: - # - './helm_vars/nginx-ingress-services/values.yaml.gotmpl' - # set: - # - name: config.dns.federator - # value: '{{ .Values.federationDomain1 }}' - # - name: config.dns.certificateDomain - # value: '*.{{ .Values.federationDomainBase1 }}' - # needs: - # - 'ingress' - + {{- if eq (env "WIRE_INGRESS_MODE") "nginx" }} + - name: 'ingress-svc' + namespace: '{{ .Values.namespace1 }}' + chart: '../.local/charts/nginx-ingress-services' + values: + - './helm_vars/nginx-ingress-services/values.yaml.gotmpl' + set: + - name: config.dns.federator + value: '{{ .Values.federationDomain1 }}' + - name: config.dns.certificateDomain + value: '*.{{ .Values.federationDomainBase1 }}' + needs: + - ingress + {{- else }} - name: 'ingress-svc' namespace: '{{ .Values.namespace1 }}' chart: '../.local/charts/wire-ingress' values: - './helm_vars/wire-ingress/values.yaml.gotmpl' set: - # Federation domain is also the SRV record created by the - # federation-test-helper service. Maybe we can find a way to make these - # differ, so we don't make any silly assumptions in the code. - name: config.dns.federator value: '{{ .Values.federationDomain1 }}' - name: config.dns.certificateDomain value: '*.{{ .Values.federationDomainBase1 }}' + {{- end }} - # - name: 'ingress-svc' - # namespace: '{{ .Values.namespace2 }}' - # chart: '../.local/charts/nginx-ingress-services' - # values: - # - './helm_vars/nginx-ingress-services/values.yaml.gotmpl' - # set: - # - name: config.dns.federator - # value: '{{ .Values.federationDomain2 }}' - # - name: config.dns.certificateDomain - # value: '*.{{ .Values.federationDomainBase2 }}' - # needs: - # - 'ingress' - + {{- if eq (env "WIRE_INGRESS_MODE") "nginx" }} + - name: 'ingress-svc' + namespace: '{{ .Values.namespace2 }}' + chart: '../.local/charts/nginx-ingress-services' + values: + - './helm_vars/nginx-ingress-services/values.yaml.gotmpl' + set: + - name: config.dns.federator + value: '{{ .Values.federationDomain2 }}' + - name: config.dns.certificateDomain + value: '*.{{ .Values.federationDomainBase2 }}' + needs: + - ingress + {{- else }} - name: 'ingress-svc' namespace: '{{ .Values.namespace2 }}' chart: '../.local/charts/wire-ingress' values: - './helm_vars/wire-ingress/values.yaml.gotmpl' set: - # Federation domain is also the SRV record created by the - # federation-test-helper service. Maybe we can find a way to make these - # differ, so we don't make any silly assumptions in the code. - name: config.dns.federator value: '{{ .Values.federationDomain2 }}' - name: config.dns.certificateDomain value: '*.{{ .Values.federationDomainBase2 }}' + {{- end }} # Note that wire-server depends on databases-ephemeral being up; and in some # cases on nginx-ingress also being up. If installing helm charts in a From bc99a36663d25e61f2e7b0594b439bfc5ba425ea Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 24 Mar 2026 13:26:53 +0100 Subject: [PATCH 42/79] replace envoy-gateway-system hardcoded name with var --- charts/integration/templates/_helpers.tpl | 10 ++++++---- charts/integration/templates/configmap.yaml | 6 +++--- charts/integration/templates/ingress-envoy.yaml | 7 ++++--- .../integration/templates/integration-integration.yaml | 2 +- charts/integration/values.yaml | 3 +++ charts/wire-ingress/README.md | 6 +++--- .../wire-ingress/templates/federation-test-helper.yaml | 9 +++++---- charts/wire-ingress/values.yaml | 3 +++ hack/bin/integration-setup-federation.sh | 8 +++++--- hack/helm_vars/wire-ingress/values.yaml.gotmpl | 5 +---- hack/helm_vars/wire-server/values.yaml.gotmpl | 1 + 11 files changed, 35 insertions(+), 25 deletions(-) diff --git a/charts/integration/templates/_helpers.tpl b/charts/integration/templates/_helpers.tpl index a2b6062eb2d..c8d159d0470 100644 --- a/charts/integration/templates/_helpers.tpl +++ b/charts/integration/templates/_helpers.tpl @@ -13,13 +13,14 @@ Name of the Gateway resource for dynamic backends in envoy mode. {{/* Federation origin domain for a given namespace (used as originDomain in the config). Returns the SRV hostname that other backends use to reach this namespace's federator. -Args: list $namespace $envoyEnabled +Args: list $namespace $envoyEnabled $controllerNamespace */}} {{- define "integration.federationOriginDomain" -}} {{- $namespace := index . 0 -}} {{- $envoyEnabled := index . 1 -}} +{{- $controllerNs := index . 2 -}} {{- if $envoyEnabled -}} -{{- printf "%s-fed.envoy-gateway-system.svc.cluster.local" $namespace -}} +{{- printf "%s-fed.%s.svc.cluster.local" $namespace $controllerNs -}} {{- else -}} {{- printf "federation-test-helper.%s.svc.cluster.local" $namespace -}} {{- end -}} @@ -28,14 +29,15 @@ Args: list $namespace $envoyEnabled {{/* Domain for a dynamic backend. Returns the correct hostname depending on whether envoy mode is enabled. -Args: list $dynamicBackend $namespace $envoyEnabled +Args: list $dynamicBackend $namespace $envoyEnabled $controllerNamespace */}} {{- define "integration.dynamicBackendDomain" -}} {{- $dynamicBackend := index . 0 -}} {{- $namespace := index . 1 -}} {{- $envoyEnabled := index . 2 -}} +{{- $controllerNs := index . 3 -}} {{- if $envoyEnabled -}} -{{- printf "%s-%s.envoy-gateway-system.svc.cluster.local" $dynamicBackend.federatorExternalHostPrefix $namespace -}} +{{- printf "%s-%s.%s.svc.cluster.local" $dynamicBackend.federatorExternalHostPrefix $namespace $controllerNs -}} {{- else -}} {{- printf "%s.%s.svc.cluster.local" $dynamicBackend.federatorExternalHostPrefix $namespace -}} {{- end -}} diff --git a/charts/integration/templates/configmap.yaml b/charts/integration/templates/configmap.yaml index 0c9c63ac4cc..b5f2d351732 100644 --- a/charts/integration/templates/configmap.yaml +++ b/charts/integration/templates/configmap.yaml @@ -77,7 +77,7 @@ data: apiPort: 5380 dohPort: 5381 - originDomain: {{ include "integration.federationOriginDomain" (list .Release.Namespace .Values.envoy.enabled) }} + originDomain: {{ include "integration.federationOriginDomain" (list .Release.Namespace .Values.envoy.enabled .Values.envoy.controllerNamespace) }} rabbitmq: host: rabbitmq @@ -158,12 +158,12 @@ data: rabbitMqVHost: / - originDomain: {{ include "integration.federationOriginDomain" (list (printf "%s-fed2" .Release.Namespace) .Values.envoy.enabled) }} + originDomain: {{ include "integration.federationOriginDomain" (list (printf "%s-fed2" .Release.Namespace) .Values.envoy.enabled .Values.envoy.controllerNamespace) }} dynamicBackends: {{- range $name, $dynamicBackend := .Values.config.dynamicBackends }} {{ $name }}: - domain: {{ include "integration.dynamicBackendDomain" (list $dynamicBackend $.Release.Namespace $.Values.envoy.enabled) }} + domain: {{ include "integration.dynamicBackendDomain" (list $dynamicBackend $.Release.Namespace $.Values.envoy.enabled $.Values.envoy.controllerNamespace) }} federatorExternalPort: {{ $dynamicBackend.federatorExternalPort }} mlsPrivateKeyPaths: removal: diff --git a/charts/integration/templates/ingress-envoy.yaml b/charts/integration/templates/ingress-envoy.yaml index 8e7980c8279..7d5cb34c88f 100644 --- a/charts/integration/templates/ingress-envoy.yaml +++ b/charts/integration/templates/ingress-envoy.yaml @@ -1,6 +1,7 @@ {{- if .Values.envoy.enabled }} {{- $gatewayName := include "integration.getDynBackendsGatewayName" . }} {{- $httpsPort := int .Values.envoy.gateway.listeners.https.port }} +{{- $controllerNs := .Values.envoy.controllerNamespace }} {{- if lt $httpsPort 1024 }} {{- fail (printf "envoy.gateway.listeners.https.port is %d (privileged, <1024). Envoy Gateway remaps it to %d on the proxy pod. Set envoy.gateway.listeners.https.port to the actual container port (e.g. %d)." $httpsPort (add $httpsPort 10000) (add $httpsPort 10000)) }} {{- end }} @@ -83,7 +84,7 @@ spec: value: true {{- range $name, $dynamicBackend := .Values.config.dynamicBackends }} {{- $httpRouteName := printf "%s-dynbackend-%s" $gatewayName $name }} -{{- $svcDomain := printf "%s-%s.envoy-gateway-system.svc.cluster.local" $dynamicBackend.federatorExternalHostPrefix $.Release.Namespace }} +{{- $svcDomain := printf "%s-%s.%s.svc.cluster.local" $dynamicBackend.federatorExternalHostPrefix $.Release.Namespace $controllerNs }} --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute @@ -131,14 +132,14 @@ spec: end end --- -# ClusterIP service in envoy-gateway-system selects the Envoy proxy pods for this Gateway. +# ClusterIP service in {{ $controllerNs }} selects the Envoy proxy pods for this Gateway. # The service name determines the SRV record used by federation discovery: # _wire-server-federator._tcp.{{ $svcDomain }} apiVersion: v1 kind: Service metadata: name: {{ $dynamicBackend.federatorExternalHostPrefix }}-{{ $.Release.Namespace }} - namespace: envoy-gateway-system + namespace: {{ $controllerNs }} spec: type: ClusterIP ports: diff --git a/charts/integration/templates/integration-integration.yaml b/charts/integration/templates/integration-integration.yaml index 5ec9bea054e..bf4f676fabd 100644 --- a/charts/integration/templates/integration-integration.yaml +++ b/charts/integration/templates/integration-integration.yaml @@ -168,7 +168,7 @@ spec: integration-dynamic-backends-ses.sh {{ .Values.config.sesEndpointUrl }} integration-dynamic-backends-s3.sh {{ .Values.config.s3EndpointUrl }} {{- range $name, $dynamicBackend := .Values.config.dynamicBackends }} - integration-dynamic-backends-vhosts.sh {{ $.Values.config.rabbitmqPutVHostUrl }} {{ include "integration.dynamicBackendDomain" (list $dynamicBackend $.Release.Namespace $.Values.envoy.enabled) }} + integration-dynamic-backends-vhosts.sh {{ $.Values.config.rabbitmqPutVHostUrl }} {{ include "integration.dynamicBackendDomain" (list $dynamicBackend $.Release.Namespace $.Values.envoy.enabled $.Values.envoy.controllerNamespace) }} {{- end }} resources: requests: diff --git a/charts/integration/values.yaml b/charts/integration/values.yaml index a50ebd00c80..65c7963b0d8 100644 --- a/charts/integration/values.yaml +++ b/charts/integration/values.yaml @@ -133,6 +133,9 @@ envoy: # Set to true to deploy Gateway API resources instead of nginx Ingress objects # for the dynamic backends. Requires an Envoy Gateway controller in the cluster. enabled: false + # Namespace where the Envoy Gateway controller runs its proxy pods. + # Change only if you installed Envoy Gateway into a non-default namespace. + controllerNamespace: envoy-gateway-system gateway: # Name of the Gateway resource. Defaults to -dynamic-backends if empty. name: "" diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 0320bac66b6..1d1b43353ee 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -513,9 +513,9 @@ An opaque Secret containing credentials for custom ACME challenge solvers, refer #### Finalize PR -- [ ] introduce a flag that switches between gateway / ingress-nginx in the tests -- [ ] investigate: migrate federation-test helper to integrations chart? -- [ ] replace "envoy-gateway-system" hardcoded namespace with chart var +- [x] introduce a flag that switches between gateway / ingress-nginx in the tests +- [x] investigate: migrate federation-test helper to integrations chart? NO, becasue we would need to pass the relase name +- [x] replace "envoy-gateway-system" hardcoded namespace with chart var - [ ] feature flag for envoypatch policies (enabled by default, turned off in tests) - [ ] document: must deploy enovy-gateway with patches enabled - [ ] envoy patch policies: adjust docs: its not a kubernetes problem, but that SRV records have to by FQDM diff --git a/charts/wire-ingress/templates/federation-test-helper.yaml b/charts/wire-ingress/templates/federation-test-helper.yaml index 5d12d75ad4e..ba459023196 100644 --- a/charts/wire-ingress/templates/federation-test-helper.yaml +++ b/charts/wire-ingress/templates/federation-test-helper.yaml @@ -1,10 +1,11 @@ {{- if (and .Values.federator.enabled .Values.federator.integrationTestHelper) }} -# Envoy Gateway runs proxy pods in envoy-gateway-system, not in the release namespace. +# This is used only for integration tests. +# Envoy Gateway runs proxy pods in {controllerNamespace}, not in the release namespace. # Kubernetes Services cannot select pods across namespaces, so we create a ClusterIP -# Service in envoy-gateway-system that selects the proxy pods by their owning-gateway +# Service in {controllerNamespace} that selects the proxy pods by their owning-gateway # labels (set by Envoy Gateway). This service becomes the SRV target for Wire federation # discovery: -# _wire-server-federator._tcp.-fed.envoy-gateway-system.svc.cluster.local +# _wire-server-federator._tcp.-fed.{controllerNamespace}.svc.cluster.local # # targetPort must match the port the Envoy proxy pod actually listens on. # When gateway.listeners.https.port is privileged (<1024), Envoy Gateway remaps it @@ -18,7 +19,7 @@ apiVersion: v1 kind: Service metadata: name: {{ .Release.Namespace }}-fed - namespace: envoy-gateway-system + namespace: {{ .Values.gateway.controllerNamespace }} spec: type: ClusterIP ports: diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index e96d1c4bf40..4fa33445cac 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -38,6 +38,9 @@ gateway: # Convenience shorthand for provider.kubernetes.envoyService.type. # Only takes effect when manageServiceType: true. # Do not combine with envoyProxy.spec.provider.kubernetes.envoyService. + # Namespace where the Envoy Gateway controller runs its proxy pods. + # Change only if you installed Envoy Gateway into a non-default namespace. + controllerNamespace: envoy-gateway-system manageServiceType: true serviceType: LoadBalancer # Annotations to add to the Service created by Envoy Gateway. diff --git a/hack/bin/integration-setup-federation.sh b/hack/bin/integration-setup-federation.sh index d6f4b27f5a7..d4f53af5e63 100755 --- a/hack/bin/integration-setup-federation.sh +++ b/hack/bin/integration-setup-federation.sh @@ -8,8 +8,10 @@ export NAMESPACE=${NAMESPACE:-test-integration} # Available $HELMFILE_ENV profiles: default, default-ssl, kind, kind-ssl HELMFILE_ENV=${HELMFILE_ENV:-default} # Available modes: gateway (default, uses wire-ingress), nginx (uses nginx-ingress-services) -WIRE_INGRESS_MODE=${WIRE_INGRESS_MODE:-gateway} +WIRE_INGRESS_MODE=${WIRE_INGRESS_MODE:-nginx} export WIRE_INGRESS_MODE +ENVOY_GATEWAY_NAMESPACE=${ENVOY_GATEWAY_NAMESPACE:-envoy-gateway-system} +export ENVOY_GATEWAY_NAMESPACE CHARTS_DIR="${TOP_LEVEL}/.local/charts" HELM_PARALLELISM=${HELM_PARALLELISM:-1} @@ -39,9 +41,9 @@ if [[ "$WIRE_INGRESS_MODE" == "nginx" ]]; then export FEDERATION_DOMAIN_BASE_2="${NAMESPACE_2}.svc.cluster.local" export FEDERATION_DOMAIN_2="federation-test-helper.${FEDERATION_DOMAIN_BASE_2}" else - export FEDERATION_DOMAIN_BASE_1="envoy-gateway-system.svc.cluster.local" + export FEDERATION_DOMAIN_BASE_1="${ENVOY_GATEWAY_NAMESPACE}.svc.cluster.local" export FEDERATION_DOMAIN_1="${NAMESPACE_1}-fed.${FEDERATION_DOMAIN_BASE_1}" - export FEDERATION_DOMAIN_BASE_2="envoy-gateway-system.svc.cluster.local" + export FEDERATION_DOMAIN_BASE_2="${ENVOY_GATEWAY_NAMESPACE}.svc.cluster.local" export FEDERATION_DOMAIN_2="${NAMESPACE_2}-fed.${FEDERATION_DOMAIN_BASE_2}" fi diff --git a/hack/helm_vars/wire-ingress/values.yaml.gotmpl b/hack/helm_vars/wire-ingress/values.yaml.gotmpl index 45b4cb18d5d..7a79c86ea7f 100644 --- a/hack/helm_vars/wire-ingress/values.yaml.gotmpl +++ b/hack/helm_vars/wire-ingress/values.yaml.gotmpl @@ -19,6 +19,7 @@ tls: gateway: className: "envoy" + controllerNamespace: {{ env "ENVOY_GATEWAY_NAMESPACE" }} manageServiceType: true serviceType: ClusterIP listeners: @@ -27,10 +28,6 @@ gateway: # We use 10443 directly so targetPort in federation-test-helper matches the # actual container port without needing a separate override. port: 10443 - # Explicit hostname prevents OverlappingTLSConfig with the federator listener - # (which uses -fed.envoy-gateway-system.svc.cluster.local). - # Without this, both listeners are catch-all on the same port and Envoy - # forces HTTP/1.1-only ALPN, breaking HTTP/2 federation requests. hostname: "*.{{ .Release.Namespace }}-integration.example.com" config: diff --git a/hack/helm_vars/wire-server/values.yaml.gotmpl b/hack/helm_vars/wire-server/values.yaml.gotmpl index b6435184fb9..a300d893702 100644 --- a/hack/helm_vars/wire-server/values.yaml.gotmpl +++ b/hack/helm_vars/wire-server/values.yaml.gotmpl @@ -682,6 +682,7 @@ background-worker: integration: envoy: enabled: {{ ne (env "WIRE_INGRESS_MODE") "nginx" }} + controllerNamespace: {{ env "ENVOY_GATEWAY_NAMESPACE" }} gateway: className: "envoy" {{- if eq (env "WIRE_INGRESS_MODE") "nginx" }} From 1735bb4452a408b112c734db2ac3ce1f4ea3af7a Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 24 Mar 2026 15:55:10 +0100 Subject: [PATCH 43/79] envoy patch policies --- charts/wire-ingress/README.md | 42 +++++++++++++++++-- .../templates/envoypatchpolicy-federator.yaml | 2 +- charts/wire-ingress/values.yaml | 5 +++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 1d1b43353ee..e6ebb6524af 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -31,6 +31,7 @@ Operators should be able to reuse most of their existing values files with minim | _(not present)_ | `gateway.name` | Name of the Gateway to attach routes to | | _(not present)_ | `gateway.infrastructure.annotations` | Annotations forwarded to the LoadBalancer Service provisioned by Envoy Gateway — see [Gateway API docs](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.GatewayInfrastructure) | | _(not present)_ | `gateway.proxyProtocol.enabled` | Creates a `ClientTrafficPolicy` enabling PROXY protocol on all Gateway listeners — required when the load balancer is configured to send PROXY protocol headers | +| _(not present)_ | `gateway.patchPolicies.enabled` | Controls whether `EnvoyPatchPolicy` resources are created (default: `true`). See [EnvoyPatchPolicy](#envoypatchpolicy) below. | | _(not present)_ | `tls.secret.create` | If `false`, the TLS Secret is not created by this chart — use when the secret is managed externally (e.g. by another chart or operator). `secrets.tlsWildcardCert` and `secrets.tlsWildcardKey` are ignored when `false`. | | _(not present)_ | `tls.secret.nameOverride` | Override the name of the TLS Secret referenced by the Gateway listener. If not set, the name is derived from the release name. | @@ -140,6 +141,41 @@ the service type via `envoyProxy.spec` or a cluster-level `EnvoyProxy`. `GatewayClass` is installed by the Envoy Gateway Helm chart and is cluster-scoped. This chart only references it by name via `gateway.className`. +### EnvoyPatchPolicy + +When `federator.enabled: true`, the chart creates an `EnvoyPatchPolicy` resource that sets +`strip_trailing_host_dot: true` on the federator filter chain. + +**Why this is needed:** Wire federation resolves remote backends via DNS SRV records. Per the DNS +specification, SRV record targets are always FQDNs — they include a trailing dot +(e.g. `peer.example.com.`). The federator passes this FQDN directly as the HTTP/2 `:authority` +header. Envoy's virtual-host matching is exact, so the trailing dot causes a `route_not_found` +error. `strip_trailing_host_dot` normalises the header before route selection. + +`EnvoyPatchPolicy` is an Envoy Gateway extension API. It must be explicitly enabled in the +EnvoyGateway ConfigMap before deploying this chart with `federator.enabled: true`: + +```yaml +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyGateway +metadata: + name: envoy-gateway + namespace: envoy-gateway-system +spec: + extensionApis: + enableEnvoyPatchPolicy: true +``` + +Set `gateway.patchPolicies.enabled: false` only if you cannot enable `EnvoyPatchPolicy` in your +cluster. In that case, federation will not work unless you apply the trailing-dot fix by other +means. + +> **Future note:** If future versions of the Wire federator stop sending FQDNs in the +> `:authority` header, this patch policy will no longer be needed. `gateway.patchPolicies.enabled` +> exists so it can be disabled at that point without a chart change. + +--- + ### Multi-ingress is out of scope Single-domain deployments are the only supported topology. Multi-domain support can be added later. @@ -516,9 +552,9 @@ An opaque Secret containing credentials for custom ACME challenge solvers, refer - [x] introduce a flag that switches between gateway / ingress-nginx in the tests - [x] investigate: migrate federation-test helper to integrations chart? NO, becasue we would need to pass the relase name - [x] replace "envoy-gateway-system" hardcoded namespace with chart var -- [ ] feature flag for envoypatch policies (enabled by default, turned off in tests) -- [ ] document: must deploy enovy-gateway with patches enabled -- [ ] envoy patch policies: adjust docs: its not a kubernetes problem, but that SRV records have to by FQDM +- [x] feature flag for envoypatch policies (enabled by default, turned off in tests) +- [x] document: must deploy enovy-gateway with patches enabled +- [x] envoy patch policies: adjust docs: its not a kubernetes problem, but that SRV records have to by FQDM - [ ] for .Values.federator.tls.useCertManager document that you'll likely needa private CA, since many public CA stopped issuing client auth certs - [ ] Write the migration guide section of this README - [ ] collate the parameters and changes better diff --git a/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml b/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml index ec85ef0f5ab..8a6263ed882 100644 --- a/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml +++ b/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml @@ -1,4 +1,4 @@ -{{- if .Values.federator.enabled }} +{{- if and .Values.federator.enabled .Values.gateway.patchPolicies.enabled }} {{/* Envoy Gateway-specific (gateway.envoyproxy.io/v1alpha1). Strips trailing dots from the :authority header on the federator listener before virtual-host matching. Wire federator resolves federation targets diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index 4fa33445cac..2336a134a4c 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -81,6 +81,11 @@ gateway: # Optional hostname restriction for the HTTP listener. Set alongside # listeners.https.hostname when using mergeGateways. hostname: "" + # Set to false to skip creating EnvoyPatchPolicy resources. + # EnvoyPatchPolicy requires extensionApis.enableEnvoyPatchPolicy: true + # in the EnvoyGateway ConfigMap (see README). + patchPolicies: + enabled: true # NOTE: Please provide names. Here are naming suggestions: # You need to reference those in the nginz helm chart nginx_conf.deeplink.endpoints From 60aa86f79d79b0d4d7eef34ba3fea95c9324c4b0 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 24 Mar 2026 16:20:54 +0100 Subject: [PATCH 44/79] rename federation-test-helper.yaml to service-test-fed.yaml --- .../{federation-test-helper.yaml => service-test-fed.yaml} | 2 +- hack/helm_vars/wire-ingress/values.yaml.gotmpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename charts/wire-ingress/templates/{federation-test-helper.yaml => service-test-fed.yaml} (83%) diff --git a/charts/wire-ingress/templates/federation-test-helper.yaml b/charts/wire-ingress/templates/service-test-fed.yaml similarity index 83% rename from charts/wire-ingress/templates/federation-test-helper.yaml rename to charts/wire-ingress/templates/service-test-fed.yaml index ba459023196..8a14d1ab314 100644 --- a/charts/wire-ingress/templates/federation-test-helper.yaml +++ b/charts/wire-ingress/templates/service-test-fed.yaml @@ -13,7 +13,7 @@ # to the actual container port in your values (e.g. 10443) to avoid this. {{- $httpsPort := int .Values.gateway.listeners.https.port }} {{- if lt $httpsPort 1024 }} -{{- fail (printf "federation-test-helper: gateway.listeners.https.port is %d (privileged, <1024). Envoy Gateway remaps it to %d on the proxy pod. Set gateway.listeners.https.port to the actual container port (e.g. %d)." $httpsPort (add $httpsPort 10000) (add $httpsPort 10000)) }} +{{- fail (printf "service-test-fed: gateway.listeners.https.port is %d (privileged, <1024). Envoy Gateway remaps it to %d on the proxy pod. Set gateway.listeners.https.port to the actual container port (e.g. %d)." $httpsPort (add $httpsPort 10000) (add $httpsPort 10000)) }} {{- end }} apiVersion: v1 kind: Service diff --git a/hack/helm_vars/wire-ingress/values.yaml.gotmpl b/hack/helm_vars/wire-ingress/values.yaml.gotmpl index 7a79c86ea7f..b4cf20a464b 100644 --- a/hack/helm_vars/wire-ingress/values.yaml.gotmpl +++ b/hack/helm_vars/wire-ingress/values.yaml.gotmpl @@ -25,7 +25,7 @@ gateway: listeners: https: # Envoy Gateway remaps privileged ports (+10000) on the proxy pod container. - # We use 10443 directly so targetPort in federation-test-helper matches the + # We use 10443 directly so targetPort in the service-test-fed.yaml matches the # actual container port without needing a separate override. port: 10443 hostname: "*.{{ .Release.Namespace }}-integration.example.com" From 66382bdc1d13ac25907d288e60a9c3a6cd2e1596 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 24 Mar 2026 16:21:10 +0100 Subject: [PATCH 45/79] update parameter documentation --- charts/wire-ingress/README.md | 161 ++++++++++++++++++++-------------- 1 file changed, 97 insertions(+), 64 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index e6ebb6524af..2bf7e28e39b 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -22,82 +22,90 @@ Operators should be able to reuse most of their existing values files with minim * non-tls ingress disabled by default. If you want to make use of automated certificate validation via http01, you need `gateway.listeners.http.enabled: true` * s3 ingress b`/minio/` path blocking. Returns 301 redirect to "/" (was 403). -### Renamed / restructured values +### New values (no equivalent in nginx-ingress-services) -| Old key | New key | Notes | -|---|---|---| -| `config.ingressClass` | `gateway.className` | Different concept: GatewayClass name, not IngressClass | -| _(not present)_ | `gateway.create` | `true` = chart creates the Gateway; `false` = BYO | -| _(not present)_ | `gateway.name` | Name of the Gateway to attach routes to | -| _(not present)_ | `gateway.infrastructure.annotations` | Annotations forwarded to the LoadBalancer Service provisioned by Envoy Gateway — see [Gateway API docs](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.GatewayInfrastructure) | -| _(not present)_ | `gateway.proxyProtocol.enabled` | Creates a `ClientTrafficPolicy` enabling PROXY protocol on all Gateway listeners — required when the load balancer is configured to send PROXY protocol headers | -| _(not present)_ | `gateway.patchPolicies.enabled` | Controls whether `EnvoyPatchPolicy` resources are created (default: `true`). See [EnvoyPatchPolicy](#envoypatchpolicy) below. | -| _(not present)_ | `tls.secret.create` | If `false`, the TLS Secret is not created by this chart — use when the secret is managed externally (e.g. by another chart or operator). `secrets.tlsWildcardCert` and `secrets.tlsWildcardKey` are ignored when `false`. | -| _(not present)_ | `tls.secret.nameOverride` | Override the name of the TLS Secret referenced by the Gateway listener. If not set, the name is derived from the release name. | +Only values that require explanation are listed. Trivial or self-explanatory values (ports, +name overrides, etc.) can be found in `values.yaml`. -### Dropped values (not applicable to Gateway API) +| Key | Default | Description | +|---|---|---| +| `gateway.create` | `true` | If `false`, no `Gateway` resource is created — set `gateway.name` to reference an existing one. Useful when sharing a Gateway across multiple releases. | +| `gateway.controllerNamespace` | `envoy-gateway-system` | Namespace where Envoy Gateway runs its proxy pods. Change only if Envoy Gateway was installed into a non-default namespace. | +| `gateway.envoyProxy.create` | `true` | If `false`, no `EnvoyProxy` resource is created. Set `gateway.envoyProxy.name` to reference an existing one, or leave it empty to inherit the GatewayClass-level `EnvoyProxy`. | +| `gateway.envoyProxy.name` | _(derived)_ | When `create: true` — name of the created resource. When `create: false` — name of an existing `EnvoyProxy` to reference via `infrastructure.parametersRef`. | +| `gateway.envoyProxy.spec` | `{}` | Free-form [EnvoyProxySpec](https://gateway.envoyproxy.io/docs/api/extension_types/#envoyproxyspec) merged verbatim. Use to set `mergeGateways`, custom service annotations, etc. | +| `gateway.serviceType` | `LoadBalancer` | Service type for the Envoy proxy service. Only used when `gateway.manageServiceType: true`. | +| `gateway.manageServiceType` | `true` | Shorthand that sets `envoyService.type` to `gateway.serviceType`. Disable when managing the service type via `gateway.envoyProxy.spec` directly. | +| `gateway.infrastructure.annotations` | `{}` | Annotations forwarded to the LoadBalancer Service provisioned by Envoy Gateway — see [Gateway API docs](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.GatewayInfrastructure). Use for cloud-specific LB settings (e.g. AWS NLB). | +| `gateway.proxyProtocol.enabled` | `false` | Creates a `ClientTrafficPolicy` enabling PROXY protocol on all listeners. Required when the upstream load balancer is configured to send PROXY protocol headers. | +| `gateway.patchPolicies.enabled` | `true` | Controls whether `EnvoyPatchPolicy` resources are created — see [EnvoyPatchPolicy](#envoypatchpolicy). | +| `gateway.listeners.https.hostname` | `""` | **Required when `federator.enabled: true`.** Restricts the HTTPS listener to a specific hostname (e.g. `*.example.com`). Without this, both the HTTPS and federator listeners are catch-all on the same port, causing Envoy to degrade ALPN to HTTP/1.1-only (`OverlappingTLSConfig`). | +| `gateway.listeners.http.enabled` | `false` | Enables the HTTP listener on port 80. Required for HTTP01 ACME challenges via cert-manager's `gatewayHTTPRoute` solver — see [HTTP01 certificate challenges](#http01-certificate-challenges). | +| `tls.secret.create` | `true` | If `false`, the TLS Secret is not created by this chart. Use when the secret is managed externally (e.g. by another operator). | +| `federator.tls.useCertManager` | `true` | Controls cert-manager for the federator TLS secret independently of `tls.useCertManager`. Requires a private CA — see [Federator TLS certificate](#federator-tls-certificate-federatortlsusecertmanager). | + +### Dropped values | Old key | Reason | |---|---| +| `config.ingressClass` | Replaced by `gateway.className` — different concept (GatewayClass name, not IngressClass) | | `ingressName` | Multi-ingress out of scope | | `config.isAdditionalIngress` | Multi-ingress out of scope | | `config.renderCSPInIngress` | Multi-ingress out of scope | | `config.dns.base` | Only used for CSP header rendering, which is a multi-ingress feature | | `tls.verify_depth` | Envoy Gateway `ClientTrafficPolicy` does not expose a direct verify-depth knob; the CA chain itself controls this | -| `tls.enabled` | This is removed since it didn't have any effect. All ingresses are always defined with TLS. | +| `tls.enabled` | Removed — had no effect; all routes are always TLS-terminated | | `secrets.tlsClientCA` | No longer supplied via values. The `federator-ca` ConfigMap is created by the wire-server chart and referenced directly. | -| `secrets.certManager.customSolversSecret` | No longer supported by the chart. Please create a custom Issuer in case you need to handle secrets. | +| `secrets.certManager.customSolversSecret` | No longer supported. Create a custom Issuer instead. | ### Fully backwards compatible values All keys below are accepted unchanged. Their names, types, and semantics are identical to `nginx-ingress-services`. -| Key | Notes | -|---|---| -| `nameOverride` | | -| `teamSettings.enabled` | | -| `accountPages.enabled` | | -| `websockets.enabled` | | -| `webapp.enabled` | | -| `fakeS3.enabled` | | -| `federator.enabled` | | -| `federator.integrationTestHelper` | | -| `federator.tls.duration` | | -| `federator.tls.renewBefore` | | -| `federator.tls.privateKey.rotationPolicy` | | -| `federator.tls.issuer.name` | | -| `federator.tls.issuer.kind` | | -| `federator.tls.issuer.group` | | -| _(not present)_ | `federator.tls.useCertManager` | Controls cert-manager for the federator TLS secret independently of `tls.useCertManager` | -| _(not present)_ | `federator.tls.secretName` | Name of the TLS Secret for the federator listener. Default: `federator-certificate-secret`. When `useCertManager: true`, cert-manager writes the issued certificate into this secret. When `useCertManager: false`, the secret must exist before deploying. | -| `tls.useCertManager` | | -| `tls.createIssuer` | | -| `tls.privateKey.rotationPolicy` | | -| `tls.privateKey.algorithm` | | -| `tls.privateKey.size` | | -| `tls.issuer.name` | | -| `tls.issuer.kind` | | -| `tls.caNamespace` | | -| `certManager.inTestMode` | | -| `certManager.certmasterEmail` | | -| `certManager.customSolvers` | | -| `service.webapp.externalPort` | | -| `service.s3.externalPort` | | -| `service.s3.serviceName` | | -| `service.useFakeS3` | | -| `service.teamSettings.externalPort` | | -| `service.accountPages.externalPort` | | -| `config.dns.https` | | -| `config.dns.ssl` | | -| `config.dns.webapp` | | -| `config.dns.fakeS3` | | -| `config.dns.federator` | | -| `config.dns.certificateDomain` | | -| `config.dns.teamSettings` | | -| `config.dns.accountPages` | | -| `secrets.tlsWildcardCert` | | -| `secrets.tlsWildcardKey` | | +| Key | +|---| +| `nameOverride` | +| `teamSettings.enabled` | +| `accountPages.enabled` | +| `websockets.enabled` | +| `webapp.enabled` | +| `fakeS3.enabled` | +| `federator.enabled` | +| `federator.integrationTestHelper` | +| `federator.tls.duration` | +| `federator.tls.renewBefore` | +| `federator.tls.privateKey.rotationPolicy` | +| `federator.tls.issuer.name` | +| `federator.tls.issuer.kind` | +| `federator.tls.issuer.group` | +| `tls.useCertManager` | +| `tls.createIssuer` | +| `tls.privateKey.rotationPolicy` | +| `tls.privateKey.algorithm` | +| `tls.privateKey.size` | +| `tls.issuer.name` | +| `tls.issuer.kind` | +| `tls.caNamespace` | +| `certManager.inTestMode` | +| `certManager.certmasterEmail` | +| `certManager.customSolvers` | +| `service.webapp.externalPort` | +| `service.s3.externalPort` | +| `service.s3.serviceName` | +| `service.useFakeS3` | +| `service.teamSettings.externalPort` | +| `service.accountPages.externalPort` | +| `config.dns.https` | +| `config.dns.ssl` | +| `config.dns.webapp` | +| `config.dns.fakeS3` | +| `config.dns.federator` | +| `config.dns.certificateDomain` | +| `config.dns.teamSettings` | +| `config.dns.accountPages` | +| `secrets.tlsWildcardCert` | +| `secrets.tlsWildcardKey` | ## Design decisions @@ -205,6 +213,31 @@ certManager: DNS01 requires credentials for your DNS provider but does not need port 80 to be open. +### Federator TLS certificate (`federator.tls.useCertManager`) + +When `federator.tls.useCertManager: true`, cert-manager issues the federator TLS certificate. +The certificate requires both **server auth** and **client auth** Extended Key Usages (EKUs), +because federator connections are mutually authenticated. + +**Most public CAs (including Let's Encrypt) no longer issue certificates with the client auth +EKU.** You will need a **private CA** (e.g. a cert-manager `ClusterIssuer` backed by an internal +CA) to issue the federator certificate. Using the same public ACME issuer as for the main +wildcard certificate will not work. + +A typical setup uses a cert-manager `ClusterIssuer` of type `CA`, referencing a private CA +secret: + +```yaml +federator: + tls: + useCertManager: true + issuer: + name: my-private-ca + kind: ClusterIssuer +``` + +--- + ### Federator mTLS uses Envoy Gateway policies Federator mTLS is implemented using: @@ -499,7 +532,7 @@ header via an inline Lua filter, matching nginx's `$ssl_client_escaped_cert` beh #### federation-test-helper Service -Template: `templates/federation-test-helper.yaml` +Template: `templates/service-test-fed.yaml` A ClusterIP Service in `envoy-gateway-system` that selects the Envoy proxy pods for this Gateway (using `gateway.envoyproxy.io/owning-gateway-*` labels). Because Envoy Gateway runs @@ -527,7 +560,7 @@ integration tests pass with `wire-ingress` in place of `nginx-ingress-services`. - [x] Done - [x] deal with the federation ingresses for the dynamic backends. remove them? they are not needed. or set up the same way as federation (but no test) -- [ ] fix integration test setup so all test pass +- [x] fix integration test setup so all test pass --- @@ -555,14 +588,14 @@ An opaque Secret containing credentials for custom ACME challenge solvers, refer - [x] feature flag for envoypatch policies (enabled by default, turned off in tests) - [x] document: must deploy enovy-gateway with patches enabled - [x] envoy patch policies: adjust docs: its not a kubernetes problem, but that SRV records have to by FQDM -- [ ] for .Values.federator.tls.useCertManager document that you'll likely needa private CA, since many public CA stopped issuing client auth certs -- [ ] Write the migration guide section of this README -- [ ] collate the parameters and changes better +- [x] for .Values.federator.tls.useCertManager document that you'll likely needa private CA, since many public CA stopped issuing client auth certs +- [ ] organize the parameter listing in this README better - [ ] move the phases out of README - [ ] clean up PR: no stray files - [ ] remove CLAUDE.md - [ ] make a note on nginx-ingress-services - [ ] create PR for the4 +- [ ] Write the migration guide section of this README --- From e9cb81a6b341a406a589c525f19e209abfaa1034 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 24 Mar 2026 19:20:24 +0100 Subject: [PATCH 46/79] use a different patch policy to support the FQDMs --- charts/wire-ingress/README.md | 42 ++++++++++++++----- .../templates/envoypatchpolicy-federator.yaml | 35 ++++++++-------- 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 2bf7e28e39b..98a85a2121e 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -12,6 +12,23 @@ The chart targets **Envoy Gateway** as the Gateway API controller. --- +## Prerequisites + +### Envoy Gateway + +[Envoy Gateway](https://gateway.envoyproxy.io/) must be installed in the cluster before deploying +this chart. The `EnvoyPatchPolicy` extension API must be enabled (required for federation — see +[EnvoyPatchPolicy](#envoypatchpolicy)): + +```yaml +config: + envoyGateway: + extensionApis: + enableEnvoyPatchPolicy: true +``` + +--- + ## Backwards compatibility The chart preserves the `values.yaml` structure of the `nginx-ingress-services` chart wherever possible. @@ -151,14 +168,21 @@ references it by name via `gateway.className`. ### EnvoyPatchPolicy -When `federator.enabled: true`, the chart creates an `EnvoyPatchPolicy` resource that sets -`strip_trailing_host_dot: true` on the federator filter chain. +When `federator.enabled: true`, the chart creates an `EnvoyPatchPolicy` resource that adds the +FQDN variant of the federator hostname (e.g. `federator.example.com.`, with trailing dot) to the +Envoy virtual host's domain list. **Why this is needed:** Wire federation resolves remote backends via DNS SRV records. Per the DNS specification, SRV record targets are always FQDNs — they include a trailing dot (e.g. `peer.example.com.`). The federator passes this FQDN directly as the HTTP/2 `:authority` header. Envoy's virtual-host matching is exact, so the trailing dot causes a `route_not_found` -error. `strip_trailing_host_dot` normalises the header before route selection. +error. Adding the FQDN as an additional domain in the route configuration allows Envoy to match +both the bare hostname and the FQDN. + +The policy targets `kind: GatewayClass` (using `gateway.className`) and patches the +`RouteConfiguration` named `//federator`. This approach works correctly with +`mergeGateways: true` because route configuration names are per-namespace even when multiple +Gateways share a single Envoy proxy. `EnvoyPatchPolicy` is an Envoy Gateway extension API. It must be explicitly enabled in the EnvoyGateway ConfigMap before deploying this chart with `federator.enabled: true`: @@ -174,10 +198,6 @@ spec: enableEnvoyPatchPolicy: true ``` -Set `gateway.patchPolicies.enabled: false` only if you cannot enable `EnvoyPatchPolicy` in your -cluster. In that case, federation will not work unless you apply the trailing-dot fix by other -means. - > **Future note:** If future versions of the Wire federator stop sending FQDNs in the > `:authority` header, this patch policy will no longer be needed. `gateway.patchPolicies.enabled` > exists so it can be disabled at that point without a chart change. @@ -589,13 +609,15 @@ An opaque Secret containing credentials for custom ACME challenge solvers, refer - [x] document: must deploy enovy-gateway with patches enabled - [x] envoy patch policies: adjust docs: its not a kubernetes problem, but that SRV records have to by FQDM - [x] for .Values.federator.tls.useCertManager document that you'll likely needa private CA, since many public CA stopped issuing client auth certs -- [ ] organize the parameter listing in this README better +- [x] organize the parameter listing in this README better +- [x] rework patch policies so merged gateways work +- [x] test now if diya / elna federation works +- [ ] test now if integration test pass +- [ ] Write the migration guide section of this README - [ ] move the phases out of README - [ ] clean up PR: no stray files - [ ] remove CLAUDE.md - [ ] make a note on nginx-ingress-services -- [ ] create PR for the4 -- [ ] Write the migration guide section of this README --- diff --git a/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml b/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml index 8a6263ed882..11bd542845a 100644 --- a/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml +++ b/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml @@ -1,15 +1,18 @@ {{- if and .Values.federator.enabled .Values.gateway.patchPolicies.enabled }} -{{/* Envoy Gateway-specific (gateway.envoyproxy.io/v1alpha1). - Strips trailing dots from the :authority header on the federator listener - before virtual-host matching. Wire federator resolves federation targets - via DNS SRV lookups; Kubernetes DNS returns FQDNs with a trailing dot - (e.g. "foo.svc.cluster.local."). HTTP/2 passes that dot in :authority, - which does not match the listener's hostname (no trailing dot) → route_not_found. - strip_trailing_host_dot normalises the header before Envoy's route selection. */}} +{{/* Adds the FQDN variant (trailing dot) of the federator hostname to the + virtual host's domain list so Envoy matches requests whose :authority + header carries a trailing dot. + Wire federator resolves federation targets via DNS SRV lookups; per + RFC 2782, SRV records return FQDNs (e.g. "federator.example.com."). + HTTP/2 passes that dot in :authority; without this patch the virtual + host only matches "federator.example.com" and returns route_not_found. + Envoy Gateway-specific (gateway.envoyproxy.io/v1alpha1). + Requires extensionApis.enableEnvoyPatchPolicy: true in the + EnvoyGateway ConfigMap. */}} apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyPatchPolicy metadata: - name: {{ include "wire-ingress.fullname" . }}-federator-strip-dot + name: {{ include "wire-ingress.fullname" . }}-federator-fqdn-domain labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" @@ -17,17 +20,15 @@ metadata: spec: targetRef: group: gateway.networking.k8s.io - kind: Gateway - name: {{ include "wire-ingress.getGatewayName" . | quote }} + kind: GatewayClass + name: {{ .Values.gateway.className | quote }} type: JSONPatch jsonPatches: - - type: "type.googleapis.com/envoy.config.listener.v3.Listener" - # The https and federator listeners share port 10443, so Envoy Gateway - # merges them into a single xDS listener named after the first section - # ("https"). The federator filter chain is at index 1 (https is index 0). - name: {{ printf "%s/%s/https" .Release.Namespace (include "wire-ingress.getGatewayName" .) | quote }} + - type: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration" + # Route config name: //federator + name: {{ printf "%s/%s/federator" .Release.Namespace (include "wire-ingress.getGatewayName" .) | quote }} operation: op: add - path: "/filter_chains/1/filters/0/typed_config/strip_trailing_host_dot" - value: true + path: "/virtual_hosts/0/domains/-" + value: {{ printf "%s." .Values.config.dns.federator | quote }} {{- end }} From e1e31696e34e1cebdcbf1bdae6b947dd4227b475 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 24 Mar 2026 19:23:25 +0100 Subject: [PATCH 47/79] test envoy by default --- hack/bin/integration-setup-federation.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/bin/integration-setup-federation.sh b/hack/bin/integration-setup-federation.sh index d4f53af5e63..4676cfa5341 100755 --- a/hack/bin/integration-setup-federation.sh +++ b/hack/bin/integration-setup-federation.sh @@ -8,7 +8,7 @@ export NAMESPACE=${NAMESPACE:-test-integration} # Available $HELMFILE_ENV profiles: default, default-ssl, kind, kind-ssl HELMFILE_ENV=${HELMFILE_ENV:-default} # Available modes: gateway (default, uses wire-ingress), nginx (uses nginx-ingress-services) -WIRE_INGRESS_MODE=${WIRE_INGRESS_MODE:-nginx} +WIRE_INGRESS_MODE=${WIRE_INGRESS_MODE:-envoy} export WIRE_INGRESS_MODE ENVOY_GATEWAY_NAMESPACE=${ENVOY_GATEWAY_NAMESPACE:-envoy-gateway-system} export ENVOY_GATEWAY_NAMESPACE From 457f1d79fc6af6f1f096ea952b974f432109f942 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 25 Mar 2026 10:14:18 +0100 Subject: [PATCH 48/79] follow-up to patch policies: make configurable --- charts/wire-ingress/README.md | 1 + .../wire-ingress/templates/envoypatchpolicy-federator.yaml | 6 ++++++ charts/wire-ingress/values.yaml | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 98a85a2121e..46b291cc296 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -56,6 +56,7 @@ name overrides, etc.) can be found in `values.yaml`. | `gateway.infrastructure.annotations` | `{}` | Annotations forwarded to the LoadBalancer Service provisioned by Envoy Gateway — see [Gateway API docs](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.GatewayInfrastructure). Use for cloud-specific LB settings (e.g. AWS NLB). | | `gateway.proxyProtocol.enabled` | `false` | Creates a `ClientTrafficPolicy` enabling PROXY protocol on all listeners. Required when the upstream load balancer is configured to send PROXY protocol headers. | | `gateway.patchPolicies.enabled` | `true` | Controls whether `EnvoyPatchPolicy` resources are created — see [EnvoyPatchPolicy](#envoypatchpolicy). | +| `gateway.patchPolicies.targetGatewayClass` | `false` | When `true`, `EnvoyPatchPolicy` targets the `GatewayClass` instead of the `Gateway`. **Required when `gateway.envoyProxy.spec.mergeGateways: true`**: with merged Gateways, policies targeting a `Gateway` are not applied — they must target the `GatewayClass`. Leave `false` for single-Gateway deployments (e.g. integration tests). | | `gateway.listeners.https.hostname` | `""` | **Required when `federator.enabled: true`.** Restricts the HTTPS listener to a specific hostname (e.g. `*.example.com`). Without this, both the HTTPS and federator listeners are catch-all on the same port, causing Envoy to degrade ALPN to HTTP/1.1-only (`OverlappingTLSConfig`). | | `gateway.listeners.http.enabled` | `false` | Enables the HTTP listener on port 80. Required for HTTP01 ACME challenges via cert-manager's `gatewayHTTPRoute` solver — see [HTTP01 certificate challenges](#http01-certificate-challenges). | | `tls.secret.create` | `true` | If `false`, the TLS Secret is not created by this chart. Use when the secret is managed externally (e.g. by another operator). | diff --git a/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml b/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml index 11bd542845a..f3c19f472f4 100644 --- a/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml +++ b/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml @@ -20,8 +20,14 @@ metadata: spec: targetRef: group: gateway.networking.k8s.io + {{- if .Values.gateway.patchPolicies.targetGatewayClass }} kind: GatewayClass name: {{ .Values.gateway.className | quote }} + {{- else }} + kind: Gateway + name: {{ include "wire-ingress.getGatewayName" . | quote }} + namespace: {{ .Release.Namespace | quote }} + {{- end }} type: JSONPatch jsonPatches: - type: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration" diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index 2336a134a4c..9da99a9e2fa 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -86,6 +86,11 @@ gateway: # in the EnvoyGateway ConfigMap (see README). patchPolicies: enabled: true + # Set to true when the GatewayClass uses mergeGateways: true. + # With mergeGateways, EnvoyPatchPolicy must target the GatewayClass + # rather than the individual Gateway. Default false targets the Gateway, + # which is correct for single-Gateway (non-merged) deployments. + targetGatewayClass: false # NOTE: Please provide names. Here are naming suggestions: # You need to reference those in the nginz helm chart nginx_conf.deeplink.endpoints From c34eeb7d79ca042ac8689c4ff6a7560e108563b6 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 25 Mar 2026 13:43:19 +0100 Subject: [PATCH 49/79] update envoypatchpolicy section --- charts/wire-ingress/README.md | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 46b291cc296..5a3f10a8d2b 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -180,24 +180,17 @@ header. Envoy's virtual-host matching is exact, so the trailing dot causes a `ro error. Adding the FQDN as an additional domain in the route configuration allows Envoy to match both the bare hostname and the FQDN. -The policy targets `kind: GatewayClass` (using `gateway.className`) and patches the -`RouteConfiguration` named `//federator`. This approach works correctly with -`mergeGateways: true` because route configuration names are per-namespace even when multiple -Gateways share a single Envoy proxy. +The policy patches the `RouteConfiguration` named `//federator`. Route +configuration names are per-namespace even when multiple Gateways share a single Envoy proxy, so +the name is predictable from chart values. -`EnvoyPatchPolicy` is an Envoy Gateway extension API. It must be explicitly enabled in the -EnvoyGateway ConfigMap before deploying this chart with `federator.enabled: true`: +**`gateway.patchPolicies.targetGatewayClass`** controls what the policy targets: -```yaml -apiVersion: gateway.envoyproxy.io/v1alpha1 -kind: EnvoyGateway -metadata: - name: envoy-gateway - namespace: envoy-gateway-system -spec: - extensionApis: - enableEnvoyPatchPolicy: true -``` +- **`false` (default)** — targets `kind: Gateway` by name. Use for standard single-Gateway + deployments, including integration tests. +- **`true`** — targets `kind: GatewayClass` (using `gateway.className`). **Required when + `gateway.envoyProxy.spec.mergeGateways: true`.** With merged Gateways, all Gateways of the same + GatewayClass share one Envoy proxy. > **Future note:** If future versions of the Wire federator stop sending FQDNs in the > `:authority` header, this patch policy will no longer be needed. `gateway.patchPolicies.enabled` @@ -613,7 +606,7 @@ An opaque Secret containing credentials for custom ACME challenge solvers, refer - [x] organize the parameter listing in this README better - [x] rework patch policies so merged gateways work - [x] test now if diya / elna federation works -- [ ] test now if integration test pass +- [x] test now if integration test pass - [ ] Write the migration guide section of this README - [ ] move the phases out of README - [ ] clean up PR: no stray files From 329198fce186e755ffcfa7dc6c300a76206aa9c0 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 25 Mar 2026 14:18:03 +0100 Subject: [PATCH 50/79] wip migration guide --- charts/wire-ingress/README.md | 45 +++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index 5a3f10a8d2b..abcf95f1713 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -14,6 +14,11 @@ The chart targets **Envoy Gateway** as the Gateway API controller. ## Prerequisites +### Gateway API + +Install the [Gateway API](https://gateway-api.sigs.k8s.io/) into your cluster. +This chart makes use of the of the kinds defined in the `gateway.networking.k8s.io/v1` API. + ### Envoy Gateway [Envoy Gateway](https://gateway.envoyproxy.io/) must be installed in the cluster before deploying @@ -27,12 +32,37 @@ config: enableEnvoyPatchPolicy: true ``` +Also make sure also you've created a `GatewayClass` object with +``` +spec: + controllerName: gateway.envoyproxy.io/gatewayclass-controller +``` + +You need to refer to this object in the `gateway.className` paramter. + --- ## Backwards compatibility + +### Migrating from the `nginx-ingress-services` chart + The chart preserves the `values.yaml` structure of the `nginx-ingress-services` chart wherever possible. -Operators should be able to reuse most of their existing values files with minimal changes. +Operators should be able to reuse most of their existing values files with minimal changes: + +Please add a `gateway` config block to your `values` yaml. And consider at least + +- `gateway.create`: if set to `false` you have to create a `Gateway` object yourself. Make sure to set `gateway.name` to your +- `gateway.className`: set this to `Gateway` class you created during installtion (see above). +- `proxyProtocol.enabled`: set this to `true` if our load balancer uses the PROXY protocol +- `gateway.listeners.https.hostname`: Please set this to `*.`. This assumes that all domains confiured `config.dns.*` are subdomains of ``. + If this is not the case then please create your own gateway (Set `gateway.create` to `false`). +- `gateway.patchPolicies.targetGatewayClass`: depends on your setup (see below) +- `gateway.envoyProxy.create` and `gateway.manageServiceType`: depends your setup + +For more details please see below. + +Feel free to remove `secrets.tlsClientCA`. This key is not longer needed. ### Behaviour changes @@ -47,18 +77,19 @@ name overrides, etc.) can be found in `values.yaml`. | Key | Default | Description | |---|---|---| | `gateway.create` | `true` | If `false`, no `Gateway` resource is created — set `gateway.name` to reference an existing one. Useful when sharing a Gateway across multiple releases. | -| `gateway.controllerNamespace` | `envoy-gateway-system` | Namespace where Envoy Gateway runs its proxy pods. Change only if Envoy Gateway was installed into a non-default namespace. | +| `gateway.className` | `""` | **Required.** Name of the `GatewayClass` installed by the Envoy Gateway controller (e.g. `envoy`). Must match the `GatewayClass` object whose `spec.controllerName` is `gateway.envoyproxy.io/gatewayclass-controller`. | +| `gateway.listeners.https.hostname` | `""` | **Required when `federator.enabled: true`.** Restricts the HTTPS listener to a specific hostname (e.g. `*.example.com`). Without this, both the HTTPS and federator listeners are catch-all on the same port, causing Envoy to degrade ALPN to HTTP/1.1-only (`OverlappingTLSConfig`). | +| `gateway.listeners.http.enabled` | `false` | Enables the HTTP listener on port 80. Required for HTTP01 ACME challenges via cert-manager's `gatewayHTTPRoute` solver — see [HTTP01 certificate challenges](#http01-certificate-challenges). | | `gateway.envoyProxy.create` | `true` | If `false`, no `EnvoyProxy` resource is created. Set `gateway.envoyProxy.name` to reference an existing one, or leave it empty to inherit the GatewayClass-level `EnvoyProxy`. | | `gateway.envoyProxy.name` | _(derived)_ | When `create: true` — name of the created resource. When `create: false` — name of an existing `EnvoyProxy` to reference via `infrastructure.parametersRef`. | | `gateway.envoyProxy.spec` | `{}` | Free-form [EnvoyProxySpec](https://gateway.envoyproxy.io/docs/api/extension_types/#envoyproxyspec) merged verbatim. Use to set `mergeGateways`, custom service annotations, etc. | -| `gateway.serviceType` | `LoadBalancer` | Service type for the Envoy proxy service. Only used when `gateway.manageServiceType: true`. | | `gateway.manageServiceType` | `true` | Shorthand that sets `envoyService.type` to `gateway.serviceType`. Disable when managing the service type via `gateway.envoyProxy.spec` directly. | +| `gateway.serviceType` | `LoadBalancer` | Service type for the Envoy proxy service. Only used when `gateway.manageServiceType: true`. | | `gateway.infrastructure.annotations` | `{}` | Annotations forwarded to the LoadBalancer Service provisioned by Envoy Gateway — see [Gateway API docs](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.GatewayInfrastructure). Use for cloud-specific LB settings (e.g. AWS NLB). | | `gateway.proxyProtocol.enabled` | `false` | Creates a `ClientTrafficPolicy` enabling PROXY protocol on all listeners. Required when the upstream load balancer is configured to send PROXY protocol headers. | -| `gateway.patchPolicies.enabled` | `true` | Controls whether `EnvoyPatchPolicy` resources are created — see [EnvoyPatchPolicy](#envoypatchpolicy). | +| `gateway.patchPolicies.enabled` | `true` | Controls whether `` resources are created — see [EnvoyPatchPolicy](#envoypatchpolicy). | | `gateway.patchPolicies.targetGatewayClass` | `false` | When `true`, `EnvoyPatchPolicy` targets the `GatewayClass` instead of the `Gateway`. **Required when `gateway.envoyProxy.spec.mergeGateways: true`**: with merged Gateways, policies targeting a `Gateway` are not applied — they must target the `GatewayClass`. Leave `false` for single-Gateway deployments (e.g. integration tests). | -| `gateway.listeners.https.hostname` | `""` | **Required when `federator.enabled: true`.** Restricts the HTTPS listener to a specific hostname (e.g. `*.example.com`). Without this, both the HTTPS and federator listeners are catch-all on the same port, causing Envoy to degrade ALPN to HTTP/1.1-only (`OverlappingTLSConfig`). | -| `gateway.listeners.http.enabled` | `false` | Enables the HTTP listener on port 80. Required for HTTP01 ACME challenges via cert-manager's `gatewayHTTPRoute` solver — see [HTTP01 certificate challenges](#http01-certificate-challenges). | +| `gateway.controllerNamespace` | `envoy-gateway-system` | Can be ignored, relevant only for integration tests. Namespace where Envoy Gateway runs its proxy pods. Change only if Envoy Gateway was installed into a non-default namespace. | | `tls.secret.create` | `true` | If `false`, the TLS Secret is not created by this chart. Use when the secret is managed externally (e.g. by another operator). | | `federator.tls.useCertManager` | `true` | Controls cert-manager for the federator TLS secret independently of `tls.useCertManager`. Requires a private CA — see [Federator TLS certificate](#federator-tls-certificate-federatortlsusecertmanager). | @@ -66,7 +97,7 @@ name overrides, etc.) can be found in `values.yaml`. | Old key | Reason | |---|---| -| `config.ingressClass` | Replaced by `gateway.className` — different concept (GatewayClass name, not IngressClass) | +| `config.ingressClass` | | | `ingressName` | Multi-ingress out of scope | | `config.isAdditionalIngress` | Multi-ingress out of scope | | `config.renderCSPInIngress` | Multi-ingress out of scope | From 373bc4324cc3988c3fa3836a233dff8444caf15c Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 25 Mar 2026 14:19:39 +0100 Subject: [PATCH 51/79] polish a bit --- charts/wire-ingress/README.md | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index abcf95f1713..f55319377c0 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -47,22 +47,21 @@ You need to refer to this object in the `gateway.className` paramter. ### Migrating from the `nginx-ingress-services` chart -The chart preserves the `values.yaml` structure of the `nginx-ingress-services` chart wherever possible. -Operators should be able to reuse most of their existing values files with minimal changes: +The chart preserves the `values.yaml` structure of the `nginx-ingress-services` chart wherever +possible. Most existing values files should work with minimal changes. -Please add a `gateway` config block to your `values` yaml. And consider at least +Add a `gateway` block to your values and review at least the following keys: -- `gateway.create`: if set to `false` you have to create a `Gateway` object yourself. Make sure to set `gateway.name` to your -- `gateway.className`: set this to `Gateway` class you created during installtion (see above). -- `proxyProtocol.enabled`: set this to `true` if our load balancer uses the PROXY protocol -- `gateway.listeners.https.hostname`: Please set this to `*.`. This assumes that all domains confiured `config.dns.*` are subdomains of ``. - If this is not the case then please create your own gateway (Set `gateway.create` to `false`). -- `gateway.patchPolicies.targetGatewayClass`: depends on your setup (see below) -- `gateway.envoyProxy.create` and `gateway.manageServiceType`: depends your setup +- `gateway.className` — set to the `GatewayClass` name created during installation (see above). +- `gateway.create` — if `false`, you must create a `Gateway` object yourself and set `gateway.name` to its name. +- `gateway.listeners.https.hostname` — set to `*.`. This assumes all domains under + `config.dns.*` are subdomains of ``. If that is not the case, create your own + `Gateway` and set `gateway.create: false`. +- `gateway.proxyProtocol.enabled` — set to `true` if your load balancer sends PROXY protocol headers. +- `gateway.patchPolicies.targetGatewayClass` — depends on your setup; see [EnvoyPatchPolicy](#envoypatchpolicy). +- `gateway.envoyProxy.create` and `gateway.manageServiceType` — depend on your setup; see the parameter table below. -For more details please see below. - -Feel free to remove `secrets.tlsClientCA`. This key is not longer needed. +`secrets.tlsClientCA` is no longer needed and can be removed. ### Behaviour changes From a6da965c9865d0e9b44f5e3a0395395b2346d248 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 25 Mar 2026 14:26:13 +0100 Subject: [PATCH 52/79] move planning out of readme --- charts/wire-ingress/PLAN.md | 357 +++++++++++++++++++++++++++++++++ charts/wire-ingress/README.md | 361 ---------------------------------- 2 files changed, 357 insertions(+), 361 deletions(-) create mode 100644 charts/wire-ingress/PLAN.md diff --git a/charts/wire-ingress/PLAN.md b/charts/wire-ingress/PLAN.md new file mode 100644 index 00000000000..f513e44243b --- /dev/null +++ b/charts/wire-ingress/PLAN.md @@ -0,0 +1,357 @@ +## Testing strategy + +### Rendering diff + +For each implementation step, render the chart and inspect the output: + +```bash +helm template release-name ./wire-ingress -f test-values.yaml +``` + +To verify routing coverage against the previous deployment, render both and compare (see the +migration guide for details). + +### Schema validation + +`values.schema.json` is maintained alongside `values.yaml`. Run `helm lint` to catch +misconfiguration early: + +```bash +helm lint ./wire-ingress -f test-values.yaml +``` + +### Test values files to maintain + +Create one values file per meaningful configuration variant to use with `helm template` and +`helm lint`: + +| File | Purpose | +|---|---| +| `ci/values-minimal.yaml` | Only required fields, all optional features disabled | +| `ci/values-full.yaml` | All features enabled (webapp, teamSettings, accountPages, fakeS3, federator, certManager) | +| `ci/values-manual-tls.yaml` | `tls.useCertManager: false`, wildcard cert supplied manually | +| `ci/values-federator.yaml` | `federator.enabled: true` with all federator-specific settings | +| `ci/values-byo-gateway.yaml` | `gateway.create: false`, referencing an external gateway | + +--- + +## Implementation plan + +The work is split into small, independently reviewable steps. Each step touches one logical +concern and can be reviewed by running `helm template` / `helm lint` on the partial chart. + +### Phase 1 — Chart scaffolding + +#### Chart.yaml, .helmignore, empty values.yaml, _helpers.tpl + +Create the chart skeleton with helpers for naming (`fullname`, `zone`, `getCertificateSecretName`, +`getIssuerName`, `getGatewayName`). + +Use `helm create` for an initial scaffolding. + +**Review:** `helm lint ./wire-ingress` passes with empty values. + +- [x] Done + +--- + +### Phase 2 — TLS + +#### TLS Secret (manual mode) + +Template: `templates/secret.yaml` +Condition: `!tls.useCertManager` + +Encodes `secrets.tlsWildcardCert` and `secrets.tlsWildcardKey` into a `kubernetes.io/tls` Secret +referenced by the Gateway listener. + +- [x] Done +- [x] Manually tested deployment + +--- + +#### cert-manager Certificate + Issuer + +Templates: `templates/certificate.yaml`, `templates/issuer.yaml` +Condition: `tls.useCertManager` + +A cert-manager `Certificate` and `Issuer`/`ClusterIssuer` for ACME HTTP-01 certificate issuance. +The `secretName` produced by the `Certificate` is referenced by the Gateway listener. + +- [x] Done +- [x] Manually tested http01 challenge, via issuer + +### Phase 3 — Gateway + +#### Optional Gateway resource + +Template: `templates/gateway.yaml` + +Creates a `gateway.networking.k8s.io/v1 Gateway` when `gateway.create: true`. The Gateway has: + +- An HTTPS listener on port 443 with TLS termination, referencing the TLS secret + +The federator listener is added in the federator phase (not here) to keep federator concerns separate. + +New values: + +```yaml +gateway: + create: true + name: "" # default: derived from release name via helper + className: envoy # GatewayClass installed by Envoy Gateway + listeners: + http: + port: 80 + https: + port: 443 +``` + +**Review:** `helm template` produces a valid `Gateway` manifest. Diff against old chart shows no +`Ingress` equivalent yet — that is expected. + +- [x] Done + +--- + +### Phase 4 — Core HTTPRoutes + +Each step adds one `HTTPRoute` (or one group of closely related routes). + +#### HTTPRoute — nginz (HTTPS endpoint) + +Template: `templates/httproute-nginz.yaml` + +Routes `config.dns.https` → `nginz` service port `http`. + +The route attaches to the HTTPS listener of the Gateway via `parentRefs`. + +**Review:** Renders correctly with and without TLS; `helm lint` passes. + +- [x] Done +- [x] Manually tested + +--- + +#### HTTPRoute — nginz websockets + +Template: `templates/httproute-nginz-websockets.yaml` +Condition: `websockets.enabled` + +Routes `config.dns.ssl` → `nginz` service port `ws`. WebSocket upgrades require no special +annotation in Envoy — they are transparent at the HTTP layer. + +**Review:** Rendered only when `websockets.enabled: true`. Hostname differs from nginz route. + +- [x] Done +- [x] Manually tested + +--- + +#### HTTPRoute + Service — webapp + +Templates: `templates/httproute-webapp.yaml`, `templates/service-webapp.yaml` +Condition: `webapp.enabled` + +Routes `config.dns.webapp` → `webapp-http` ClusterIP service port `service.webapp.externalPort`. + +**Review:** Absent from rendered output when `webapp.enabled: false`. + +- [x] Done +- [x] Manually tested + +--- + +#### HTTPRoute + Service — team-settings + +Templates: `templates/httproute-team-settings.yaml`, `templates/service-team-settings.yaml` +Condition: `teamSettings.enabled` + +Routes `config.dns.teamSettings` → `team-settings-http` ClusterIP service port `service.teamSettings.externalPort`. + +- [x] Done +- [x] Manually tested + +--- + +#### HTTPRoute + Service — account-pages + +Templates: `templates/httproute-account-pages.yaml`, `templates/service-account-pages.yaml` +Condition: `accountPages.enabled` + +Routes `config.dns.accountPages` → `account-pages-http` ClusterIP service port `service.accountPages.externalPort`. + +- [x] Done +- [x] Manually tested + +--- + +#### HTTPRoute + Service — fakeS3 / minio + +Template: `templates/httproute-minio.yaml` +Condition: `fakeS3.enabled` + +Routes `config.dns.fakeS3` → `fake-aws-s3` service directly (no intermediary ClusterIP service needed — the fake-aws-s3 chart creates its own service). + +Access to `/minio/` paths is blocked by a `RequestRedirect` to `/` (301), placed as a prefix +match rule before the catch-all. This is standard Gateway API — no Envoy extensions required. + +**Review:** Two rules rendered: one redirect rule for `/minio/` prefix, one catch-all for `/`. + +- [x] Done +- [x] Manually tested assets work + +--- + +### Phase 5 — Federator + +#### Gateway listener for federator + +Extend `templates/gateway.yaml` to add a separate TLS listener for `config.dns.federator` when +`federator.enabled: true`. + +The federator requires its own listener so that `ClientTrafficPolicy` can enforce mTLS only on +that listener, not on the main HTTPS listener. + +- [x] Done + +--- + +#### HTTPRoute for federator + +Template: `templates/httproute-federator.yaml` +Condition: `federator.enabled` + +Routes `config.dns.federator` → `federator` service port `federator-ext`, attaching to the +federator listener. + +Fails with an error if `config.isAdditionalIngress` is set, since federation and multi-ingress +cannot be combined. + +- [x] Done + +--- + +#### ClientTrafficPolicy for federator mTLS + +Template: `templates/clienttrafficpolicy-federator.yaml` +Condition: `federator.enabled` + +Envoy Gateway-specific (`gateway.envoyproxy.io/v1alpha1`). Configures: + +- `tls.clientValidation.caCertificateRef` → references `federator-ca-secret` +- Forwards the client certificate as `X-SSL-Certificate` request header (implementation-specific + header injection) + +Enforces mTLS client certificate validation and forwards the client certificate as the +`X-SSL-Certificate` request header to the federator backend. + +> **Incompatibility note:** The `tls.verify_depth` value is not directly mapped. Envoy Gateway's +> `ClientTrafficPolicy` does not expose a depth knob; validation depth is implicitly controlled by +> the CA chain provided in `federator-ca-secret`. + +- [x] Done +- [x] Manually tested a federated request (see check-federation-certs.sh script) + +--- + +#### Federator TLS secret + X-SSL-Certificate header injection + +Templates: `templates/secret-federator.yaml`, `templates/certificate-federator.yaml`, `templates/envoyextensionpolicy-federator.yaml` +Condition: `federator.enabled` + +Creates `federator-certificate-secret` (manual mode) or a cert-manager `Certificate` with both +`server auth` and `client auth` EKUs (`tls.useCertManager: true`). + +The `federator-ca` ConfigMap is **not** created by this chart — it is created by the wire-server +chart and must exist in the release namespace before deploying with `federator.enabled: true`. + +The `EnvoyExtensionPolicy` injects the mTLS client certificate as the `X-SSL-Certificate` request +header via an inline Lua filter, matching nginx's `$ssl_client_escaped_cert` behaviour. + +- [x] Done +- [x] Manually tested + +--- + +### Phase 6 — Integration test helper + +#### federation-test-helper Service + +Template: `templates/service-test-fed.yaml` + +A ClusterIP Service in `envoy-gateway-system` that selects the Envoy proxy pods for this +Gateway (using `gateway.envoyproxy.io/owning-gateway-*` labels). Because Envoy Gateway runs +proxy pods in its own namespace, a cross-namespace Service is needed to expose them for +DNS-based federation discovery. + +The service is named `-fed` and lives in `envoy-gateway-system`, so the SRV record +that Wire federation discovery resolves is: + +``` +_wire-server-federator._tcp.-fed.envoy-gateway-system.svc.cluster.local +``` + +- [x] Done + +--- + +### Phase 7 — Switch integration tests to wire-ingress + +Replace all uses of `nginx-ingress-services` in `hack/` with `wire-ingress`. + +The integration test setup deploys two federation namespaces (`namespace1`, `namespace2`) each +with their own ingress release. Both currently use `nginx-ingress-services`. The goal is to make +integration tests pass with `wire-ingress` in place of `nginx-ingress-services`. + +- [x] Done +- [x] deal with the federation ingresses for the dynamic backends. remove them? they are not needed. or set up the same way as federation (but no test) +- [x] fix integration test setup so all test pass + +--- + +### Phase 8 — custom solver secret + +#### Custom ACME solver secret + +Template: `templates/custom-solvers-secret.yaml` + +An opaque Secret containing credentials for custom ACME challenge solvers, referenced by +`certManager.customSolvers`. + +- [x] Drop this functionality and document this +- [x] Done + +--- + +### Phase 9 — Documentation and CI values + +#### Finalize PR + +- [x] introduce a flag that switches between gateway / ingress-nginx in the tests +- [x] investigate: migrate federation-test helper to integrations chart? NO, becasue we would need to pass the relase name +- [x] replace "envoy-gateway-system" hardcoded namespace with chart var +- [x] feature flag for envoypatch policies (enabled by default, turned off in tests) +- [x] document: must deploy enovy-gateway with patches enabled +- [x] envoy patch policies: adjust docs: its not a kubernetes problem, but that SRV records have to by FQDM +- [x] for .Values.federator.tls.useCertManager document that you'll likely needa private CA, since many public CA stopped issuing client auth certs +- [x] organize the parameter listing in this README better +- [x] rework patch policies so merged gateways work +- [x] test now if diya / elna federation works +- [x] test now if integration test pass +- [x] Write the migration guide section of this README +- [x] move the phases out of README +- [ ] clean up PR: no stray files +- [ ] remove CLAUDE.md +- [ ] make a note on nginx-ingress-services + +--- + +## Migration guide + +_To be written after implementation. Will cover:_ + +- Which values files can be reused as-is +- Which keys need renaming (see backwards compatibility table above) +- How to verify the migration with `helm template` diff +- Envoy Gateway prerequisites (CRDs, controller install) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index f55319377c0..d515179b916 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -292,364 +292,3 @@ Federator mTLS is implemented using: apply only to that listener - The `X-SSL-Certificate` header forwarding is handled via Envoy Gateway's `HTTPRouteFilter` with request header injection from the client cert (implementation-specific) - ---- ---- - -## Testing strategy - -### Rendering diff - -For each implementation step, render the chart and inspect the output: - -```bash -helm template release-name ./wire-ingress -f test-values.yaml -``` - -To verify routing coverage against the previous deployment, render both and compare (see the -migration guide for details). - -### Schema validation - -`values.schema.json` is maintained alongside `values.yaml`. Run `helm lint` to catch -misconfiguration early: - -```bash -helm lint ./wire-ingress -f test-values.yaml -``` - -### Test values files to maintain - -Create one values file per meaningful configuration variant to use with `helm template` and -`helm lint`: - -| File | Purpose | -|---|---| -| `ci/values-minimal.yaml` | Only required fields, all optional features disabled | -| `ci/values-full.yaml` | All features enabled (webapp, teamSettings, accountPages, fakeS3, federator, certManager) | -| `ci/values-manual-tls.yaml` | `tls.useCertManager: false`, wildcard cert supplied manually | -| `ci/values-federator.yaml` | `federator.enabled: true` with all federator-specific settings | -| `ci/values-byo-gateway.yaml` | `gateway.create: false`, referencing an external gateway | - ---- - -## Implementation plan - -The work is split into small, independently reviewable steps. Each step touches one logical -concern and can be reviewed by running `helm template` / `helm lint` on the partial chart. - -### Phase 1 — Chart scaffolding - -#### Chart.yaml, .helmignore, empty values.yaml, _helpers.tpl - -Create the chart skeleton with helpers for naming (`fullname`, `zone`, `getCertificateSecretName`, -`getIssuerName`, `getGatewayName`). - -Use `helm create` for an initial scaffolding. - -**Review:** `helm lint ./wire-ingress` passes with empty values. - -- [x] Done - ---- - -### Phase 2 — TLS - -#### TLS Secret (manual mode) - -Template: `templates/secret.yaml` -Condition: `!tls.useCertManager` - -Encodes `secrets.tlsWildcardCert` and `secrets.tlsWildcardKey` into a `kubernetes.io/tls` Secret -referenced by the Gateway listener. - -- [x] Done -- [x] Manually tested deployment - ---- - -#### cert-manager Certificate + Issuer - -Templates: `templates/certificate.yaml`, `templates/issuer.yaml` -Condition: `tls.useCertManager` - -A cert-manager `Certificate` and `Issuer`/`ClusterIssuer` for ACME HTTP-01 certificate issuance. -The `secretName` produced by the `Certificate` is referenced by the Gateway listener. - -- [x] Done -- [x] Manually tested http01 challenge, via issuer - -### Phase 3 — Gateway - -#### Optional Gateway resource - -Template: `templates/gateway.yaml` - -Creates a `gateway.networking.k8s.io/v1 Gateway` when `gateway.create: true`. The Gateway has: - -- An HTTPS listener on port 443 with TLS termination, referencing the TLS secret - -The federator listener is added in the federator phase (not here) to keep federator concerns separate. - -New values: - -```yaml -gateway: - create: true - name: "" # default: derived from release name via helper - className: envoy # GatewayClass installed by Envoy Gateway - listeners: - http: - port: 80 - https: - port: 443 -``` - -**Review:** `helm template` produces a valid `Gateway` manifest. Diff against old chart shows no -`Ingress` equivalent yet — that is expected. - -- [x] Done - ---- - -### Phase 4 — Core HTTPRoutes - -Each step adds one `HTTPRoute` (or one group of closely related routes). - -#### HTTPRoute — nginz (HTTPS endpoint) - -Template: `templates/httproute-nginz.yaml` - -Routes `config.dns.https` → `nginz` service port `http`. - -The route attaches to the HTTPS listener of the Gateway via `parentRefs`. - -**Review:** Renders correctly with and without TLS; `helm lint` passes. - -- [x] Done -- [x] Manually tested - ---- - -#### HTTPRoute — nginz websockets - -Template: `templates/httproute-nginz-websockets.yaml` -Condition: `websockets.enabled` - -Routes `config.dns.ssl` → `nginz` service port `ws`. WebSocket upgrades require no special -annotation in Envoy — they are transparent at the HTTP layer. - -**Review:** Rendered only when `websockets.enabled: true`. Hostname differs from nginz route. - -- [x] Done -- [x] Manually tested - ---- - -#### HTTPRoute + Service — webapp - -Templates: `templates/httproute-webapp.yaml`, `templates/service-webapp.yaml` -Condition: `webapp.enabled` - -Routes `config.dns.webapp` → `webapp-http` ClusterIP service port `service.webapp.externalPort`. - -**Review:** Absent from rendered output when `webapp.enabled: false`. - -- [x] Done -- [x] Manually tested - ---- - -#### HTTPRoute + Service — team-settings - -Templates: `templates/httproute-team-settings.yaml`, `templates/service-team-settings.yaml` -Condition: `teamSettings.enabled` - -Routes `config.dns.teamSettings` → `team-settings-http` ClusterIP service port `service.teamSettings.externalPort`. - -- [x] Done -- [x] Manually tested - ---- - -#### HTTPRoute + Service — account-pages - -Templates: `templates/httproute-account-pages.yaml`, `templates/service-account-pages.yaml` -Condition: `accountPages.enabled` - -Routes `config.dns.accountPages` → `account-pages-http` ClusterIP service port `service.accountPages.externalPort`. - -- [x] Done -- [x] Manually tested - ---- - -#### HTTPRoute + Service — fakeS3 / minio - -Template: `templates/httproute-minio.yaml` -Condition: `fakeS3.enabled` - -Routes `config.dns.fakeS3` → `fake-aws-s3` service directly (no intermediary ClusterIP service needed — the fake-aws-s3 chart creates its own service). - -Access to `/minio/` paths is blocked by a `RequestRedirect` to `/` (301), placed as a prefix -match rule before the catch-all. This is standard Gateway API — no Envoy extensions required. - -**Review:** Two rules rendered: one redirect rule for `/minio/` prefix, one catch-all for `/`. - -- [x] Done -- [x] Manually tested assets work - ---- - -### Phase 5 — Federator - -#### Gateway listener for federator - -Extend `templates/gateway.yaml` to add a separate TLS listener for `config.dns.federator` when -`federator.enabled: true`. - -The federator requires its own listener so that `ClientTrafficPolicy` can enforce mTLS only on -that listener, not on the main HTTPS listener. - -- [x] Done - ---- - -#### HTTPRoute for federator - -Template: `templates/httproute-federator.yaml` -Condition: `federator.enabled` - -Routes `config.dns.federator` → `federator` service port `federator-ext`, attaching to the -federator listener. - -Fails with an error if `config.isAdditionalIngress` is set, since federation and multi-ingress -cannot be combined. - -- [x] Done - ---- - -#### ClientTrafficPolicy for federator mTLS - -Template: `templates/clienttrafficpolicy-federator.yaml` -Condition: `federator.enabled` - -Envoy Gateway-specific (`gateway.envoyproxy.io/v1alpha1`). Configures: - -- `tls.clientValidation.caCertificateRef` → references `federator-ca-secret` -- Forwards the client certificate as `X-SSL-Certificate` request header (implementation-specific - header injection) - -Enforces mTLS client certificate validation and forwards the client certificate as the -`X-SSL-Certificate` request header to the federator backend. - -> **Incompatibility note:** The `tls.verify_depth` value is not directly mapped. Envoy Gateway's -> `ClientTrafficPolicy` does not expose a depth knob; validation depth is implicitly controlled by -> the CA chain provided in `federator-ca-secret`. - -- [x] Done -- [x] Manually tested a federated request (see check-federation-certs.sh script) - ---- - -#### Federator TLS secret + X-SSL-Certificate header injection - -Templates: `templates/secret-federator.yaml`, `templates/certificate-federator.yaml`, `templates/envoyextensionpolicy-federator.yaml` -Condition: `federator.enabled` - -Creates `federator-certificate-secret` (manual mode) or a cert-manager `Certificate` with both -`server auth` and `client auth` EKUs (`tls.useCertManager: true`). - -The `federator-ca` ConfigMap is **not** created by this chart — it is created by the wire-server -chart and must exist in the release namespace before deploying with `federator.enabled: true`. - -The `EnvoyExtensionPolicy` injects the mTLS client certificate as the `X-SSL-Certificate` request -header via an inline Lua filter, matching nginx's `$ssl_client_escaped_cert` behaviour. - -- [x] Done -- [x] Manually tested - ---- - -### Phase 6 — Integration test helper - -#### federation-test-helper Service - -Template: `templates/service-test-fed.yaml` - -A ClusterIP Service in `envoy-gateway-system` that selects the Envoy proxy pods for this -Gateway (using `gateway.envoyproxy.io/owning-gateway-*` labels). Because Envoy Gateway runs -proxy pods in its own namespace, a cross-namespace Service is needed to expose them for -DNS-based federation discovery. - -The service is named `-fed` and lives in `envoy-gateway-system`, so the SRV record -that Wire federation discovery resolves is: - -``` -_wire-server-federator._tcp.-fed.envoy-gateway-system.svc.cluster.local -``` - -- [x] Done - ---- - -### Phase 7 — Switch integration tests to wire-ingress - -Replace all uses of `nginx-ingress-services` in `hack/` with `wire-ingress`. - -The integration test setup deploys two federation namespaces (`namespace1`, `namespace2`) each -with their own ingress release. Both currently use `nginx-ingress-services`. The goal is to make -integration tests pass with `wire-ingress` in place of `nginx-ingress-services`. - -- [x] Done -- [x] deal with the federation ingresses for the dynamic backends. remove them? they are not needed. or set up the same way as federation (but no test) -- [x] fix integration test setup so all test pass - ---- - -### Phase 8 — custom solver secret - -#### Custom ACME solver secret - -Template: `templates/custom-solvers-secret.yaml` - -An opaque Secret containing credentials for custom ACME challenge solvers, referenced by -`certManager.customSolvers`. - -- [x] Drop this functionality and document this -- [x] Done - ---- - -### Phase 9 — Documentation and CI values - -#### Finalize PR - -- [x] introduce a flag that switches between gateway / ingress-nginx in the tests -- [x] investigate: migrate federation-test helper to integrations chart? NO, becasue we would need to pass the relase name -- [x] replace "envoy-gateway-system" hardcoded namespace with chart var -- [x] feature flag for envoypatch policies (enabled by default, turned off in tests) -- [x] document: must deploy enovy-gateway with patches enabled -- [x] envoy patch policies: adjust docs: its not a kubernetes problem, but that SRV records have to by FQDM -- [x] for .Values.federator.tls.useCertManager document that you'll likely needa private CA, since many public CA stopped issuing client auth certs -- [x] organize the parameter listing in this README better -- [x] rework patch policies so merged gateways work -- [x] test now if diya / elna federation works -- [x] test now if integration test pass -- [ ] Write the migration guide section of this README -- [ ] move the phases out of README -- [ ] clean up PR: no stray files -- [ ] remove CLAUDE.md -- [ ] make a note on nginx-ingress-services - ---- - -## Migration guide - -_To be written after implementation. Will cover:_ - -- Which values files can be reused as-is -- Which keys need renaming (see backwards compatibility table above) -- How to verify the migration with `helm template` diff -- Envoy Gateway prerequisites (CRDs, controller install) From caf3618709ea086a2f928477af73e493cc0ee207 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 25 Mar 2026 14:32:19 +0100 Subject: [PATCH 53/79] small corrections --- charts/wire-ingress/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index d515179b916..ce8638461e9 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -86,7 +86,7 @@ name overrides, etc.) can be found in `values.yaml`. | `gateway.serviceType` | `LoadBalancer` | Service type for the Envoy proxy service. Only used when `gateway.manageServiceType: true`. | | `gateway.infrastructure.annotations` | `{}` | Annotations forwarded to the LoadBalancer Service provisioned by Envoy Gateway — see [Gateway API docs](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.GatewayInfrastructure). Use for cloud-specific LB settings (e.g. AWS NLB). | | `gateway.proxyProtocol.enabled` | `false` | Creates a `ClientTrafficPolicy` enabling PROXY protocol on all listeners. Required when the upstream load balancer is configured to send PROXY protocol headers. | -| `gateway.patchPolicies.enabled` | `true` | Controls whether `` resources are created — see [EnvoyPatchPolicy](#envoypatchpolicy). | +| `gateway.patchPolicies.enabled` | `true` | Controls whether `EnvoyPatchPolicy` resources are created — see [EnvoyPatchPolicy](#envoypatchpolicy). | | `gateway.patchPolicies.targetGatewayClass` | `false` | When `true`, `EnvoyPatchPolicy` targets the `GatewayClass` instead of the `Gateway`. **Required when `gateway.envoyProxy.spec.mergeGateways: true`**: with merged Gateways, policies targeting a `Gateway` are not applied — they must target the `GatewayClass`. Leave `false` for single-Gateway deployments (e.g. integration tests). | | `gateway.controllerNamespace` | `envoy-gateway-system` | Can be ignored, relevant only for integration tests. Namespace where Envoy Gateway runs its proxy pods. Change only if Envoy Gateway was installed into a non-default namespace. | | `tls.secret.create` | `true` | If `false`, the TLS Secret is not created by this chart. Use when the secret is managed externally (e.g. by another operator). | @@ -290,5 +290,6 @@ Federator mTLS is implemented using: certificate validation, verify depth) - A separate `Gateway` listener (or dedicated `Gateway`) for the federator so that mTLS settings apply only to that listener -- The `X-SSL-Certificate` header forwarding is handled via Envoy Gateway's `HTTPRouteFilter` with - request header injection from the client cert (implementation-specific) +- `X-SSL-Certificate` header forwarding is handled via an `EnvoyExtensionPolicy` with an inline + Lua filter that reads the URL-encoded PEM client certificate from the connection and injects it + as a request header, matching nginx's `$ssl_client_escaped_cert` behaviour From e6d9479d52cf3289e280771d709f6e1958075b3d Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 25 Mar 2026 14:38:35 +0100 Subject: [PATCH 54/79] revert to normal --- .envrc | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- go.sh | 13 -------- 2 files changed, 91 insertions(+), 17 deletions(-) delete mode 100755 go.sh diff --git a/.envrc b/.envrc index 4ae8d1476ec..fbb67a797ad 100644 --- a/.envrc +++ b/.envrc @@ -1,8 +1,95 @@ +# Build a folder ./.env that contains the dev-shell which load all the right env +# vars. +# +# To speed up the nix evaluation, we only rebuild our environment when `./nix` +# or any of the `default.nix` files change. We do this by adding all these files +# to the nix store and using the store paths as a cache key. + +# FUTUREWORK: The speedhack saves only a couple of Seconds when cd'ing into the +# repo's directory. The price is some state we have to manage manually (e.g. +# `rm .direnv`) and a non-intuitive usage of flakes. +# +# The hack could be replaced by the line +# `use flake .\#` +# +# The env variable exports could then be added to the flake's devShell. + +nix_files=$(find . -name '*.nix' | grep -v '^./dist-newstyle') +for nix_file in $nix_files; do + watch_file "$nix_file" +done +watch_file ./services/nginz/third_party/nginx-zauth-module/* +watch_file ./libs/libzauth/**/* +store_paths=$(echo "$nix_files" ./services/nginz/third_party/nginx-zauth-module/ ./libs/libzauth/ | xargs nix-store --add ./nix) +layout_dir=$(direnv_layout_dir) +env_dir=./.env + +export NIX_CONFIG='extra-experimental-features = nix-command flakes' + +[[ -d "$layout_dir" ]] || mkdir -p "$layout_dir" + +if [[ ! -d "$env_dir" || ! -f "$layout_dir/nix-rebuild" || "$store_paths" != $(<"$layout_dir/nix-rebuild") ]]; then + bcmd=nix + if command -v nom &>/dev/null; then + if [[ "${USE_NOM}" != "0" ]]; then + bcmd=nom + fi + fi + echo "🔧 Building environment" + $bcmd build '.#wireServer.devEnv' -Lv --out-link ./.env --fallback + echo "$store_paths" >"$layout_dir/nix-rebuild" +fi + +PATH_add "./.env/bin" +PATH_add "./.env-hs-run/bin" +path_add "PKG_CONFIG_PATH" "./.env/lib/pkgconfig" +path_add "LIBRARY_PATH" "./.env/lib" +path_add "PYTHONPATH" "./hack/python" +PATH_add "./dist" + +# source .profile from `$env`. This sets NIX_PATH to pkgs defined in +# ./nix/default.nix. Tis is useful for nix tooling that runs inside this direnv, +# e.g. "nix-shell -p foo" will get "foo" for pkgs defined in ./nix/default.nix +[[ -f "./.env/.profile" ]] && source_env "./.env/.profile" + +# Locale +export LC_ALL=en_US.UTF-8 +export LANG=en_US.UTF-8 + +# RabbitMQ +export RABBITMQ_USERNAME=guest +export RABBITMQ_PASSWORD=alpaca-grapefruit + +export RABBITMQ_USERNAME_V0=guest +export RABBITMQ_PASSWORD_V0=alpaca-grapefruit + +export RABBITMQ_USERNAME_V1=guest +export RABBITMQ_PASSWORD_V1=alpaca-grapefruit + +# Redis +export REDIS_PASSWORD=very-secure-redis-cluster-password +export REDIS_ADDITIONAL_WRITE_PASSWORD=very-secure-redis-master-password + +# Integration tests +export INTEGRATION_DYNAMIC_BACKENDS_POOLSIZE=3 + +# AWS credentials for locally running services +# Keep these in sync with deploy/dockerephmeral/init.sh +export AWS_REGION="eu-west-1" +export AWS_ACCESS_KEY_ID="dummykey" +export AWS_SECRET_ACCESS_KEY="dummysecret" + +# integration test suite timeout +export TEST_TIMEOUT_SECONDS=2 + +# OTEL +OTEL_SEMCONV_STABILITY_OPT_IN=http + # uncomment if you plan to run the integration setup manually against kube-ci -unset AWS_REGION -unset AWS_ACCESS_KEY_ID -unset AWS_SECRET_ACCESS_KEY -source_env ../cailleach/.envrc +# unset AWS_REGION +# unset AWS_ACCESS_KEY_ID +# unset AWS_SECRET_ACCESS_KEY +# source_env ../cailleach/.envrc # allow local .envrc overrides [[ -f .envrc.local ]] && source_env .envrc.local diff --git a/go.sh b/go.sh deleted file mode 100755 index f4f17dcc470..00000000000 --- a/go.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -set -xe - -export HELM_DATA_HOME=$(mktemp -d) -export HELM_CONFIG_HOME=$(mktemp -d) -export HELM_CACHE_HOME=$(mktemp -d) - -make clean-charts - -NAMESPACE=test-stefan-2 DOCKER_TAG=0.0.2-pr.13994 make kube-integration-setup - -NAMESPACE=test-stefan-2 DOCKER_TAG=0.0.2-pr.13994 HELM_PARALLELISM=0 make kube-integration-test From b57c88376d7c9c16604fe12fd974412d2d3d0939 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 25 Mar 2026 14:40:10 +0100 Subject: [PATCH 55/79] remove unused file --- hack/helmfile-federation-v0.yaml.gotmpl | 124 ------------------------ 1 file changed, 124 deletions(-) delete mode 100644 hack/helmfile-federation-v0.yaml.gotmpl diff --git a/hack/helmfile-federation-v0.yaml.gotmpl b/hack/helmfile-federation-v0.yaml.gotmpl deleted file mode 100644 index 5247d1ba5be..00000000000 --- a/hack/helmfile-federation-v0.yaml.gotmpl +++ /dev/null @@ -1,124 +0,0 @@ ---- -helmDefaults: - wait: true - timeout: 600 - devel: true - createNamespace: true - -environments: - default: - values: - - federationCACertificate: {{ readFile "../services/nginz/integration-test/conf/nginz/integration-ca.pem" | quote }} - - rabbitmqUsername: guest - - rabbitmqPassword: guest ---- -repositories: - - name: jetstack - url: 'https://charts.jetstack.io' - - - name: bedag - url: 'https://bedag.github.io/helm-charts/' - - - name: wire - url: 'https://s3-eu-west-1.amazonaws.com/public.wire.com/charts-develop' - -releases: - - name: 'cert-manager' - namespace: cert-manager - chart: jetstack/cert-manager - set: - - name: installCRDs - value: true - - - name: 'federation-certs' - namespace: cert-manager - chart: bedag/raw - values: - - resources: - - apiVersion: v1 - kind: Secret - metadata: - name: federation-ca - namespace: cert-manager - data: - tls.crt: {{ readFile "../services/nginz/integration-test/conf/nginz/integration-ca.pem" | b64enc | quote }} - tls.key: {{ readFile "../services/nginz/integration-test/conf/nginz/integration-ca-key.pem" | b64enc | quote }} - - apiVersion: cert-manager.io/v1 - kind: ClusterIssuer - metadata: - name: federation - spec: - ca: - secretName: federation-ca - needs: - - 'cert-manager/cert-manager' - - - name: 'fake-aws' - namespace: wire-federation-v0 - chart: wire/fake-aws - version: 4.38.0-mandarin.14 - values: - - './helm_vars/fake-aws/values.yaml' - - - name: 'databases-ephemeral' - namespace: wire-federation-v0 - chart: 'wire/databases-ephemeral' - version: 4.38.0-mandarin.14 - - - name: 'rabbitmq' - namespace: wire-federation-v0 - chart: 'wire/rabbitmq' - version: 4.38.0-mandarin.14 - values: - - './helm_vars/rabbitmq/values.yaml.gotmpl' - - # - name: 'ingress' - # namespace: wire-federation-v0 - # chart: 'wire/ingress-nginx-controller' - # version: 4.38.0-mandarin.14 - # values: - # - './helm_vars/ingress-nginx-controller/values.yaml.gotmpl' - - # - name: 'ingress-svc' - # namespace: wire-federation-v0 - # chart: 'wire/nginx-ingress-services' - # version: 4.38.0-mandarin.14 - # values: - # - './helm_vars/nginx-ingress-services/values.yaml.gotmpl' - # set: - # - name: config.dns.federator - # value: wire-federation-v0.svc.cluster.local - # - name: config.dns.certificateDomain - # value: '*.wire-federation-v0.svc.cluster.local' - # needs: - # - 'ingress' - # - 'cert-manager/cert-manager' - # - 'cert-manager/federation-certs' - - - name: 'ingress-svc' - namespace: wire-federation-v0 - chart: '../.local/charts/wire-ingress' - values: - - './helm_vars/wire-ingress/values.yaml.gotmpl' - set: - # Federation domain is also the SRV record created by the - # federation-test-helper service. Maybe we can find a way to make these - # differ, so we don't make any silly assumptions in the code. - - name: config.dns.federator - value: wire-federation-v0.svc.cluster.local - - name: config.dns.certificateDomain - value: '*.wire-federation-v0.svc.cluster.local' - needs: - - 'cert-manager/cert-manager' - - 'cert-manager/federation-certs' - - - name: wire-server - namespace: wire-federation-v0 - chart: wire/wire-server - version: 4.38.0-mandarin.14 - values: - - './helm_vars/wire-federation-v0/values.yaml.gotmpl' - needs: - - 'cert-manager/cert-manager' - - 'cert-manager/federation-certs' - From dba41cccc24122471d2a15823a0e7a9b262463cd Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 25 Mar 2026 14:43:54 +0100 Subject: [PATCH 56/79] revert file --- hack/bin/integration-test.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hack/bin/integration-test.sh b/hack/bin/integration-test.sh index a0a0751d210..198750ee081 100755 --- a/hack/bin/integration-test.sh +++ b/hack/bin/integration-test.sh @@ -11,10 +11,7 @@ UPLOAD_LOGS=${UPLOAD_LOGS:-0} echo "Running integration tests on wire-server with parallelism=${HELM_PARALLELISM} ..." CHART=wire-server -# tests=(integration stern galley cargohold gundeck federator spar brig) -# tests=(federator) -tests=(federator integration) -# tests=(brig) +tests=(integration stern galley cargohold gundeck federator spar brig) cleanup() { if ((CLEANUP_LOCAL_FILES > 0)); then From d5a92eff0fdf067145cb04bf9c0ca3f4cf7b49c7 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 25 Mar 2026 14:45:17 +0100 Subject: [PATCH 57/79] update comment --- hack/bin/integration-setup-federation.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/bin/integration-setup-federation.sh b/hack/bin/integration-setup-federation.sh index 4676cfa5341..61e13b1391a 100755 --- a/hack/bin/integration-setup-federation.sh +++ b/hack/bin/integration-setup-federation.sh @@ -7,7 +7,7 @@ TOP_LEVEL="$DIR/../.." export NAMESPACE=${NAMESPACE:-test-integration} # Available $HELMFILE_ENV profiles: default, default-ssl, kind, kind-ssl HELMFILE_ENV=${HELMFILE_ENV:-default} -# Available modes: gateway (default, uses wire-ingress), nginx (uses nginx-ingress-services) +# This controls if integration tests run against ingress-nginx ofr envoy-gateway WIRE_INGRESS_MODE=${WIRE_INGRESS_MODE:-envoy} export WIRE_INGRESS_MODE ENVOY_GATEWAY_NAMESPACE=${ENVOY_GATEWAY_NAMESPACE:-envoy-gateway-system} From fb06b53998cadf85d21684c9f48435129e6d8e42 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 25 Mar 2026 14:50:24 +0100 Subject: [PATCH 58/79] rename file ingress-envoy.aml to envoy-gateway.yaml --- .../templates/{ingress-envoy.yaml => envoy-gateway.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename charts/integration/templates/{ingress-envoy.yaml => envoy-gateway.yaml} (100%) diff --git a/charts/integration/templates/ingress-envoy.yaml b/charts/integration/templates/envoy-gateway.yaml similarity index 100% rename from charts/integration/templates/ingress-envoy.yaml rename to charts/integration/templates/envoy-gateway.yaml From 6fce96e00927c0e70ac7f2d07416e0f009066e04 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 25 Mar 2026 14:56:28 +0100 Subject: [PATCH 59/79] add missing backentrafficpolicy to support websockets --- .../backendtrafficpolicy-websockets.yaml | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 charts/wire-ingress/templates/backendtrafficpolicy-websockets.yaml diff --git a/charts/wire-ingress/templates/backendtrafficpolicy-websockets.yaml b/charts/wire-ingress/templates/backendtrafficpolicy-websockets.yaml new file mode 100644 index 00000000000..c39393fbd23 --- /dev/null +++ b/charts/wire-ingress/templates/backendtrafficpolicy-websockets.yaml @@ -0,0 +1,25 @@ +{{- if .Values.websockets.enabled }} +{{/* Disables the stream idle timeout for WebSocket connections. + Envoy's default stream_idle_timeout is 5 minutes; once an HTTP connection + is upgraded to WebSocket, the timer fires if no frames flow in either + direction, closing the connection. Wire clients can be idle much longer + than that (infrequent push notifications), causing unnecessary reconnects. + Setting streamIdleTimeout to "0s" disables the idle timer entirely. + Envoy Gateway-specific (gateway.envoyproxy.io/v1alpha1). */}} +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: BackendTrafficPolicy +metadata: + name: {{ include "wire-ingress.fullname" . }}-nginz-websockets + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: {{ include "wire-ingress.fullname" . }}-nginz-websockets + timeout: + http: + streamIdleTimeout: "0s" +{{- end }} From a51ed9e22677b24f95ce7fc6aec8be311585083b Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 25 Mar 2026 14:58:41 +0100 Subject: [PATCH 60/79] remove CLAUDE.md --- charts/wire-ingress/CLAUDE.md | 5 ----- charts/wire-ingress/PLAN.md | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) delete mode 100644 charts/wire-ingress/CLAUDE.md diff --git a/charts/wire-ingress/CLAUDE.md b/charts/wire-ingress/CLAUDE.md deleted file mode 100644 index f277724b9f4..00000000000 --- a/charts/wire-ingress/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -# Working mode for wire-ingress - -- Work through the implementation plan in README.md one step at a time. -- After completing each step, stop and summarise what was done, then ask the user before proceeding to the next step. -- Keep README.md up to date with every change — if a plan step is completed, a design decision changes, or a backwards-compatibility note needs updating, update the README in the same commit/change. diff --git a/charts/wire-ingress/PLAN.md b/charts/wire-ingress/PLAN.md index f513e44243b..b61fcd3c1e1 100644 --- a/charts/wire-ingress/PLAN.md +++ b/charts/wire-ingress/PLAN.md @@ -341,8 +341,8 @@ An opaque Secret containing credentials for custom ACME challenge solvers, refer - [x] test now if integration test pass - [x] Write the migration guide section of this README - [x] move the phases out of README -- [ ] clean up PR: no stray files -- [ ] remove CLAUDE.md +- [x] clean up PR: no stray files +- [x] remove CLAUDE.md - [ ] make a note on nginx-ingress-services --- From f5b4422ea3092224d1af8dc89f6987b20e3c9bb3 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 25 Mar 2026 15:11:21 +0100 Subject: [PATCH 61/79] moved todo to ticket --- charts/wire-ingress/PLAN.md | 1 - 1 file changed, 1 deletion(-) diff --git a/charts/wire-ingress/PLAN.md b/charts/wire-ingress/PLAN.md index b61fcd3c1e1..d26e6454dcd 100644 --- a/charts/wire-ingress/PLAN.md +++ b/charts/wire-ingress/PLAN.md @@ -343,7 +343,6 @@ An opaque Secret containing credentials for custom ACME challenge solvers, refer - [x] move the phases out of README - [x] clean up PR: no stray files - [x] remove CLAUDE.md -- [ ] make a note on nginx-ingress-services --- From d27cf7555227c62c55dec0e5ef6d647bd61a72f2 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Fri, 27 Mar 2026 10:56:03 +0100 Subject: [PATCH 62/79] prevent any untested changes to the nginx-ingress-services chart --- hack/bin/integration-setup-federation.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/hack/bin/integration-setup-federation.sh b/hack/bin/integration-setup-federation.sh index 61e13b1391a..39c97d76ccd 100755 --- a/hack/bin/integration-setup-federation.sh +++ b/hack/bin/integration-setup-federation.sh @@ -7,7 +7,7 @@ TOP_LEVEL="$DIR/../.." export NAMESPACE=${NAMESPACE:-test-integration} # Available $HELMFILE_ENV profiles: default, default-ssl, kind, kind-ssl HELMFILE_ENV=${HELMFILE_ENV:-default} -# This controls if integration tests run against ingress-nginx ofr envoy-gateway +# This controls if integration tests run against ingress-nginx or envoy-gateway WIRE_INGRESS_MODE=${WIRE_INGRESS_MODE:-envoy} export WIRE_INGRESS_MODE ENVOY_GATEWAY_NAMESPACE=${ENVOY_GATEWAY_NAMESPACE:-envoy-gateway-system} @@ -15,6 +15,16 @@ export ENVOY_GATEWAY_NAMESPACE CHARTS_DIR="${TOP_LEVEL}/.local/charts" HELM_PARALLELISM=${HELM_PARALLELISM:-1} +changed_files=$(git --no-pager diff-tree --no-commit-id -r --name-only HEAD) + +if [[ "$WIRE_INGRESS_MODE" != "nginx" ]] && echo "$changed_files" | grep -q "^charts/nginx-ingress-services"; then + echo "ERROR: Changes detected in charts/nginx-ingress-services but WIRE_INGRESS_MODE is '${WIRE_INGRESS_MODE}'." + echo "This failure is intentional: changes to nginx-ingress-services are not exercised by the" + echo "integration test suite when running in envoy mode, and would be merged without any test coverage." + echo "To test these changes, re-run with WIRE_INGRESS_MODE=nginx." + exit 1 +fi + # shellcheck disable=SC1091 . "$DIR/helm_overrides.sh" "${DIR}"/integration-cleanup.sh @@ -28,7 +38,6 @@ HELM_PARALLELISM=${HELM_PARALLELISM:-1} # (e.g. cassandra from underneath databases-ephemeral) echo "updating recursive dependencies ..." charts=(fake-aws databases-ephemeral rabbitmq wire-server ingress-nginx-controller nginx-ingress-services wire-ingress) -# charts=(fake-aws databases-ephemeral rabbitmq wire-server ingress-nginx-controller nginx-ingress-services) mkdir -p ~/.parallel && touch ~/.parallel/will-cite printf '%s\n' "${charts[@]}" | parallel -P "${HELM_PARALLELISM}" "$DIR/update.sh" "$CHARTS_DIR/{}" From 1206c7843922f9379e641dcfd404ebfa1b6956e0 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Fri, 27 Mar 2026 11:29:56 +0100 Subject: [PATCH 63/79] remove PLAN.md --- charts/wire-ingress/PLAN.md | 356 ------------------------------------ 1 file changed, 356 deletions(-) delete mode 100644 charts/wire-ingress/PLAN.md diff --git a/charts/wire-ingress/PLAN.md b/charts/wire-ingress/PLAN.md deleted file mode 100644 index d26e6454dcd..00000000000 --- a/charts/wire-ingress/PLAN.md +++ /dev/null @@ -1,356 +0,0 @@ -## Testing strategy - -### Rendering diff - -For each implementation step, render the chart and inspect the output: - -```bash -helm template release-name ./wire-ingress -f test-values.yaml -``` - -To verify routing coverage against the previous deployment, render both and compare (see the -migration guide for details). - -### Schema validation - -`values.schema.json` is maintained alongside `values.yaml`. Run `helm lint` to catch -misconfiguration early: - -```bash -helm lint ./wire-ingress -f test-values.yaml -``` - -### Test values files to maintain - -Create one values file per meaningful configuration variant to use with `helm template` and -`helm lint`: - -| File | Purpose | -|---|---| -| `ci/values-minimal.yaml` | Only required fields, all optional features disabled | -| `ci/values-full.yaml` | All features enabled (webapp, teamSettings, accountPages, fakeS3, federator, certManager) | -| `ci/values-manual-tls.yaml` | `tls.useCertManager: false`, wildcard cert supplied manually | -| `ci/values-federator.yaml` | `federator.enabled: true` with all federator-specific settings | -| `ci/values-byo-gateway.yaml` | `gateway.create: false`, referencing an external gateway | - ---- - -## Implementation plan - -The work is split into small, independently reviewable steps. Each step touches one logical -concern and can be reviewed by running `helm template` / `helm lint` on the partial chart. - -### Phase 1 — Chart scaffolding - -#### Chart.yaml, .helmignore, empty values.yaml, _helpers.tpl - -Create the chart skeleton with helpers for naming (`fullname`, `zone`, `getCertificateSecretName`, -`getIssuerName`, `getGatewayName`). - -Use `helm create` for an initial scaffolding. - -**Review:** `helm lint ./wire-ingress` passes with empty values. - -- [x] Done - ---- - -### Phase 2 — TLS - -#### TLS Secret (manual mode) - -Template: `templates/secret.yaml` -Condition: `!tls.useCertManager` - -Encodes `secrets.tlsWildcardCert` and `secrets.tlsWildcardKey` into a `kubernetes.io/tls` Secret -referenced by the Gateway listener. - -- [x] Done -- [x] Manually tested deployment - ---- - -#### cert-manager Certificate + Issuer - -Templates: `templates/certificate.yaml`, `templates/issuer.yaml` -Condition: `tls.useCertManager` - -A cert-manager `Certificate` and `Issuer`/`ClusterIssuer` for ACME HTTP-01 certificate issuance. -The `secretName` produced by the `Certificate` is referenced by the Gateway listener. - -- [x] Done -- [x] Manually tested http01 challenge, via issuer - -### Phase 3 — Gateway - -#### Optional Gateway resource - -Template: `templates/gateway.yaml` - -Creates a `gateway.networking.k8s.io/v1 Gateway` when `gateway.create: true`. The Gateway has: - -- An HTTPS listener on port 443 with TLS termination, referencing the TLS secret - -The federator listener is added in the federator phase (not here) to keep federator concerns separate. - -New values: - -```yaml -gateway: - create: true - name: "" # default: derived from release name via helper - className: envoy # GatewayClass installed by Envoy Gateway - listeners: - http: - port: 80 - https: - port: 443 -``` - -**Review:** `helm template` produces a valid `Gateway` manifest. Diff against old chart shows no -`Ingress` equivalent yet — that is expected. - -- [x] Done - ---- - -### Phase 4 — Core HTTPRoutes - -Each step adds one `HTTPRoute` (or one group of closely related routes). - -#### HTTPRoute — nginz (HTTPS endpoint) - -Template: `templates/httproute-nginz.yaml` - -Routes `config.dns.https` → `nginz` service port `http`. - -The route attaches to the HTTPS listener of the Gateway via `parentRefs`. - -**Review:** Renders correctly with and without TLS; `helm lint` passes. - -- [x] Done -- [x] Manually tested - ---- - -#### HTTPRoute — nginz websockets - -Template: `templates/httproute-nginz-websockets.yaml` -Condition: `websockets.enabled` - -Routes `config.dns.ssl` → `nginz` service port `ws`. WebSocket upgrades require no special -annotation in Envoy — they are transparent at the HTTP layer. - -**Review:** Rendered only when `websockets.enabled: true`. Hostname differs from nginz route. - -- [x] Done -- [x] Manually tested - ---- - -#### HTTPRoute + Service — webapp - -Templates: `templates/httproute-webapp.yaml`, `templates/service-webapp.yaml` -Condition: `webapp.enabled` - -Routes `config.dns.webapp` → `webapp-http` ClusterIP service port `service.webapp.externalPort`. - -**Review:** Absent from rendered output when `webapp.enabled: false`. - -- [x] Done -- [x] Manually tested - ---- - -#### HTTPRoute + Service — team-settings - -Templates: `templates/httproute-team-settings.yaml`, `templates/service-team-settings.yaml` -Condition: `teamSettings.enabled` - -Routes `config.dns.teamSettings` → `team-settings-http` ClusterIP service port `service.teamSettings.externalPort`. - -- [x] Done -- [x] Manually tested - ---- - -#### HTTPRoute + Service — account-pages - -Templates: `templates/httproute-account-pages.yaml`, `templates/service-account-pages.yaml` -Condition: `accountPages.enabled` - -Routes `config.dns.accountPages` → `account-pages-http` ClusterIP service port `service.accountPages.externalPort`. - -- [x] Done -- [x] Manually tested - ---- - -#### HTTPRoute + Service — fakeS3 / minio - -Template: `templates/httproute-minio.yaml` -Condition: `fakeS3.enabled` - -Routes `config.dns.fakeS3` → `fake-aws-s3` service directly (no intermediary ClusterIP service needed — the fake-aws-s3 chart creates its own service). - -Access to `/minio/` paths is blocked by a `RequestRedirect` to `/` (301), placed as a prefix -match rule before the catch-all. This is standard Gateway API — no Envoy extensions required. - -**Review:** Two rules rendered: one redirect rule for `/minio/` prefix, one catch-all for `/`. - -- [x] Done -- [x] Manually tested assets work - ---- - -### Phase 5 — Federator - -#### Gateway listener for federator - -Extend `templates/gateway.yaml` to add a separate TLS listener for `config.dns.federator` when -`federator.enabled: true`. - -The federator requires its own listener so that `ClientTrafficPolicy` can enforce mTLS only on -that listener, not on the main HTTPS listener. - -- [x] Done - ---- - -#### HTTPRoute for federator - -Template: `templates/httproute-federator.yaml` -Condition: `federator.enabled` - -Routes `config.dns.federator` → `federator` service port `federator-ext`, attaching to the -federator listener. - -Fails with an error if `config.isAdditionalIngress` is set, since federation and multi-ingress -cannot be combined. - -- [x] Done - ---- - -#### ClientTrafficPolicy for federator mTLS - -Template: `templates/clienttrafficpolicy-federator.yaml` -Condition: `federator.enabled` - -Envoy Gateway-specific (`gateway.envoyproxy.io/v1alpha1`). Configures: - -- `tls.clientValidation.caCertificateRef` → references `federator-ca-secret` -- Forwards the client certificate as `X-SSL-Certificate` request header (implementation-specific - header injection) - -Enforces mTLS client certificate validation and forwards the client certificate as the -`X-SSL-Certificate` request header to the federator backend. - -> **Incompatibility note:** The `tls.verify_depth` value is not directly mapped. Envoy Gateway's -> `ClientTrafficPolicy` does not expose a depth knob; validation depth is implicitly controlled by -> the CA chain provided in `federator-ca-secret`. - -- [x] Done -- [x] Manually tested a federated request (see check-federation-certs.sh script) - ---- - -#### Federator TLS secret + X-SSL-Certificate header injection - -Templates: `templates/secret-federator.yaml`, `templates/certificate-federator.yaml`, `templates/envoyextensionpolicy-federator.yaml` -Condition: `federator.enabled` - -Creates `federator-certificate-secret` (manual mode) or a cert-manager `Certificate` with both -`server auth` and `client auth` EKUs (`tls.useCertManager: true`). - -The `federator-ca` ConfigMap is **not** created by this chart — it is created by the wire-server -chart and must exist in the release namespace before deploying with `federator.enabled: true`. - -The `EnvoyExtensionPolicy` injects the mTLS client certificate as the `X-SSL-Certificate` request -header via an inline Lua filter, matching nginx's `$ssl_client_escaped_cert` behaviour. - -- [x] Done -- [x] Manually tested - ---- - -### Phase 6 — Integration test helper - -#### federation-test-helper Service - -Template: `templates/service-test-fed.yaml` - -A ClusterIP Service in `envoy-gateway-system` that selects the Envoy proxy pods for this -Gateway (using `gateway.envoyproxy.io/owning-gateway-*` labels). Because Envoy Gateway runs -proxy pods in its own namespace, a cross-namespace Service is needed to expose them for -DNS-based federation discovery. - -The service is named `-fed` and lives in `envoy-gateway-system`, so the SRV record -that Wire federation discovery resolves is: - -``` -_wire-server-federator._tcp.-fed.envoy-gateway-system.svc.cluster.local -``` - -- [x] Done - ---- - -### Phase 7 — Switch integration tests to wire-ingress - -Replace all uses of `nginx-ingress-services` in `hack/` with `wire-ingress`. - -The integration test setup deploys two federation namespaces (`namespace1`, `namespace2`) each -with their own ingress release. Both currently use `nginx-ingress-services`. The goal is to make -integration tests pass with `wire-ingress` in place of `nginx-ingress-services`. - -- [x] Done -- [x] deal with the federation ingresses for the dynamic backends. remove them? they are not needed. or set up the same way as federation (but no test) -- [x] fix integration test setup so all test pass - ---- - -### Phase 8 — custom solver secret - -#### Custom ACME solver secret - -Template: `templates/custom-solvers-secret.yaml` - -An opaque Secret containing credentials for custom ACME challenge solvers, referenced by -`certManager.customSolvers`. - -- [x] Drop this functionality and document this -- [x] Done - ---- - -### Phase 9 — Documentation and CI values - -#### Finalize PR - -- [x] introduce a flag that switches between gateway / ingress-nginx in the tests -- [x] investigate: migrate federation-test helper to integrations chart? NO, becasue we would need to pass the relase name -- [x] replace "envoy-gateway-system" hardcoded namespace with chart var -- [x] feature flag for envoypatch policies (enabled by default, turned off in tests) -- [x] document: must deploy enovy-gateway with patches enabled -- [x] envoy patch policies: adjust docs: its not a kubernetes problem, but that SRV records have to by FQDM -- [x] for .Values.federator.tls.useCertManager document that you'll likely needa private CA, since many public CA stopped issuing client auth certs -- [x] organize the parameter listing in this README better -- [x] rework patch policies so merged gateways work -- [x] test now if diya / elna federation works -- [x] test now if integration test pass -- [x] Write the migration guide section of this README -- [x] move the phases out of README -- [x] clean up PR: no stray files -- [x] remove CLAUDE.md - ---- - -## Migration guide - -_To be written after implementation. Will cover:_ - -- Which values files can be reused as-is -- Which keys need renaming (see backwards compatibility table above) -- How to verify the migration with `helm template` diff -- Envoy Gateway prerequisites (CRDs, controller install) From a59a6c73f3a953cc711ee3ea379105d04af14b74 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Fri, 27 Mar 2026 11:32:00 +0100 Subject: [PATCH 64/79] add changelog entry --- changelog.d/5-internal/WPB-23903 | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/5-internal/WPB-23903 diff --git a/changelog.d/5-internal/WPB-23903 b/changelog.d/5-internal/WPB-23903 new file mode 100644 index 00000000000..c7a1e11ef4f --- /dev/null +++ b/changelog.d/5-internal/WPB-23903 @@ -0,0 +1 @@ +New `wire-ingress` Helm chart — Gateway API / Envoy Gateway replacement for `nginx-ingress-services`. Not yet production-ready. From 300c32e07d0e1a531b9d449e77dfb7eae514bdf9 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 29 Apr 2026 11:51:59 +0200 Subject: [PATCH 65/79] Prevent spoofing of the X-SSL-Certificate header --- .../wire-ingress/templates/clienttrafficpolicy-federator.yaml | 3 +++ .../wire-ingress/templates/envoyextensionpolicy-federator.yaml | 2 ++ 2 files changed, 5 insertions(+) diff --git a/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml b/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml index 0b21f785526..75c57fb1dc9 100644 --- a/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml +++ b/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml @@ -16,6 +16,9 @@ spec: name: {{ include "wire-ingress.getGatewayName" . | quote }} sectionName: federator tls: + {{/* Optional at the ingress level so the federator service can throw the + appropriate error when a cert is missing. Lua filter strips spoofed + X-SSL-Certificate header if no cert was actually provided. */}} clientValidation: optional: true caCertificateRefs: diff --git a/charts/wire-ingress/templates/envoyextensionpolicy-federator.yaml b/charts/wire-ingress/templates/envoyextensionpolicy-federator.yaml index 6473f17871d..b0a600ee501 100644 --- a/charts/wire-ingress/templates/envoyextensionpolicy-federator.yaml +++ b/charts/wire-ingress/templates/envoyextensionpolicy-federator.yaml @@ -19,6 +19,8 @@ spec: - type: Inline inline: | function envoy_on_request(request_handle) + {{/* Strip any client-provided header to prevent spoofing */}} + request_handle:headers():remove("X-SSL-Certificate") local ssl = request_handle:connection():ssl() if ssl ~= nil then local cert = ssl:urlEncodedPemEncodedPeerCertificate() From 249e3b5d18c59fe3259e699263c5e05668c81232 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 29 Apr 2026 12:58:37 +0200 Subject: [PATCH 66/79] fix: remove unused arg --- integration/test/Testlib/ModService.hs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/integration/test/Testlib/ModService.hs b/integration/test/Testlib/ModService.hs index d265786130f..cd6dc14d0f1 100644 --- a/integration/test/Testlib/ModService.hs +++ b/integration/test/Testlib/ModService.hs @@ -645,11 +645,11 @@ prepareNginzRuntimeFiles resource = do sm <- getServiceMap domain mBaseDir <- asks (.servicesCwdBase) case mBaseDir of - Nothing -> liftIO $ prepareNginzK8sRuntimeFiles domain sm + Nothing -> liftIO $ prepareNginzK8sRuntimeFiles sm Just basedir -> liftIO $ prepareNginzLocalRuntimeFiles resource sm basedir -prepareNginzK8sRuntimeFiles :: String -> ServiceMap -> IO (FilePath, FilePath, FilePath) -prepareNginzK8sRuntimeFiles domain sm = do +prepareNginzK8sRuntimeFiles :: ServiceMap -> IO (FilePath, FilePath, FilePath) +prepareNginzK8sRuntimeFiles sm = do tmpDir <- createTempDirectory "/tmp" "nginz-" copyDirectoryRecursively "/etc/wire/nginz/" tmpDir @@ -669,8 +669,6 @@ prepareNginzK8sRuntimeFiles domain sm = do prepareNginzLocalRuntimeFiles :: BackendResource -> ServiceMap -> FilePath -> IO (FilePath, FilePath, FilePath) prepareNginzLocalRuntimeFiles resource sm basedir = do - let domain = berDomain resource - -- Create a whole temporary directory and copy all nginx's config files. -- This is necessary because nginx assumes local imports are relative to -- the location of the main configuration file. From adc4668a86572e3d976e84554a59d0ccb33bf0d2 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 29 Apr 2026 13:00:02 +0200 Subject: [PATCH 67/79] integration tests: Prevent spoofing of the X-SSL-Certificate header --- charts/integration/templates/envoy-gateway.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/charts/integration/templates/envoy-gateway.yaml b/charts/integration/templates/envoy-gateway.yaml index 7d5cb34c88f..38e5b34e9c9 100644 --- a/charts/integration/templates/envoy-gateway.yaml +++ b/charts/integration/templates/envoy-gateway.yaml @@ -123,6 +123,8 @@ spec: - type: Inline inline: | function envoy_on_request(request_handle) + {{/* Strip any client-provided header to prevent spoofing */}} + request_handle:headers():remove("X-SSL-Certificate") local ssl = request_handle:connection():ssl() if ssl ~= nil then local cert = ssl:urlEncodedPemEncodedPeerCertificate() From d9dac756185755d19b790c8a559190b617205b9b Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 29 Apr 2026 13:16:39 +0200 Subject: [PATCH 68/79] Set namespace consitently --- .../wire-ingress/templates/backendtrafficpolicy-websockets.yaml | 1 + charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml | 1 + .../wire-ingress/templates/envoyextensionpolicy-federator.yaml | 1 + charts/wire-ingress/templates/envoypatchpolicy-federator.yaml | 1 + charts/wire-ingress/templates/envoyproxy.yaml | 1 + charts/wire-ingress/templates/gateway.yaml | 1 + charts/wire-ingress/templates/httproute-account-pages.yaml | 1 + charts/wire-ingress/templates/httproute-federator.yaml | 1 + charts/wire-ingress/templates/httproute-minio.yaml | 1 + charts/wire-ingress/templates/httproute-nginz-websockets.yaml | 1 + charts/wire-ingress/templates/httproute-nginz.yaml | 1 + charts/wire-ingress/templates/httproute-team-settings.yaml | 1 + charts/wire-ingress/templates/httproute-webapp.yaml | 1 + charts/wire-ingress/templates/secret.yaml | 1 + charts/wire-ingress/templates/service-account-pages.yaml | 1 + charts/wire-ingress/templates/service-team-settings.yaml | 1 + charts/wire-ingress/templates/service-webapp.yaml | 1 + 17 files changed, 17 insertions(+) diff --git a/charts/wire-ingress/templates/backendtrafficpolicy-websockets.yaml b/charts/wire-ingress/templates/backendtrafficpolicy-websockets.yaml index c39393fbd23..b9445e5c26d 100644 --- a/charts/wire-ingress/templates/backendtrafficpolicy-websockets.yaml +++ b/charts/wire-ingress/templates/backendtrafficpolicy-websockets.yaml @@ -10,6 +10,7 @@ apiVersion: gateway.envoyproxy.io/v1alpha1 kind: BackendTrafficPolicy metadata: name: {{ include "wire-ingress.fullname" . }}-nginz-websockets + namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" diff --git a/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml b/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml index 75c57fb1dc9..a2fa7413314 100644 --- a/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml +++ b/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml @@ -5,6 +5,7 @@ apiVersion: gateway.envoyproxy.io/v1alpha1 kind: ClientTrafficPolicy metadata: name: {{ include "wire-ingress.getGatewayName" . }}-federator-mtls + namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" diff --git a/charts/wire-ingress/templates/envoyextensionpolicy-federator.yaml b/charts/wire-ingress/templates/envoyextensionpolicy-federator.yaml index b0a600ee501..fa1db73025f 100644 --- a/charts/wire-ingress/templates/envoyextensionpolicy-federator.yaml +++ b/charts/wire-ingress/templates/envoyextensionpolicy-federator.yaml @@ -6,6 +6,7 @@ apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyExtensionPolicy metadata: name: {{ include "wire-ingress.fullname" . }}-federator-cert-header + namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" diff --git a/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml b/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml index f3c19f472f4..15bbbfae6f9 100644 --- a/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml +++ b/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml @@ -13,6 +13,7 @@ apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyPatchPolicy metadata: name: {{ include "wire-ingress.fullname" . }}-federator-fqdn-domain + namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" diff --git a/charts/wire-ingress/templates/envoyproxy.yaml b/charts/wire-ingress/templates/envoyproxy.yaml index 3a3829e54cc..e130dd3cbb7 100644 --- a/charts/wire-ingress/templates/envoyproxy.yaml +++ b/charts/wire-ingress/templates/envoyproxy.yaml @@ -4,6 +4,7 @@ apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyProxy metadata: name: {{ $name | quote }} + namespace: {{ .Release.Namespace }} spec: {{- with .Values.gateway.envoyProxy.spec }} {{- toYaml . | nindent 2 }} diff --git a/charts/wire-ingress/templates/gateway.yaml b/charts/wire-ingress/templates/gateway.yaml index 93ece9a7506..dfd954b094c 100644 --- a/charts/wire-ingress/templates/gateway.yaml +++ b/charts/wire-ingress/templates/gateway.yaml @@ -6,6 +6,7 @@ apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: {{ include "wire-ingress.getGatewayName" . | quote }} + namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" diff --git a/charts/wire-ingress/templates/httproute-account-pages.yaml b/charts/wire-ingress/templates/httproute-account-pages.yaml index 6e5b22e076e..d1f14db10f2 100644 --- a/charts/wire-ingress/templates/httproute-account-pages.yaml +++ b/charts/wire-ingress/templates/httproute-account-pages.yaml @@ -3,6 +3,7 @@ apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: {{ include "wire-ingress.fullname" . }}-account-pages + namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" diff --git a/charts/wire-ingress/templates/httproute-federator.yaml b/charts/wire-ingress/templates/httproute-federator.yaml index 6882f04aa91..67f32ea5565 100644 --- a/charts/wire-ingress/templates/httproute-federator.yaml +++ b/charts/wire-ingress/templates/httproute-federator.yaml @@ -3,6 +3,7 @@ apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: {{ include "wire-ingress.fullname" . }}-federator + namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" diff --git a/charts/wire-ingress/templates/httproute-minio.yaml b/charts/wire-ingress/templates/httproute-minio.yaml index 3c9bd50a9d1..25bf6510000 100644 --- a/charts/wire-ingress/templates/httproute-minio.yaml +++ b/charts/wire-ingress/templates/httproute-minio.yaml @@ -3,6 +3,7 @@ apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: {{ include "wire-ingress.fullname" . }}-minio + namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" diff --git a/charts/wire-ingress/templates/httproute-nginz-websockets.yaml b/charts/wire-ingress/templates/httproute-nginz-websockets.yaml index f9647011926..58a1b5d5664 100644 --- a/charts/wire-ingress/templates/httproute-nginz-websockets.yaml +++ b/charts/wire-ingress/templates/httproute-nginz-websockets.yaml @@ -3,6 +3,7 @@ apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: {{ include "wire-ingress.fullname" . }}-nginz-websockets + namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" diff --git a/charts/wire-ingress/templates/httproute-nginz.yaml b/charts/wire-ingress/templates/httproute-nginz.yaml index 4f005fa44b5..ae320181c83 100644 --- a/charts/wire-ingress/templates/httproute-nginz.yaml +++ b/charts/wire-ingress/templates/httproute-nginz.yaml @@ -2,6 +2,7 @@ apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: {{ include "wire-ingress.fullname" . }}-nginz + namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" diff --git a/charts/wire-ingress/templates/httproute-team-settings.yaml b/charts/wire-ingress/templates/httproute-team-settings.yaml index 8f0bce3baf0..35d1e5bd1fb 100644 --- a/charts/wire-ingress/templates/httproute-team-settings.yaml +++ b/charts/wire-ingress/templates/httproute-team-settings.yaml @@ -3,6 +3,7 @@ apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: {{ include "wire-ingress.fullname" . }}-team-settings + namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" diff --git a/charts/wire-ingress/templates/httproute-webapp.yaml b/charts/wire-ingress/templates/httproute-webapp.yaml index e84b4d78929..e130a9dd268 100644 --- a/charts/wire-ingress/templates/httproute-webapp.yaml +++ b/charts/wire-ingress/templates/httproute-webapp.yaml @@ -3,6 +3,7 @@ apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: {{ include "wire-ingress.fullname" . }}-webapp + namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" diff --git a/charts/wire-ingress/templates/secret.yaml b/charts/wire-ingress/templates/secret.yaml index e0094ba1777..8d3ccb4af32 100644 --- a/charts/wire-ingress/templates/secret.yaml +++ b/charts/wire-ingress/templates/secret.yaml @@ -3,6 +3,7 @@ apiVersion: v1 kind: Secret metadata: name: {{ include "wire-ingress.getCertificateSecretName" . | quote }} + namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" diff --git a/charts/wire-ingress/templates/service-account-pages.yaml b/charts/wire-ingress/templates/service-account-pages.yaml index 09fc3bce9e5..b8c2f09cc43 100644 --- a/charts/wire-ingress/templates/service-account-pages.yaml +++ b/charts/wire-ingress/templates/service-account-pages.yaml @@ -3,6 +3,7 @@ apiVersion: v1 kind: Service metadata: name: account-pages-http + namespace: {{ .Release.Namespace }} spec: type: ClusterIP ports: diff --git a/charts/wire-ingress/templates/service-team-settings.yaml b/charts/wire-ingress/templates/service-team-settings.yaml index 666a90d6010..ebbdb8b61e1 100644 --- a/charts/wire-ingress/templates/service-team-settings.yaml +++ b/charts/wire-ingress/templates/service-team-settings.yaml @@ -3,6 +3,7 @@ apiVersion: v1 kind: Service metadata: name: team-settings-http + namespace: {{ .Release.Namespace }} spec: type: ClusterIP ports: diff --git a/charts/wire-ingress/templates/service-webapp.yaml b/charts/wire-ingress/templates/service-webapp.yaml index 10958b36341..ce813484622 100644 --- a/charts/wire-ingress/templates/service-webapp.yaml +++ b/charts/wire-ingress/templates/service-webapp.yaml @@ -4,6 +4,7 @@ apiVersion: v1 kind: Service metadata: name: webapp-http + namespace: {{ .Release.Namespace }} spec: type: ClusterIP ports: From 196c682b2962c4d80d3e9d0dd7dec20bf242318a Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 29 Apr 2026 13:20:26 +0200 Subject: [PATCH 69/79] apply labels consitenly --- charts/wire-ingress/templates/envoyproxy.yaml | 4 ++++ charts/wire-ingress/templates/service-account-pages.yaml | 4 ++++ charts/wire-ingress/templates/service-team-settings.yaml | 4 ++++ charts/wire-ingress/templates/service-test-fed.yaml | 4 ++++ charts/wire-ingress/templates/service-webapp.yaml | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/charts/wire-ingress/templates/envoyproxy.yaml b/charts/wire-ingress/templates/envoyproxy.yaml index e130dd3cbb7..2f05f7046f2 100644 --- a/charts/wire-ingress/templates/envoyproxy.yaml +++ b/charts/wire-ingress/templates/envoyproxy.yaml @@ -5,6 +5,10 @@ kind: EnvoyProxy metadata: name: {{ $name | quote }} namespace: {{ .Release.Namespace }} + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" spec: {{- with .Values.gateway.envoyProxy.spec }} {{- toYaml . | nindent 2 }} diff --git a/charts/wire-ingress/templates/service-account-pages.yaml b/charts/wire-ingress/templates/service-account-pages.yaml index b8c2f09cc43..7a77dbea0d6 100644 --- a/charts/wire-ingress/templates/service-account-pages.yaml +++ b/charts/wire-ingress/templates/service-account-pages.yaml @@ -4,6 +4,10 @@ kind: Service metadata: name: account-pages-http namespace: {{ .Release.Namespace }} + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" spec: type: ClusterIP ports: diff --git a/charts/wire-ingress/templates/service-team-settings.yaml b/charts/wire-ingress/templates/service-team-settings.yaml index ebbdb8b61e1..08b1fe6dfb1 100644 --- a/charts/wire-ingress/templates/service-team-settings.yaml +++ b/charts/wire-ingress/templates/service-team-settings.yaml @@ -4,6 +4,10 @@ kind: Service metadata: name: team-settings-http namespace: {{ .Release.Namespace }} + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" spec: type: ClusterIP ports: diff --git a/charts/wire-ingress/templates/service-test-fed.yaml b/charts/wire-ingress/templates/service-test-fed.yaml index 8a14d1ab314..dfd00bff640 100644 --- a/charts/wire-ingress/templates/service-test-fed.yaml +++ b/charts/wire-ingress/templates/service-test-fed.yaml @@ -20,6 +20,10 @@ kind: Service metadata: name: {{ .Release.Namespace }}-fed namespace: {{ .Values.gateway.controllerNamespace }} + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" spec: type: ClusterIP ports: diff --git a/charts/wire-ingress/templates/service-webapp.yaml b/charts/wire-ingress/templates/service-webapp.yaml index ce813484622..832e5b0b030 100644 --- a/charts/wire-ingress/templates/service-webapp.yaml +++ b/charts/wire-ingress/templates/service-webapp.yaml @@ -5,6 +5,10 @@ kind: Service metadata: name: webapp-http namespace: {{ .Release.Namespace }} + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" spec: type: ClusterIP ports: From 7f220cc813c9dc3d6ffc79a9b56d25ed35ff591f Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 29 Apr 2026 14:24:29 +0200 Subject: [PATCH 70/79] leave comments to keep service names in-sync --- charts/integration/templates/_helpers.tpl | 1 + charts/wire-ingress/templates/service-test-fed.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/charts/integration/templates/_helpers.tpl b/charts/integration/templates/_helpers.tpl index c8d159d0470..1c0bd85ad52 100644 --- a/charts/integration/templates/_helpers.tpl +++ b/charts/integration/templates/_helpers.tpl @@ -13,6 +13,7 @@ Name of the Gateway resource for dynamic backends in envoy mode. {{/* Federation origin domain for a given namespace (used as originDomain in the config). Returns the SRV hostname that other backends use to reach this namespace's federator. +NOTE: Keep the naming assumption %s-fed in sync with the wire-ingress and nginx-ingress-services chart! Args: list $namespace $envoyEnabled $controllerNamespace */}} {{- define "integration.federationOriginDomain" -}} diff --git a/charts/wire-ingress/templates/service-test-fed.yaml b/charts/wire-ingress/templates/service-test-fed.yaml index dfd00bff640..38ae03cfc73 100644 --- a/charts/wire-ingress/templates/service-test-fed.yaml +++ b/charts/wire-ingress/templates/service-test-fed.yaml @@ -18,6 +18,7 @@ apiVersion: v1 kind: Service metadata: + # NOTE: keep this name in sync with with the "integrations" helm chart name: {{ .Release.Namespace }}-fed namespace: {{ .Values.gateway.controllerNamespace }} labels: From 0377f367d61b9fafe444998f53eaa6ec2edd7dbe Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Wed, 29 Apr 2026 14:48:03 +0200 Subject: [PATCH 71/79] Fix spelling --- charts/wire-ingress/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index ce8638461e9..c4ec274c6e4 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -8,7 +8,7 @@ The chart targets **Envoy Gateway** as the Gateway API controller. ## Status -**This chart is in development. Dont use it in production yet!** +**This chart is in development. Don't use it in production yet!** --- @@ -17,7 +17,7 @@ The chart targets **Envoy Gateway** as the Gateway API controller. ### Gateway API Install the [Gateway API](https://gateway-api.sigs.k8s.io/) into your cluster. -This chart makes use of the of the kinds defined in the `gateway.networking.k8s.io/v1` API. +This chart makes use of the kinds defined in the `gateway.networking.k8s.io/v1` API. ### Envoy Gateway @@ -32,13 +32,13 @@ config: enableEnvoyPatchPolicy: true ``` -Also make sure also you've created a `GatewayClass` object with +Also make sure you've created a `GatewayClass` object with ``` spec: controllerName: gateway.envoyproxy.io/gatewayclass-controller ``` -You need to refer to this object in the `gateway.className` paramter. +You need to refer to this object in the `gateway.className` parameter. --- @@ -63,10 +63,10 @@ Add a `gateway` block to your values and review at least the following keys: `secrets.tlsClientCA` is no longer needed and can be removed. -### Behaviour changes +### Behavior changes * non-tls ingress disabled by default. If you want to make use of automated certificate validation via http01, you need `gateway.listeners.http.enabled: true` -* s3 ingress b`/minio/` path blocking. Returns 301 redirect to "/" (was 403). +* s3 ingress `/minio/` path blocking. Returns 301 redirect to "/" (was 403). ### New values (no equivalent in nginx-ingress-services) From 05e23add40b22bb8c706fb3a259f2eaef759c08d Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Thu, 30 Apr 2026 13:58:40 +0200 Subject: [PATCH 72/79] integration tests: solve trailing dot same way as rest --- .../integration/templates/envoy-gateway.yaml | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/charts/integration/templates/envoy-gateway.yaml b/charts/integration/templates/envoy-gateway.yaml index 38e5b34e9c9..98ddae3617e 100644 --- a/charts/integration/templates/envoy-gateway.yaml +++ b/charts/integration/templates/envoy-gateway.yaml @@ -60,29 +60,9 @@ spec: - name: federator-ca kind: ConfigMap --- -# EnvoyPatchPolicy strips the trailing dot that Kubernetes DNS appends to FQDNs. -# Wire federator resolves targets via SRV and sends the raw FQDN (with trailing dot) -# as the HTTP/2 :authority header; strip_trailing_host_dot normalises it before -# Envoy's virtual-host matching, preventing route_not_found errors. -apiVersion: gateway.envoyproxy.io/v1alpha1 -kind: EnvoyPatchPolicy -metadata: - name: {{ $gatewayName }}-strip-dot -spec: - targetRef: - group: gateway.networking.k8s.io - kind: Gateway - name: {{ $gatewayName | quote }} - type: JSONPatch - jsonPatches: - - type: "type.googleapis.com/envoy.config.listener.v3.Listener" - # Single HTTPS listener → only one filter chain at index 0. - name: {{ printf "%s/%s/https" .Release.Namespace $gatewayName | quote }} - operation: - op: add - path: "/filter_chains/0/filters/0/typed_config/strip_trailing_host_dot" - value: true -{{- range $name, $dynamicBackend := .Values.config.dynamicBackends }} +{{- $backendNames := keys .Values.config.dynamicBackends | sortAlpha }} +{{- range $index, $name := $backendNames }} +{{- $dynamicBackend := index $.Values.config.dynamicBackends $name }} {{- $httpRouteName := printf "%s-dynbackend-%s" $gatewayName $name }} {{- $svcDomain := printf "%s-%s.%s.svc.cluster.local" $dynamicBackend.federatorExternalHostPrefix $.Release.Namespace $controllerNs }} --- @@ -134,6 +114,31 @@ spec: end end --- +# EnvoyPatchPolicy adds the FQDN variant (with trailing dot) of the backend domain +# to the virtual host's domain list. Wire federator resolves targets via DNS SRV records; +# per RFC 2782, SRV record targets are FQDNs (e.g. "backend-fed.ns.svc.cluster.local."). +# HTTP/2 passes that dot in :authority; without this patch the virtual host only matches +# the bare domain and returns route_not_found. Adding the FQDN allows Envoy to match both. +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyPatchPolicy +metadata: + name: {{ $httpRouteName }}-fqdn-domain +spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: {{ $gatewayName | quote }} + type: JSONPatch + jsonPatches: + - type: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration" + # RouteConfiguration is per-listener, named // + name: {{ printf "%s/%s/https" $.Release.Namespace $gatewayName | quote }} + operation: + op: add + # Virtual hosts are indexed in the order of stable key sorting (sortAlpha). + path: {{ printf "/virtual_hosts/%d/domains/-" $index | quote }} + value: {{ printf "%s." $svcDomain | quote }} +--- # ClusterIP service in {{ $controllerNs }} selects the Envoy proxy pods for this Gateway. # The service name determines the SRV record used by federation discovery: # _wire-server-federator._tcp.{{ $svcDomain }} From 707c7a3f83a5bb19363f106a6b04b3314e5157c9 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 5 May 2026 13:49:22 +0200 Subject: [PATCH 73/79] Update error message for keeping ingress solutions in sync --- hack/bin/integration-setup-federation.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hack/bin/integration-setup-federation.sh b/hack/bin/integration-setup-federation.sh index 39c97d76ccd..75e2bc5ce4e 100755 --- a/hack/bin/integration-setup-federation.sh +++ b/hack/bin/integration-setup-federation.sh @@ -21,7 +21,9 @@ if [[ "$WIRE_INGRESS_MODE" != "nginx" ]] && echo "$changed_files" | grep -q "^ch echo "ERROR: Changes detected in charts/nginx-ingress-services but WIRE_INGRESS_MODE is '${WIRE_INGRESS_MODE}'." echo "This failure is intentional: changes to nginx-ingress-services are not exercised by the" echo "integration test suite when running in envoy mode, and would be merged without any test coverage." - echo "To test these changes, re-run with WIRE_INGRESS_MODE=nginx." + echo "To test these changes, change to WIRE_INGRESS_MODE=nginx. and merge the changes" + echo "Then in a follow-up PR change WIRE_INGRESS_MODE=envoy and re-implement the changes also in charts/wire-ingress" + echo "FUTUREWORK: Remove WIRE_INGRESS_MODE once ingress-nginx is no longer supported by wire-server" exit 1 fi From fab3f52fa44e2f9db7a5f67590f4e71812c94038 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 5 May 2026 14:27:12 +0200 Subject: [PATCH 74/79] generalize the s3 httproute from minio --- .../{httproute-minio.yaml => httproute-s3.yaml} | 13 ++----------- charts/wire-ingress/values.yaml | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 11 deletions(-) rename charts/wire-ingress/templates/{httproute-minio.yaml => httproute-s3.yaml} (76%) diff --git a/charts/wire-ingress/templates/httproute-minio.yaml b/charts/wire-ingress/templates/httproute-s3.yaml similarity index 76% rename from charts/wire-ingress/templates/httproute-minio.yaml rename to charts/wire-ingress/templates/httproute-s3.yaml index 25bf6510000..7564ca46bfa 100644 --- a/charts/wire-ingress/templates/httproute-minio.yaml +++ b/charts/wire-ingress/templates/httproute-s3.yaml @@ -17,17 +17,8 @@ spec: hostnames: - {{ required "config.dns.fakeS3 is required when fakeS3.enabled is true" .Values.config.dns.fakeS3 | quote }} rules: - - matches: - - path: - type: PathPrefix - value: /minio/ - filters: - - type: RequestRedirect - requestRedirect: - path: - type: ReplaceFullPath - replaceFullPath: / - statusCode: 301 + {{- toYaml .Values.fakeS3.guardingRules | nindent 4 }} + {{/* Default catch-all rule routes to the S3 backend */}} - matches: - path: type: PathPrefix diff --git a/charts/wire-ingress/values.yaml b/charts/wire-ingress/values.yaml index 9da99a9e2fa..fb941ef7d5b 100644 --- a/charts/wire-ingress/values.yaml +++ b/charts/wire-ingress/values.yaml @@ -111,6 +111,21 @@ webapp: enabled: true fakeS3: enabled: true + # Guard rules applied BEFORE the default catch-all rule. + # These handle provider-specific paths. Adjust if using a different S3 provider. + # Uses Gateway API HTTPRoute rule format (matches/filters/backendRefs). + guardingRules: + - matches: + - path: + type: PathPrefix + value: /minio/ + filters: + - type: RequestRedirect + requestRedirect: + path: + type: ReplaceFullPath + replaceFullPath: / + statusCode: 301 teamSettings: enabled: false accountPages: From e395316483bb9b156805e2e109d1cd4b034a5696 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 5 May 2026 15:00:10 +0200 Subject: [PATCH 75/79] Document dependency on wire-server chart --- charts/wire-ingress/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/charts/wire-ingress/README.md b/charts/wire-ingress/README.md index c4ec274c6e4..05dce813be1 100644 --- a/charts/wire-ingress/README.md +++ b/charts/wire-ingress/README.md @@ -8,7 +8,7 @@ The chart targets **Envoy Gateway** as the Gateway API controller. ## Status -**This chart is in development. Don't use it in production yet!** +**This chart is in development. Don't use it in production yet! See FUTUREWORK below** --- @@ -19,6 +19,9 @@ The chart targets **Envoy Gateway** as the Gateway API controller. Install the [Gateway API](https://gateway-api.sigs.k8s.io/) into your cluster. This chart makes use of the kinds defined in the `gateway.networking.k8s.io/v1` API. +You must use install it in the same namespace as the `wire-server` helm chart, otherwise references will not work. +FUTUREWORK: Make this helm chart a subchart of `wire-server` before releasing it and remove this paragraph. + ### Envoy Gateway [Envoy Gateway](https://gateway.envoyproxy.io/) must be installed in the cluster before deploying From 24630f1cc9d810b0fee86bc20f7ce43cd845444d Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 5 May 2026 15:04:22 +0200 Subject: [PATCH 76/79] remove duplicated default in template --- .../templates/clienttrafficpolicy-proxy-protocol.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/wire-ingress/templates/clienttrafficpolicy-proxy-protocol.yaml b/charts/wire-ingress/templates/clienttrafficpolicy-proxy-protocol.yaml index 4969d3fbf2e..80151319890 100644 --- a/charts/wire-ingress/templates/clienttrafficpolicy-proxy-protocol.yaml +++ b/charts/wire-ingress/templates/clienttrafficpolicy-proxy-protocol.yaml @@ -14,5 +14,5 @@ spec: kind: Gateway name: {{ include "wire-ingress.getGatewayName" . | quote }} proxyProtocol: - optional: {{ .Values.gateway.proxyProtocol.optional | default false }} + optional: {{ .Values.gateway.proxyProtocol.optional }} {{- end }} From 599b57dcf591f0a2e39cb7354216100a5ef26ee9 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 5 May 2026 15:09:42 +0200 Subject: [PATCH 77/79] Add additional guard to secret creation --- charts/wire-ingress/templates/secret.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/wire-ingress/templates/secret.yaml b/charts/wire-ingress/templates/secret.yaml index 8d3ccb4af32..3cf5a1d23f0 100644 --- a/charts/wire-ingress/templates/secret.yaml +++ b/charts/wire-ingress/templates/secret.yaml @@ -1,4 +1,4 @@ -{{- if and (not .Values.tls.useCertManager) .Values.tls.secret.create }} +{{- if and (not .Values.tls.useCertManager) .Values.tls.secret.create .Values.secrets.tlsWildcardCert .Values.secrets.tlsWildcardKey }} apiVersion: v1 kind: Secret metadata: From c52c64dfe4695972481d5eea5179e4b554c41018 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 5 May 2026 15:10:36 +0200 Subject: [PATCH 78/79] remove yaml separator --- charts/wire-ingress/templates/service-webapp.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/charts/wire-ingress/templates/service-webapp.yaml b/charts/wire-ingress/templates/service-webapp.yaml index 832e5b0b030..7e2d0d496a4 100644 --- a/charts/wire-ingress/templates/service-webapp.yaml +++ b/charts/wire-ingress/templates/service-webapp.yaml @@ -1,5 +1,4 @@ {{- if .Values.webapp.enabled }} ---- apiVersion: v1 kind: Service metadata: From b76200c08ef071b8e802ceaf5777c53fbb4ff664 Mon Sep 17 00:00:00 2001 From: Stefan Matting Date: Tue, 5 May 2026 15:25:30 +0200 Subject: [PATCH 79/79] refactor: strip unnecessary "get" prefix from helpers --- charts/wire-ingress/templates/_helpers.tpl | 8 ++++---- charts/wire-ingress/templates/certificate-federator.yaml | 2 +- charts/wire-ingress/templates/certificate.yaml | 4 ++-- .../templates/clienttrafficpolicy-federator.yaml | 4 ++-- .../templates/clienttrafficpolicy-proxy-protocol.yaml | 4 ++-- .../templates/envoypatchpolicy-federator.yaml | 4 ++-- charts/wire-ingress/templates/envoyproxy.yaml | 2 +- charts/wire-ingress/templates/gateway.yaml | 6 +++--- .../wire-ingress/templates/httproute-account-pages.yaml | 2 +- charts/wire-ingress/templates/httproute-federator.yaml | 2 +- .../templates/httproute-nginz-websockets.yaml | 2 +- charts/wire-ingress/templates/httproute-nginz.yaml | 2 +- charts/wire-ingress/templates/httproute-s3.yaml | 2 +- .../wire-ingress/templates/httproute-team-settings.yaml | 2 +- charts/wire-ingress/templates/httproute-webapp.yaml | 2 +- charts/wire-ingress/templates/issuer.yaml | 6 +++--- charts/wire-ingress/templates/secret.yaml | 2 +- charts/wire-ingress/templates/service-test-fed.yaml | 2 +- 18 files changed, 29 insertions(+), 29 deletions(-) diff --git a/charts/wire-ingress/templates/_helpers.tpl b/charts/wire-ingress/templates/_helpers.tpl index 8a3edc6429a..263f190c90c 100644 --- a/charts/wire-ingress/templates/_helpers.tpl +++ b/charts/wire-ingress/templates/_helpers.tpl @@ -20,7 +20,7 @@ Determine DNS zone based on the HTTPS FQDN (e.g. "nginz-https.example.com" → " {{/* Name of the TLS certificate secret. Differs based on whether cert-manager is used. */}} -{{- define "wire-ingress.getCertificateSecretName" -}} +{{- define "wire-ingress.certificateSecretName" -}} {{- if .Values.tls.secret.nameOverride -}} {{- .Values.tls.secret.nameOverride -}} {{- else -}} @@ -38,7 +38,7 @@ Name of the TLS certificate secret. Differs based on whether cert-manager is use {{/* Name of the custom ACME solver secret. */}} -{{- define "wire-ingress.getCustomSolversSecretName" -}} +{{- define "wire-ingress.customSolversSecretName" -}} {{- $nameParts := list (include "wire-ingress.fullname" .) -}} {{- $nameParts = append $nameParts "cert-manager-custom-solvers" -}} {{- join "-" $nameParts -}} @@ -59,14 +59,14 @@ Returns the Letsencrypt ACME API server URL. {{/* Name of the cert-manager Issuer / ClusterIssuer. */}} -{{- define "wire-ingress.getIssuerName" -}} +{{- define "wire-ingress.issuerName" -}} {{ .Values.tls.issuer.name }} {{- end -}} {{/* Name of the Gateway resource. Uses gateway.name if set, otherwise derives one from the release name. */}} -{{- define "wire-ingress.getGatewayName" -}} +{{- define "wire-ingress.gatewayName" -}} {{- if .Values.gateway.name -}} {{ .Values.gateway.name }} {{- else -}} diff --git a/charts/wire-ingress/templates/certificate-federator.yaml b/charts/wire-ingress/templates/certificate-federator.yaml index b02c257c01f..0e5ef5219cc 100644 --- a/charts/wire-ingress/templates/certificate-federator.yaml +++ b/charts/wire-ingress/templates/certificate-federator.yaml @@ -17,7 +17,7 @@ spec: group: {{ .Values.federator.tls.issuer.group }} {{- end }} {{- else }} - name: {{ include "wire-ingress.getIssuerName" . | quote }} + name: {{ include "wire-ingress.issuerName" . | quote }} kind: {{ .Values.tls.issuer.kind }} {{- end }} usages: diff --git a/charts/wire-ingress/templates/certificate.yaml b/charts/wire-ingress/templates/certificate.yaml index 907ed721cbc..61ee9cb272b 100644 --- a/charts/wire-ingress/templates/certificate.yaml +++ b/charts/wire-ingress/templates/certificate.yaml @@ -10,14 +10,14 @@ metadata: heritage: "{{ .Release.Service }}" spec: issuerRef: - name: {{ include "wire-ingress.getIssuerName" . | quote }} + name: {{ include "wire-ingress.issuerName" . | quote }} kind: {{ .Values.tls.issuer.kind }} usages: - server auth duration: 2160h # 90d, Letsencrypt default; NOTE: changes are ignored by Letsencrypt renewBefore: 360h # 15d isCA: false - secretName: {{ include "wire-ingress.getCertificateSecretName" . | quote }} + secretName: {{ include "wire-ingress.certificateSecretName" . | quote }} privateKey: algorithm: {{ .Values.tls.privateKey.algorithm }} diff --git a/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml b/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml index a2fa7413314..f51a72058cb 100644 --- a/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml +++ b/charts/wire-ingress/templates/clienttrafficpolicy-federator.yaml @@ -4,7 +4,7 @@ apiVersion: gateway.envoyproxy.io/v1alpha1 kind: ClientTrafficPolicy metadata: - name: {{ include "wire-ingress.getGatewayName" . }}-federator-mtls + name: {{ include "wire-ingress.gatewayName" . }}-federator-mtls namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" @@ -14,7 +14,7 @@ spec: targetRefs: - group: gateway.networking.k8s.io kind: Gateway - name: {{ include "wire-ingress.getGatewayName" . | quote }} + name: {{ include "wire-ingress.gatewayName" . | quote }} sectionName: federator tls: {{/* Optional at the ingress level so the federator service can throw the diff --git a/charts/wire-ingress/templates/clienttrafficpolicy-proxy-protocol.yaml b/charts/wire-ingress/templates/clienttrafficpolicy-proxy-protocol.yaml index 80151319890..ed856304088 100644 --- a/charts/wire-ingress/templates/clienttrafficpolicy-proxy-protocol.yaml +++ b/charts/wire-ingress/templates/clienttrafficpolicy-proxy-protocol.yaml @@ -2,7 +2,7 @@ apiVersion: gateway.envoyproxy.io/v1alpha1 kind: ClientTrafficPolicy metadata: - name: {{ include "wire-ingress.getGatewayName" . }}-proxy-protocol + name: {{ include "wire-ingress.gatewayName" . }}-proxy-protocol namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" @@ -12,7 +12,7 @@ spec: targetRefs: - group: gateway.networking.k8s.io kind: Gateway - name: {{ include "wire-ingress.getGatewayName" . | quote }} + name: {{ include "wire-ingress.gatewayName" . | quote }} proxyProtocol: optional: {{ .Values.gateway.proxyProtocol.optional }} {{- end }} diff --git a/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml b/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml index 15bbbfae6f9..5b52b9ed938 100644 --- a/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml +++ b/charts/wire-ingress/templates/envoypatchpolicy-federator.yaml @@ -26,14 +26,14 @@ spec: name: {{ .Values.gateway.className | quote }} {{- else }} kind: Gateway - name: {{ include "wire-ingress.getGatewayName" . | quote }} + name: {{ include "wire-ingress.gatewayName" . | quote }} namespace: {{ .Release.Namespace | quote }} {{- end }} type: JSONPatch jsonPatches: - type: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration" # Route config name: //federator - name: {{ printf "%s/%s/federator" .Release.Namespace (include "wire-ingress.getGatewayName" .) | quote }} + name: {{ printf "%s/%s/federator" .Release.Namespace (include "wire-ingress.gatewayName" .) | quote }} operation: op: add path: "/virtual_hosts/0/domains/-" diff --git a/charts/wire-ingress/templates/envoyproxy.yaml b/charts/wire-ingress/templates/envoyproxy.yaml index 2f05f7046f2..12ff6f42b32 100644 --- a/charts/wire-ingress/templates/envoyproxy.yaml +++ b/charts/wire-ingress/templates/envoyproxy.yaml @@ -1,5 +1,5 @@ {{- if (and .Values.gateway.create .Values.gateway.envoyProxy.create) }} -{{- $name := .Values.gateway.envoyProxy.name | default (include "wire-ingress.getGatewayName" .) }} +{{- $name := .Values.gateway.envoyProxy.name | default (include "wire-ingress.gatewayName" .) }} apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyProxy metadata: diff --git a/charts/wire-ingress/templates/gateway.yaml b/charts/wire-ingress/templates/gateway.yaml index dfd954b094c..16b3f7bb720 100644 --- a/charts/wire-ingress/templates/gateway.yaml +++ b/charts/wire-ingress/templates/gateway.yaml @@ -5,7 +5,7 @@ apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: - name: {{ include "wire-ingress.getGatewayName" . | quote }} + name: {{ include "wire-ingress.gatewayName" . | quote }} namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" @@ -15,7 +15,7 @@ spec: gatewayClassName: {{ .Values.gateway.className | quote }} {{- $envoyProxyName := "" }} {{- if .Values.gateway.envoyProxy.create }} - {{- $envoyProxyName = .Values.gateway.envoyProxy.name | default (include "wire-ingress.getGatewayName" .) }} + {{- $envoyProxyName = .Values.gateway.envoyProxy.name | default (include "wire-ingress.gatewayName" .) }} {{- else if .Values.gateway.envoyProxy.name }} {{- $envoyProxyName = .Values.gateway.envoyProxy.name }} {{- end }} @@ -40,7 +40,7 @@ spec: tls: mode: Terminate certificateRefs: - - name: {{ include "wire-ingress.getCertificateSecretName" . | quote }} + - name: {{ include "wire-ingress.certificateSecretName" . | quote }} kind: Secret {{- if .Values.federator.enabled }} - name: federator diff --git a/charts/wire-ingress/templates/httproute-account-pages.yaml b/charts/wire-ingress/templates/httproute-account-pages.yaml index d1f14db10f2..c3ef24a374b 100644 --- a/charts/wire-ingress/templates/httproute-account-pages.yaml +++ b/charts/wire-ingress/templates/httproute-account-pages.yaml @@ -10,7 +10,7 @@ metadata: heritage: "{{ .Release.Service }}" spec: parentRefs: - - name: {{ include "wire-ingress.getGatewayName" . | quote }} + - name: {{ include "wire-ingress.gatewayName" . | quote }} namespace: {{ .Release.Namespace | quote }} kind: Gateway sectionName: https diff --git a/charts/wire-ingress/templates/httproute-federator.yaml b/charts/wire-ingress/templates/httproute-federator.yaml index 67f32ea5565..a747c27d8c2 100644 --- a/charts/wire-ingress/templates/httproute-federator.yaml +++ b/charts/wire-ingress/templates/httproute-federator.yaml @@ -10,7 +10,7 @@ metadata: heritage: "{{ .Release.Service }}" spec: parentRefs: - - name: {{ include "wire-ingress.getGatewayName" . | quote }} + - name: {{ include "wire-ingress.gatewayName" . | quote }} namespace: {{ .Release.Namespace | quote }} kind: Gateway sectionName: federator diff --git a/charts/wire-ingress/templates/httproute-nginz-websockets.yaml b/charts/wire-ingress/templates/httproute-nginz-websockets.yaml index 58a1b5d5664..5d9881d98d9 100644 --- a/charts/wire-ingress/templates/httproute-nginz-websockets.yaml +++ b/charts/wire-ingress/templates/httproute-nginz-websockets.yaml @@ -10,7 +10,7 @@ metadata: heritage: "{{ .Release.Service }}" spec: parentRefs: - - name: {{ include "wire-ingress.getGatewayName" . | quote }} + - name: {{ include "wire-ingress.gatewayName" . | quote }} namespace: {{ .Release.Namespace | quote }} kind: Gateway sectionName: https diff --git a/charts/wire-ingress/templates/httproute-nginz.yaml b/charts/wire-ingress/templates/httproute-nginz.yaml index ae320181c83..7bc50bb2890 100644 --- a/charts/wire-ingress/templates/httproute-nginz.yaml +++ b/charts/wire-ingress/templates/httproute-nginz.yaml @@ -9,7 +9,7 @@ metadata: heritage: "{{ .Release.Service }}" spec: parentRefs: - - name: {{ include "wire-ingress.getGatewayName" . | quote }} + - name: {{ include "wire-ingress.gatewayName" . | quote }} namespace: {{ .Release.Namespace | quote }} kind: Gateway sectionName: https diff --git a/charts/wire-ingress/templates/httproute-s3.yaml b/charts/wire-ingress/templates/httproute-s3.yaml index 7564ca46bfa..afb68412d74 100644 --- a/charts/wire-ingress/templates/httproute-s3.yaml +++ b/charts/wire-ingress/templates/httproute-s3.yaml @@ -10,7 +10,7 @@ metadata: heritage: "{{ .Release.Service }}" spec: parentRefs: - - name: {{ include "wire-ingress.getGatewayName" . | quote }} + - name: {{ include "wire-ingress.gatewayName" . | quote }} namespace: {{ .Release.Namespace | quote }} kind: Gateway sectionName: https diff --git a/charts/wire-ingress/templates/httproute-team-settings.yaml b/charts/wire-ingress/templates/httproute-team-settings.yaml index 35d1e5bd1fb..2de4cc0ea49 100644 --- a/charts/wire-ingress/templates/httproute-team-settings.yaml +++ b/charts/wire-ingress/templates/httproute-team-settings.yaml @@ -10,7 +10,7 @@ metadata: heritage: "{{ .Release.Service }}" spec: parentRefs: - - name: {{ include "wire-ingress.getGatewayName" . | quote }} + - name: {{ include "wire-ingress.gatewayName" . | quote }} namespace: {{ .Release.Namespace | quote }} kind: Gateway sectionName: https diff --git a/charts/wire-ingress/templates/httproute-webapp.yaml b/charts/wire-ingress/templates/httproute-webapp.yaml index e130a9dd268..158836040d1 100644 --- a/charts/wire-ingress/templates/httproute-webapp.yaml +++ b/charts/wire-ingress/templates/httproute-webapp.yaml @@ -10,7 +10,7 @@ metadata: heritage: "{{ .Release.Service }}" spec: parentRefs: - - name: {{ include "wire-ingress.getGatewayName" . | quote }} + - name: {{ include "wire-ingress.gatewayName" . | quote }} namespace: {{ .Release.Namespace | quote }} kind: Gateway sectionName: https diff --git a/charts/wire-ingress/templates/issuer.yaml b/charts/wire-ingress/templates/issuer.yaml index a71c7f9f662..6e6fb4820d6 100644 --- a/charts/wire-ingress/templates/issuer.yaml +++ b/charts/wire-ingress/templates/issuer.yaml @@ -6,7 +6,7 @@ kind: "{{ .Values.tls.issuer.kind }}" {{- fail (cat ".tls.issuer.kind can only be one of Issuer or ClusterIssuer, got: " .Values.tls.issuer.kind) }} {{- end }} metadata: - name: {{ include "wire-ingress.getIssuerName" . | quote }} + name: {{ include "wire-ingress.issuerName" . | quote }} {{- if eq .Values.tls.issuer.kind "Issuer" }} namespace: {{ .Release.Namespace }} {{- end }} @@ -20,7 +20,7 @@ spec: email: {{ required "Missing value: certmasterEmail" .Values.certManager.certmasterEmail | quote }} # NOTE: this secret doesn't need to be created manually, cert-manager manages it privateKeySecretRef: - name: {{ include "wire-ingress.getIssuerName" . -}}-account-key + name: {{ include "wire-ingress.issuerName" . -}}-account-key solvers: {{- if .Values.certManager.customSolvers }} {{ toYaml .Values.certManager.customSolvers | indent 6 }} @@ -31,7 +31,7 @@ spec: - http01: gatewayHTTPRoute: parentRefs: - - name: {{ include "wire-ingress.getGatewayName" . | quote }} + - name: {{ include "wire-ingress.gatewayName" . | quote }} namespace: {{ .Release.Namespace | quote }} kind: Gateway {{- end }} diff --git a/charts/wire-ingress/templates/secret.yaml b/charts/wire-ingress/templates/secret.yaml index 3cf5a1d23f0..52d1adbfe2b 100644 --- a/charts/wire-ingress/templates/secret.yaml +++ b/charts/wire-ingress/templates/secret.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Secret metadata: - name: {{ include "wire-ingress.getCertificateSecretName" . | quote }} + name: {{ include "wire-ingress.certificateSecretName" . | quote }} namespace: {{ .Release.Namespace }} labels: chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" diff --git a/charts/wire-ingress/templates/service-test-fed.yaml b/charts/wire-ingress/templates/service-test-fed.yaml index 38ae03cfc73..096a9b213ac 100644 --- a/charts/wire-ingress/templates/service-test-fed.yaml +++ b/charts/wire-ingress/templates/service-test-fed.yaml @@ -33,6 +33,6 @@ spec: protocol: TCP targetPort: {{ $httpsPort }} selector: - gateway.envoyproxy.io/owning-gateway-name: {{ include "wire-ingress.getGatewayName" . }} + gateway.envoyproxy.io/owning-gateway-name: {{ include "wire-ingress.gatewayName" . }} gateway.envoyproxy.io/owning-gateway-namespace: {{ .Release.Namespace }} {{- end }}