For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.
Advanced settings
You can update several installation settings in your Helm values file. For example, you can update the namespace, set resource limits and requests, or enable extensions such as for AI.
Set the version you want to configure in an environment variable, such as the latest patch version (2.4.0).
export NEW_VERSION=2.4.0-
Show all values:
helm show values oci://cr.kgateway.dev/kgateway-dev/charts/kgateway --version v$NEW_VERSION -
Get a file with all values: You can get a
kgateway/values.yamlfile for the upgrade version by pulling and inspecting the Helm chart locally.helm pull oci://cr.kgateway.dev/kgateway-dev/charts/kgateway --version v$NEW_VERSION tar -xvf kgateway-v$NEW_VERSION.tgz open kgateway/values.yaml
For more information, see the Helm reference docs.
Development builds
When using the development build 2.4.0-main, add --set controller.image.pullPolicy=Always to ensure you get the latest image. For production environments, this setting is not recommended as it might impact performance.
Experimental Gateway API features
The KGW_ENABLE_EXPERIMENTAL_GATEWAY_API_FEATURES feature gate controls support for experimental Gateway API features such as the following:
- TCPRoutes
- TLSRoutes
- ListenerSets
- CORS policies
- Retries
- Session persistence
In kgateway version 2.2 and later, this setting defaults to true, so experimental features are enabled by default and no additional configuration is required. To disable these features, set the environment variable to false in your kgateway controller deployment in your Helm values file.
controller:
extraEnv:
KGW_ENABLE_EXPERIMENTAL_GATEWAY_API_FEATURES: "false"Leader election
Leader election is enabled by default to ensure that you can run kgateway in a multi-control plane replica setup for high availability.
You can disable leader election by setting the KGW_DISABLE_LEADER_ELECTION environment variable to "true" through the controller.extraEnv Helm value.
controller:
extraEnv:
KGW_DISABLE_LEADER_ELECTION: "true"Namespace discovery
You can limit the namespaces that kgateway watches for gateway configuration. For example, you might have a multi-tenant cluster with different namespaces for different tenants. You can limit kgateway to only watch a specific namespace for gateway configuration.
Namespace selectors are a list of matched expressions or labels.
matchExpressions: Use this field for more complex selectors where you want to specify an operator such asInorNotIn.matchLabels: Use this field for simple selectors where you want to specify a label key-value pair.
Each entry in the list is disjunctive (OR semantics). This means that a namespace is selected if it matches any selector.
You can also use matched expressions and labels together in the same entry, which is conjunctive (AND semantics).
The following example selects namespaces for discovery that meet either of the following conditions:
- The namespace has the label
environment=prodand the labelversion=v2, or - The namespace has the label
version=v3
discoveryNamespaceSelectors:
- matchExpressions:
- key: environment
operator: In
values:
- prod
matchLabels:
version: v2
- matchLabels:
version: v3TLS encryption
You can enable TLS encryption for the xDS gRPC server in the kgateway control plane. For more information, see the TLS encryption docs.
Strict validation
Kgateway supports two validation modes for routes and policies in the control plane: standard and strict. The validation mode controls how the control plane handles invalid configuration before it is sent to Envoy.
Validation modes
Kgateway supports the following validation modes. The mode is set globally on the controller through a single Helm value.
| Mode | Behavior |
|---|---|
standard (default) | The control plane translates all valid resources and replaces invalid routes with a direct response (typically HTTP 500). Valid routes that are unrelated to the invalid resource are unaffected. This mode protects multi-tenant clusters from individual misconfiguration without dropping the entire snapshot. |
strict | In addition to the standard behavior, the control plane runs an Envoy preflight validation against the generated xDS snapshot. If Envoy would reject the snapshot, the entire snapshot is blocked and the previous valid configuration remains in place. This mode prevents misconfigurations that would otherwise cause Envoy to NACK an xDS update from reaching the data plane. |
standard mode is the default and is appropriate for most production environments. strict mode is recommended when you cannot tolerate a NACKed xDS update reaching the data plane; for example, you might have downstream automation that depends on every accepted change being safe.
Enable strict validation
Set the validation.level Helm value to strict when you install or upgrade kgateway. Restart the control plane to apply the change.
validation:
level: strictInternally, the Helm chart passes the value to the control plane through the KGW_VALIDATION_MODE environment variable. If you manage the control plane deployment manually, set KGW_VALIDATION_MODE=STRICT on the kgateway container.
The accepted values for validation.level are standard and strict (case-insensitive). Any other value causes the Helm install to fail.
Verify the validation mode
To check which mode is active, inspect the KGW_VALIDATION_MODE environment variable on the kgateway controller deployment. The expected output is standard or strict.
kubectl -n kgateway-system get deployment kgateway \
-o jsonpath='{.spec.template.spec.containers[*].env[?(@.name=="KGW_VALIDATION_MODE")].value}'Transformation policies and strict validation
Strict validation runs the preflight against an Envoy binary that is bundled in the kgateway control plane image. The control plane image is built from the envoy-wrapper image, which bundles the rustformation dynamic module, and the validator sets ENVOY_DYNAMIC_MODULES_SEARCH_PATH=/usr/local/lib before invoking the preflight. As a result, the preflight understands rustformation per-route config and can validate TrafficPolicies that use transformation.
For more information about transformation engines, see Transformation engines.
ReferenceGrant enforcement modes
In multi-tenant clusters, different teams typically own separate namespaces and share a gateway. The Gateway API ReferenceGrant mechanism controls which cross-namespace references are permitted, ensuring that one team cannot silently access another team’s resources. Without a ReferenceGrant in the target namespace, the reference is denied.
In kgateway, you can configure how strictly you want ReferenceGrant requirements to be enforced by using the KGW_REFERENCE_GRANT_MODE environment variable on the control plane. You can choose between the following modes:
STRICT: Enforce ReferenceGrants for all cross-namespace references. This mode provides the strongest namespace isolation and is recommended for new clusters.PERMISSIVE(default): Enforce ReferenceGrants forBackendRefandSecretRefreferences, but not for cross-namespaceExtensionRefreferences. Before reference grant modes were introduced, TrafficPolicy resources were able to reference and access a GatewayExtension resource in another namespace without a ReferenceGrant.PERMISSIVEmode allows these setups to function as before. Over time, you can add the missing ReferenceGrant resources in the required namespaces and migrate your cluster toSTRICTReferenceGrant validation.OFF: Disable all ReferenceGrant validation. Not recommended for multi-tenant or production environments.Caution
Do not use
OFFin multi-tenant or production environments. It breaks Gateway API compliance, bypasses namespace isolation, and lets any namespace access backends, secrets, and GatewayExtensions in other namespaces without restriction.
Reference validation by mode
The following table shows which cross-namespace references are checked in each mode. Same-namespace references always pass, regardless of the mode.
| Source resource | Field | Referenced resource | STRICT |
PERMISSIVE (default) |
OFF |
|---|---|---|---|---|---|
| HTTPRoute / GRPCRoute / TCPRoute / TLSRoute | spec.rules[].backendRefs | Service / Backend | checked | checked | allowed |
| Gateway / ListenerSet | spec.listeners[].tls.certificateRefs | Secret | checked | checked | allowed |
| TrafficPolicy | spec.basicAuth.secretRef / spec.apiKeyAuth.secretRef | Secret | checked | checked | allowed |
| GatewayExtension (ExtAuth, ExtProc, RateLimit, OAuth2) | spec.<type>.grpcService.backendRef | Service | checked | checked | allowed |
| TrafficPolicy | spec.<plugin>.extensionRef | GatewayExtension (same namespace) | allowed | allowed | allowed |
| TrafficPolicy | spec.<plugin>.extensionRef | GatewayExtension (different namespace) | checked | allowed | allowed |
Enable STRICT mode
-
Check which mode is currently active by inspecting the
KGW_REFERENCE_GRANT_MODEenvironment variable on the controller deployment. If the variable is not set, the active mode isPERMISSIVE.kubectl -n kgateway-system get deployment kgateway \ -o jsonpath='{.spec.template.spec.containers[*].env[?(@.name=="KGW_REFERENCE_GRANT_MODE")].value}' -
Make sure that any existing cross-namespace TrafficPolicy → GatewayExtension references have a corresponding ReferenceGrant.
-
Get the current Helm values for your kgateway release and save them to a file.
helm get values kgateway -n kgateway-system -o yaml > values.yaml open values.yaml -
Add the following values to enable
STRICTReferenceGrant validation.controller: extraEnv: KGW_REFERENCE_GRANT_MODE: "STRICT" -
Apply the change by upgrading the Helm release.
helm upgrade -i -n kgateway-system kgateway \ oci://cr.kgateway.dev/kgateway-dev/charts/kgateway \ --version 2.4.0 \ -f values.yaml -
Confirm that the kgateway control plane restarted and is running.
kubectl get pods -n kgateway-system -
Verify the active mode.
kubectl -n kgateway-system get deployment kgateway \ -o jsonpath='{.spec.template.spec.containers[*].env[?(@.name=="KGW_REFERENCE_GRANT_MODE")].value}'
Disable automatic RBAC creation
By default, the kgateway Helm chart creates a ClusterRole and ClusterRoleBinding that grant the controller’s service account the permissions it needs to watch and manage Kubernetes resources. In environments where RBAC resources are managed externally, such as by a platform or security team that controls all cluster-scoped permissions, you can disable the creation of these resources by setting rbac.create: false.
Caution
If you disable the creation of ClusterRole and ClusterRoleBinding resources, you must create equivalent resources yourself before or alongside the kgateway installation. Without these resources, the controller cannot watch and manage Gateways, HTTPRoutes, Secrets, or other resources.
To skip RBAC resource creation, set rbac.create: false in your Helm values:
rbac:
create: falseCommon labels
Add custom labels to all resources that are created by the Helm charts, including the Deployment, Service, ServiceAccount, and ClusterRoles. This allows you to better organize your resources or integrate with external tooling.
The following snippet adds the label-key and kgw-managed labels to all resources.
commonLabels:
label-key: label-value
kgw-managed: "true"Topology spread constraints
Use topology spread constraints to control how kgateway controller pods are distributed across failure domains such as zones or nodes. This setup helps improve availability and resilience by preventing all replicas from landing in the same zone or node.
For more information, see the Kubernetes topology spread constraints documentation.
The following example spreads controller pods evenly across availability zones, and prevents scheduling if the skew cannot be satisfied.
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/name: kgatewayPriorityClass
You can assign a PriorityClassName to the control plane pods by using the Helm chart. Priority indicates the importance of a pod relative to other pods. If a pod cannot be scheduled, the scheduler tries to preempt (evict) lower priority pods to make scheduling of the pending pod possible.
To assign a PriorityClassName to the control plane, you must first create a PriorityClass resource. The following example creates a PriorityClass with the name system-cluster-critical that assigns a priority of 1 million.
kubectl apply -f- <<EOF
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: system-cluster-critical
value: 1000000
globalDefault: false
description: "Use this priority class on system-critical pods only."
EOFIn your Helm values file, add the name of the PriorityClass in the controller.priorityClassName field.
controller:
priorityClassName: Autoscaling
You can configure Horizontal Pod Autoscaler (HPA) or Vertical Pod Autoscaler (VPA) policies for the kgateway control plane. To set up these policies, you use the horizontalPodAutoscaler or verticalPodAutoscaler fields in the Helm chart.
Note
Note that kgateway uses leader election if multiple replicas are present. The elected leader’s workload is typically larger than the workload of non-leader replicas and therefore drives the overall infrastructure cost. Because of that, Vertical Pod Autoscaling can be a reasonable solution to ensure that the elected leader has the resources it needs to perform its work successfully. In cases where the leader has a large workload, Horizontal Pod Autoscaling might not be as effective, as it adds more replicas that do not reduce the workload of the elected leader.
Warning
If you plan to set up both VPA and HPA policies, make sure to closely monitor performance and cost during scale up events. Using both policies can lead to conflict or even destructive loops that impact the performance of your control plane.
Vertical Pod Autoscaler (VPA)
Vertical Pod Autoscaler (VPA) is a Kubernetes component that automatically adjusts the CPU and memory reservations of your pods to match their actual usage.
The following Helm configuration ensures that the control plane pod is always assigned a minimum of 0.1 CPU cores (100millicores) and 128Mi of memory.
controller:
verticalPodAutoscaler:
updatePolicy:
updateMode: Auto
resourcePolicy:
containerPolicies:
- containerName: "*"
minAllowed:
cpu: 100m
memory: 128MiHorizontal Pod Autoscaler (HPA)
Horizontal Pod Autoscaler (HPA) adds more instances of the pod to your environment when certain memory or CPU thresholds are reached.
In the following example, you want to have 1 control plane replica running at any given time. If the CPU utilization averages 80%, you want to gradually scale up your replicas. You can have a maximum of 5 replicas at any given time.
controller:
horizontalPodAutoscaler:
minReplicas: 1
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 80Note: To monitor the memory and CPU threshold, you must deploy the Kubernetes metrics-server to your cluster. The metrics-server retrieves metrics, such as CPU and memory consumption, for your workloads.
You can install the server with the following command:
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
kubectl -n kube-system patch deployment metrics-server \
--type=json \
-p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'Then, start monitoring CPU and memory consumption with the kubectl top pod command.
PodDisruptionBudget
Configure a Pod Disruption Budget to ensure that a minimum number of control plane instances are up and running at any given time during voluntary disruptions, such as upgrades. In this example, 50% of your control plane instances must be running.
controller:
podDisruptionBudget:
minAvailable: 50%Controller probes
You can customize the readiness and startup probes for the kgateway controller container by using the controller.readinessProbe and controller.startupProbe Helm values. Your settings are deep-merged with the default probe configuration, so you only need to specify the fields you want to change.
By default, both probes use an httpGet handler that checks the /readyz endpoint on the health port. The default readiness probe polls every 10 seconds with an initial delay of 1 second. The default startup probe polls every second with no initial delay and a failure threshold of 600, allowing up to 10 minutes for the controller to start.
If you provide an exec, grpc, or tcpSocket handler, the default httpGet handler is replaced entirely. Otherwise, the httpGet handler is kept and your overrides are merged on top.
The following example adjusts the timing fields of the default readiness probe without changing the default httpGet handler.
controller:
readinessProbe:
initialDelaySeconds: 5
periodSeconds: 20
failureThreshold: 3The following example replaces the default httpGet handler with a custom exec handler on the startup probe.
controller:
startupProbe:
exec:
command: ["cat", "/tmp/ready"]
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 60xDS first-connect grace period
By default, the control plane waits 1 second after a new proxy connects before sending its first xDS snapshot. This gives per-client translation time to converge and prevents newly started gateway pods from receiving incomplete configuration after a controller restart.
You can adjust the grace period by using the KGW_XDS_FIRST_CONNECT_DELAY environment variable on the controller. The value is a Go duration string, for example 2s. Set it to 0 to disable the grace period entirely.
controller:
extraEnv:
KGW_XDS_FIRST_CONNECT_DELAY: "2s"Controller admin server bind address
The kgateway controller runs an admin and debug server on port 9095. By default, the server binds to localhost and is only accessible from within the pod.
To access the admin and debug servers from your local machine, use the kubectl port-forward command to expose port 9095 on your local machine. No change of the bind address is required.
kubectl port-forward deployment/kgateway -n kgateway-system 9095:9095If you need other pods in the cluster to reach the admin server directly, you can change the bind address by using the controller.admin.bindAddress Helm value or the KGW_ADMIN_BIND_ADDRESS environment variable. Setting bindAddress to 0.0.0.0 makes the server listen on all pod interfaces, so other pods can reach it at http://<pod-ip>:9095. To find the pod IP, run kubectl get pod -l app.kubernetes.io/name=kgateway -n kgateway-system -o wide.
Warning
The admin server exposes pprof profiling endpoints, logging controls, and internal config snapshots. Only expose it outside the pod in trusted environments, such as a local development cluster or a dedicated profiling setup.
controller:
admin:
bindAddress: 0.0.0.0