Network and Port Reference
This reference lists every network connection the Axual Platform makes, the port each one reaches, the protocol it carries, and the port that carries it once TLS is in use.
Type |
Reference |
Goal |
Write a network rule that permits exactly the traffic the platform needs, and no more |
Audience |
An operator who can create NetworkPolicies, or change firewall or service mesh rules, in the cluster hosting the platform |
When to use |
When writing or auditing least-privilege network rules for the platform |
Network overview
The diagram below maps the platform: which components talk to each other, the protocol each connection carries, and its main port. Use it to orient, and the tables that follow to write a rule.
Port and TLS conventions
Four properties of the model decide what a rule has to say:
- Every port is a container port
-
A port in this reference is the port the process listens on inside the pod. A Kubernetes NetworkPolicy matches that port, never the port on the Service object. Most Governance components publish a Service on port
80that forwards to container port8080. A policy written against80matches nothing, and silently drops the traffic it was meant to allow. Listen ports per component gives both numbers wherever they differ. - TLS does not work the same way on every component
-
Some components serve plain text or TLS on the one port, chosen by configuration. Some open a second port for TLS and keep both listening. Some do not serve TLS at all, and sit behind an Ingress or Route that terminates it. The
TLS portcolumn in Component flows gives the port that carries TLS for each connection, so a rule can be written for either state without working out which pattern applies. - Management ports are never TLS
-
The
8086actuator ports, the Rest Proxy’s8081, and the Prometheus endpoints on9404,5555and2112all serve plain HTTP with no TLS option in the chart. The5005debug ports are plain TCP, and exist only when debugging is switched on. Scrape rules from the monitoring namespace stay plain regardless of how the rest of the platform is configured. - TLS is off by default where it is configurable
-
The shipped chart defaults leave
tls.enabledatfalsefor Platform Manager, andkafka.internalListenerTlsEnabledatfalsefor the Kafka internal listener. A default install therefore carries plain HTTP and plain Kafka on connections that can carry TLS.tls.enableddoes not by itself make a component serve HTTPS. On Platform Manager it also needstls.serverKeypairSecretName, which is what setsSERVER_SSL_KEY_STORE. The Metrics Exposer accepts the same two values and does build a server keystore from them, in an init container, but nothing then points its HTTP connector at that keystore: its templates set noSERVER_SSL_KEY_STORE, its configuration file sets noserver.sslproperties, and the only TLS options it passes to the JVM are client-side. It goes on listening in plain text on9080.
Component flows
Each row is one connection and translates to one policy rule. Port is the port on the
receiving pod under the shipped chart defaults, and Protocol is what it carries there.
TLS port is the port that carries the same connection once TLS is in use, which is often the
same number and sometimes a different one. Component overview lists the component
abbreviations.
| Category | Sender | Receiver | Port | Protocol | TLS port | Data exchanged |
|---|---|---|---|---|---|---|
Governance |
|
|
8080 |
HTTP |
8080 |
Self-Service API calls proxied to Platform Manager |
|
|
8080 |
HTTP |
2 |
Platform UI static assets |
|
|
|
8080 |
HTTP |
2 |
Topic Browse API calls |
|
|
|
9080 |
HTTP |
2 |
Metrics Exposer API calls |
|
|
|
8080 |
HTTP |
8443 |
Token introspection and authorisation |
|
|
|
8080 |
HTTP |
8443 |
User information and token validation |
|
|
|
3306 |
MySQL |
3306 |
Topic, application, environment, user and role metadata |
|
|
|
8200 |
HTTP |
8200 |
Secrets, private keys and certificates |
|
|
|
3306 |
MySQL |
3306 |
Keycloak realm and user configuration |
|
|
|
8080 |
HTTP |
8080 |
Topic authorisation metadata |
|
Streaming |
|
|
8080 |
HTTP |
8443 |
Schema registration and retrieval |
|
|
9093 |
Kafka |
9093 |
Topic and Access Control List (ACL) configuration through the Kafka AdminClient |
|
|
|
8080 |
HTTP |
8443 |
Schemas used to deserialise topic data |
|
|
|
9093 |
Kafka |
9093 |
Topic message content |
|
|
|
9093 |
Kafka |
9093 |
Schema storage on a Kafka topic |
|
|
|
8080 |
HTTP |
8443 |
Schemas and schema IDs |
|
|
|
9093 |
Kafka |
9093 |
Produced and consumed messages |
|
|
|
8080 |
HTTP |
8443 |
OIDC token validation, only when |
|
Kafka internal |
|
|
9090 |
Kafka |
9090 1 |
KRaft controller quorum |
|
|
9091 |
Kafka |
9091 1 |
Inter-broker replication |
|
Run-time |
|
Ververica |
4 |
HTTPS |
4 |
Flink application lifecycle control requests, only when Flink support is enabled |
|
|
11000 |
HTTP |
11000 |
Connector lifecycle control requests |
|
|
|
8000 |
HTTP |
2 |
KSML application lifecycle control and Kafka Connect log requests |
|
|
|
9093 |
Kafka |
9093 |
Connector config, offset and status topics plus connector data |
|
|
|
8200 |
HTTP |
8200 |
Connector secrets, private keys and certificates |
|
|
|
9093 |
Kafka |
9093 |
Topic message content |
|
|
|
8080 |
HTTP |
8443 |
Schemas used to describe topic data |
|
|
Kube API server |
443 |
HTTPS |
443 1 |
Creates and monitors KSML application deployments, reads Kafka Connect worker logs |
|
Distribution |
|
|
9096 |
Kafka |
9096 1 |
Reads from the source cluster |
|
Remote |
9096 |
Kafka |
9096 1 |
Writes to the destination cluster |
|
External ingress |
Client |
|
8080 |
HTTP |
2 |
All Self-Service and management traffic |
Client |
|
9094 |
Kafka |
9094 |
External producer and consumer traffic |
|
Client |
|
8443 |
HTTPS |
8443 1 |
Schema lookups by client applications |
|
Client |
|
18111 |
HTTPS |
18111 1 |
Produce and consume over REST |
|
|
|
8080 |
HTTP |
2 |
Platform operations issued from an AI agent |
|
Identity |
|
Identity Provider |
443 |
HTTPS |
443 1 |
Identity verification over OIDC |
Observability |
Prometheus |
|
8086 |
HTTP |
3 |
Scrapes |
Prometheus |
|
8086 |
HTTP |
3 |
Scrapes |
|
Prometheus |
|
8086 |
HTTP |
3 |
Scrapes |
|
Prometheus |
|
8086 |
HTTP |
3 |
Scrapes |
|
Prometheus |
|
9000 |
HTTP |
3 |
Scrapes the Keycloak management listener |
|
Prometheus |
|
8080 |
HTTP |
8443 |
Scrapes |
|
Prometheus |
|
8081 |
HTTP |
3 |
Scrapes |
|
Prometheus |
|
9404 |
HTTP |
3 |
Scrapes the broker JMX exporter |
|
Prometheus |
|
9404 |
HTTP |
3 |
Scrapes the controller JMX exporter |
|
Prometheus |
|
5555 |
HTTP |
3 |
Scrapes Kafka Connect metrics |
|
Prometheus |
|
2112 |
HTTP |
3 |
Scrapes Runtime Provisioner metrics |
|
Prometheus |
|
9404 |
HTTP |
3 |
Scrapes the Axual Distributor JMX exporter, only when |
|
|
Prometheus |
9090 |
HTTP |
3 |
Queries the figures it exposes to dashboards |
1 The port is TLS-only and has no plain-text mode, so the connection is already encrypted under the shipped defaults.
2 The pod always listens in plain text on this port, because the chart configures no
server-side TLS for it. The ingress.tls and route.tls values hold the certificate that the
Ingress or Route uses to terminate TLS in front of the pod; the pod behind it still receives
plain HTTP. A rule for this hop therefore never becomes a TLS rule.
3 A management or metrics port. These serve plain traffic only and have no TLS option in the chart, whether or not the rest of the platform uses TLS, so a scrape rule never becomes a TLS rule.
4 The port of the Ververica Platform REST API, taken from the Flink URL configured on the Instance. It is operator-supplied, so the chart has no default for it.
Listen ports per component
Container is the port inside the pod and the value a NetworkPolicy
matches. Service is the port published on the Kubernetes Service, used by clients addressing
the component through DNS. TLS port is the port that carries this traffic once TLS is in use.
A dash in Service means the port is not published on a Service.
| Component | Container | Service | TLS port | Protocol | Purpose |
|---|---|---|---|---|---|
API Gateway ( |
8080 |
80 |
2 |
HTTP |
Self-Service and management API |
8086 |
8086 |
3 |
HTTP |
Actuator health and Prometheus metrics |
|
5005 |
- |
3 |
TCP |
Remote JVM debug, only when |
|
Platform Manager ( |
8080 |
80 |
8080 |
HTTP |
Platform Manager API |
8086 |
8086 |
3 |
HTTP |
Actuator health and Prometheus metrics |
|
5005 |
- |
3 |
TCP |
Remote JVM debug, only when |
|
Platform UI ( |
8080 |
80 |
2 |
HTTP |
Web interface |
Topic Browse ( |
8080 |
80 |
2 |
HTTP |
Topic Browse API |
8086 |
8086 |
3 |
HTTP |
Actuator health and Prometheus metrics |
|
5005 |
- |
3 |
TCP |
Remote JVM debug, only when |
|
Metrics Exposer ( |
9080 |
80 |
2 |
HTTP |
Metrics Exposer API |
8086 |
8086 |
3 |
HTTP |
Actuator health and Prometheus metrics |
|
5005 |
- |
3 |
TCP |
Remote JVM debug, only when |
|
Keycloak ( |
8080 |
80 |
8443 |
HTTP |
Authentication |
9000 |
9000 |
3 |
HTTP |
Health and metrics |
|
8443 |
8443 |
8443 1 |
HTTPS |
Authentication over TLS |
|
Platform Manager MySQL ( |
3306 |
3306 |
3306 |
MySQL |
Platform Manager database |
Keycloak MySQL ( |
3306 |
3306 |
3306 |
MySQL |
Keycloak database |
Vault ( |
8200 |
8200 |
8200 |
HTTP |
Secrets API |
8201 |
8201 |
8201 1 |
HTTPS |
Cluster replication between Vault nodes |
|
8202 |
- |
3 |
HTTP |
Replication traffic between Vault nodes |
|
Kafka broker ( |
9093 |
9093 |
9093 |
Kafka |
In-cluster client traffic |
9094 |
9094 |
9094 |
Kafka |
External client traffic |
|
9095 |
9095 |
9095 1 |
Kafka |
Simple Authentication and Security Layer (SASL) SCRAM-SHA-512 client traffic, only when |
|
9096 |
9096 |
9096 1 |
Kafka |
Cross-cluster traffic used by Axual Distributor, only when |
|
9097 |
9097 |
9097 1 |
Kafka |
OAuth client traffic, only when |
|
9091 |
- |
9091 1 |
Kafka |
Inter-broker replication, also used by the Strimzi operator |
|
9404 |
- |
3 |
HTTP |
JMX Prometheus exporter |
|
8443 |
- |
8443 1 |
HTTPS |
Strimzi Kafka Agent readiness |
|
KRaft controller ( |
9090 |
- |
9090 1 |
Kafka |
Controller quorum and metadata replication |
9404 |
- |
3 |
HTTP |
JMX Prometheus exporter |
|
8443 |
- |
8443 1 |
HTTPS |
Strimzi Kafka Agent readiness |
|
Apicurio Registry ( |
8080 |
20500 |
8443 |
HTTP |
Registry API, and Prometheus metrics on |
8443 |
21500 |
8443 1 |
HTTPS |
Registry API over TLS |
|
5005 |
- |
3 |
TCP |
Remote JVM debug, only when |
|
Rest Proxy ( |
18111 |
18111 |
18111 1 |
HTTPS |
Rest Proxy API |
8081 |
8081 |
3 |
HTTP |
Actuator health and Prometheus metrics |
|
5005 |
- |
3 |
TCP |
Remote JVM debug, only when |
|
Axual Connect ( |
11000 |
11000 |
11000 |
HTTP |
Kafka Connect REST API, set by |
5555 |
5555 |
3 |
HTTP |
Prometheus metrics, set by |
|
Axual Distributor ( |
8083 |
- |
3 |
HTTP |
Kafka Connect REST API |
9404 |
- |
3 |
HTTP |
JMX Prometheus exporter, only when |
|
Runtime Provisioner ( |
8000 |
80 |
2 |
HTTP |
Provisioner API |
2112 |
2112 |
3 |
HTTP |
Prometheus metrics |
1 The port is TLS-only and has no plain-text mode.
2 The pod always listens in plain text on this port, because the chart configures no
server-side TLS for it. The ingress.tls and route.tls values hold the certificate that the
Ingress or Route uses to terminate TLS in front of the pod; the pod behind it still receives
plain HTTP.
3 A management, metrics or debug port. These serve plain traffic only and have no TLS option in the chart, whether or not the rest of the platform uses TLS.
The Apicurio Registry serves 8080 and 8443 at the same time, so choosing TLS here means
choosing the other port rather than reconfiguring the same one. Its Service publishes them on
20500 and 21500, the widest gap on the platform between a Service port and the container
port a NetworkPolicy has to match.
Two components carry no metrics port. The two MySQL deployments run without the Bitnami exporter, which the chart leaves disabled, and the Platform UI is nginx serving static files, so it has nothing to expose.
No Axual chart declares the Kafka broker’s 9090, 9091, 9404 and 8443, or either of
Axual Distributor’s ports. Those belong to the Strimzi operator, so the numbers above come from
the Strimzi contract instead.
Example network policies
These manifests implement the flows above for a default namespace layout, with the Governance
components in a namespace called axual, the Streaming components in one called kafka, and
the Run-time components in one called connect. Each file lists the placeholders to replace at
the top.
How the policies fit together
There is one policy per component, carrying both its ingress and its egress rules, so the complete rule for a component can be read in one place. Metrics are the exception: every scrape rule lives in one file instead, so the ports Prometheus needs can be read together.
Both ends of every connection need a rule. A policy restricts egress on the pod that opens the connection and ingress on the pod that accepts it, and Kubernetes drops the traffic unless both permit it.
Apply them in this order:
-
The baseline, in each namespace that holds platform components.
-
The layer policies for the layers deployed, in any order.
-
The metrics policy, which needs the Run-time policy applied with it.
Baseline: deny all, restore DNS
The baseline denies all traffic in its namespace and then restores DNS egress. Without that DNS rule every pod fails to resolve service names, and the platform appears to hang rather than fail.
It belongs in each namespace rather than once per cluster, so the same pair of policies is
applied to axual, kafka and connect with the namespace changed.
Components that initiate nothing, such as the Platform UI, declare only Ingress from here on
and let the baseline govern their egress.
Baseline deny with DNS egress restored
# Baseline: deny everything in the namespace, then allow DNS back.
#
# Apply this first. Without the DNS rule every pod fails to resolve service names and the
# platform appears to hang rather than fail, which is the single most common mistake when
# introducing NetworkPolicies.
#
# Replace `axual` with the namespace holding the platform.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: axual
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: axual
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Governance layer
One policy per Governance component, each carrying its own ingress and egress. The two
databases are separate deployments labelled platform-manager-mysql and keycloak-mysql;
no pod is labelled mysql.
The baseline does not reach either of them. The Bitnami MySQL chart creates its own
NetworkPolicy for the pods it manages, allowing all egress and ingress on 3306, and Kubernetes
combines policies by union rather than by precedence. A namespace-wide default-deny therefore
leaves those pods as permissive as the chart left them.
To bring them under the baseline, set networkPolicy.enabled to false on both
platform-manager-mysql and keycloak-mysql, then write the rules for 3306 yourself as the
policy below does.
Governance layer
# Governance layer. See "Governance layer" in the Network and Port Reference, which explains
# the Bitnami MySQL policy this one has to work around.
#
# Placeholders to replace before applying:
#
# namespace: axual the namespace holding the Governance components
# app.kubernetes.io/instance the Helm release name, `axual` below
# kafka / connect the namespaces holding the Streaming and Run-time layers
# axual-kafka the Kafka resource name; strimzi.io/name is that plus `-kafka`
# monitoring / ingress-nginx the namespaces holding Prometheus and the ingress controller
---
# The API Gateway is the only entry point into the Governance layer, and it fans out to
# every other component.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-gateway
namespace: axual
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: api-gateway
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: platform-manager
- podSelector:
matchLabels:
app.kubernetes.io/name: platform-ui
- podSelector:
matchLabels:
app.kubernetes.io/name: topic-browse
- podSelector:
matchLabels:
app.kubernetes.io/name: keycloak
ports:
- protocol: TCP
port: 8080
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: metrics-exposer
ports:
- protocol: TCP
port: 9080
---
# Platform Manager holds the platform state and reaches every backing service.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: platform-manager
namespace: axual
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: platform-manager
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: api-gateway
- podSelector:
matchLabels:
app.kubernetes.io/name: topic-browse
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: keycloak
ports:
- protocol: TCP
port: 8080
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: platform-manager-mysql
ports:
- protocol: TCP
port: 3306
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: platform-manager-vault
ports:
- protocol: TCP
port: 8200
# Cross-namespace peers: both selectors in one peer, so the rule is those pods only.
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kafka
podSelector:
matchLabels:
app.kubernetes.io/name: apicurio-registry
ports:
- protocol: TCP
port: 8080
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kafka
podSelector:
matchLabels:
strimzi.io/cluster: axual-kafka
strimzi.io/kind: Kafka
strimzi.io/name: axual-kafka-kafka
ports:
- protocol: TCP
port: 9093
# Connector and KSML provisioning. Drop both if the Run-time layer is not deployed.
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: connect
podSelector:
matchLabels:
app.kubernetes.io/name: axual-connect
ports:
- protocol: TCP
port: 11000
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: connect
podSelector:
matchLabels:
app.kubernetes.io/name: runtime-provisioner
ports:
- protocol: TCP
port: 8000
---
# Topic Browse reads topic data from Kafka and schemas from the registry, and asks Platform
# Manager for the connection details it needs.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: topic-browse
namespace: axual
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: topic-browse
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: api-gateway
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: platform-manager
ports:
- protocol: TCP
port: 8080
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kafka
podSelector:
matchLabels:
app.kubernetes.io/name: apicurio-registry
ports:
- protocol: TCP
port: 8080
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kafka
podSelector:
matchLabels:
strimzi.io/cluster: axual-kafka
strimzi.io/kind: Kafka
strimzi.io/name: axual-kafka-kafka
ports:
- protocol: TCP
port: 9093
---
# The Platform UI serves static assets and initiates nothing, so it declares no egress.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: platform-ui
namespace: axual
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: platform-ui
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: api-gateway
ports:
- protocol: TCP
port: 8080
---
# The Metrics Exposer answers the Gateway on 9080 and queries Prometheus for the figures.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: metrics-exposer
namespace: axual
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: metrics-exposer
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: api-gateway
ports:
- protocol: TCP
port: 9080
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 9090
---
# Keycloak. Browsers reach it directly through the ingress during the login redirect.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: keycloak
namespace: axual
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: keycloak
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
- podSelector:
matchLabels:
app.kubernetes.io/name: api-gateway
- podSelector:
matchLabels:
app.kubernetes.io/name: platform-manager
# Apicurio Registry OIDC token validation, when its chart enables authentication.
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kafka
podSelector:
matchLabels:
app.kubernetes.io/name: apicurio-registry
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: keycloak-mysql
ports:
- protocol: TCP
port: 3306
# Upstream identity provider. Replace the CIDR, or drop the rule if none is configured.
- to:
- ipBlock:
cidr: 203.0.113.0/24
ports:
- protocol: TCP
port: 443
---
# Platform Manager's database. Needs `networkPolicy.enabled: false` on the subchart to take
# effect; see the Governance layer notes.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: platform-manager-mysql
namespace: axual
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: platform-manager-mysql
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: platform-manager
ports:
- protocol: TCP
port: 3306
---
# Keycloak's database, with the same caveat about the chart's own NetworkPolicy.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: keycloak-mysql
namespace: axual
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: keycloak-mysql
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: keycloak
ports:
- protocol: TCP
port: 3306
---
# Vault. Validates service account tokens through the Kubernetes API, hence the egress rule.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: platform-manager-vault
namespace: axual
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: platform-manager-vault
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: platform-manager
ports:
- protocol: TCP
port: 8200
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: connect
podSelector:
matchLabels:
app.kubernetes.io/name: axual-connect
ports:
- protocol: TCP
port: 8200
egress:
# Replace with the API server endpoint: the address behind the `kubernetes` Service.
- to:
- ipBlock:
cidr: 198.51.100.0/32
ports:
- protocol: TCP
port: 443
Streaming layer
The Kafka pods are the exception to one policy per component. Strimzi creates them, and the
Cluster Operator generates its own NetworkPolicy for them. That policy confines the internal
ports 9090, 9091 and 8443 to cluster pods and the operator, and leaves the client
listeners and the metrics port reachable from every source. The policy below covers what it
does not.
Selecting the Kafka pods needs care. Each of the obvious labels has a limit:
-
strimzi.io/nameis<cluster>-kafkaon both brokers and controllers, so it cannot separate the two roles. -
strimzi.io/broker-roleandstrimzi.io/controller-roledo separate them, but both labels are present on every Kafka pod, with a value of"true"or"false". Match on the value, not on whether the label is present. -
strimzi.io/clusterwithstrimzi.io/kind: Kafkaalso matches the Kafka Exporter when it is enabled. A rule meant for the whole cluster needsstrimzi.io/nameas well, which is what Strimzi’s own generated policies use.
The Rest Proxy is a smaller trap. Its chart sets app.kubernetes.io/instance to
<release>-rest-proxy, where every other chart on the platform sets it to the release name
alone, so a selector copied from another component matches nothing.
Streaming layer
# Streaming layer. See "Streaming layer" in the Network and Port Reference.
#
# Placeholders to replace before applying:
#
# namespace: kafka the namespace holding the Streaming components
# axual-kafka the Kafka resource name; strimzi.io/name is that plus `-kafka`
# app.kubernetes.io/instance the Helm release name, `axual` below
# axual / connect the namespaces holding the Governance and Run-time layers
# ingress-nginx the namespace holding the ingress controller
# 10.0.0.0/8 the address range reaching the external listeners
---
# Egress for the Kafka pods, which the Strimzi-generated policy does not cover. Both roles
# are selected together: a broker reaches the controller quorum on 9090 and its peers on
# 9091, and a controller reaches the other controllers on 9090.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: kafka-egress
namespace: kafka
spec:
podSelector:
matchLabels:
strimzi.io/cluster: axual-kafka
strimzi.io/kind: Kafka
strimzi.io/name: axual-kafka-kafka
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
strimzi.io/cluster: axual-kafka
strimzi.io/kind: Kafka
strimzi.io/name: axual-kafka-kafka
ports:
- protocol: TCP
port: 9090
- protocol: TCP
port: 9091
---
# The Apicurio Registry stores schemas on a Kafka topic, so it is a Kafka client as well as
# a server. It serves 8080 and 8443 at the same time; its Service publishes them on 20500
# and 21500, but a NetworkPolicy matches the container ports.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: apicurio-registry
namespace: kafka
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: apicurio-registry
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: axual
podSelector:
matchLabels:
app.kubernetes.io/name: platform-manager
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: axual
podSelector:
matchLabels:
app.kubernetes.io/name: topic-browse
- podSelector:
matchLabels:
app.kubernetes.io/name: rest-proxy
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: connect
ports:
- protocol: TCP
port: 8080
# Schema lookups by client applications, terminating TLS at the pod on 8443.
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- protocol: TCP
port: 8443
egress:
- to:
- podSelector:
matchLabels:
strimzi.io/cluster: axual-kafka
strimzi.io/kind: Kafka
strimzi.io/name: axual-kafka-kafka
ports:
- protocol: TCP
port: 9093
# OIDC token validation against Keycloak, which lives in the Governance namespace. Drop
# this rule when `security.authentication.enabled` is left off.
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: axual
podSelector:
matchLabels:
app.kubernetes.io/name: keycloak
ports:
- protocol: TCP
port: 8080
---
# The Rest Proxy serves its API over TLS on 18111 and its management endpoints on 8081.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: rest-proxy
namespace: kafka
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: rest-proxy
# The Rest Proxy chart sets the instance label to `<release>-rest-proxy`, where every
# other chart on the platform sets it to the release name alone.
app.kubernetes.io/instance: axual-rest-proxy
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 10.0.0.0/8
ports:
- protocol: TCP
port: 18111
egress:
- to:
- podSelector:
matchLabels:
strimzi.io/cluster: axual-kafka
strimzi.io/kind: Kafka
strimzi.io/name: axual-kafka-kafka
ports:
- protocol: TCP
port: 9093
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: apicurio-registry
ports:
- protocol: TCP
port: 8080
Run-time layer
These policies cover the pods the charts create: Axual Connect, the Runtime Provisioner and Axual Distributor. KSML application pods are not among them, because the Provisioner creates them at run time rather than a chart and their labels are not known ahead of time. Under a namespace default-deny those pods need rules of their own for the Kafka internal listener and the Apicurio Registry.
Axual Distributor runs as a Strimzi KafkaConnect resource, and Strimzi treats that differently
from a Kafka resource: it generates no NetworkPolicy for it. Nothing therefore grants the
Cluster Operator access to the Kafka Connect REST API on 8083, so the policy below does it
explicitly. Without that rule the operator cannot manage connectors.
Run-time layer
# Run-time layer. See "Run-time layer" in the Network and Port Reference.
#
# Placeholders to replace before applying:
#
# namespace: connect the namespace holding the Run-time components
# app.kubernetes.io/instance the Helm release name, `axual` below
# axual / kafka the namespaces holding the Governance and Streaming layers
# axual-kafka the Kafka resource name; strimzi.io/name is that plus `-kafka`
# strimzi the namespace running the Strimzi Cluster Operator
# 198.51.100.0/32 the Kubernetes API server endpoint
---
# Axual Connect accepts connector lifecycle calls from Platform Manager and reaches Kafka
# and Vault.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: axual-connect
namespace: connect
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: axual-connect
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: axual
podSelector:
matchLabels:
app.kubernetes.io/name: platform-manager
ports:
- protocol: TCP
port: 11000
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kafka
podSelector:
matchLabels:
strimzi.io/cluster: axual-kafka
strimzi.io/kind: Kafka
strimzi.io/name: axual-kafka-kafka
ports:
- protocol: TCP
port: 9093
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: axual
podSelector:
matchLabels:
app.kubernetes.io/name: platform-manager-vault
ports:
- protocol: TCP
port: 8200
---
# The Runtime Provisioner accepts application lifecycle calls from Platform Manager and creates
# KSML deployments through the Kubernetes API.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: runtime-provisioner
namespace: connect
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: runtime-provisioner
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: axual
podSelector:
matchLabels:
app.kubernetes.io/name: platform-manager
ports:
- protocol: TCP
port: 8000
egress:
# Replace the CIDR with the API server endpoint for the cluster. On a managed cluster
# this is the address behind the `kubernetes` Service in the `default` namespace.
- to:
- ipBlock:
cidr: 198.51.100.0/32
ports:
- protocol: TCP
port: 443
---
# Axual Distributor runs as a Strimzi KafkaConnect resource, so Strimzi creates its pods and
# they carry Strimzi's labels. Unlike the Kafka resource, a KafkaConnect gets no generated
# NetworkPolicy, so the Cluster Operator's access to the REST API on 8083 has to be granted
# here. Without this rule the operator cannot manage connectors.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: distributor
namespace: connect
spec:
podSelector:
matchLabels:
strimzi.io/kind: KafkaConnect
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: strimzi
ports:
- protocol: TCP
port: 8083
egress:
# The inter-cluster listener on the local cluster, present only when
# `kafka.interClusterListener.enabled` is set.
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kafka
podSelector:
matchLabels:
strimzi.io/cluster: axual-kafka
strimzi.io/kind: Kafka
strimzi.io/name: axual-kafka-kafka
ports:
- protocol: TCP
port: 9096
# The destination cluster, which is outside this cluster. Replace the CIDR with the
# address range of the remote brokers.
- to:
- ipBlock:
cidr: 203.0.113.0/24
ports:
- protocol: TCP
port: 9096
Metrics scraping
Every scrape rule lives here rather than spread across the layer policies, so the ports Prometheus needs can be read in one place and applied as their own step. The file covers the Governance management ports, the Keycloak management listener, the Apicurio Registry metrics endpoint on its API port, the Rest Proxy actuator, and the Run-time metrics ports.
It leaves out the Kafka brokers and controllers. Their 9404 is already open to every source in
the policy Strimzi generates, so a rule here would add nothing.
Apply the Run-time policy alongside this one. Selecting a pod with an Ingress
policy closes every port that policy does not list, so these rules on their own cut Platform
Manager off from Axual Connect on 11000 and the Runtime Provisioner on 8000, and connector and
KSML provisioning stop.
|
Metrics scraping
# Metrics scraping. See "Metrics scraping" in the Network and Port Reference, which explains
# why the Run-time policy has to be applied alongside this one.
#
# Placeholders to replace before applying:
#
# axual / kafka / connect the namespaces holding the three layers
# monitoring the namespace running Prometheus
# app.kubernetes.io/instance the Helm release name, `axual` below
---
# Governance: the Spring Boot components share one management port, and Keycloak keeps its
# own management listener.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: monitoring-scrape-governance
namespace: axual
spec:
podSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- api-gateway
- platform-manager
- topic-browse
- metrics-exposer
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 8086
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: monitoring-scrape-keycloak
namespace: axual
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: keycloak
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 9000
---
# Streaming: the Apicurio Registry serves metrics on its API port rather than a separate
# management port, so this rule opens 8080 to the monitoring namespace.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: monitoring-scrape-apicurio-registry
namespace: kafka
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: apicurio-registry
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 8080
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: monitoring-scrape-rest-proxy
namespace: kafka
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: rest-proxy
# The Rest Proxy chart sets the instance label to `<release>-rest-proxy`, where every
# other chart on the platform sets it to the release name alone.
app.kubernetes.io/instance: axual-rest-proxy
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 8081
---
# Run-time: Axual Connect and the Runtime Provisioner each expose their own metrics port.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: monitoring-scrape-axual-connect
namespace: connect
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: axual-connect
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 5555
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: monitoring-scrape-runtime-provisioner
namespace: connect
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: runtime-provisioner
app.kubernetes.io/instance: axual
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 2112
---
# Axual Distributor runs as a Strimzi KafkaConnect resource, so its pods carry Strimzi's
# labels. Selecting on the kind matches them without naming the tenant and instance the
# resource name is built from. The port exists only when `connect.metrics.enabled` is set.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: monitoring-scrape-distributor
namespace: connect
spec:
podSelector:
matchLabels:
strimzi.io/kind: KafkaConnect
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 9404