feat(keycloak)!: NetworkPolicy, on by default - the full convention in one chart
Install-test / Install-test apache-tika (pull_request) Successful in 1m14s
Install-test / Install-test rss-bridge (pull_request) Successful in 54s
Install-test / Install-test patchmon (pull_request) Successful in 1m35s
Install-test / Install-test bentopdf (pull_request) Successful in 1m2s
Validate Helm Charts / Detect changed charts (pull_request) Successful in 3s
Validate Helm Charts / Resource quantities (pull_request) Successful in 13s
Validate Helm Charts / Selector match (pull_request) Successful in 10s
Validate Helm Charts / Bump level (pull_request) Successful in 4s
Validate Helm Charts / YAML scalars (pull_request) Successful in 10s
Validate Helm Charts / NetworkPolicy (pull_request) Failing after 15s
Install-test / Install-test bulwark (pull_request) Successful in 1m25s
Validate Helm Charts / HTTPRoute match (pull_request) Successful in 9s
Validate Helm Charts / Build apache-tika (pull_request) Successful in 6s
Validate Helm Charts / Build bentopdf (pull_request) Successful in 5s
Validate Helm Charts / Trivy config apache-tika (pull_request) Successful in 14s
Validate Helm Charts / Build bulwark (pull_request) Successful in 5s
Validate Helm Charts / Build calibre-web-automated (pull_request) Successful in 6s
Validate Helm Charts / Build gotenberg (pull_request) Successful in 7s
Validate Helm Charts / Build rallly (pull_request) Successful in 13s
Validate Helm Charts / Build searxng (pull_request) Successful in 17s
Validate Helm Charts / Build sure (pull_request) Successful in 18s
Validate Helm Charts / Build template-chart (pull_request) Successful in 6s
Validate Helm Charts / Build cyberchef (pull_request) Successful in 5s
Validate Helm Charts / Build homeassistant (pull_request) Successful in 7s
Validate Helm Charts / Build keycloak (pull_request) Successful in 11s
Validate Helm Charts / Build outline (pull_request) Successful in 8s
Validate Helm Charts / Build patchmon (pull_request) Successful in 6s
Validate Helm Charts / Build rss-bridge (pull_request) Successful in 5s
Install-test / Install-test rallly (pull_request) Successful in 1m39s
Validate Helm Charts / Build urlaubsverwaltung (pull_request) Successful in 5s
Validate Helm Charts / Build zipline (pull_request) Successful in 5s
Validate Helm Charts / Build voucher-vault (pull_request) Successful in 6s
Validate Helm Charts / Build ytdlp-web-player (pull_request) Successful in 6s
Validate Helm Charts / Trivy config homeassistant (pull_request) Successful in 11s
Validate Helm Charts / Trivy config bentopdf (pull_request) Successful in 15s
Validate Helm Charts / Trivy config bulwark (pull_request) Successful in 13s
Validate Helm Charts / Trivy config calibre-web-automated (pull_request) Successful in 16s
Validate Helm Charts / Trivy config cyberchef (pull_request) Successful in 26s
Validate Helm Charts / Trivy config gotenberg (pull_request) Successful in 19s
Validate Helm Charts / Trivy config patchmon (pull_request) Successful in 13s
Validate Helm Charts / Trivy config keycloak (pull_request) Successful in 19s
Validate Helm Charts / Trivy config outline (pull_request) Successful in 12s
Validate Helm Charts / Trivy config rallly (pull_request) Successful in 16s
Validate Helm Charts / Trivy config sure (pull_request) Successful in 13s
Validate Helm Charts / Trivy config template-chart (pull_request) Successful in 14s
Validate Helm Charts / Trivy config urlaubsverwaltung (pull_request) Successful in 21s
Validate Helm Charts / Trivy config rss-bridge (pull_request) Successful in 17s
Validate Helm Charts / Trivy config searxng (pull_request) Successful in 11s
Validate Helm Charts / Trivy config voucher-vault (pull_request) Successful in 15s
Validate Helm Charts / Trivy config ytdlp-web-player (pull_request) Successful in 13s
Validate Helm Charts / Trivy config zipline (pull_request) Successful in 13s
Install-test / Install-test calibre-web-automated (pull_request) Successful in 2m8s
Install-test / Install-test cyberchef (pull_request) Successful in 1m9s
Install-test / Install-test gotenberg (pull_request) Successful in 1m40s
Install-test / Install-test homeassistant (pull_request) Successful in 2m30s
Install-test / Install-test keycloak (pull_request) Successful in 1m58s
Install-test / Install-test searxng (pull_request) Successful in 1m5s
Install-test / Install-test outline (pull_request) Successful in 1m57s
Install-test / Install-test sure (pull_request) Successful in 2m30s
Install-test / Install-test urlaubsverwaltung (pull_request) Successful in 1m38s
Install-test / Install-test voucher-vault (pull_request) Successful in 2m6s
Install-test / Install-test ytdlp-web-player (pull_request) Successful in 1m5s
Install-test / Install-test zipline (pull_request) Successful in 1m50s
Validate Helm Charts / Install-test (pull_request) Successful in 29m30s
Install-test / Install-test apache-tika (pull_request) Successful in 1m14s
Install-test / Install-test rss-bridge (pull_request) Successful in 54s
Install-test / Install-test patchmon (pull_request) Successful in 1m35s
Install-test / Install-test bentopdf (pull_request) Successful in 1m2s
Validate Helm Charts / Detect changed charts (pull_request) Successful in 3s
Validate Helm Charts / Resource quantities (pull_request) Successful in 13s
Validate Helm Charts / Selector match (pull_request) Successful in 10s
Validate Helm Charts / Bump level (pull_request) Successful in 4s
Validate Helm Charts / YAML scalars (pull_request) Successful in 10s
Validate Helm Charts / NetworkPolicy (pull_request) Failing after 15s
Install-test / Install-test bulwark (pull_request) Successful in 1m25s
Validate Helm Charts / HTTPRoute match (pull_request) Successful in 9s
Validate Helm Charts / Build apache-tika (pull_request) Successful in 6s
Validate Helm Charts / Build bentopdf (pull_request) Successful in 5s
Validate Helm Charts / Trivy config apache-tika (pull_request) Successful in 14s
Validate Helm Charts / Build bulwark (pull_request) Successful in 5s
Validate Helm Charts / Build calibre-web-automated (pull_request) Successful in 6s
Validate Helm Charts / Build gotenberg (pull_request) Successful in 7s
Validate Helm Charts / Build rallly (pull_request) Successful in 13s
Validate Helm Charts / Build searxng (pull_request) Successful in 17s
Validate Helm Charts / Build sure (pull_request) Successful in 18s
Validate Helm Charts / Build template-chart (pull_request) Successful in 6s
Validate Helm Charts / Build cyberchef (pull_request) Successful in 5s
Validate Helm Charts / Build homeassistant (pull_request) Successful in 7s
Validate Helm Charts / Build keycloak (pull_request) Successful in 11s
Validate Helm Charts / Build outline (pull_request) Successful in 8s
Validate Helm Charts / Build patchmon (pull_request) Successful in 6s
Validate Helm Charts / Build rss-bridge (pull_request) Successful in 5s
Install-test / Install-test rallly (pull_request) Successful in 1m39s
Validate Helm Charts / Build urlaubsverwaltung (pull_request) Successful in 5s
Validate Helm Charts / Build zipline (pull_request) Successful in 5s
Validate Helm Charts / Build voucher-vault (pull_request) Successful in 6s
Validate Helm Charts / Build ytdlp-web-player (pull_request) Successful in 6s
Validate Helm Charts / Trivy config homeassistant (pull_request) Successful in 11s
Validate Helm Charts / Trivy config bentopdf (pull_request) Successful in 15s
Validate Helm Charts / Trivy config bulwark (pull_request) Successful in 13s
Validate Helm Charts / Trivy config calibre-web-automated (pull_request) Successful in 16s
Validate Helm Charts / Trivy config cyberchef (pull_request) Successful in 26s
Validate Helm Charts / Trivy config gotenberg (pull_request) Successful in 19s
Validate Helm Charts / Trivy config patchmon (pull_request) Successful in 13s
Validate Helm Charts / Trivy config keycloak (pull_request) Successful in 19s
Validate Helm Charts / Trivy config outline (pull_request) Successful in 12s
Validate Helm Charts / Trivy config rallly (pull_request) Successful in 16s
Validate Helm Charts / Trivy config sure (pull_request) Successful in 13s
Validate Helm Charts / Trivy config template-chart (pull_request) Successful in 14s
Validate Helm Charts / Trivy config urlaubsverwaltung (pull_request) Successful in 21s
Validate Helm Charts / Trivy config rss-bridge (pull_request) Successful in 17s
Validate Helm Charts / Trivy config searxng (pull_request) Successful in 11s
Validate Helm Charts / Trivy config voucher-vault (pull_request) Successful in 15s
Validate Helm Charts / Trivy config ytdlp-web-player (pull_request) Successful in 13s
Validate Helm Charts / Trivy config zipline (pull_request) Successful in 13s
Install-test / Install-test calibre-web-automated (pull_request) Successful in 2m8s
Install-test / Install-test cyberchef (pull_request) Successful in 1m9s
Install-test / Install-test gotenberg (pull_request) Successful in 1m40s
Install-test / Install-test homeassistant (pull_request) Successful in 2m30s
Install-test / Install-test keycloak (pull_request) Successful in 1m58s
Install-test / Install-test searxng (pull_request) Successful in 1m5s
Install-test / Install-test outline (pull_request) Successful in 1m57s
Install-test / Install-test sure (pull_request) Successful in 2m30s
Install-test / Install-test urlaubsverwaltung (pull_request) Successful in 1m38s
Install-test / Install-test voucher-vault (pull_request) Successful in 2m6s
Install-test / Install-test ytdlp-web-player (pull_request) Successful in 1m5s
Install-test / Install-test zipline (pull_request) Successful in 1m50s
Validate Helm Charts / Install-test (pull_request) Successful in 29m30s
Major. This is the richest policy of the sweep and the one with the largest
blast radius, and it is the only chart whose three ports fall into three
different classes - so it is where the convention is visible in full:
http (8080) NOT addressed by any probe, so it CAN be restricted by
source, and it is: own namespace, allowedNamespaces, and
the ingress controller. The only real inbound restriction
in this whole rollout, possible only because the probes use
a different port.
management (9000) the port all three probes address, so it stays open inside
the cluster. That matters here specifically: this surface
carries health and metrics UNAUTHENTICATED, and "no
Ingress" was its only protection before this object. The
policy turns "anything that can route to the pod" into
"anything inside the cluster"; probeSources closes the rest.
jgroups (7800) the cluster bus, restricted to the pods this policy itself
selects - a podSelector with no namespaceSelector, the
narrowest rule the object can express.
All four port numbers come from keycloak.settings rather than being written
down twice, so moving keycloak.ports.http moves the policy with it. And the
egress rule for the database is the CONFIGURED port, keycloak.db.port - this is
the one chart in the sweep that does not have to guess, because its database
port is a value instead of a field inside an opaque secret.
The outbound cluster-bus rule is not a duplicate of the inbound one: policyTypes
lists Egress, so a replica dialling its peer is subject to this policy too, and
without it the bus would be open inbound and blocked outbound - a cluster that
never forms, with two nodes that each look healthy.
THE BLAST RADIUS IS WRITTEN INTO THE CHART, because nothing in CI can catch it:
this release is the cluster's identity provider, no ingress controller runs in
the install-test, and the probes use 9000 - so the pod becomes Ready whether or
not the http rule is right. NOTES.txt therefore asks for two checks after the
first upgrade: log in, and look at whether any consumer uses the in-cluster
Service address instead of the public issuer URL (those namespaces need
allowedNamespaces). Not allowed at all, and named as the likely first surprise:
SMTP, because the mail server is configured per realm where the chart cannot
see it.
The test's overlay guard is tightened in the same commit, and keycloak is why.
It counted any source-restricted rule, and this chart restricts two of them in
its own defaults - so the guard would have been satisfied while the probe
branch, the only branch an overlay exists to reach, was never rendered. It now
counts restricted PROBE rules. All twelve failure paths were re-run against the
change.
Part of #5
This commit is contained in:
6 files changed
+523
-5
No files matched your search
@@ -884,3 +884,101 @@ httpRoute:
|
||||
# Empty means [ingress.admin.domain]. Required (via that value) while
|
||||
# ingress.admin.enabled is true and httpRoute.enabled is true.
|
||||
hostnames: []
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# NetworkPolicy (Gitea #5). On by default. The reference implementation with
|
||||
# the full reasoning is template-chart; the convention is in README, "Chart
|
||||
# style guidelines", and the operator's view on this chart's wiki page.
|
||||
# ---------------------------------------------------------------------------
|
||||
networkPolicy:
|
||||
# THE RICHEST POLICY IN THIS REPOSITORY, AND THE ONE WITH THE LARGEST BLAST
|
||||
# RADIUS. Both halves matter.
|
||||
#
|
||||
# WHAT IT ALLOWS, inbound, and the three ports are three different cases:
|
||||
# - http (8080): RESTRICTED BY SOURCE to this namespace, allowedNamespaces
|
||||
# and the ingress controller. The only real inbound restriction in the
|
||||
# whole sweep, and possible only because no probe uses this port.
|
||||
# - management (9000): open inside the cluster, because all three probes
|
||||
# address it. This is the port whose health and metrics surface is
|
||||
# UNAUTHENTICATED; before this object its only protection was that no
|
||||
# Ingress pointed at it. probeSources closes the rest.
|
||||
# - jgroups (7800): this release's own pods only.
|
||||
# Outbound: DNS, the CONFIGURED database port (keycloak.db.port - this chart
|
||||
# does not have to guess), the cluster bus, and 443 for identity brokering.
|
||||
#
|
||||
# THE BLAST RADIUS: this release is the cluster's identity provider. If
|
||||
# ingressController below is wrong, EVERY LOGIN EVERYWHERE BREAKS, and no
|
||||
# part of CI can catch it - no ingress controller runs in the install-test,
|
||||
# and the probes use 9000 so the pod goes Ready either way. The source was
|
||||
# measured on the live cluster, but measured labels are not proven traffic:
|
||||
# after the first upgrade, verify with a real login.
|
||||
#
|
||||
# AND THE SECOND TRAP: a consumer that reaches Keycloak on its IN-CLUSTER
|
||||
# Service address instead of its public URL is a pod in another namespace,
|
||||
# and the http rule blocks it. Put those namespaces in allowedNamespaces.
|
||||
# Consumers using the public issuer URL come through Traefik and are covered.
|
||||
#
|
||||
# NOT allowed, and the likely first surprise: SMTP. Mail is configured per
|
||||
# REALM, which this chart never sees - see egress.extraPorts.
|
||||
enabled: true
|
||||
# Namespaces whose pods may reach this workload, in addition to the release's
|
||||
# own namespace, which is always allowed. Empty means: own namespace only.
|
||||
#
|
||||
# Matched on the "kubernetes.io/metadata.name" label Kubernetes sets on every
|
||||
# namespace itself, so no labelling work is needed on a namespace this chart
|
||||
# does not own - and no typo protection either: a name that does not exist
|
||||
# matches nothing and is silently ineffective. Note the granularity: an entry
|
||||
# opens the port to EVERY pod in that namespace.
|
||||
allowedNamespaces: []
|
||||
# Source CIDRs allowed to reach the management port (keycloak.ports.management, 9000 by default), which is the port all three probes address.
|
||||
#
|
||||
# EMPTY MEANS OPEN, NOT BLOCKED. With no entry that rule is rendered WITHOUT a
|
||||
# "from" selector, so the port is reachable from anywhere the CNI routes to -
|
||||
# inside the cluster, since it carries no NodePort.
|
||||
#
|
||||
# That is the deliberate choice between two bad defaults. The kubelet's probes
|
||||
# originate from the IP of the WORKER NODE running the pod, an address this
|
||||
# chart cannot know and must not guess: a CIDR that excludes the real node
|
||||
# blocks every probe, the pod never becomes Ready, the rollout times out, and
|
||||
# the symptom reads as a broken application rather than as a policy.
|
||||
#
|
||||
# Narrow it by listing the worker node IPs (e.g. ["10.0.1.11/32"]) - and mind
|
||||
# the companion trap: once this list is non-empty the rule IS restricted, so
|
||||
# everything else that needs the port has to be in it. The chart adds the own
|
||||
# namespace, the ingressController below and allowedNamespaces to the same rule for exactly that reason.
|
||||
probeSources: []
|
||||
# The ingress controller allowed to reach the routed port once probeSources
|
||||
# restricts it. Rendered only while ingress.enabled or httpRoute.enabled is true, and only in
|
||||
# the restricted branch - with the default (open) rule the controller reaches
|
||||
# the port anyway. The two keys become ONE "from" entry and are therefore an
|
||||
# AND: pods carrying podLabels IN namespace. That is the point of having them
|
||||
# at all - the controller's namespace in allowedNamespaces would open the port
|
||||
# to every pod in kube-system.
|
||||
#
|
||||
# MEASURED ON THIS CLUSTER, NOT ASSUMED (2026-10-14): ingress-nginx is gone,
|
||||
# the only IngressClass is "traefik" and it is the default, and the controller
|
||||
# is the DaemonSet rke2-traefik in kube-system. The same Traefik serves the
|
||||
# Gateway API here, so this one source covers the Ingress and the HTTPRoute
|
||||
# path alike. A policy written against the wrong controller is accepted, looks
|
||||
# strict, and silently blocks all web traffic - and ingress.className says
|
||||
# nothing about it, because a class names an implementation, not the pods the
|
||||
# traffic comes from.
|
||||
ingressController:
|
||||
namespace: kube-system
|
||||
podLabels:
|
||||
app.kubernetes.io/name: rke2-traefik
|
||||
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
|
||||
# in the pod is a trap, not a feature.
|
||||
#
|
||||
# PORTS, NOT DESTINATIONS, and that is a limit of the object rather than
|
||||
# laziness: a NetworkPolicy matches CIDRs and selectors and never hostnames,
|
||||
# so "only to the database host" cannot be written at all. Each entry
|
||||
# permits its port to ANY destination. What the cap still buys is real: a
|
||||
# compromised pod cannot open arbitrary outbound connections.
|
||||
#
|
||||
# SMTP is the entry this chart needs most: 587 or 465, for the mail server
|
||||
# configured inside a realm. Also an LDAP user federation (389 or 636), or
|
||||
# a database that is somehow not on keycloak.db.port.
|
||||
extraPorts: []
|
||||
Reference in new issue
Block a user