agent-platform release v4.7.2

Added

  • gateway.jwksEgress.external.fqdns, .cidrs and .port (443), in both charts: the destinations the agentgateway controller may reach for a JWKS the routes do not name, and for an issuer reached by address rather than by name. fqdns takes Cilium FQDN selectors (matchName, matchPattern), read by the cilium flavour and behind the DNS proxy rule its policy renders; the kubernetes flavour selects addresses and never names, so it ignores them. cidrs takes IP blocks of either family in both flavours, and is also the only way to reach what the kubernetes flavour cannot reach by name — its wide rule for a name is 0.0.0.0/0 and covers public IPv4 only, so a private identity provider inside worldExcludedCIDRs and an issuer resolved over IPv6 belong there. Each list is its own rule on .port, independent of gateway.jwksEgress.enabled. Both lists are typed: a cidrs block of either family no API server accepts fails the render, and an fqdns item is a selector object, never a bare string the Cilium CRD refuses.

Changed

  • jwtAuthentication.jwks.host is a hostname, and seven shapes that rendered green now fail the render (#312). Each reached runtime as 401 token uses the unknown key on every request, because the controller fetched no keys: an empty host; an empty jwks.port, which renders a backend the API server refuses; a host that carries a port (dex.example.com:5556), which belongs in jwks.port; an address literal of either family (198.51.100.7, 2001:db8::1, 1.2.3.999), which the controller cannot select by name — name its blocks in gateway.jwksEgress.external.cidrs instead; a host that is no hostname, a scheme or the JWKS path glued on (accounts.google.com/keys) and an empty or hyphen-terminated label (a..b.example.com, keys-.example.com) included, where the kubernetes flavour still opened its wide rule and hid the failure; and a host of fewer than three labels (dex, dex.giantswarm, okta.com), which is neither a qualified Service name nor a public issuer — a short Service name resolves through the pod’s search path, which the controller’s egress rule cannot follow. The route subtrees are open objects in values.schema.json, so these are template guards; each names the value to set. The last one follows networkPolicy.enabled: with no policy rendered every destination is reachable and the classification decides nothing.

Fixed

  • The agentgateway controller’s network policy reaches every external JWKS host the jwtAuthentication routes name, in both flavours (#312). The controller fetches each policy’s JWKS and pushes the keys to the data plane over xDS, so this is the controller’s egress; the data-plane policies do not change. The policy reads kagent.controllerRoute, modelManager.route and agentManager.route’s jwtAuthentication.jwks and opens each host that is not in-cluster on its own port: a toFQDNs matchName in the cilium flavour, an address block minus networkPolicy.kubernetes.worldExcludedCIDRs in the kubernetes flavour. The kubernetes flavour selects addresses and never names, so one named external host widens the controller’s egress to every public IPv4 destination on that port, minus the excluded blocks — and only while networkPolicy.kubernetes.apiServerCIDR is a real API-server block, because its default 0.0.0.0/0 on every port already covers that. An installation that wants it narrow names the issuer’s blocks in gateway.jwksEgress.external.cidrs. gateway.jwksEgress.enabled is now demanded for an in-cluster jwks.host only. A host counts as in-cluster when its third dot-separated label is svc and the labels after it are empty, cluster or cluster.local — the forms the pod’s search path produces. A public host that carries an svc label elsewhere (a.b.svc.example.com) is external and gets its own rule. Every host is classified and selected in its normalized form — lower case, root dot removed — so dex.giantswarm.svc.cluster.local. names the Service it looks like and no longer widens the controller’s egress to every public destination on the JWKS port. A route whose jwks.port is 443 originates TLS to the issuer without jwks.tls.enabled: the port serves no plain HTTP, so the fetch no longer returns no keys. TLS implied by the port verifies against jwks.tls.caSecretName or the system trust, never global.identity.ca.secretName: that key is the platform identity provider’s own CA, it signed no public issuer’s certificate, and pinning it would fail the fetch with the same 401. jwks.tls.enabled: true names that provider deliberately and keeps the fallback. No installation needs to act: with in-cluster JWKS hosts only, the whole render is byte-identical to before in both flavours, which make verify-wiring asserts against origin/main.