feat(template-chart): networkPolicy.ingress.ambientMesh, plus its checked CI exception
Gitea #143. A pod cannot be reached inside Istio's ambient mesh unless its NetworkPolicy lets ztunnel's HBONE tunnel in - ambient explicitly does not bypass policy enforcement - and 15008 is deliberately no containerPort of the application, so assertion 2 of ci/run-networkpolicy-test.sh rejected it. The switch is a named intention rather than a free port list, and it renders two things that cannot be had separately: 15008/TCP inbound, and - where probeSources is non-empty - 169.254.7.127/32 as an additional peer, because inside the mesh the kubelet's probes are redirected away from the worker node's address. Whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe: the pod never becomes Ready and the symptom reads as a broken application. That is assertion 4 of the same script, one value further along. Assertion 2 keeps its edge. It gets ONE named exception for ONE port number, gated on one value, and it is not granted in the main loop at all - which renders every chart with the value at its default, so 15008 stays an ordinary failure there. The free-port variant was design A of #143 and would have opened the assertion for all 30 charts. Assertion 7 holds the exception to five things on two renders per chart: the port and the ipBlock are absent while the switch is off, 15008 is present while it is on, 15008 is still the ONLY ingress port that is not a containerPort, and wherever the rule carrying it restricts sources it also carries the ipBlock. The last one is reachable because these renders apply ci/networkpolicy/<chart>.yaml, where probeSources is non-empty. Built into the existing script, as for #136: the exception weakens assertion 2 and belongs beside it - a separate script could go green while the exception it is paired with is wrong, with nothing connecting the two. The job already runs over every chart on every pull request. Found by running it: the policy's name comes from Chart.yaml's name, not from the directory - template-chart is called "xxx". Not proven, and said so in values.yaml, the template header and the script's header: that 15008 alone suffices comes from Istio's documentation, and the probe-source half reaches no release, because probeSources is empty in every chart here. No namespace of this cluster carries istio.io/dataplane-mode, so there is no path on which either could be measured. What is proven is the render and the assertions.
This commit is contained in:
4 files changed
+548
No files matched your search
@@ -96,6 +96,24 @@ spec this policy selects.
|
||||
{{- $probeSources := $np.probeSources | default list }}
|
||||
{{- $allowedNs := $np.allowedNamespaces | default list }}
|
||||
{{- $ic := $np.ingressController | default dict }}
|
||||
{{- /* networkPolicy.ingress - the policy's INGRESS DIRECTION, and not to be
|
||||
confused with networkPolicy.ingressController one line up, nor with the
|
||||
chart's top-level .Values.ingress. Three different things whose names
|
||||
overlap as substrings:
|
||||
|
||||
.Values.ingress the Ingress OBJECT this chart renders
|
||||
.Values.networkPolicy.ingress switches on the policy's inbound side
|
||||
.Values.networkPolicy.ingressController
|
||||
the SOURCE SELECTOR for the ingress
|
||||
controller's pods, a sibling of
|
||||
networkPolicy.ingress and NO PART OF
|
||||
IT
|
||||
|
||||
Named here because a search for "ingress" matches all three, and one
|
||||
round of this work already reported ingressController as an inbound
|
||||
escape hatch on the strength of the substring alone. */}}
|
||||
{{- $npIngress := $np.ingress | default dict }}
|
||||
{{- $ambientMesh := $npIngress.ambientMesh }}
|
||||
{{- $routed := or .Values.ingress.enabled .Values.httpRoute.enabled }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
@@ -129,6 +147,29 @@ spec:
|
||||
- protocol: {{ .protocol | default "TCP" }}
|
||||
port: {{ .containerPort }}
|
||||
{{- end }}
|
||||
{{- if $ambientMesh }}
|
||||
{{- /* FIRST HALF OF networkPolicy.ingress.ambientMesh. 15008/TCP is
|
||||
ztunnel's HBONE tunnel, the port every inbound mesh connection
|
||||
arrives on once the namespace carries istio.io/dataplane-mode.
|
||||
Istio's own documentation is explicit that ambient "does not and
|
||||
will never bypass Kubernetes NetworkPolicy enforcement", so
|
||||
without this port a pod in the mesh is simply unreachable.
|
||||
|
||||
It is the one port in this rule that is NOT a containerPort of
|
||||
the selected pod spec - ztunnel terminates it, not the
|
||||
application - so ci/run-networkpolicy-test.sh holds a NAMED
|
||||
exception for exactly this number, gated on exactly this value.
|
||||
Anything else that is not a containerPort still fails, and so
|
||||
does 15008 itself while the value is off.
|
||||
|
||||
NOT MEASURED, and the chart should not pretend otherwise: that
|
||||
15008 ALONE suffices comes from Istio's documentation. What has
|
||||
been measured on this cluster is only which listeners ztunnel
|
||||
opens. Provable at the first namespace that joins the mesh, and
|
||||
no namespace carries the label yet. */}}
|
||||
- protocol: TCP
|
||||
port: 15008
|
||||
{{- end }}
|
||||
{{- if $probeSources }}
|
||||
{{- /* RESTRICTED, because the operator supplied probeSources. The
|
||||
kubelet's probes come from the IP of the WORKER NODE running the
|
||||
@@ -168,6 +209,35 @@ spec:
|
||||
- ipBlock:
|
||||
cidr: {{ . | quote }}
|
||||
{{- end }}
|
||||
{{- if $ambientMesh }}
|
||||
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason
|
||||
the switch is one value instead of two. Inside the mesh the
|
||||
kubelet's probes are redirected and no longer arrive from the
|
||||
worker node's address: they arrive from 169.254.7.127, which is
|
||||
therefore the probeSources entry nobody would think to add.
|
||||
|
||||
The two halves are deliberately inseparable. An operator who
|
||||
only opens 15008 by hand has a policy that passes every review -
|
||||
and the moment probeSources is non-empty, every probe is dropped,
|
||||
the pod never becomes Ready, and the symptom reads as a broken
|
||||
application rather than as a policy. That is assertion 4 of
|
||||
ci/run-networkpolicy-test.sh, re-created one value further along.
|
||||
One switch cannot be set halfway.
|
||||
|
||||
Only rendered in this branch, because this is the only branch
|
||||
with a "from" list at all: with probeSources empty the rule is
|
||||
open and needs no peer. The IPv6 counterpart
|
||||
fd16:9254:7127:1337:ffff:ffff:ffff:ffff is deliberately absent -
|
||||
this cluster is SingleStack IPv4, and an ipBlock of the wrong
|
||||
family is accepted by the API server and matches nothing.
|
||||
|
||||
UNPROVEN IN OPERATION: probeSources is empty in every chart of
|
||||
this repository (stalwart sets it to the empty list explicitly),
|
||||
so no release reaches this branch today. What CI proves is its
|
||||
render, through the overlay in ci/networkpolicy. */}}
|
||||
- ipBlock:
|
||||
cidr: 169.254.7.127/32
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
{{- /* NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only
|
||||
inside the cluster, because this port carries no NodePort. The
|
||||
|
||||
Reference in new issue
Block a user