Network Policies
Securing inter-service communication with Kubernetes NetworkPolicies
Berserk includes optional Kubernetes NetworkPolicies that restrict both ingress and egress traffic for each service. When enabled, only known communication paths are allowed -- blocking unauthorized pod-to-pod traffic and outbound connections.
The model is built around a single public edge. The gateway is the only service meant to take traffic from outside the cluster: it authenticates requests and proxies them on to the rest of the stack (UI over HTTP, plus gRPC to meta, query, and ingest). ingest is the one other externally reachable service, accepting OTLP/Loki telemetry from external agents. Every other service accepts connections only from the specific in-cluster peers it talks to.
NetworkPolicy enforcement requires a CNI plugin. On EKS, use the VPC CNI
v1.14+ with ENABLE_NETWORK_POLICY=true on the aws-node DaemonSet, or
install Calico. Without a compatible CNI, the NetworkPolicy resources are
created but have no effect.
Enabling
Network policies are disabled by default. Enable them in your values file:
global:
networkPolicy:
enabled: trueService Communication Map
When network policies are enabled, only the gateway and ingest accept ingress from outside the cluster. Everything else is reachable only from the listed in-cluster peers:
| Service | Accepts ingress from (peers) | Connects out to (peers) | External ingress |
|---|---|---|---|
| gateway | public edge | ui, permissions, meta, query, ingest | Yes |
| ingest | external telemetry sources | meta | Yes |
| meta | gateway, query, ingest, janitor, ui, nursery | -- | No |
| query | ui, janitor | meta, nursery | Yes (exception) |
| nursery | query | meta | No |
| janitor | -- | meta, query | No |
| ui | gateway | gateway, query, meta, permissions | No |
| permissions | gateway, ui | -- | No |
query is a known exception: it still sets allowExternal: true, so external
clients (and the gateway's gRPC proxy) reach query:9510 through that open
door rather than an explicit peer rule, and the customer post-rollout
validation probe can connect directly. Moving query fully behind the gateway
-- adding gateway to its ingressFrom and dropping allowExternal -- is a
planned follow-up.
Beyond the peers above, every service also gets:
- DNS egress (port 53 UDP/TCP), always.
- External egress to the CIDR allowlist (S3 on 443, PostgreSQL on 5432 by
default) when
allowExternalEgressis set -- the default for every service. See External Egress. - OTLP egress to
ingest:4317when observability is enabled. See OTLP Telemetry.
A couple of services carry extra in-cluster rules not shown above: query pods
accept and make cross-pod connections on port 9520 (the QWS worker-sibling
lane), and meta additionally accepts connections from one-off setup /
admin operator pods (e.g. kubectl run bzrk-cli) used for token and table
creation.
External Egress
Services that need to reach external endpoints (S3, PostgreSQL) use a configurable CIDR allowlist. By default, HTTPS (443) and PostgreSQL (5432) are open to all IPs. Tighten these for production:
global:
networkPolicy:
enabled: true
externalEgress:
# S3 VPC endpoint
- cidr: 10.0.0.0/16
ports:
- port: 443
protocol: TCP
# RDS PostgreSQL
- cidr: 10.1.0.0/24
ports:
- port: 5432
protocol: TCPOTLP Telemetry
When global.observability.otlpEnabled is true, all services automatically get
egress to the OTLP endpoint. Two cases are handled:
Default endpoint (ingest:4317): Egress to the ingest pod is added
automatically via pod selector. The ingest service also gets an ingress rule
allowing all namespace pods to send telemetry on port 4317.
External collector: If global.observability.otlpEndpoint points outside
the namespace, configure global.networkPolicy.otlpEgress with the
appropriate CIDR rules:
global:
observability:
otlpEnabled: true
otlpEndpoint: "otel-collector.monitoring:4317"
networkPolicy:
enabled: true
otlpEgress:
- cidr: 10.2.0.0/16
ports:
- port: 4317
protocol: TCPHelm prints a warning during install/upgrade if OTLP is enabled with a
non-default endpoint but no otlpEgress rules are configured.
Custom Rules
Add custom ingress or egress rules for all services via the global values, or per-service via the sub-chart values.
Global (applied to all services):
global:
networkPolicy:
additionalIngress:
- from:
- namespaceSelector:
matchLabels:
name: monitoring
ports:
- port: 9090
protocol: TCPPer-service (e.g., allow a specific namespace to reach query):
query:
networkPolicy:
additionalIngress:
- from:
- namespaceSelector:
matchLabels:
name: data-team
ports:
- port: 9510
protocol: TCPPer-Service Configuration
Each service supports these networkPolicy values:
| Value | Type | Description |
|---|---|---|
allowExternal | bool | Allow ingress from any source on service ports |
allowExternalEgress | bool | Allow egress to global.networkPolicy.externalEgress CIDRs |
ingressFrom | list | Berserk peers allowed to connect ([{app, ports}]) |
egressTo | list | Berserk peers this service connects to ([{app, ports}]) |
additionalIngress | list | Extra raw NetworkPolicy ingress rules |
additionalEgress | list | Extra raw NetworkPolicy egress rules |