34 Commits
Author SHA1 Message Date
jklein fb275935c9 docs(README): the ambient-mesh switch and the named exception it costs the render test
Validate Helm Charts / Detect changed charts (pull_request) Successful in 4s
Validate Helm Charts / Resource quantities (pull_request) Successful in 11s
Validate Helm Charts / Selector match (pull_request) Successful in 11s
Validate Helm Charts / HTTPRoute match (pull_request) Successful in 8s
Validate Helm Charts / Bump level (pull_request) Successful in 3s
Validate Helm Charts / YAML scalars (pull_request) Successful in 8s
Validate Helm Charts / NetworkPolicy (pull_request) Successful in 19s
Validate Helm Charts / Build apache-tika (pull_request) Successful in 4s
Validate Helm Charts / Trivy config apache-tika (pull_request) Successful in 10s
Validate Helm Charts / Build bentopdf (pull_request) Successful in 7s
Validate Helm Charts / Build bulwark (pull_request) Successful in 5s
Validate Helm Charts / Build garage (pull_request) Successful in 5s
Validate Helm Charts / Build gotenberg (pull_request) Successful in 7s
Validate Helm Charts / Build keycloak (pull_request) Successful in 6s
Validate Helm Charts / Build minecraft-router (pull_request) Successful in 12s
Validate Helm Charts / Build outline (pull_request) Successful in 5s
Validate Helm Charts / Build paperless-ngx (pull_request) Successful in 5s
Validate Helm Charts / Build calibre-web-automated (pull_request) Successful in 5s
Validate Helm Charts / Build cyberchef (pull_request) Successful in 5s
Validate Helm Charts / Build freesailarr (pull_request) Successful in 6s
Validate Helm Charts / Build homeassistant (pull_request) Successful in 8s
Validate Helm Charts / Build matrix-synapse (pull_request) Successful in 6s
Validate Helm Charts / Build minecraft-server (pull_request) Successful in 5s
Validate Helm Charts / Build patchmon (pull_request) Successful in 4s
Validate Helm Charts / Build rallly (pull_request) Successful in 7s
Validate Helm Charts / Build rss-bridge (pull_request) Successful in 4s
Validate Helm Charts / Build sure (pull_request) Successful in 3s
Validate Helm Charts / Build teamspeak-server (pull_request) Successful in 4s
Validate Helm Charts / Build voucher-vault (pull_request) Successful in 4s
Validate Helm Charts / Build ytdlp-web-player (pull_request) Successful in 6s
Validate Helm Charts / Build zipline (pull_request) Successful in 4s
Validate Helm Charts / Build samba (pull_request) Successful in 5s
Validate Helm Charts / Build satisfactory (pull_request) Successful in 4s
Validate Helm Charts / Build searxng (pull_request) Successful in 4s
Validate Helm Charts / Build stalwart (pull_request) Successful in 4s
Validate Helm Charts / Build template-chart (pull_request) Successful in 4s
Validate Helm Charts / Build urlaubsverwaltung (pull_request) Successful in 5s
Validate Helm Charts / Build valkey (pull_request) Successful in 4s
Validate Helm Charts / Trivy config bentopdf (pull_request) Successful in 11s
Validate Helm Charts / Trivy config bulwark (pull_request) Successful in 13s
Validate Helm Charts / Trivy config calibre-web-automated (pull_request) Successful in 11s
Validate Helm Charts / Trivy config cyberchef (pull_request) Successful in 20s
Validate Helm Charts / Trivy config freesailarr (pull_request) Successful in 13s
Validate Helm Charts / Trivy config garage (pull_request) Successful in 10s
Validate Helm Charts / Trivy config gotenberg (pull_request) Successful in 11s
Validate Helm Charts / Trivy config homeassistant (pull_request) Successful in 13s
Validate Helm Charts / Trivy config keycloak (pull_request) Successful in 11s
Validate Helm Charts / Trivy config matrix-synapse (pull_request) Successful in 20s
Validate Helm Charts / Trivy config minecraft-router (pull_request) Successful in 19s
Validate Helm Charts / Trivy config minecraft-server (pull_request) Successful in 13s
Validate Helm Charts / Trivy config outline (pull_request) Successful in 12s
Validate Helm Charts / Trivy config paperless-ngx (pull_request) Successful in 13s
Validate Helm Charts / Trivy config patchmon (pull_request) Successful in 10s
Validate Helm Charts / Trivy config rss-bridge (pull_request) Successful in 12s
Validate Helm Charts / Trivy config samba (pull_request) Successful in 23s
Validate Helm Charts / Trivy config satisfactory (pull_request) Successful in 13s
Validate Helm Charts / Trivy config searxng (pull_request) Successful in 15s
Validate Helm Charts / Trivy config rallly (pull_request) Successful in 11s
Validate Helm Charts / Trivy config stalwart (pull_request) Successful in 15s
Validate Helm Charts / Trivy config sure (pull_request) Successful in 12s
Validate Helm Charts / Trivy config teamspeak-server (pull_request) Successful in 11s
Validate Helm Charts / Trivy config template-chart (pull_request) Successful in 11s
Validate Helm Charts / Trivy config urlaubsverwaltung (pull_request) Successful in 11s
Validate Helm Charts / Trivy config valkey (pull_request) Successful in 15s
Validate Helm Charts / Trivy config voucher-vault (pull_request) Successful in 10s
Validate Helm Charts / Trivy config ytdlp-web-player (pull_request) Successful in 13s
Validate Helm Charts / Trivy config zipline (pull_request) Successful in 11s
Install-test / Install-test apache-tika (pull_request) Successful in 1m4s
Install-test / Install-test bentopdf (pull_request) Successful in 57s
Install-test / Install-test bulwark (pull_request) Successful in 1m6s
Install-test / Install-test calibre-web-automated (pull_request) Successful in 1m31s
Install-test / Install-test cyberchef (pull_request) Successful in 45s
Install-test / Install-test freesailarr (pull_request) Successful in 3m0s
Install-test / Install-test garage (pull_request) Successful in 1m0s
Install-test / Install-test gotenberg (pull_request) Successful in 1m2s
Install-test / Install-test homeassistant (pull_request) Successful in 1m55s
Install-test / Install-test matrix-synapse (pull_request) Successful in 1m17s
Install-test / Install-test keycloak (pull_request) Successful in 2m8s
Install-test / Install-test minecraft-router (pull_request) Successful in 38s
Install-test / Install-test minecraft-server (pull_request) Successful in 1m25s
Install-test / Install-test outline (pull_request) Successful in 2m0s
Install-test / Install-test paperless-ngx (pull_request) Successful in 2m35s
Install-test / Install-test patchmon (pull_request) Successful in 1m2s
Install-test / Install-test rallly (pull_request) Successful in 1m15s
Install-test / Install-test rss-bridge (pull_request) Successful in 46s
Install-test / Install-test samba (pull_request) Successful in 1m6s
Install-test / Install-test sure (pull_request) Successful in 2m1s
Install-test / Install-test searxng (pull_request) Successful in 52s
Install-test / Install-test stalwart (pull_request) Successful in 1m0s
Install-test / Install-test teamspeak-server (pull_request) Successful in 1m14s
Install-test / Install-test urlaubsverwaltung (pull_request) Successful in 1m31s
Install-test / Install-test valkey (pull_request) Successful in 1m8s
Install-test / Install-test voucher-vault (pull_request) Successful in 1m35s
Install-test / Install-test ytdlp-web-player (pull_request) Successful in 50s
Install-test / Install-test zipline (pull_request) Successful in 1m35s
Validate Helm Charts / Install-test (pull_request) Successful in 38m26s
Gitea #143. Section 15 gets the switch itself - what it renders, why its two
halves are one value, and the two things it does not prove - plus the three
names that overlap as substrings (ingress, networkPolicy.ingress,
networkPolicy.ingressController), because a search for "ingress" matches all
three and one run during this work mistook the third for an inbound escape
hatch on that basis alone.

