mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-13 08:05:19 +09:00
## What this PR does This keeps the TLS-passthrough services on port 443 of the tenant Gateway and makes the passthrough rules hold on Cilium 1.20.2. It is stacked on #3343 and has to land with it (stack #4717). On 1.20, upstream Cilium marks an HTTPS-terminate listener and a TLS-passthrough listener on one port `Conflicted` when their hostnames overlap, and drops both from Envoy. That took `*.<apex>` and the `api`, `vm-exportproxy` and `cdi-uploadproxy` passthrough listeners down together on every tenant Gateway in `dns01` and `existingSecret` mode (#3912). #3343 now ships a patched operator that conflicts the pair only when the hostnames are equal, so the layout stays as it is on main: one Gateway, one address, everything on 443. What remains is the equal-hostname case and the cleanup that 1.20 allows. Under `http01`, a name a passthrough listener answers is now reserved by the spec alone. Before, the controller dropped the terminate listener for such a name only once a TLSRoute was attached to the passthrough listener and its backend Service resolved, which copied how Cilium builds filter chains. Without a working TLSRoute, an HTTPRoute on `api.<apex>` kept its terminate listener next to `tls-api`, and on 1.20 that equal-hostname pair takes both listeners down. Now such an HTTPRoute gets no listener and no certificate, TLSRoute or not. If all its hostnames are reserved it reads `Accepted=False` with `NoMatchingListenerHostname`. If it also claims a free hostname it stays `Accepted` and is served there. The backend lookup, its Service and ReferenceGrant watches and their RBAC rules are gone. Other changes: - `tlsPassthroughListeners` is accepted under `dns01` and `existingSecret`. The old refusal relied on 1.19.5 serving all ports from one Envoy listener; 1.20 splits ports whose SNI overlaps. - A TenantGateway reads `Ready=False` with reason `GatewayClassUnsupported` when its GatewayClass lists features in `status.supportedFeatures` but not `TLSRoute`, while it renders passthrough listeners. A class that lists nothing is not judged. Cilium 1.20.2 lists `TLSRoute`. - Comments, the README and one error message no longer describe Cilium 1.19.5 as the shipped release. - The gateway chart writes `tlsPassthroughServices` on the publishing tenant only, behind the same `gateway.enabled` switch and `publishing.exposedServices` filter as the platform TLSRoutes. Before, every tenant Gateway got the three passthrough listeners with nothing routed to them, and the reservation above would have taken those names from a child tenant's own HTTPRoutes. The uniform `allowedRoutes.kinds` on port 443 from #3087 stays. The Cilium bug behind it is fixed since 1.19.6, but several tests pin it, so removing it is a separate cleanup. ### Upgrade notes Only the publishing tenant keeps the `api`, `vm-exportproxy` and `cdi-uploadproxy` passthrough listeners. That is `tenant-root` unless `publishing.ingressName` says otherwise, and only for names in `publishing.exposedServices` while `gateway.enabled` is on. Other tenants lose these listeners on upgrade. Nothing shipped was attached to them, so a child tenant's own HTTPRoute on `api.<child-apex>` keeps its listener and certificate. Two narrow cases do change. On the publishing tenant under `http01`, an HTTPRoute on an exposed passthrough name loses its listener and certificate when the platform TLSRoute for that name forwards nowhere (the owning package is not installed, or its backends do not resolve). A TLSRoute attached by hand to a child tenant's `tls-*` listener loses its parent. To keep that listener, merge-patch `tlsPassthroughServices` into the tenant's `TenantGateway` after the upgrade. From then on the chart does not render the key there, and later upgrades leave the patch alone. `dns01` and `existingSecret` do not change: the wildcard listener still covers such a name, and the passthrough listener answers it by its exact name. Tested locally: Go tests for the controller, `go vet`, helm-unittest for `extra/gateway` and `cozystack-controller`, `make generate` and `make manifests` with no diff. The gateway e2e scenario checks that a child tenant renders no passthrough listener. It then declares `tls-api` and a passthrough listener on a native port on that tenant, checks that the tenant stays Ready with no route behind either, and checks the reservation against `tls-api`. Unit tests catch a regression in either change. In e2e, dropping the reservation turns the gateway suite red, and dropping the chart scoping does not, because CI never sets `gateway.enabled` (#4846). The controller was not run on a live cluster; the operator patch it depends on was, see #3343. ### Downstream repositories - [ ] No downstream repository is affected by this change - [x] [cozystack/website](https://github.com/cozystack/website) - follow-up: https://github.com/cozystack/website/issues/725 - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note feat(gateway)!: the tenant Gateway renders the api, vm-exportproxy and cdi-uploadproxy passthrough listeners only on the publishing tenant, for the names publishing.exposedServices lists while gateway.enabled is on. Under certMode http01 a name a TLS-passthrough listener answers no longer gets an HTTPS listener on 443, with or without a TLSRoute behind it. On the publishing tenant, an HTTPRoute on such a name whose TLSRoute forwards nowhere loses its listener and certificate. A TLSRoute attached by hand to a tls-* listener of another tenant loses its parent. An HTTPRoute with some reserved and some free hostnames used to be rejected whole; it is now Accepted and its free hostnames get a listener and a certificate. tlsPassthroughListeners is accepted under dns01 and existingSecret. A TenantGateway whose GatewayClass does not list TLSRoute in its supported features reads Ready=False while it renders passthrough listeners. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * TLS passthrough listeners are supported with HTTP-01, DNS-01, and existing-secret certificate modes. Edge-terminated Gateways remain unsupported. * Declaring a passthrough hostname reserves it from HTTPS termination and certificate creation, even when no route is attached. * Passthrough listeners are rendered only for exposed services on the enabled publishing Gateway. * **Bug Fixes** * Gateways that declare passthrough listeners but explicitly lack TLSRoute support are now reported as not ready. * Routes targeting a hostname served by a passthrough listener on a different Gateway are correctly withdrawn. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
150 lines
7.5 KiB
YAML
150 lines
7.5 KiB
YAML
cilium:
|
|
# Required for the supported service-routing topology. Cozystack does not
|
|
# provide a supported alternative owner for ClusterIP translation when this
|
|
# is false; on kube-ovn, kube-proxy is absent and the OVN service load balancer
|
|
# is explicitly disabled. A false value can therefore break Service
|
|
# connectivity. tests/kube_proxy_replacement_test.yaml asserts the rendered
|
|
# value across the defaults and every variant valuesFiles combination.
|
|
#
|
|
# The source-side admission-webhook denies in packages/system/ingress-nginx
|
|
# and packages/system/kubeovn-webhook also rely on Cilium translating the
|
|
# Service before egress policy. Both policies retain a target-side ingressDeny,
|
|
# so even a second unsupported change that introduced another translator would
|
|
# not make the webhooks fail open.
|
|
#
|
|
# No test here can observe a live cluster's values, so an operator override in
|
|
# the field is caught only by templates/kube-proxy-replacement-beacon.yaml,
|
|
# which renders a status ConfigMap whenever this is not true. The beacon keeps
|
|
# a live unsupported override visible; it is not an alternative supported
|
|
# mode, and the required remediation is to restore true.
|
|
kubeProxyReplacement: true
|
|
# Upstream cilium with hostFirewall enabled and the IPv6 datapath disabled
|
|
# (ipv6.enabled=false, the default here) drops ALL node IPv6 before any
|
|
# policy evaluation ("Unsupported L3 protocol", DROP_UNKNOWN_L3 in
|
|
# bpf/bpf_host.c), breaking ICMPv6 Neighbor Discovery and BGP unnumbered on
|
|
# IPv6/L3 fabrics. The cozystack cilium image carries a BPF patch
|
|
# (images/cilium/patches/) that passes IPv6 to the kernel stack instead.
|
|
# Consequence: Cilium host policies apply to IPv4 only; node IPv6 is not
|
|
# filtered by Cilium.
|
|
hostFirewall:
|
|
enabled: true
|
|
hubble:
|
|
enabled: false
|
|
externalIPs:
|
|
enabled: true
|
|
nodePort:
|
|
enabled: true
|
|
loadBalancer:
|
|
algorithm: maglev
|
|
serviceTopology: true
|
|
ipam:
|
|
mode: "kubernetes"
|
|
image:
|
|
repository: ghcr.io/cozystack/cozystack/cilium
|
|
tag: v1.6.0
|
|
digest: "sha256:136a7dfff4d6adcd448424c2354144160028a8e96eb6558b917fd3ee6d7b39fe"
|
|
envoy:
|
|
enabled: true
|
|
# Keep the per-type xDS the 1.19 agent and envoy speak. The 1.20 chart
|
|
# defaults to ADS, which a 1.19 agent never serves and a 1.20 agent in
|
|
# ADS mode serves exclusively, so while the agent and envoy DaemonSets
|
|
# roll, a node with mixed versions gives envoy no config. Moving to ADS
|
|
# needs a step of its own once every node runs 1.20.
|
|
xdsMode: split
|
|
# Upstream default is {} — no requests/limits. The embedded envoy DaemonSet
|
|
# idles at ~100 MB RAM/node and grows under L7 traffic; without requests
|
|
# the DaemonSet schedules onto any node with no reserved headroom, and
|
|
# without a memory limit a runaway listener could OOM the node.
|
|
# The baseline matches the commented-out example in the upstream Helm values.
|
|
resources:
|
|
requests:
|
|
cpu: 100m
|
|
memory: 512Mi
|
|
limits:
|
|
memory: 1Gi
|
|
# The cilium-agent DaemonSet had the same gap the envoy DaemonSet above
|
|
# already closed. Beyond the node-headroom argument, a memory limit is what
|
|
# sets memory.max on the pod cgroup, and the Talos userspace OOM handler
|
|
# (v1.12+) only ever selects cgroups that lack it — so an unlimited agent is
|
|
# an eviction candidate on every node regardless of what caused the pressure.
|
|
#
|
|
# The limit has to hold the agent's BPF maps as well as its heap. Read at
|
|
# cilium 1.19.5: the CT, NAT, neighbor and socket rev-NAT maps are sized as a
|
|
# share of total node RAM (bpf-map-dynamic-size-ratio, 0.0025 by default),
|
|
# each capped at 16Mi entries (LimitTableMax). They are LRU hash maps, which
|
|
# the kernel always preallocates in full, and since Linux 5.11 that memory is
|
|
# charged to the memcg of the process that creates them, i.e. this container.
|
|
# A map reused from bpffs stays charged to whoever created it, so a limit too
|
|
# small for the maps first fails on the start that recreates them: after a
|
|
# reboot, or when an upgrade changes a map's size or layout. Policy maps do
|
|
# not scale with RAM: they are LPM tries sized by bpf.policyMapMax that
|
|
# allocate per entry.
|
|
#
|
|
# One DaemonSet serves every node, so the limit cannot follow node RAM and
|
|
# covers the map ceiling instead: just under 20Gi of kernel memory with every
|
|
# map at 16Mi entries for both IPv4 and IPv6 (IPv6 is off by default, but
|
|
# turning it on must not bring the OOM back), plus 4Gi for the agent itself,
|
|
# the figure from the upstream values' commented example. A limit is a
|
|
# ceiling, not a reservation, so it costs no schedulable memory. What it does
|
|
# cost is the backstop against a leak in the agent itself: on every node the
|
|
# agent is stopped at 24Gi minus its own map memory, which on most nodes is
|
|
# no practical backstop. memory.max still keeps the pod out of the Talos
|
|
# handler's victim set, which is what the limit is for. Pinning the map sizes
|
|
# instead would cap connection capacity on large nodes and, on upgrade,
|
|
# recreate the maps and drop their conntrack and NAT state.
|
|
resources:
|
|
requests:
|
|
cpu: 100m
|
|
memory: 256Mi
|
|
limits:
|
|
memory: 24Gi
|
|
# Shared by the agent's init containers (config, mount-cgroup, mount-bpf-fs,
|
|
# apply-sysctl-overwrites, clean-cilium-state). All are short-lived setup
|
|
# steps, but each one still has to carry a limit for the pod cgroup to get
|
|
# memory.max at all.
|
|
initResources:
|
|
requests:
|
|
cpu: 10m
|
|
memory: 32Mi
|
|
limits:
|
|
memory: 256Mi
|
|
gatewayAPI:
|
|
enabled: true
|
|
# Upstream default is false — Envoy then advertises no ALPN protocols on
|
|
# TLS-terminating Gateway listeners, and browsers (which negotiate HTTP/2
|
|
# exclusively through TLS ALPN "h2") silently fall back to HTTP/1.1 on
|
|
# every request. ingress-nginx, which the Gateway API path replaces,
|
|
# advertised h2 out of the box, so false here is a client-visible
|
|
# regression, not a neutral default. With true, ALPN offers h2 then
|
|
# http/1.1 — clients without HTTP/2 keep negotiating http/1.1 unchanged.
|
|
# This only affects the client↔gateway hop: gateway↔backend stays
|
|
# HTTP/1.1 unless a Service opts in per GEP-1911 via appProtocol
|
|
# kubernetes.io/h2c (enableAlpn also switches that support on; no
|
|
# cozystack-shipped Service declares such a value today).
|
|
# Platform-managed clusters can flip this through the platform chart's
|
|
# gateway.http2 value, which overrides this default either way.
|
|
enableAlpn: true
|
|
rollOutCiliumPods: true
|
|
operator:
|
|
# A rebuild of the upstream operator carrying the Go patches in
|
|
# images/cilium-operator/patches/: it accepts an HTTPS listener and a TLS
|
|
# passthrough listener on one port when the passthrough hostname is
|
|
# strictly narrower, and serves such a port from one Envoy listener.
|
|
# `make image` stamps the ref; until it does, the committed value is the
|
|
# unpatched upstream operator the rebuild starts from, so a tree rendered
|
|
# without a build still pulls an image that exists.
|
|
image:
|
|
override: "quay.io/cilium/operator-generic:v1.20.2@sha256:64d8798350e8569b8e7622563fed6e44dce2625f311e4651b774816516c744fc"
|
|
rollOutPods: true
|
|
replicas: 1
|
|
resources:
|
|
limits:
|
|
cpu: 1000m
|
|
memory: 1Gi
|
|
requests:
|
|
cpu: 100m
|
|
memory: 128Mi
|
|
# kubectl and jq for the hook Jobs in templates/ipam-migration.yaml.
|
|
ipamMigration:
|
|
image: docker.io/alpine/k8s:1.36.2@sha256:44ef4942e171939b9c665a4a84beb80e2dcdb9a24330d4651cfdfd2e9deecc47
|