chainloop-ee chart can expose Chainloop through Kubernetes Gateway API HTTPRoute and GRPCRoute resources instead of, or alongside, Ingress. When the Gateway is Envoy Gateway, the chart also renders the traffic policies that long-running gRPC streams and large uploads need.
This guide is for platform operators deploying the Enterprise edition. The chart attaches routes to a Gateway you already run. It does not create the Gateway, its listeners or its public certificates.
Prerequisites
- Gateway API CRDs that serve
gateway.networking.k8s.io/v1HTTPRouteandGRPCRoute. - A Gateway controller that supports HTTP/2 cleartext (h2c) to the backend Services. The chart sets
appProtocol: kubernetes.io/h2con the Services, so the controller must supportHTTPRouteBackendProtocolH2C. - A Gateway with listeners and public TLS certificates for the hostnames listed in Hostnames.
- For the Envoy Gateway traffic policies: the Envoy Gateway CRDs that serve
gateway.envoyproxy.io/v1alpha1BackendTrafficPolicy. - For TLS between the Gateway and the pods: CRDs that serve
gateway.networking.k8s.io/v1BackendTLSPolicyand a controller that supports it.
Enable Gateway API Routes
Set a base domain and the Gateway the routes attach to:values.yaml
httpRoute.enabled turns on routes for every component. To route only some components, leave it false and set <component>.httpRoute.enabled: true instead. A component’s httpRoute.enabled: false does not turn its routes off while the global flag is true.
Each component can also override hostname and parentRefs under frontend.httpRoute, backend.httpRoute, controlplane.httpRoute and cas.httpRoute.
Hostnames
The chart prefixes the base domain for each route. IfhttpRoute.hostname is empty, it falls back to ingress.hostname.
<component>.httpRoute.hostname replaces the derived hostname. The control plane and CAS gRPC routes use <component>.httpRouteAPI.hostname. If neither that nor a base domain is set, they use the component’s HTTP hostname.
The backend URL that integrations call back to, such as the GitHub App or GitLab webhooks, is derived from these hostnames. See backend external URL.
Example: Gateway API Only, Without Ingress
This example exposes Chainloop only through an Envoy Gateway, with noIngress resources. It assumes the release is installed in the chainloop namespace, and the Gateway runs in the infra namespace.
First, create a Gateway with an HTTPS listener for all Chainloop hostnames. A single wildcard certificate for *.chainloop.example.com in the Secret chainloop-wildcard-tls covers them. The routes live in another namespace, so the listener must allow them through allowedRoutes:
gateway.yaml
GatewayClass if your Envoy Gateway installation already provides one, and use its name in gatewayClassName. To limit which namespaces can attach routes, use from: Selector instead of from: All.
Then add the routes to your chart values:
values.yaml
Ingress flags default to false, so this renders no Ingress. When you move an existing installation from Ingress to the Gateway, remove or set to false any of these flags your values still enable: ingress.enabled, frontend.ingress.enabled, backend.ingress.enabled, backend.mcpIngress.enabled, backend.samlDiscoverIngress.enabled, controlplane.ingress.enabled, controlplane.ingressAPI.enabled, cas.ingress.enabled and cas.ingressAPI.enabled.
The chart renders five HTTPRoutes (app, app-api, mcp, cp and cas), three GRPCRoutes (app-api, cp-api and cas-api), and, with Envoy Gateway, one BackendTrafficPolicy per route. The CLI installer points to cp-api.chainloop.example.com:443 and cas-api.chainloop.example.com:443, or to cp. and cas. with shared endpoints.
Check that no Ingress is left and that the routes are attached to the Gateway:
Accepted for chainloop-gateway.
Envoy Gateway Traffic Policies
Without extra configuration, Envoy applies a 15-second timeout to every request, including gRPC streams. Its default 32 KiB connection buffer and 64 KiB HTTP/2 windows towards the backend also slow down large uploads. The chart therefore renders one Envoy GatewayBackendTrafficPolicy per route, named after the route. Each policy sets the route’s request timeout. Routes that carry gRPC also get larger buffer and HTTP/2 window settings.
The defaults, available in chart 0.601.1 and later:
values.yaml
With shared endpoints, the CLI sends its gRPC traffic to the control plane and CAS
HTTPRoutes. Those routes then get the gRPC timeout and flow control.
The request timeout also covers streaming responses, so long-lived MCP sessions can be cut after timeouts.api. Raise it if your clients need longer sessions.
When the Policies Are Rendered
httpRoute.envoyGateway.enabled accepts three values:
auto(default): render the policies only when Helm sees thegateway.envoyproxy.io/v1alpha1BackendTrafficPolicyAPI in the cluster.true: always render them.false: never render them.
helm template and GitOps pipelines that render without access to the cluster do not see the API, so auto renders nothing. In that case, set enabled: true, or pass --api-versions gateway.envoyproxy.io/v1alpha1/BackendTrafficPolicy to helm template.
The same flag also gates the rate limit policy for the SAML discovery route, which is rendered when backend.samlDiscoverIngress.enabled is true. Before chart 0.601.1, that policy was rendered whenever the route was. When upgrading with auto and an offline render, set enabled: true to keep the rate limit.
Existing Policies
If you already manageBackendTrafficPolicy resources for the Chainloop routes, remove them before you enable the chart policies, or set enabled: false. Do not attach two policies to the same route.
Other Gateway Implementations
With a Gateway controller other than Envoy Gateway, keepenabled: auto or set it to false. The chart then renders no gateway.envoyproxy.io resources. Configure equivalent request timeouts and upload buffers in your controller, otherwise its defaults may cut gRPC streams and large uploads.
Client-Side Settings
The chart only configures the Gateway’s connections towards the Chainloop pods. Listener buffers, HTTP/2 windows towards clients and header handling belong to an Envoy GatewayClientTrafficPolicy attached to the Gateway, which you manage with the Gateway itself.
Shared Control Plane and CAS Endpoints
The control plane and CAS serve HTTP and native gRPC on one HTTP port, so a single hostname per component can carry both. This requires Chainloop OSS imagesv1.126.0 or later.
By default the chart keeps sending clients to the legacy cp-api and cas-api endpoints. To switch the backend, the control plane’s CAS client, the Kubernetes sandbox CLI and the CLI installer (/cli/install.sh) to the shared endpoints, set:
values.yaml
cp.chainloop.example.com:443 and cas.chainloop.example.com:443. Values set in backend.preconfiguredCliSettings still take precedence.
This flag only changes which endpoints clients use. The legacy cp-api and cas-api routes, and the ingressAPI, httpRouteAPI and serviceAPI settings, keep working but are deprecated. CLIs that are already installed keep their saved addresses, so reconfigure them:
useSharedEndpoints: false and reconfigure the CLIs to the legacy addresses.
TLS Between the Gateway and the Pods
By default, public TLS terminates at the Gateway and the Gateway reaches the backend, control plane and CAS pods over h2c. To encrypt that hop as well:- Enable TLS in the pods with a Secret containing
tls.crtandtls.key:backend.tlsConfig.secret.name,controlplane.tls.existingSecretandcas.tls.existingSecret. For the control plane and CAS, the Secret enables TLS on both the HTTP and gRPC listeners. Direct HTTP clients must then use HTTPS. - Let the chart render a Gateway API
BackendTLSPolicyper component, so the Gateway connects with TLS and verifies the pod certificate. This option is available in chart releases after0.606.0.
chainloop-ee in the namespace chainloop, create the certificate Secrets and an internal-ca ConfigMap with the CA bundle in ca.crt first, then set:
values.yaml
- The component’s Gateway routes must be enabled. Without routes, the chart renders no policy.
- A pod TLS Secret is required. Without one, rendering fails.
hostnamemust be a DNS name in the pod certificate’s SANs. The Gateway uses it for SNI and certificate verification.- Set exactly one trust source:
caCertificateRefs(ConfigMaps in the release namespace, each with aca.crtkey) orwellKnownCACertificates: System(the Gateway’s system trust store). Certificate verification cannot be skipped.
http port. The control plane and CAS policies target both the shared Service http port and the legacy -api Service grpc port, with the same hostname and CA. The MCP and metrics listeners stay plaintext.
The upstream TLS connection must negotiate HTTP/2 through ALPN. According to the Envoy Gateway 1.6 release notes, backend TLS includes h2 by default from that version. On older versions, set spec.backendTLS.alpnProtocols: [h2, http/1.1] on the EnvoyProxy of your GatewayClass.
Trust for Internal Clients
TheBackendTLSPolicy only covers the Gateway. Chainloop components also call each other directly. Add your private CA to the customCAs list so the backend, workers, control plane and CAS trust the pod certificates. Make sure the certificates cover the names those clients dial: the short Service names, the -api Service names, and the namespace-qualified names where used.
The Kubernetes sandbox CLI uses one TLS setting for the platform, control plane and CAS endpoints, so either all of them use TLS or none do. Sandbox clients do not get the customCAs certificates, so provision private CA trust for them separately.
Certificate renewal is not handled by the chart. Renew certificates through your issuer and restart or reload the workloads when the Secrets change, for example with Reloader.
Test HTTP, native gRPC, internal calls and certificate renewal in a separate deployment before enabling pod TLS in production. Changing the listeners and the Gateway policies is not atomic.
Using Ingress Instead
The control plane and CASIngress resources also send HTTP/2 to the shared ports, which requires Chainloop OSS images v1.126.0 or later. The chart sets the upstream protocol annotations for community ingress-nginx (backend-protocol: GRPC, or GRPCS with pod TLS) and F5 NGINX (nginx.org/grpc-services and nginx.org/http2) on the Ingress. For Traefik it sets traefik.ingress.kubernetes.io/service.serversscheme (h2c, or https with pod TLS) on the Service. Every backend behind an ingress-nginx Ingress for these components, including extraPaths, must accept HTTP/2. Other controllers need their own HTTP/2 upstream settings.
The /mcp and MCP OAuth paths are served by a separate <release>-backend-mcp-paths Ingress. F5 NGINX does not merge Ingress resources that share a host, so set backend.ingress.mcpPathsInline: true to serve those paths from the backend Ingress. Do not set it with community ingress-nginx, where the GRPC backend protocol would then apply to the MCP paths too.
Verify
Check that the routes and policies are rendered and accepted:Accepted and ResolvedRefs for their parent Gateway, and policies should report Accepted. Then log in with the CLI and run an attestation that uploads an artifact, to exercise the control plane and CAS gRPC paths.