The render-test section gets assertion 7 as a table row, the re-measured
figures (30 charts, 333 assertions, ~25s), and the six fail paths that were
executed - including the two that are only visible to it: an ungated ipBlock,
which assertion 2 cannot see because it never looks at "from" peers, and a
value declared in the schema but missing from values.yaml, which a --set
render alone would accept.
2026-10-19 13:16:35 +00:00
jklein 8f50ec838b feat(satisfactory): 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.
2026-10-19 13:16:35 +00:00
jklein 805dcb18ac feat(valkey): 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.
2026-10-19 13:16:34 +00:00
jklein 185795d110 feat(minecraft-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.
2026-10-19 13:16:34 +00:00
jklein c3bfc35efe 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.
2026-10-19 13:16:34 +00:00
jklein 3c90328b45 feat(samba): 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.
2026-10-19 13:16:34 +00:00
jklein 1880d22c54 feat(stalwart): 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.
2026-10-19 13:16:34 +00:00
jklein e9aa94108f feat(minecraft-router): 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.
2026-10-19 13:16:34 +00:00
jklein 11b8ad5bb4 feat(keycloak): 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.
2026-10-19 13:16:34 +00:00
jklein e97ffaf2d7 feat(garage): 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.
2026-10-19 13:16:34 +00:00
jklein dcf825f2eb test(networkpolicy): tie the ambient probe-source half to probeSources, not to a chart name
Gitea #143. Five charts offer no networkPolicy.probeSources - their probes are
exec probes and put no packet on the network - so for them 169.254.7.127/32
would be an ipBlock that matches nothing, which is exactly the strict-looking
empty rule this script exists to catch. Assertion 7 now exempts them on the
absence of that value, the same conditionality assertion 4 and the overlay
guard already use, and records the exemption as a held assertion rather than
as silence.

Also names two limits of assertion 7 in its header: assertions 1, 3, 4 and 5
are not re-run on the switched-on render, and assertion 3's omission is the
interesting one - with probeSources empty, 15008 sits in a rule with no
"from" that neither of assertion 3's two justifications covers. Teaching it a
third would mean writing a rule against a guess, because where ztunnel dials
from cannot be settled until a namespace joins the mesh.
2026-10-19 13:16:34 +00:00
jklein a7ec82447d feat(homeassistant): 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.
2026-10-19 13:16:34 +00:00
jklein bd99aaa908 feat(zipline): 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.
2026-10-19 13:16:34 +00:00
jklein 7b369fa78d feat(ytdlp-web-player): 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.
2026-10-19 13:16:33 +00:00
jklein 51ce5d858c feat(voucher-vault): 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.
2026-10-19 13:16:33 +00:00
jklein f3665c117b feat(urlaubsverwaltung): 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.
2026-10-19 13:16:33 +00:00
jklein 593c187656 feat(sure): 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.
2026-10-19 13:16:33 +00:00
jklein 123c05ffe2 feat(searxng): 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.
2026-10-19 13:16:33 +00:00
jklein d4fc26809c feat(rss-bridge): 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.
2026-10-19 13:16:33 +00:00
jklein a4372af025 feat(rallly): 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.
2026-10-19 13:16:33 +00:00
jklein d4c588344e feat(patchmon): 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.
2026-10-19 13:16:25 +00:00
jklein 0e9c2dc782 feat(paperless-ngx): 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.
2026-10-19 13:16:25 +00:00
jklein 67f1a10067 feat(outline): 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.
2026-10-19 13:16:25 +00:00
jklein cb7672153f feat(matrix-synapse): 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.
2026-10-19 13:16:24 +00:00
jklein 4265a50dc9 feat(gotenberg): 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.
2026-10-19 13:16:24 +00:00
jklein f9686e37fc feat(freesailarr): 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.
2026-10-19 13:16:13 +00:00
jklein a28443c3b8 feat(calibre-web-automated): 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.
2026-10-19 13:16:13 +00:00
jklein b80c25316f feat(bulwark): 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.
2026-10-19 13:16:13 +00:00
jklein 3fd493ba9a feat(bentopdf): 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.
2026-10-19 13:16:13 +00:00
jklein fda1c7c5ff feat(apache-tika): 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.
2026-10-19 13:16:13 +00:00
jklein 1861966e12 feat(cyberchef): networkPolicy.ingress.ambientMesh
Gitea #143. Additive, default false, so the render is byte-identical to the
previous release - proven by diffing both renders 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. 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.

Minor, not major: additive value, unchanged default, unchanged render.
2026-10-19 13:16:12 +00:00
jklein cd2e4c0f15 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.
2026-10-19 13:16:12 +00:00
jlab-renovate-bot 79aa97475e Update gotenberg/gotenberg Docker tag to v8.38.1
Publish Gotenberg Helm Chart / Publish Gotenberg Helm Chart (push) Successful in 9s
Publish Helm Chart with patched Application Version / publish-helm-chart (push) Successful in 9s
SonarQube Analysis / SonarQube Analysis (push) Successful in 30s
2026-10-19 13:01:59 +00:00
jlab-renovate-bot da46744bb8 Update lukevella/rallly Docker tag to v4.15.5
renovate/stability-days Updates have not met minimum release age requirement
Validate Helm Charts / Detect changed charts (pull_request) Successful in 3s
Validate Helm Charts / Resource quantities (pull_request) Successful in 9s
Validate Helm Charts / Selector match (pull_request) Successful in 10s
Validate Helm Charts / HTTPRoute match (pull_request) Successful in 9s
Validate Helm Charts / Bump level (pull_request) Successful in 4s
Validate Helm Charts / YAML scalars (pull_request) Successful in 9s
Validate Helm Charts / NetworkPolicy (pull_request) Successful in 10s
Validate Helm Charts / Build rallly (pull_request) Successful in 5s
Validate Helm Charts / Trivy config rallly (pull_request) Successful in 14s
Install-test / Install-test rallly (pull_request) Successful in 1m36s
Validate Helm Charts / Install-test (pull_request) Successful in 1m36s
Publish Helm Chart with patched Application Version / publish-helm-chart (push) Successful in 8s
Publish Rallly Helm Chart / Publish Rallly Helm Chart (push) Successful in 8s
SonarQube Analysis / SonarQube Analysis (push) Successful in 33s
2026-10-19 08:04:32 +00:00
121 changed files with 3829 additions and 37 deletions

No files matched your search

+26 -2
View File
@@ -231,6 +231,7 @@ Measured locally: **30 charts, 408 scalars verified, 0 failed**, no cluster. The
| no ingress rule allows every source by accident | `from: []` allows everything, identically to having no `from` at all, while reading in a diff and in `kubectl` output as a restriction — the one mistake in this class that makes a policy *weaker* while looking *stricter* | nobody |
| every port a **network** probe addresses is either unrestricted, or the chart offers `networkPolicy.probeSources` **and** says in `NOTES.txt` what a wrong CIDR costs | the kubelet probes from the IP of the worker node running the pod, which no chart can know. A restricted probe port without that address drops every probe: the pod never becomes `Ready`, the rollout times out, and the symptom reads as a broken application | the install-test, in production's CNI — **but not in CI**, see below |
| **cross-chart egress**: where a chart dials another chart *of this repository*, its egress rule must contain the **pod** ports behind that chart's Services (#136) | an egress rule naming the **Service** port. kube-proxy does the ClusterIP's destination NAT *before* the policy is evaluated at the pod's interface, so the policy sees `podIP:targetPort` and the rule matches nothing wherever `port` and `targetPort` differ | nobody: the symptom is a **timeout**, not `connection refused`, and no error mentions a NetworkPolicy — `paperless-ngx` 14.0.0 shipped it and cost an outage on 2026-10-15 |
| **the ambient-mesh switch**, on two renders per chart: with `networkPolicy.ingress.ambientMesh` off, neither `15008` nor `169.254.7.127/32` appears; with it on, `15008` is present and is still the **only** ingress port that is no `containerPort`, and a source-restricted rule carrying it also carries the `ipBlock` (#143) | the named exception decaying into the hole it was carved around. Without the off-half a chart could render `15008` unconditionally and nothing would notice; without the only-port half the exception becomes the free port key that was rejected, and every mistyped ingress port passes with the switch on | nobody — and in production as a pod unreachable in the mesh, or one whose every probe is dropped the first time `probeSources` is narrowed |
Egress ports are otherwise **deliberately not** held against the pod's `containerPort`s: an egress port is a port on the *destination*, and that comparison would fail every chart that reaches a database.
@@ -245,7 +246,9 @@ Four things to know before touching it:
- **Subchart documents are skipped by the comment assertion**, for a structural reason and not a lenient one: a dependency is fetched from the Helm registry rather than from the copy in this repo, so the policy `paperless-ngx` and `stalwart` bundle is whatever `valkey` version is *published*, and nothing in the parent chart can change its rendered comments. The subchart's own PR is where it is caught, because this test runs over `valkey` too.
- **Anti-vacuum guard**, as in the tests above: `ci/networkpolicy/<chart>.yaml` is a render-only overlay applied **last**, whose job is to render the **source-restricted probe rule** — a branch no chart's own defaults ever reach, and the one containing the expensive mistake (a `namespaceSelector` and a `podSelector` written as two list entries instead of one would be an OR, opening the port to every pod in `kube-system`). A chart that *has* an overlay and still renders no restricted **probe** rule fails. That counter is specifically the probe rule and not "any restricted rule", because `keycloak` restricts two rules in its own defaults and would have satisfied a looser guard while the branch went unrendered.
Measured locally: **30 charts, 210 assertions held, 0 failed**, no cluster, ~15 seconds. All twelve fail paths were exercised rather than assumed — and one earned its keep immediately: the `probeSources` check was a substring test, so a chart whose key had been **deleted** while the long comment above it still discussed the value passed it. It now looks for the key. The cross-chart assertion added two of those 210, and its own six fail paths were executed the same way: a required port removed from the rule, a wrong number in its place, a peer chart renamed away, the policy's name no longer following the `<release>-<chart>-<kind>` convention, the peers rendering no Service at all (which would make the requirement empty, and is treated as a failure because an empty requirement reads exactly like a satisfied one), and the gated rule made unconditional — which is the failure path of the *gate-off* half, since with the gate off and the rule properly gated the assertion must stay silent.
Measured locally: **30 charts, 333 assertions held, 0 failed**, no cluster, ~25 seconds (the ambient-mesh assertion added a second render per chart, and roughly 10 seconds with it). All twelve fail paths were exercised rather than assumed — and one earned its keep immediately: the `probeSources` check was a substring test, so a chart whose key had been **deleted** while the long comment above it still discussed the value passed it. It now looks for the key. The cross-chart assertion added two of those 210, and its own six fail paths were executed the same way: a required port removed from the rule, a wrong number in its place, a peer chart renamed away, the policy's name no longer following the `<release>-<chart>-<kind>` convention, the peers rendering no Service at all (which would make the requirement empty, and is treated as a failure because an empty requirement reads exactly like a satisfied one), and the gated rule made unconditional — which is the failure path of the *gate-off* half, since with the gate off and the rule properly gated the assertion must stay silent.
**The ambient-mesh assertion (#143) was built the same way, and six of its fail paths were executed**: a second, different port added under the exception (rejected — the exception covers exactly one number); `15008` rendered ungated, caught by assertion 2 in the main loop, which renders the switch at its default; the `ipBlock` rendered ungated, which **only** this assertion can catch, because assertion 2 never looks at `from` peers; the `ipBlock` half deleted while `15008` stayed, i.e. the half-set switch the design exists to make impossible, reachable because `ci/networkpolicy/template-chart.yaml` fills `probeSources`; the policy's name taken off the `<release>-<chart>-<kind>` convention; and the value present in the schema but absent from `values.yaml`, which a `--set` render alone would not have noticed. The name check earned its keep on the first run rather than in a rehearsal: it read the **directory** name, and `template-chart`'s chart is called `xxx`.
**What this test does not and cannot cover, named so the gap is not mistaken for coverage:** that traffic still flows. No ingress controller runs in the install-test cluster, so the path from Traefik to a pod is proven nowhere in this pipeline — and, measured on the PR for #5, **k3s exempts the kubelet's probe traffic from policy**, so a blocked probe path does *not* turn the install-test red either (`cyberchef` became `Ready` in 69s with its probe port restricted to an address no probe can come from). What the install-test *does* prove is enforcement of everything the application itself needs: with `outline`'s DNS egress rule removed, its pod never became `Ready` and the job failed after 5m59s. So the net under this convention is real, but it is an **egress** net — which raises the stakes for assertion 2, since a wrong ingress port is caught mechanically here or not at all.
@@ -693,7 +696,9 @@ Every port of a workload falls into one of four, and this is the part to get rig
#### Values
`networkPolicy.enabled`, `.allowedNamespaces`, `.probeSources`, `.ingressController`, `.egress.extraPorts` — and a chart ships **only the ones that reach a rule**. A chart may add a **named** egress switch where a port depends on something the values cannot see: `paperless-ngx`' `.egress.mailImport` opens IMAPS `993`, off by default, because its mail accounts are rows in its own database and no value says whether a release fetches mail. The bar for one of those: it names what it opens, and it is **not** a second switch for a port some *other* value already decides — that is why the Tika/Gotenberg rule stayed gated on `paperless.files.tikaGotenberg.enabled` and got no policy switch of its own. Two values that can drift apart re-arm the outage the rule was fixed for. A value that silently does nothing is worse than one that is absent, because it reads as a control: `samba` and `satisfactory` carry `enabled` alone (every inbound rule is open to any source), and `teamspeak-server` has `allowedNamespaces` but no `probeSources`.
`networkPolicy.enabled`, `.allowedNamespaces`, `.probeSources`, `.ingressController`, `.ingress.ambientMesh`, `.egress.extraPorts` — and a chart ships **only the ones that reach a rule**, with `.enabled` and `.ingress.ambientMesh` the two every chart has.
**Three of those names overlap as substrings and are three different things**, which is worth stating because a search for `ingress` matches all of them: top-level `ingress` is the Ingress **object** a chart renders, `networkPolicy.ingress` is the policy's **inbound side**, and `networkPolicy.ingressController` is the **source selector** for the controller's pods — a *sibling* of `networkPolicy.ingress` and no part of it. The 21 charts carrying `ingressController` had **no** inbound escape hatch before #143, and one search run during that work reported them as having one on the strength of the substring alone. A chart may add a **named** egress switch where a port depends on something the values cannot see: `paperless-ngx`' `.egress.mailImport` opens IMAPS `993`, off by default, because its mail accounts are rows in its own database and no value says whether a release fetches mail. The bar for one of those: it names what it opens, and it is **not** a second switch for a port some *other* value already decides — that is why the Tika/Gotenberg rule stayed gated on `paperless.files.tikaGotenberg.enabled` and got no policy switch of its own. Two values that can drift apart re-arm the outage the rule was fixed for. A value that silently does nothing is worse than one that is absent, because it reads as a control: `samba` and `satisfactory` carry `enabled` alone (every inbound rule is open to any source), and `teamspeak-server` has `allowedNamespaces` but no `probeSources`.
**No chart ships `allowedNamespaces` pre-filled, ever.** A chart that named `mc-router`, or `paperless-jk`, or `stalwart` in its defaults would be baking in an assumption about *this* cluster's namespace layout — which is exactly the kind of claim a chart cannot keep true. So the default is the empty list and the chart is **restrictive**; filling it is the **deployment adaptation**, made where the namespace layout is actually visible. That is why a sweep like this produces a list of release-side one-liners: those are the expected procedure, not a defect list, and the breaking-change major on each chart is what announces them.
@@ -701,6 +706,25 @@ Every port of a workload falls into one of four, and this is the part to get rig
`ingressController` is a separate value with two keys rather than a line in `allowedNamespaces` for one reason: **its two selectors render as one `from` entry, which is an AND** — those pods in that namespace. Written as two list entries they would be an OR, and putting `kube-system` into `allowedNamespaces` instead would open the port to every pod in the cluster's own namespace. Its default is **measured, not assumed**: `ingress-nginx` is gone from this cluster, the only `IngressClass` is `traefik`, and the controller is the DaemonSet `rke2-traefik` in `kube-system` — which also serves the Gateway API here, so one source covers the Ingress and the HTTPRoute path alike. `ingress.className` says nothing about it: a class names an implementation, not the pods the traffic comes from.
#### The ambient-mesh switch, and the one named exception in the render test (#143)
**`networkPolicy.ingress.ambientMesh`, in all 30 charts, default `false`.** Istio runs on this cluster in ambient mode, and Istio's own documentation is explicit that *"ambient does not and will never bypass Kubernetes `NetworkPolicy` enforcement"* — so until this value existed, **no chart here could put a pod into the mesh at all**. Additive, unchanged default, unchanged render: **minor** per chart, and the render was diffed against the previous release per chart rather than asserted.
**It renders two things, and that they are one value is the whole design.**
1. **`15008/TCP` inbound** — ztunnel's HBONE tunnel, where every inbound mesh connection arrives.
2. **`169.254.7.127/32` as an additional peer**, but only where the rule restricts sources at all. Inside the mesh the kubelet's probes are **redirected** and no longer arrive from the worker node's address.
Point 2 is the one nobody thinks of, which is why the two halves cannot be had separately. An operator who adds `15008` to a port list by hand writes a policy that passes review — and the first time `probeSources` is narrowed, every probe is dropped, the pod never becomes `Ready`, and the symptom reads as a broken application rather than as a policy. That is the probe-path trap of this section one value further along. **A switch whose halves can only be had together cannot be set halfway**, so this is a named intention and not a port list. Charts with no `probeSources` at all render the port half only: their probe rule is never source-restricted, and an `ipBlock` for a redirected probe would match nothing while making the rule read as if it did something.
**The interesting part is the CI, because the obvious implementation was the worst one.** Assertion 2 of `ci/run-networkpolicy-test.sh` holds every ingress port against the selected pod spec's `containerPort`s, and `15008` is deliberately none — ztunnel terminates it, not the application. A free `ingress.extraPorts` key would have had to exempt *operator-supplied ports* from that assertion, which opens it for **all 30 charts**: every mistyped ingress port, the NodePort mistake included, would then pass. So the assertion keeps its edge and 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.
**An exception without its own check is the hole it was carved around**, so assertion 7 holds it to five things on **two renders of every chart**: with the switch off, neither `15008` nor the `ipBlock` is present; with it on, `15008` is present, `15008` is still the **only** ingress port that is not a `containerPort`, and wherever the rule carrying it restricts sources it carries the `ipBlock` too. The policy is found by the `<release>-<chart>-` name convention, because an exception must not be granted to an object the test could not identify. It lives in the existing script rather than a new one for the reason #136's cross-chart assertion does, only more so: **the exception weakens assertion 2, so it belongs beside it** — a separate script can be green while the exception it is paired with is wrong, and nothing would connect the two.
**Two things this does not prove, and they are not footnotes.** That `15008` *alone* suffices comes from Istio's documentation; what is measured on this cluster is only which listeners ztunnel opens. And the probe-source half reaches no release, because `probeSources` is empty in every chart (`stalwart` sets it to `[]` explicitly) — CI proves its render through the overlays in `ci/networkpolicy`, not its effect. Both become provable at the first namespace to join the mesh, and **none carries `istio.io/dataplane-mode`** (measured 2026-10-19, 0 of 97). Whether ztunnel needs a source selector of its own is open for the same reason — but it is *not* the unknowable case it looked like: ztunnel runs with its own pod IPs in `istio-system` (no `hostNetwork` on the DaemonSet, Istio 1.30.6), so a peer for it would be a `namespaceSelector` plus `podSelector`, not a node-IP `ipBlock`.
**Consumer side:** switching this on for a release is a value key *and* a chart version in **one** PR in `jk-cluster-config`, because Fleet does not retry a failed apply — and `networkPolicy` carries `additionalProperties: false` in all 30 charts, so an unknown key does not get ignored, it fails the render.
#### What these policies do not do — and it belongs in every chart, not just here
- **Egress is coarse: by port, never by destination.** A `NetworkPolicy` matches `ipBlock` CIDRs and pod/namespace selectors and **never hostnames**, so "only to the database host" is not expressible at all. This cluster's CNI is Canal (Flannel plus Calico for policy) and has no FQDN rule; Calico's `GlobalNetworkSet` could express one but would bind every chart to Calico — the same argument that kept implementation-specific objects out of the Gateway-API sweep (#114) — so it is **not used**. This is a limit of the object, and each chart names what it costs *that* chart.
+1 -1
View File
@@ -5,5 +5,5 @@ icon: https://www.apache.org/logos/res/tika/default.png
type: application
version: 11.0.0+up3.3.1.0.full
version: 11.1.0+up3.3.1.0.full
appVersion: "3.3.1.0-full"
@@ -50,6 +50,14 @@ selects.
{{- $ns := .Release.Namespace }}
{{- $probeSources := $np.probeSources | default list }}
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -83,6 +91,26 @@ spec:
- ports:
- protocol: TCP
port: 9998
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -110,6 +138,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -31,6 +31,17 @@
"type": "string"
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -115,6 +115,57 @@ networkPolicy:
# everything else that needs the port has to be in it. The chart adds the own
# namespace and allowedNamespaces to the same rule for exactly that reason.
probeSources: []
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+1 -1
View File
@@ -5,7 +5,7 @@ icon: https://raw.githubusercontent.com/alam00000/bentopdf/main/public/images/fa
type: application
version: 2.0.0+up2.8.8
version: 2.1.0+up2.8.8
appVersion: "2.8.8"
maintainers:
@@ -44,6 +44,14 @@ selects.
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- $ic := $np.ingressController | default dict }}
{{- $routed := or .Values.ingress.enabled .Values.httpRoute.enabled }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -76,6 +84,26 @@ spec:
- ports:
- protocol: TCP
port: 8080
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -118,6 +146,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -45,6 +45,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -362,6 +362,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+1 -1
View File
@@ -21,7 +21,7 @@ type: application
# duplicated here. The short version: eight tag shapes, six of them things
# nobody should pin, and plain `docker` versioning excludes all six - so that
# block deliberately carries NO versioningTemplate.
version: 2.0.0+up1.12.0
version: 2.1.0+up1.12.0
appVersion: "1.12.0"
maintainers:
@@ -50,6 +50,14 @@ selects.
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- $ic := $np.ingressController | default dict }}
{{- $routed := .Values.ingress.enabled }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -84,6 +92,26 @@ spec:
- ports:
- protocol: TCP
port: 3000
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -126,6 +154,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -45,6 +45,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -883,6 +883,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+1 -1
View File
@@ -5,7 +5,7 @@ name: calibre-web-automated
description: A Helm chart to deploy calibere-web-automated
icon: https://raw.githubusercontent.com/crocodilestick/Calibre-Web-Automated/main/README_images/cwa-logo-round-dark.png
version: 8.0.0+upv4.0.6
version: 8.1.0+upv4.0.6
appVersion: v4.0.6
maintainers:
@@ -45,6 +45,14 @@ selects.
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- $ic := $np.ingressController | default dict }}
{{- $routed := .Values.ingress.enabled }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -79,6 +87,26 @@ spec:
- ports:
- protocol: TCP
port: 8083
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -121,6 +149,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -45,6 +45,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -250,6 +250,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+446
View File
@@ -83,6 +83,15 @@
# because a green tick for a code path nobody entered is worse than an
# honest gap (README, "Two rules for every check added here").
# - PORT RANGES (endPort). Same treatment: reported, never counted.
# - THAT 15008 IS ENOUGH TO REACH A POD IN THE AMBIENT MESH. Assertion 7
# asserts the RENDER of networkPolicy.ingress.ambientMesh in both
# directions, and nothing beyond it. That the HBONE port alone suffices
# comes from Istio's documentation; measured on this cluster is only which
# listeners ztunnel opens, and no namespace carries istio.io/dataplane-mode
# yet, so there is no path on which it could be measured end to end. The
# probe-source half (169.254.7.127/32) is in the same position: its render is
# asserted, its effect is not, because probeSources is empty in every chart
# of this repository.
#
# AND THE ANTI-VACUUM GUARDS, because this test could be green over nothing:
#
@@ -492,6 +501,20 @@ for policy in policies:
# port is a port on the DESTINATION and has nothing to do with this pod's
# containerPorts, so holding egress against them would fail every chart that
# reaches a database.
#
# THE ONE NAMED EXCEPTION, AND IT IS NOT GRANTED HERE (Gitea #143). Port
# 15008 - ztunnel's HBONE tunnel - is terminated by the mesh and not by the
# application, so it is legitimately no containerPort while
# networkPolicy.ingress.ambientMesh is true. This loop renders every chart
# with that value at its DEFAULT, which is false, so for this assertion
# 15008 is an ordinary number and stays an ordinary failure - that is the
# negative half of the exception and it costs nothing. The exception itself
# lives in assertion 7, on a SECOND render with the value on, and it permits
# exactly that one number. It is deliberately not implemented as "skip
# operator-supplied ports when a gate is set": that was design A in #143 and
# would have opened this assertion for all 30 charts, letting every mistyped
# ingress port through - including the NodePort mistake this assertion
# exists for.
for i, rule in enumerate(spec.get("ingress") or []):
if not isinstance(rule, dict):
fail("%s ingress[%d] is not a mapping" % (tag, i))
@@ -870,6 +893,11 @@ EGRESS_PEER_ROWS="paperless-ngx|apache-tika,gotenberg|paperless.files.tikaGotenb
# leaves the parsed JSON in $2. The render/split/parse steps are repeated here
# instead of refactored out of the loop on purpose: the five assertions above
# are load-bearing and were not worth disturbing for this.
# RCJ_WITH_OVERLAY=1 additionally applies ci/networkpolicy/<chart>.yaml, last,
# exactly as the main loop does. Off by default so the cross-chart rows below
# keep rendering the consumer the way its release does; assertion 7 switches it
# on, because the overlay is the ONLY way the source-restricted branch - and
# with it the probe-source half of the ambient switch - is reachable at all.
render_chart_json() {
RCJ_CHART="$1"
RCJ_OUT="$2"
@@ -883,6 +911,9 @@ render_chart_json() {
RCJ_VALUES=(-f "$CI_DIR/trivy/values/$RCJ_CHART.yaml")
RCJ_LABEL="ci/trivy/values/$RCJ_CHART.yaml"
fi
if [ "${RCJ_WITH_OVERLAY:-}" = "1" ] && [ -f "$OVERLAY_DIR/$RCJ_CHART.yaml" ]; then
RCJ_VALUES+=(-f "$OVERLAY_DIR/$RCJ_CHART.yaml")
fi
"$ROOT/ci/helm-dependencies.sh" "$ROOT/$RCJ_CHART" >/dev/null || return 1
RCJ_MANIFEST="$RCJ_OUT.manifest.yaml"
helm template "$RELEASE" "$ROOT/$RCJ_CHART" \
@@ -1210,6 +1241,420 @@ PY
fi
done
# --- Assertion 7: the ambient-mesh switch (Gitea #143) -----------------------
# networkPolicy.ingress.ambientMesh renders the two things a pod needs before it
# can be reached inside Istio's ambient mesh, and the whole design question of
# #143 was how to allow the first of them without blunting assertion 2:
#
# 15008/TCP inbound - ztunnel's HBONE tunnel. Terminated by the
# mesh, so it is NOT a containerPort of the
# application. Assertion 2 would reject it, and
# it is right to reject it by default.
# 169.254.7.127/32 as a peer - where probeSources is non-empty. Inside the
# mesh the kubelet's probes are redirected and
# no longer arrive from the worker node's
# address.
#
# WHAT THIS ASSERTION IS FOR. The exception assertion 2 grants is NAMED and
# single-valued: one port number, gated on one value. The danger of any
# exception is that it stops being checked and becomes the hole it was carved
# around, so the exception is held to five things at once, on TWO renders of
# every chart:
#
# switch OFF (the main loop's render, reused)
# - 15008 must be ABSENT. Without this half the exception is a hole: a
# chart could render the port unconditionally and nothing would notice,
# because assertion 7 would find it present and assertion 2 is where it
# would have failed.
# - 169.254.7.127/32 must be absent too, for the same reason.
# switch ON
# - 15008/TCP must be PRESENT, or the value is decorative.
# - 15008 must be the ONLY ingress port that is not a containerPort. This is
# the line between a named exception and design A of #143: every other
# mistyped or NodePort number still fails here, with the switch on.
# - wherever the rule carrying 15008 restricts sources, that rule's "from"
# must contain 169.254.7.127/32. This is the inseparability of the two
# halves, asserted rather than trusted - and it is REACHABLE, because
# these renders apply ci/networkpolicy/<chart>.yaml, which is where
# probeSources is non-empty (template-chart, gotenberg).
#
# And the policy is found by the NAME CONVENTION, <release>-<chart>-*, the same
# way assertion 6 finds it: an exception must not be granted to an object this
# test did not identify. A chart whose policy stops following the convention
# fails here instead of silently losing its coverage.
#
# TWO LIMITS OF THIS ASSERTION, named rather than left to be discovered:
#
# - ASSERTIONS 1, 3, 4 AND 5 ARE NOT RE-RUN ON THE SWITCHED-ON RENDER. Only
# assertion 2's subject matter is, because that is the one the exception
# touches. Assertion 3 is the interesting omission: with the switch on and
# probeSources empty, 15008 sits in a rule with no "from", and assertion 3's
# two justifications for an open rule - a network probe addresses the port,
# or a NodePort publishes it - cover neither. That is intended rather than
# overlooked. The port has to be reachable from wherever ztunnel dials from,
# and that address is not knowable from a render: ztunnel runs with its own
# pod IPs in istio-system (measured 2026-10-19, no hostNetwork on the
# DaemonSet, Istio 1.30.6), but whether a peer of its own is needed cannot
# be settled until a namespace actually joins the mesh. Teaching assertion 3
# a third justification before then would be a rule written against a guess.
# - THE PROBE-SOURCE HALF IS CONDITIONAL ON THE CHART OFFERING probeSources,
# like assertion 4 and the overlay guard. A chart with exec-only probes has
# no probe on the network to redirect, so the ipBlock would match nothing.
#
# BUILT INTO THIS SCRIPT rather than added as a new test with its own pipeline
# job - the same decision as assertion 6 for #136, and here it is stronger than
# convenience. The exception WEAKENS assertion 2, so it belongs next to it: a
# separate script can be green while the exception it is paired with is wrong,
# and nothing would connect the two. Everything else is already here as well -
# the job runs over every chart on every pull request and so cannot be skipped
# by a path filter, helm is already the YAML parser through ci/yaml2json, and
# the verdict, grouping and summary plumbing is shared.
#
# EVERY CHART MUST OFFER THE VALUE, and a chart that does not fails. Same
# mechanism as assertion 0: the mistake arrives by copy into a NEW chart whose
# own diff nobody reads for it, which is exactly how garage (#81) and keycloak
# (#83) arrived with no policy at all after #5 had been filed.
AMBIENT_VALUE="networkPolicy.ingress.ambientMesh"
for CHART in "${CHARTS[@]}"; do
# A chart whose main-loop render already failed has nothing to compare
# against; it is reported there and would only produce a second, derived
# error here.
case " $FAILED " in *" $CHART "*) continue ;; esac
[ -s "$WORK/$CHART.json" ] || continue
echo "::group::ambient-mesh switch: $CHART"
ROW_FAIL=""
ON_JSON="$WORK/ambient-$CHART-on.json"
if ! RCJ_WITH_OVERLAY=1 render_chart_json "$CHART" "$ON_JSON" \
--set "$AMBIENT_VALUE=true"; then
sed 's/^/ /' "$WORK/xerr"
echo " FAIL $CHART does not render with $AMBIENT_VALUE=true"
echo "::error title=ambient-mesh $CHART::$CHART does not render with $AMBIENT_VALUE=true. Since Gitea #143 every chart in this repository offers that value, and networkPolicy carries additionalProperties: false in all of them - so an unknown key does not get ignored, it fails the render. Add the key to values.yaml AND to values.schema.json (schema and template belong together per chart), and render the ingress port 15008 plus, inside the source-restricted branch, the ipBlock 169.254.7.127/32. Copy template-chart/templates/xxx.networkpolicy.yaml."
ROW_FAIL=1
fi
# The policy's name is built from Chart.yaml's name, which is NOT always the
# directory name - template-chart is called "xxx", and the whole point of that
# chart is that it is a copy template. Reading the directory name here found
# exactly that on the first run, so the name comes from Chart.yaml.
CHART_NAME="$(sed -n 's/^name:[[:space:]]*//p' "$ROOT/$CHART/Chart.yaml" \
| head -1 | tr -d '[:space:]')"
if [ -z "$CHART_NAME" ]; then
echo " FAIL $CHART has no name in Chart.yaml"
echo "::error title=ambient-mesh $CHART::$CHART/Chart.yaml declares no name, so the NetworkPolicy's conventional name could not be derived."
ROW_FAIL=1
fi
if [ -z "$ROW_FAIL" ]; then
set +e
python3 - "$CHART" "$RELEASE" "$AMBIENT_VALUE" "$WORK/$CHART.json" "$ON_JSON" \
"$ROOT/$CHART" "$CHART_NAME" \
>"$WORK/ambient-$CHART.out" 2>"$WORK/ambient-$CHART.pyerr" <<'PY'
import json, re, sys
chart, release, gate, off_path, on_path, chart_dir, chart_name = sys.argv[1:8]
PORT = 15008
CIDR = "169.254.7.127/32"
lines = []
def ok(msg): lines.append("OK|%s: %s" % (chart, msg))
def skip(msg): lines.append("SKIP|%s: %s" % (chart, msg))
def fail(msg): lines.append("FAIL|%s: %s" % (chart, msg))
def docs_of(path):
return [d for d in (json.load(open(path)).get("docs") or []) if isinstance(d, dict)]
def pod_templates(node):
out = []
if isinstance(node, dict):
for key, value in node.items():
if (key == "template" and isinstance(value, dict)
and isinstance(value.get("spec"), dict)
and "containers" in value["spec"]):
out.append(value)
out.extend(pod_templates(value))
elif isinstance(node, list):
for value in node:
out.extend(pod_templates(value))
return out
def labels_of(template):
meta = template.get("metadata")
labels = meta.get("labels") if isinstance(meta, dict) else None
return labels if isinstance(labels, dict) else {}
def matches(selector, labels):
for key, value in selector.items():
if key not in labels or str(labels[key]) != str(value):
return False
return True
def container_ports(template):
out = []
spec = template.get("spec") or {}
for key in ("containers", "initContainers"):
for container in spec.get(key) or []:
if not isinstance(container, dict):
continue
for port in container.get("ports") or []:
if isinstance(port, dict) and port.get("containerPort") is not None:
out.append((int(port["containerPort"]), port.get("name")))
return out
def own_policies(path):
"""This chart's OWN NetworkPolicies, by the <release>-<chart>- name
convention - so a bundled subchart's policy can neither satisfy nor break an
assertion the parent chart is responsible for."""
prefix = "%s-%s-" % (release, chart_name)
out = []
for doc in docs_of(path):
if doc.get("kind") != "NetworkPolicy":
continue
name = ((doc.get("metadata") or {}).get("name")) or ""
if name.startswith(prefix):
out.append((name, doc))
return out
def ingress_rules(doc):
spec = doc.get("spec") if isinstance(doc.get("spec"), dict) else {}
return [r for r in (spec.get("ingress") or []) if isinstance(r, dict)]
def rule_ports(rule):
"""[(number_or_name, protocol)] for the rule's ports."""
out = []
for port in rule.get("ports") or []:
if not isinstance(port, dict):
continue
value = port.get("port")
proto = str(port.get("protocol") or "TCP")
if isinstance(value, int) or (isinstance(value, str) and value.isdigit()):
out.append((int(value), proto))
elif value is not None:
out.append((value, proto))
return out
def cidrs_of(rule):
out = []
for peer in rule.get("from") or []:
if isinstance(peer, dict) and isinstance(peer.get("ipBlock"), dict):
out.append(str(peer["ipBlock"].get("cidr")))
return out
# --- The value is declared, in BOTH places it has to be --------------------
# The render with the switch on already proves the SCHEMA declares it - an
# undeclared key cannot pass additionalProperties: false. What that render
# cannot prove is that values.yaml ships the documented default, and a value
# only reachable through --set is not a value an operator finds.
values_yaml = ""
try:
values_yaml = open("%s/values.yaml" % chart_dir, encoding="utf-8").read()
except IOError:
pass
if re.search(r"^\s*ambientMesh\s*:", values_yaml, re.M):
ok("values.yaml ships the ambientMesh key with its default, and the render "
"with %s=true succeeded - which is itself the proof that "
"values.schema.json declares it, since networkPolicy carries "
"additionalProperties: false" % gate)
else:
fail("renders with %s=true - so the schema knows the key - but values.yaml "
"contains no ambientMesh key at all. A value that exists only in the "
"schema is reachable through --set and findable nowhere: the defaults "
"are what an operator reads. Add it with its comment, default false, "
"as in template-chart." % gate)
off_policies = own_policies(off_path)
on_policies = own_policies(on_path)
if not off_policies or not on_policies:
fail("renders no NetworkPolicy named %s-%s-* (off: %d, on: %d), so the "
"ambient-mesh exception could not be held against this chart's own "
"policy. The convention is {{ .Release.Name }}-{{ .Chart.Name }}-<kind>; "
"if the name changed, this assertion has to follow - it is not skipped, "
"because an exception granted to an object this test cannot identify is "
"worth less than no exception at all."
% (release, chart_name, len(off_policies), len(on_policies)))
else:
# --- The switch OFF half ------------------------------------------------
off_hits, off_cidr_hits = [], []
for name, doc in off_policies:
for i, rule in enumerate(ingress_rules(doc)):
for value, proto in rule_ports(rule):
if value == PORT:
off_hits.append("%s ingress[%d] %s/%s" % (name, i, value, proto))
for cidr in cidrs_of(rule):
if cidr == CIDR:
off_cidr_hits.append("%s ingress[%d]" % (name, i))
if off_hits:
fail("allows ingress port %d with %s at its default (false): %s. The "
"exception assertion 2 grants for %d is gated on that value, and "
"this is the half that keeps it from being a hole - a port rendered "
"unconditionally would otherwise be found present by this assertion "
"and never held against the pod spec by assertion 2. Gate the port "
"on the value." % (PORT, gate, ", ".join(off_hits), PORT))
elif off_cidr_hits:
fail("carries the ipBlock %s with %s at its default (false): %s. The "
"probe-source half of the switch is for the mesh only, where the "
"kubelet's probes are redirected; outside it the address matches "
"nothing and makes the rule read as if it did something."
% (CIDR, gate, ", ".join(off_cidr_hits)))
else:
ok("with %s at its default the policy allows neither port %d nor the "
"ipBlock %s - the negative half of assertion 2's named exception, "
"without which the exception would be a hole" % (gate, PORT, CIDR))
# --- The switch ON half -------------------------------------------------
templates = []
for doc in docs_of(on_path):
templates.extend(pod_templates(doc))
found_port, bad_ports, restricted_without_cidr, carriers = [], [], [], []
for name, doc in on_policies:
spec = doc.get("spec") if isinstance(doc.get("spec"), dict) else {}
selector = spec.get("podSelector")
match_labels = (selector or {}).get("matchLabels") or {}
selected = [t for t in templates if matches(match_labels, labels_of(t))]
declared = set()
for t in selected:
for number, pname in container_ports(t):
declared.add(number)
if pname:
declared.add(pname)
for i, rule in enumerate(ingress_rules(doc)):
for value, proto in rule_ports(rule):
if value == PORT:
found_port.append("%s ingress[%d] %d/%s" % (name, i, PORT, proto))
carriers.append((name, i, rule))
if proto != "TCP":
bad_ports.append("%s ingress[%d] renders %d as %s, but "
"HBONE is TCP" % (name, i, PORT, proto))
elif value not in declared and selected:
bad_ports.append(
"%s ingress[%d] allows %r, which is no containerPort of "
"the selected pod spec" % (name, i, value))
if not found_port:
fail("renders no ingress port %d with %s=true, so the value is "
"decorative: the chart accepts it, the schema declares it, and the "
"policy that comes out is the same one as before. A pod whose "
"namespace has joined the ambient mesh is then unreachable, because "
"ambient does not bypass NetworkPolicy enforcement." % (PORT, gate))
else:
ok("with %s=true the policy allows %s - ztunnel's HBONE tunnel, the one "
"port assertion 2 grants a named exception for"
% (gate, ", ".join(found_port)))
if bad_ports:
fail("with %s=true the policy allows ingress port(s) that are NOT "
"containerPorts of the selected pod spec and are NOT the one number "
"the exception covers (%d): %s. This is the line between a named "
"exception and the free port key that was rejected as design A of "
"#143 - with the switch on, every OTHER wrong port still fails, "
"including a NodePort number written where a pod port belongs."
% (gate, PORT, "; ".join(bad_ports)))
elif found_port:
ok("with %s=true, port %d is still the ONLY ingress port of this chart "
"that is not a containerPort of the selected pod spec - the exception "
"covers exactly one number and nothing rode in beside it"
% (gate, PORT))
# The inseparability of the two halves, where the render can reach it.
#
# Conditional on the chart OFFERING probeSources, exactly as assertion 4 and
# the overlay guard are, and for the same reason: a chart with exec-only
# probes (valkey, minecraft-server) puts no probe packet on the network at
# all, so there is no probe to redirect and 169.254.7.127/32 would be an
# entry that matches nothing - the kind of strict-looking, empty rule this
# script exists to catch. Those charts render the port half only, and say so
# in their values.yaml.
offers_probe_sources = bool(re.search(
r"^\s*probeSources\s*:", values_yaml, re.M))
for name, i, rule in carriers:
if not rule.get("from"):
continue
if not offers_probe_sources:
ok("%s ingress[%d] carries port %d in a source-restricted rule and "
"no ipBlock %s - correct here, because this chart offers no "
"networkPolicy.probeSources: its probes put no packet on the "
"network, so there is no redirected probe to allow"
% (name, i, PORT, CIDR))
continue
if CIDR in cidrs_of(rule):
ok("%s ingress[%d] carries port %d AND the ipBlock %s in the same "
"\"from\" list - the two halves of the switch are inseparable, "
"which is the reason it is one value and not two"
% (name, i, PORT, CIDR))
else:
restricted_without_cidr.append(
"%s ingress[%d] (peers: %s)"
% (name, i, ", ".join(cidrs_of(rule)) or "no ipBlock at all"))
if restricted_without_cidr:
fail("with %s=true the rule carrying port %d restricts its sources but "
"does not include the ipBlock %s: %s. Inside the mesh the kubelet's "
"probes are redirected and arrive from that address instead of from "
"the worker node's, so a restricted rule without it drops every "
"probe - the pod never becomes Ready and the symptom reads as a "
"broken application rather than as a policy. That is assertion 4 of "
"this script, re-created one value further along, and it is the "
"whole reason the two halves are a single switch."
% (gate, PORT, CIDR, "; ".join(restricted_without_cidr)))
if not any(r.get("from") for _n, _i, r in carriers):
skip("the rule carrying port %d has no \"from\" list in this render, so "
"the probe-source half (%s) is not reachable here and was not "
"checked. That is the state of every chart's DEFAULTS - probeSources "
"is empty everywhere - and it is why ci/networkpolicy/<chart>.yaml "
"exists: template-chart and gotenberg render the restricted branch "
"and the half IS checked there. Reported, not counted as passing."
% (PORT, CIDR))
for line in lines:
print(line)
PY
RC=$?
set -e
if [ "$RC" -gt 1 ]; then
sed 's/^/ /' "$WORK/ambient-$CHART.pyerr"
echo "::error title=ambient-mesh $CHART::the ambient-mesh comparison itself failed for $CHART (python exit $RC). Treated as a failure, never as a pass."
ROW_FAIL=1
else
while IFS='|' read -r VERDICT DETAIL; do
case "$VERDICT" in
OK)
TOTAL_ASSERTIONS=$((TOTAL_ASSERTIONS + 1))
echo " ok $DETAIL"
;;
SKIP) echo " gap $DETAIL" ;;
FAIL)
ROW_FAIL=1
echo " FAIL $DETAIL"
echo "::error title=ambient-mesh $CHART::$DETAIL"
;;
*) [ -n "$VERDICT" ] && echo " $VERDICT $DETAIL" ;;
esac
done <"$WORK/ambient-$CHART.out"
fi
fi
echo "::endgroup::"
if [ -n "$ROW_FAIL" ]; then
FAILED="$FAILED $CHART(ambient-mesh)"
echo "ambient-mesh $CHART: FAILED"
else
AMBIENT_OK="${AMBIENT_OK:-} $CHART"
echo "ambient-mesh $CHART: ok"
fi
done
# --- Report ------------------------------------------------------------------
count() { set -- $1; echo "$#"; }
listing() { set -- $1; [ "$#" -eq 0 ] && { echo "–"; return; }; printf '`%s`' "$1"; shift; for C in "$@"; do printf ', `%s`' "$C"; done; echo; }
@@ -1225,6 +1670,7 @@ SUMMARY="${GITHUB_STEP_SUMMARY:-/dev/null}"
echo "| Result | Count | Charts |"
echo "|---|---|---|"
echo "| Policies checked | $(count "$CHECKED") | $(listing "$CHECKED") |"
echo "| Ambient-mesh switch held (Gitea #143) | $(count "${AMBIENT_OK:-}") | $(listing "${AMBIENT_OK:-}") |"
echo "| Failed | $(count "$FAILED") | $(listing "$FAILED") |"
echo
echo "$TOTAL_ASSERTIONS assertion(s) held in total."
+1 -1
View File
@@ -5,7 +5,7 @@ icon: https://raw.githubusercontent.com/gchq/CyberChef/master/src/web/static/ima
type: application
version: 10.0.0+up11.4.0
version: 10.1.0+up11.4.0
appVersion: "11.4.0"
maintainers:
@@ -51,6 +51,14 @@ selects.
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- $ic := $np.ingressController | default dict }}
{{- $routed := or .Values.ingress.enabled .Values.httpRoute.enabled }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -85,6 +93,26 @@ spec:
- ports:
- protocol: TCP
port: 8080
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -128,6 +156,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -45,6 +45,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -189,6 +189,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+1 -1
View File
@@ -8,7 +8,7 @@ description: A Helm chart to deploy a Wireguard-tunneled media automation stack
type: application
version: 5.0.0+up1.0.0
version: 5.1.0+up1.0.0
# The chart's own version marker, freely chosen and tied to no upstream. The
# stack bundles ten independently versioned projects (nine of them on by
# default), so there is no single "app version" to track here.
@@ -68,6 +68,14 @@ selects.
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- $ic := $np.ingressController | default dict }}
{{- $routed := or .Values.ingress.enabled .Values.httpRoute.enabled }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -125,6 +133,26 @@ spec:
port: 6767
- protocol: TCP
port: 5007
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -168,6 +196,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -45,6 +45,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -1412,6 +1412,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+1 -1
View File
@@ -19,7 +19,7 @@ type: application
# offer those as "updates", which is why the garage block in renovate.json5
# carries a versioningTemplate anchored to ^v<major>.<minor>.<patch>$ - same
# shape as the stalwart block, for the same reason.
version: 2.0.0+upv2.4.1
version: 2.1.0+upv2.4.1
appVersion: "v2.4.1"
maintainers:
@@ -54,6 +54,14 @@ selects.
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- $ic := $np.ingressController | default dict }}
{{- $routed := or .Values.ingress.enabled .Values.httpRoute.enabled }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -140,6 +148,26 @@ spec:
- ports:
- protocol: TCP
port: {{ $settings.ports.admin | int64 }}
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -167,6 +195,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -45,6 +45,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -576,6 +576,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+2 -2
View File
@@ -5,8 +5,8 @@ icon: https://gotenberg.dev/img/logo.png
type: application
version: 9.0.0+up8.37.0
appVersion: "8.37.0"
version: 9.2.0+up8.38.1
appVersion: "8.38.1"
maintainers:
- name: jklein
@@ -54,6 +54,14 @@ selects.
{{- $ns := .Release.Namespace }}
{{- $probeSources := $np.probeSources | default list }}
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -86,6 +94,26 @@ spec:
- ports:
- protocol: TCP
port: 3000
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -113,6 +141,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -31,6 +31,17 @@
"type": "string"
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -140,6 +140,57 @@ networkPolicy:
# everything else that needs the port has to be in it. The chart adds the own
# namespace and allowedNamespaces to the same rule for exactly that reason.
probeSources: []
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# REMOTE ASSETS: lets Chromium fetch over TCP 80 and 443, to any
# destination. OFF by default, and both halves of that are deliberate.
+1 -2
View File
@@ -4,8 +4,7 @@ description: A Helm chart to deploy Home Assistant on Kubernetes
icon: https://www.home-assistant.io/images/home-assistant-logo.svg
type: application
version: 7.0.0+up2026.8.3
version: 7.1.0+up2026.8.3
appVersion: "2026.8.3"
maintainers:
@@ -56,6 +56,14 @@ selects.
{{- $ns := .Release.Namespace }}
{{- $probeSources := $np.probeSources | default list }}
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -86,6 +94,26 @@ spec:
- ports:
- protocol: TCP
port: 8123
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -110,6 +138,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -14,6 +14,17 @@
"type": "object",
"additionalProperties": false,
"properties": {
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"enabled": {
"type": "boolean"
},
+51
View File
@@ -288,3 +288,54 @@ networkPolicy:
# everything else that needs the port has to be in it. The chart adds the own
# namespace and allowedNamespaces to the same rule for exactly that reason.
probeSources: []
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
+1 -1
View File
@@ -43,7 +43,7 @@ type: application
# procedure lives in NOTES.txt and on the wiki page instead of in a
# packageRules entry. Read the "MINOR UPGRADES" section of NOTES.txt before
# merging an app-version PR that changes the minor.
version: 2.0.0+up26.8.0
version: 2.1.0+up26.8.0
appVersion: "26.8.0"
maintainers:
@@ -81,6 +81,14 @@ selects.
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- $ic := $np.ingressController | default dict }}
{{- $routed := or .Values.ingress.enabled .Values.httpRoute.enabled }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -166,6 +174,26 @@ spec:
- ports:
- protocol: TCP
port: {{ $settings.ports.management | int64 }}
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -193,6 +221,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -45,6 +45,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -967,6 +967,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+1 -1
View File
@@ -3,7 +3,7 @@ name: matrix-synapse
description: A Helm chart to deploy a Matrix Synapse server on Kubernetes
icon: https://raw.githubusercontent.com/element-hq/synapse/develop/docs/favicon.png
type: application
version: 8.0.0+upv1.159.0
version: 8.1.0+upv1.159.0
appVersion: "v1.159.0"
maintainers:
- name: jklein
@@ -49,6 +49,14 @@ WHAT THESE POLICIES DO NOT DO:
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- $ic := $np.ingressController | default dict }}
{{- $routed := or .Values.ingress.enabled .Values.httpRoute.enabled }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -76,6 +84,26 @@ spec:
- ports:
- protocol: TCP
port: 8008
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's
@@ -121,6 +149,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -45,6 +45,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -364,6 +364,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports FOR SYNAPSE ONLY. These deliberately do NOT
# widen the delegation server's policy: an entry meant for Synapse's
+1 -1
View File
@@ -5,7 +5,7 @@ icon: https://avatars.githubusercontent.com/u/988985
type: application
version: 5.1.0+up1.48.0
version: 5.2.0+up1.48.0
appVersion: "1.48.0"
maintainers:
@@ -54,6 +54,14 @@ selects.
{{- $ns := .Release.Namespace }}
{{- $probeSources := $np.probeSources | default list }}
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -105,6 +113,26 @@ spec:
- ports:
- protocol: TCP
port: {{ .Values.server.apiPort | int64 }}
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -129,6 +157,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -31,6 +31,17 @@
"type": "string"
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -202,6 +202,57 @@ networkPolicy:
# everything else that needs the port has to be in it. The chart adds the own
# namespace and allowedNamespaces to the same rule for exactly that reason.
probeSources: []
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+1 -1
View File
@@ -23,7 +23,7 @@ type: application
# continuously, so a pod restart could pull a different image than the last one
# without anything being recorded anywhere. The dated tags are immutable, so the
# image is now pinned by the chart version like every other chart in this repo.
version: 7.0.0+up2026.8.2.java25
version: 7.1.0+up2026.8.2.java25
appVersion: "2026.8.2-java25"
maintainers:
@@ -53,6 +53,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:
@@ -92,6 +97,38 @@ spec:
- ports:
- protocol: TCP
port: {{ .Values.server.port | 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
exec probes, which put no packet on the network at all.
WHICH RULE IT JOINS:
the game-port rule, in BOTH of its branches. That rule is open when the
Service is a NodePort (players arrive from outside, already masqueraded)
and restricted to the namespace otherwise, and the two branches are
separate rules in this template - so the port is added twice, or it
would be missing from whichever branch a release happens to render.
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 }}
{{- end }}
{{- if not (eq .Values.server.service.type "NodePort") }}
{{- /*
@@ -107,6 +144,38 @@ spec:
- ports:
- protocol: TCP
port: {{ .Values.server.port | 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
exec probes, which put no packet on the network at all.
WHICH RULE IT JOINS:
the game-port rule, in BOTH of its branches. That rule is open when the
Service is a NodePort (players arrive from outside, already masqueraded)
and restricted to the namespace otherwise, and the two branches are
separate rules in this template - so the port is added twice, or it
would be missing from whichever branch a release happens to render.
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 }}
from:
- namespaceSelector:
matchLabels:
+11
View File
@@ -24,6 +24,17 @@
"type": "string"
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+36
View File
@@ -352,6 +352,42 @@ networkPolicy:
# matches nothing and is silently ineffective. Note the granularity: an entry
# opens the port to EVERY pod in that namespace.
allowedNamespaces: []
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# It renders 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod whose
# namespace has joined the mesh is unreachable.
#
# ONE HALF SHORTER THAN ELSEWHERE, deliberately. In other charts 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 has 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. An ipBlock for one would match nothing while making the
# rule look like it did something, which is the kind of strict-looking empty
# rule ci/run-networkpolicy-test.sh exists to catch; that script ties the
# exemption to the absence of probeSources rather than to a chart name.
#
# NOT PROVEN: that 15008 alone is enough comes from Istio's documentation;
# measured on this cluster is only which listeners ztunnel opens, and no
# namespace carries istio.io/dataplane-mode yet.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+1 -1
View File
@@ -5,7 +5,7 @@ icon: https://raw.githubusercontent.com/outline/outline/main/public/images/icon-
type: application
version: 8.1.0+up1.11.0
version: 8.2.0+up1.11.0
appVersion: 1.11.0
maintainers:
@@ -51,6 +51,14 @@ selects.
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- $ic := $np.ingressController | default dict }}
{{- $routed := or .Values.ingress.enabled .Values.httpRoute.enabled }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -85,6 +93,26 @@ spec:
- ports:
- protocol: TCP
port: 3000
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -127,6 +155,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -45,6 +45,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -241,6 +241,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+1 -2
View File
@@ -5,8 +5,7 @@ icon: https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/dev/src-ui/s
type: application
version: 14.1.0+up3.3.1
version: 14.2.0+up3.3.1
appVersion: 3.3.1
maintainers:
@@ -79,6 +79,14 @@ that the egress rule below contains their containerPorts.
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- $ic := $np.ingressController | default dict }}
{{- $routed := or .Values.ingress.enabled .Values.httpRoute.enabled }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -113,6 +121,26 @@ spec:
- ports:
- protocol: TCP
port: 8000
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -155,6 +183,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -87,6 +87,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -636,6 +636,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Outbound IMAPS (993) for paperless' mail import. OFF, and it has to be a
# value rather than something the chart derives: the mail accounts are ROWS
+1 -1
View File
@@ -5,7 +5,7 @@ icon: https://raw.githubusercontent.com/PatchMon/PatchMon/main/frontend/public/a
type: application
version: 8.0.0+up2.1.3
version: 8.1.0+up2.1.3
appVersion: "2.1.3"
maintainers:
@@ -45,6 +45,14 @@ selects.
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- $ic := $np.ingressController | default dict }}
{{- $routed := .Values.ingress.enabled }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -80,6 +88,26 @@ spec:
- ports:
- protocol: TCP
port: 3000
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -122,6 +150,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -45,6 +45,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -288,6 +288,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+2 -2
View File
@@ -5,8 +5,8 @@ icon: https://raw.githubusercontent.com/lukevella/rallly/main/apps/landing/publi
type: application
version: 9.0.0+up4.15.4
appVersion: "4.15.4"
version: 9.1.0+up4.15.5
appVersion: "4.15.5"
maintainers:
- name: jklein
@@ -45,6 +45,14 @@ selects.
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- $ic := $np.ingressController | default dict }}
{{- $routed := .Values.ingress.enabled }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -79,6 +87,26 @@ spec:
- ports:
- protocol: TCP
port: 3000
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -121,6 +149,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -45,6 +45,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -252,6 +252,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+1 -1
View File
@@ -5,7 +5,7 @@ icon: https://raw.githubusercontent.com/RSS-Bridge/rss-bridge/master/static/logo
type: application
version: 3.0.0+up2026.09.30
version: 3.1.0+up2026.09.30
appVersion: "2026-09-30"
maintainers:
@@ -48,6 +48,14 @@ selects.
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- $ic := $np.ingressController | default dict }}
{{- $routed := or .Values.ingress.enabled .Values.httpRoute.enabled }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -85,6 +93,26 @@ spec:
- ports:
- protocol: TCP
port: 80
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -127,6 +155,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -46,6 +46,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -419,6 +419,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+1 -2
View File
@@ -5,6 +5,5 @@ icon: https://avatars.githubusercontent.com/u/13281359
type: application
version: 8.0.0+up4.23.10
version: 8.1.0+up4.23.10
appVersion: 4.23.10
+34
View File
@@ -49,6 +49,11 @@ selects.
*/ -}}
{{- if .Values.networkPolicy.enabled }}
{{- $np := .Values.networkPolicy }}
{{- /* 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:
@@ -90,6 +95,35 @@ spec:
port: 445
- protocol: TCP
port: 139
{{- 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, and 445 is additionally published as a NodePort.
WHICH RULE IT JOINS:
the only rule this policy has, the one carrying 445 and 139.
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 }}
egress:
{{- /*
DNS, unconditionally. There is no value to switch this off, and that is
+11
View File
@@ -17,6 +17,17 @@
"enabled": {
"type": "boolean"
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+36
View File
@@ -128,6 +128,42 @@ networkPolicy:
# broadcasts on 137/138 UDP are not published by this chart's Service at all,
# and clients reach the share by address rather than by browse list.
enabled: true
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# It renders 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod whose
# namespace has joined the mesh is unreachable.
#
# ONE HALF SHORTER THAN ELSEWHERE, deliberately. In other charts 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 has 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. An ipBlock for one would match nothing while making the
# rule look like it did something, which is the kind of strict-looking empty
# rule ci/run-networkpolicy-test.sh exists to catch; that script ties the
# exemption to the absence of probeSources rather than to a chart name.
#
# NOT PROVEN: that 15008 alone is enough comes from Istio's documentation;
# measured on this cluster is only which listeners ztunnel opens, and no
# namespace carries istio.io/dataplane-mode yet.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+1 -1
View File
@@ -3,7 +3,7 @@ name: satisfactory
description: A Helm chart to deploy a Satisfactory Gameserver on Kubernetes
icon: https://raw.githubusercontent.com/wolveix/satisfactory-server/main/.github/logo.png
type: application
version: 8.0.0+upv1.9.10
version: 8.1.0+upv1.9.10
appVersion: "v1.9.10"
maintainers:
- name: jklein
@@ -57,6 +57,11 @@ every port here against the containerPorts of the pod spec this policy
selects.
*/ -}}
{{- if .Values.networkPolicy.enabled }}
{{- /* 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 := .Values.networkPolicy.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -98,4 +103,34 @@ spec:
port: {{ include "satisfactory.formatNumber" .Values.server.gamePort }}
- protocol: TCP
port: {{ include "satisfactory.formatNumber" .Values.server.messagingPort }}
{{- 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. The chart's networkPolicy
block has nothing but enabled. Measured in the render: two exec probes
and one tcpSocket.
WHICH RULE IT JOINS:
the only rule this policy has, the one carrying the game and messaging
ports.
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 }}
{{- end }}
+11
View File
@@ -14,6 +14,17 @@
"type": "object",
"additionalProperties": false,
"properties": {
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"enabled": {
"type": "boolean"
}
+36
View File
@@ -185,3 +185,39 @@ networkPolicy:
# as both - a TCP-only rule would be accepted and would drop half the game
# traffic.
enabled: true
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# It renders 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod whose
# namespace has joined the mesh is unreachable.
#
# ONE HALF SHORTER THAN ELSEWHERE, deliberately. In other charts 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 has 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. An ipBlock for one would match nothing while making the
# rule look like it did something, which is the kind of strict-looking empty
# rule ci/run-networkpolicy-test.sh exists to catch; that script ties the
# exemption to the absence of probeSources rather than to a chart name.
#
# NOT PROVEN: that 15008 alone is enough comes from Istio's documentation;
# measured on this cluster is only which listeners ztunnel opens, and no
# namespace carries istio.io/dataplane-mode yet.
ambientMesh: false
+1 -1
View File
@@ -9,7 +9,7 @@ type: application
# (2026.8.22-9fea41204) and "latest" moves daily. appVersion is therefore the
# exact tag, and the +up suffix normalizes the dash to a dot as the versioning
# scheme requires - the same shape rss-bridge and minecraft-server use.
version: 2.0.0+up2026.10.13.22c64b8d3
version: 2.1.0+up2026.10.13.22c64b8d3
appVersion: "2026.10.13-22c64b8d3"
maintainers:
@@ -46,6 +46,14 @@ selects.
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- $ic := $np.ingressController | default dict }}
{{- $routed := or .Values.ingress.enabled .Values.httpRoute.enabled }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -80,6 +88,26 @@ spec:
- ports:
- protocol: TCP
port: 8080
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -122,6 +150,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -45,6 +45,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -465,6 +465,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+1 -1
View File
@@ -37,7 +37,7 @@ type: application
#
# Note for whoever bumps this next: the suffix tracks appVersion, so a major
# here keeps the +up<appVersion> it was merged with.
version: 2.0.0+upv0.16.26
version: 2.1.0+upv0.16.26
appVersion: "v0.16.26"
maintainers:
@@ -61,6 +61,14 @@ unenforced policy is accepted and filters nothing.
{{- $probeSources := .Values.networkPolicy.probeSources | default list -}}
{{- $allowedNs := .Values.networkPolicy.allowedNamespaces | default list -}}
{{- $ic := .Values.networkPolicy.ingressController | default dict -}}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := .Values.networkPolicy.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
{{- range $group, $spec := fromYaml (include "stalwart.nodes" .) }}
{{- $name := printf "%s-%s" (include "stalwart.fullname" $root) $group }}
---
@@ -105,6 +113,26 @@ spec:
- ports:
- protocol: {{ $http.protocol | default "TCP" }}
port: {{ int $http.containerPort }}
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if or $probeSources $allowedNs }}
{{- /*
Restricted because networkPolicy.probeSources or .allowedNamespaces is
@@ -147,6 +175,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -334,6 +334,17 @@
"minLength": 1
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"description": "Egress is restricted by PORT, not by destination: a NetworkPolicy matches CIDRs and selectors and never hostnames, so no host value from this file can appear in it.",
"type": "object",
+51
View File
@@ -541,6 +541,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
# Egress is restricted BY PORT, not by destination, and the reason is a limit
# of the object rather than laziness: a NetworkPolicy matches ipBlock CIDRs
# and pod/namespace selectors, never hostnames — so dataStore.postgres.host
+1 -1
View File
@@ -5,7 +5,7 @@ icon: https://raw.githubusercontent.com/we-promise/sure/main/public/android-chro
type: application
version: 2.0.0+up0.7.4
version: 2.1.0+up0.7.4
appVersion: "0.7.4"
maintainers:
+52
View File
@@ -52,6 +52,14 @@ selects.
{{- $allowedNs := $np.allowedNamespaces | default list }}
{{- $ic := $np.ingressController | default dict }}
{{- $routed := .Values.ingress.enabled }}
{{- /* networkPolicy.ingress - the policy's INBOUND side, and not the same thing
as networkPolicy.ingressController (the SOURCE SELECTOR for the ingress
controller's pods, a SIBLING of it and no part of it) nor as the
top-level .Values.ingress (the Ingress object). All three match a search
for "ingress"; one round of this work already mistook the second for an
inbound escape hatch on the strength of the substring. */}}
{{- $npIngress := $np.ingress | default dict }}
{{- $ambientMesh := $npIngress.ambientMesh }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -86,6 +94,26 @@ spec:
- ports:
- protocol: TCP
port: 3000
{{- if $ambientMesh }}
{{- /* FIRST HALF OF 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 simply 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 therefore holds a NAMED exception for exactly this number, gated
on exactly this value - and assertion 7 of that script proves, on a
second render, that 15008 stays the ONLY such port and that it is absent
while the value is false.
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 }}
{{- if $probeSources }}
{{- /*
RESTRICTED, because the operator supplied probeSources. The kubelet's probes
@@ -128,6 +156,30 @@ spec:
- ipBlock:
cidr: {{ . | quote }}
{{- end }}
{{- if $ambientMesh }}
{{- /* SECOND HALF OF networkPolicy.ingress.ambientMesh, and the reason it is
one value and not 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.
An operator who only opens 15008 by hand writes a policy that passes
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 one value further along. A switch whose
halves can only be had together cannot be set halfway.
Only in this branch, because this is the only branch with a "from" list:
with no sources restricted the rule is open and needs no peer. The IPv6
counterpart is deliberately absent - this cluster is SingleStack IPv4,
and an ipBlock of the wrong family is accepted and matches nothing.
UNPROVEN IN OPERATION: probeSources is empty in every chart here, so no
release reaches this branch. CI proves its render, through the overlays
in ci/networkpolicy. */}}
- ipBlock:
cidr: 169.254.7.127/32
{{- end }}
{{- else }}
{{- /*
NO "from" SELECTOR, WHICH MEANS OPEN - deliberately, and only inside the
+11
View File
@@ -45,6 +45,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+51
View File
@@ -443,6 +443,57 @@ networkPolicy:
namespace: kube-system
podLabels:
app.kubernetes.io/name: rke2-traefik
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# IT RENDERS TWO THINGS, and that they come together is the point:
#
# 1. 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod
# whose namespace has joined the mesh is unreachable.
# 2. 169.254.7.127/32 as an additional peer - but ONLY where the rule
# restricts sources at all, which here means probeSources is non-empty.
# Inside the mesh the kubelet's probes are redirected and no longer come
# from the worker node's address.
#
# WHY ONE SWITCH AND NOT TWO: point 2 is the one nobody thinks of. Whoever
# adds "15008" to a port list by hand writes a policy that passes review, and
# the first time probeSources is narrowed every probe is dropped - the pod
# never becomes Ready and the symptom reads as a broken application rather
# than as a policy. A switch whose halves can only be had together cannot be
# set halfway, which is why this is a named intention and not a port list.
#
# TWO THINGS IT DOES NOT PROVE:
# - That 15008 alone is enough. That 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 carries
# istio.io/dataplane-mode yet.
# - That the probe-source half works. probeSources is empty in every chart
# here, so no release reaches that branch. CI proves its render, not its
# effect.
#
# Note where the port lands: it joins the rule that carries the probe port,
# so once probeSources restricts that rule, 15008 is restricted with it.
# Whether ztunnel needs a peer of its own is open - it runs with its own pod
# IPs in istio-system (measured: no hostNetwork on the DaemonSet, Istio
# 1.30.6), so if one proves necessary it is expressible as a
# namespaceSelector plus podSelector and needs no unknowable node CIDR.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
+1 -1
View File
@@ -5,5 +5,5 @@ icon: https://avatars.githubusercontent.com/u/136759148
type: application
version: 6.0.0+up6.0.0.beta13.1
version: 6.1.0+up6.0.0.beta13.1
appVersion: "6.0.0-beta13.1"
@@ -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
+11
View File
@@ -24,6 +24,17 @@
"type": "string"
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
+36
View File
@@ -132,6 +132,42 @@ networkPolicy:
# matches nothing and is silently ineffective. Note the granularity: an entry
# opens the port to EVERY pod in that namespace.
allowedNamespaces: []
# The policy's INBOUND side. Mind the three names that overlap as substrings,
# because a search for "ingress" matches all of them and they are different
# things:
#
# ingress (top level) the Ingress OBJECT this chart
# renders - host, TLS, className
# networkPolicy.ingress this block: what the policy lets IN
# networkPolicy.ingressController the SOURCE SELECTOR for the ingress
# controller's pods. A SIBLING of this block
# and NO PART OF IT, despite the name.
ingress:
# Opens the pod for Istio's ambient mesh (Gitea #143). OFF by default and
# additive: while it is false this chart renders byte for byte as it did
# before the value existed.
#
# It renders 15008/TCP inbound - ztunnel's HBONE tunnel. Every inbound mesh
# connection arrives on it, and ambient "does not and will never bypass
# Kubernetes NetworkPolicy enforcement", so without this port a pod whose
# namespace has joined the mesh is unreachable.
#
# ONE HALF SHORTER THAN ELSEWHERE, deliberately. In other charts 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 has 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. An ipBlock for one would match nothing while making the
# rule look like it did something, which is the kind of strict-looking empty
# rule ci/run-networkpolicy-test.sh exists to catch; that script ties the
# exemption to the absence of probeSources rather than to a chart name.
#
# NOT PROVEN: that 15008 alone is enough comes from Istio's documentation;
# measured on this cluster is only which listeners ztunnel opens, and no
# namespace carries istio.io/dataplane-mode yet.
ambientMesh: false
egress:
# Additional outbound TCP ports. DNS (UDP and TCP 53) is always allowed and
# has no switch - a knob whose only other setting breaks every name lookup
@@ -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
+11
View File
@@ -45,6 +45,17 @@
}
}
},
"ingress": {
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"ambientMesh": {
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
"type": ["boolean", "null"]
}
}
},
"egress": {
"type": ["object", "null"],
"additionalProperties": false,
Loaded 100 of 121 files, more files were not shown because too many files have changed in this diff. Show more