agent-platform release v4.3.0

Added

  • Agent Substrate ships inside the chart (meta chart 4.0, giantswarm/agent-platform#342). kagent API v2 has no runtime without it — every agent is a Substrate actor in a gVisor worker pod — so two roster entries deliver it from the Giant Swarm Substrate line (giantswarm/substrate, branch giantswarm: the upstream release kagent’s go.mod pins plus the carried patches; FORK.md there is the ledger), oci://ghcr.io/giantswarm/substrate/helm: components.substrate-crds (the three ate.dev CRDs as templates) and components.substrate (the control plane — ate-api-server, ate-controller, the atenet router, egress gateway and dns, the per-node atelet DaemonSet — in ate-system, the podcertificate-controller in its own namespace). Both follow components.kagent when left unset (the render refuses kagent on with either off, and Substrate on without its CRDs — agent-platform.validateSubstrate), both land in ate-system through the new roster key components.<name>.targetNamespace (the chart’s Roles and Service names are fixed to it), both carry one version pin — the same string in the two versionRanges and in kagent.substrateWorkerPool.workerImage, held to one by make verify-components: the range >=0.0.27-gs.2 <0.0.28-0 (the line’s releases of upstream 0.0.27 from v0.0.27-gs.2 on — the egress gateway’s frontend policy for its agentgateway dataplane, the connection string from a Secret, atelet scheduling), its floor the worker image’s tag. Roster components rather than the kagent charts’ substrate subchart switches: each release has its own Flux status, the order is explicit, the repository is a value (a mirror for a proxied installation, with substrate.image.registry), Substrate’s namespace is not kagent’s. The substrate: block is forwarded verbatim (the chart has no schema): postgres.enabled: auto (below), rustfs.enabled: false (the bundled in-cluster store is a lab’s), atelet.storageBackend, atelet.{nodeSelector,tolerations,affinity} (carried patch of the line; empty = every node the DaemonSet controller admits, the worker nodes on a cluster whose control planes are tainted), atelet.extraEnv (an S3-compatible store’s endpoint and credentials). Bootstrap: the connectivity release’s pre-install,pre-upgrade hook Job <release>-substrate-bootstrap mints what the substrate chart mounts but does not render — the CA pools service-dns-ca-pool, pod-identity-ca-pool (podcertificate-controller-system), the JWT authority pool actor-id-jwt-pool, the CA pool actor-id-ca-pool and the derived trust anchor actor-id-ca-certs (ate-system), and the ConfigMap ate-api-authentication with the apiserver’s own issuer read from its OpenID discovery document — with openssl in an init container (an ED25519 root per CA pool, an ECDSA P-256 ES256 authority, in the pools’ wire format) and kubectl, creates the two namespaces bare when missing, and never touches a pool that exists (a re-run, every upgrade, logs present; a regenerated root would orphan every certificate issued from it). Hook include agent-platform.hooks.job (templates/_hooks.tpl) and the hook identity <release>-hooks (a ClusterRole on secrets, configmaps and namespaces for the hook’s lifetime; hooks.kubectlImage, hooks.opensslImage). Install order: substrate-crds, kagent-crds → agent-platform-connectivity → substrate → kagent → the managers — the connectivity release dependsOn the CRD components, never kagent or substrate, which depend on it (their pods start against what its hooks mint), so nothing waits on a pod that waits on a later release and components.kagent.installDisableWait is gone. Database: postgres.databases — a map of further CNPG Databases on the platform Cluster (<clusterName>-<key>, owned by the application role, retain) each with a derived connection Secret <clusterName>-<key>-app copied into postgres.namespace and every secretNamespaces entry by the post-install,post-upgrade hook <release>-postgres-databases (CNPG mints <clusterName>-app for the initdb database only, a Database mints none; the hook waits for it and rewrites dbname, uri, jdbc-uri, pgpass; server-side applied, idempotent); shipped entry substrate (spec.name substrate, secretNamespaces: [ate-system], renders while the component is on), an installation adds its own. substrate.postgres.enabled: auto resolves in the meta chart’s shape pass: the Cluster’s Database with postgres.enabled (the meta chart derives substrate.postgres.connectionStringSecretRef → <clusterName>-substrate-app/uri; a disagreeing explicit value fails the render), the chart’s bundled single-instance StatefulSet without it (a lab); true/false force, connectionString names an external one, none of the three fails the render. Snapshot store: kagent.harness.snapshotLocation (the platform Harness’s snapshotPolicy.location, s3://<bucket>/<prefix>) is required whenever kagent is on — S3 via IRSA on CAPA (bucket provisioning documented, not rendered), an S3-compatible store through substrate.atelet.extraEnv, a lab’s in-cluster store; the render fails without it. Scheduling: the WorkerPool pinned to one CPU architecture (kagent.substrateWorkerPool.template.nodeSelector kubernetes.io/arch: amd64; the golden snapshot is architecture-specific). Kyverno: one PolicyException per Substrate workload in kyvernoPolicies.policyExceptionNamespace — substrate-atelet, substrate-workers (label ate.dev/worker-pool, every WorkerPool in the kagent namespace), substrate-control-plane, substrate-podcertificate-controller — each naming exactly the restricted-PSS rules its pod spec violates with their autogen- copies, looked up in the new kyvernoPolicies.rules map; make verify-kyverno (tests/verify-kyverno.py) renders the substrate chart at the pin with the forwarded values, computes every workload’s violations (and the worker pod’s, from ate-controller’s pod template) and holds the exceptions to them. Network policies (both flavours, templates/substrate/netpol.yaml): Substrate’s hops — atelet ↔ ate-api, the kagent controller → ate-api and the atenet router, the router → a worker’s tunnel :443, ate-api → atelet’s hostPort 8085 (the egress rule upstream lacks), the workers → the egress gateway and the dns — and the actors’ destinations on the egress gateway atenet-egress (muster, the kagent controller, the LLM provider or the agentgateway LLM listener, the built-in tool server, world:443, cluster 443/10443), which the kagent controller admits (substrate-actors-to-kagent-controller); the worker pods reach only the egress gateway, the dns and the cluster DNS; make verify-kagent-netpol asserts it. Prerequisites: Kubernetes 1.35 with the ClusterTrustBundle, ClusterTrustBundleProjection and PodCertificateRequest gates on apiserver, controller-manager and kubelet (README “Agent Substrate”, UPGRADE.md); a live render refuses a cluster that does not serve certificates.k8s.io/v1beta1/PodCertificateRequest, naming the gates and that the kubelet’s cannot be seen — never helm template. Security write-up for installation owners and reviewers: docs/substrate-security.md. Not lab-verified: Kyverno admission, Cilium enforcement of the policies and IRSA against S3 (the lab has none of the three); their render is asserted, the runtime proof is the first Giant Swarm installation of the rollout.

Changed

  • kyvernoPolicies.rules (rule → ClusterPolicy of the cluster’s Pod Security Standard policies, upstream kyverno-policies’ names by default) replaces kyvernoPolicies.seccompPolicyName, seccompRuleNames, volumeTypesPolicyName and volumeTypesRuleNames; the CNPG ImageVolume exception reads restricted-volumes from it. The helper agent-platform.kyverno.exceptions renders an exception’s exceptions: from a rule list. An installation that overrode the four keys moves the names into the map (UPGRADE.md); the schema refuses the old keys.
  • The kagent controller’s network policies open Substrate: egress to ate-api-server :443 and atenet-router :8080 in ate-system (replacing the egress to the v1alpha2 agent pods), and the CNPG Cluster’s policy admits ate-api-server on 5432 while Substrate’s database rides the Cluster. The model-serving predictor policies admit the actors through Substrate’s egress gateway instead of app: kagent pods.

Removed

  • The kagent-declarative-seccomp PolicyException and the <release>-kagent-agent-muster-egress CiliumNetworkPolicy, both selecting app: kagent — the label of the v1alpha2 per-agent Deployments, which nothing carries on kagent API v2 (templates/kagent/policy-exception.yaml is gone). Their successors are substrate-workers and the actors’ rules on substrate-atenet-egress; the kagent controller’s ingress policies no longer admit app: kagent pods. components.kagent.installDisableWait: the kagent release depends on the connectivity release now, so the CNPG connection Secret exists before its first install and every component install waits for its workload.