feat(teamspeak-server): networkPolicy.ingress.ambientMesh

Gitea #143. Additive, default false, so the render is byte-identical to the
previous release - proven by diffing both renders against origin/main rather
than asserted.

Switched on it adds 15008/TCP, ztunnel's HBONE tunnel, to the rule carrying
the probe port, and - inside that rule's source-restricted branch -
169.254.7.127/32, the address the kubelet's probes arrive from once the pod is
in the mesh. Ambient does not bypass NetworkPolicy enforcement, so without the
port a pod whose namespace has joined the mesh is unreachable.

The two halves are one value because the second is the one nobody thinks of:
15008 added by hand leaves a policy that passes review and drops every probe
the first time probeSources is narrowed, and a pod that never becomes Ready
reads as a broken application rather than as a policy.

Minor, not major: additive value, unchanged default, unchanged render.

Port half only: this chart offers no networkPolicy.probeSources - its probes
put no packet on the network - so there is no redirected probe to allow and an
ipBlock for one would match nothing while making the rule look like it did
something. ci/run-networkpolicy-test.sh ties that exemption to the absence of
probeSources, not to a chart name.
This commit is contained in:
jklein committed 2026-10-19 17:56:57 +00:00
1 parent 445ca36d7d
commit bc580ee291
4 files changed
+86 -1

No files matched your search

@@ -50,6 +50,11 @@ selects.
{{- $np := .Values.networkPolicy }}
{{- $ns := .Release.Namespace }}
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same
thing as the top-level .Values.ingress (the Ingress object) - both match
a search for "ingress". */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -96,6 +101,39 @@ spec:
- ports:
- protocol: TCP
port: {{ .Values.server.fileTransferPort | int64 }}
{{- if $ambientMesh }}
{{- /* networkPolicy.ingress.ambientMesh (Gitea #143). 15008/TCP is ztunnel's
HBONE tunnel, the port every inbound connection arrives on once the
namespace carries istio.io/dataplane-mode - ambient "does not and will
never bypass Kubernetes NetworkPolicy enforcement", so without it a pod
in the mesh is unreachable.
It is the one port here that is NOT a containerPort of the selected pod
spec: ztunnel terminates it, not the application. ci/run-networkpolicy-
test.sh holds a NAMED exception for exactly this number, gated on exactly
this value, and proves on a second render that it stays the only such
port and that it is absent while the value is false.
THE PORT HALF ONLY, and that is not an omission. Elsewhere this switch
also adds 169.254.7.127/32 as a probe source, because inside the mesh the
kubelet's probes are redirected away from the worker node's address.
This chart offers no networkPolicy.probeSources at all, so the rule
carrying the probe port is never restricted by source - and an
unrestricted rule needs no probe address. Measured in the render: three
tcpSocket probes, so these ARE network probes - they are simply never
restricted here.
WHICH RULE IT JOINS:
the file-transfer rule, the policy's open TCP rule. The voice rule is
UDP and the rule on 10080 is restricted to the namespace. A policy is an
OR over its rules, so which rule carries the port decides only which
sources reach it - and an open TCP rule is the honest default while it
is unknown where ztunnel dials from.
NOT MEASURED: that 15008 alone suffices comes from Istio's
documentation. Measured on this cluster is only which listeners ztunnel
opens. Provable at the first namespace to join the mesh; none has. */}}
- protocol: TCP
port: 15008
{{- end }}
{{- /*
THE WEB QUERY INTERFACE, and the one rule in this chart with real security
value. It has no Service and no probe, so it can be restricted, and it is: this