Skip to main content
The operator manages Kubernetes NetworkPolicy resources at two levels, both off by default:
  • Cluster policies — per-cluster policies covering the internal traffic of ClickHouseCluster and KeeperCluster resources, enabled through spec.networkPolicy on each custom resource.
  • Operator pod policies — chart-shipped policies restricting ingress to the controller manager pod itself for the metrics and webhook endpoints.
A NetworkPolicy is only enforced when the cluster’s CNI plugin implements it (for example Calico or Cilium). On a CNI without NetworkPolicy enforcement the resources are created but silently have no effect — Kubernetes does not return an error. Confirm your CNI enforces policies before relying on them.

Cluster NetworkPolicies

Enable the managed policy per cluster:
The managed policies cover cluster-internal traffic only. Selecting the pods switches them to default deny for ingress, and the operator allows exactly what the clusters need to function: A keeper admits ClickHouse clusters based on their keeperClusterRef — adding or removing a reference updates the keeper’s policy automatically, including references from other namespaces.

Allowing clients and monitoring

Client connections and metrics scraping are not covered: with the managed policy enabled, nothing can reach the client ports (9000/8123, or the TLS variants) or the metrics port until you allow it. NetworkPolicies are additive, so grant access with your own policy next to the managed one:
The same pattern applies to Prometheus scrapes (port 9363 on ClickHouse, 9090 on Keeper) — allow your monitoring namespace explicitly. Setting networkPolicy.policy: Disabled (the default) removes the managed policy; user-defined policies are never touched by the operator unless they carry the cluster’s app label.

Cluster-wide opt-out

NetworkPolicy management can also be disabled cluster-wide via the operator’s ENABLE_NETWORK_POLICY environment variable. With ENABLE_NETWORK_POLICY=false, the operator skips the NetworkPolicy reconcile step for every ClickHouseCluster and KeeperCluster regardless of their spec.networkPolicy.policy, and does not watch NetworkPolicy resources at all. The operator’s ServiceAccount therefore does not need RBAC permissions on networkpolicies.networking.k8s.io, which is useful when running the operator under a restricted ServiceAccount that intentionally omits those permissions.
With Helm, the same switch is exposed as a chart value:

Operator pod policies

The chart also ships optional policies that restrict which traffic can reach the controller manager pod — the operator process itself. They cover the two ports the operator exposes to other clients: the metrics endpoint and the admission webhook.

What the Helm chart creates

When enabled, the chart creates up to two ingress-only policies, both selecting the controller manager pod: Both policies declare only policyTypes: [Ingress]. They do not restrict egress from the operator, and they do not touch ClickHouse server or Keeper pods.

Default-deny behavior

Selecting a pod with an ingress NetworkPolicy switches that pod to default deny for ingress: once either policy applies, any inbound traffic to the controller manager pod that is not explicitly allowed is dropped. After enabling, the only ingress that reaches the operator is:
  • a metrics scrape from a namespace labeled metrics: enabled, and
  • an admission webhook call from a namespace labeled webhook: enabled.
Everything else to the pod is denied. This is the intended hardening, but it means an unlabeled scraper or webhook caller stops working the moment the policies take effect.

Enabling the policies

With Helm, set the gate in your values:
allow-webhook-traffic additionally requires webhook.enabled: true (the default), so disabling the webhook also removes its policy. With the raw kubectl manifests, uncomment the [NETWORK POLICY] section as described in the kubectl install guide. The raw manifests ship the same two policies.

Labeling client namespaces

Because both policies match the source by namespaceSelector, every namespace that needs to reach the operator must carry the matching label. A scrape or webhook call from an unlabeled namespace is dropped.
Pair this with the metrics RBAC described in Monitoring → Securing the metrics endpoint: the NetworkPolicy controls reachability, while the ClusterRole binding controls authorization. Both must be in place for a secured scrape to succeed.
Admission webhook requests originate from the Kubernetes API server, not from an ordinary pod. Whether that traffic is subject to a NetworkPolicy, and from which source it appears, depends on your control-plane topology and CNI — managed control planes in particular may reach the webhook from an address that no namespaceSelector can match. If the API server’s traffic is not covered by a webhook: enabled namespace, enabling allow-webhook-traffic can block admission and make ClickHouseCluster/KeeperCluster create and update requests time out. Test admission on a non-production cluster after enabling, and add an explicit allow rule for the API server if needed.

Verifying

After enabling, confirm that:
  • Prometheus still scrapes the metrics endpoint (its namespace is labeled metrics: enabled and bound to the metrics-reader ClusterRole).
  • Creating or updating a ClickHouseCluster still passes admission (the webhook is reachable).
If a scrape returns no data or a CR apply hangs, an unlabeled source namespace or the API server reachability caveat above is the most likely cause.
Last modified on August 25, 2026