Install-test / Install-test apache-tika (pull_request) Successful in 1m21s
Install-test / Install-test bentopdf (pull_request) Successful in 1m16s
Install-test / Install-test cyberchef (pull_request) Successful in 1m6s
Install-test / Install-test gotenberg (pull_request) Successful in 1m32s
Install-test / Install-test outline (pull_request) Failing after 1m16s
Install-test / Install-test rss-bridge (pull_request) Successful in 1m1s
Install-test / Install-test searxng (pull_request) Successful in 1m13s
Validate Helm Charts / Install-test (pull_request) Failing after 9m57s
Install-test / Install-test ytdlp-web-player (pull_request) Successful in 1m11s
Validate Helm Charts / Detect changed charts (pull_request) Successful in 3s
Validate Helm Charts / Resource quantities (pull_request) Failing after 18s
Validate Helm Charts / HTTPRoute match (pull_request) Failing after 13s
Validate Helm Charts / Selector match (pull_request) Failing after 17s
Validate Helm Charts / Bump level (pull_request) Successful in 8s
Validate Helm Charts / YAML scalars (pull_request) Failing after 16s
Validate Helm Charts / NetworkPolicy (pull_request) Failing after 9s
Validate Helm Charts / Build apache-tika (pull_request) Successful in 5s
Validate Helm Charts / Trivy config apache-tika (pull_request) Successful in 13s
Validate Helm Charts / Build bentopdf (pull_request) Successful in 5s
Validate Helm Charts / Build cyberchef (pull_request) Successful in 6s
Validate Helm Charts / Build outline (pull_request) Successful in 5s
Validate Helm Charts / Build template-chart (pull_request) Successful in 5s
Validate Helm Charts / Trivy config outline (pull_request) Failing after 12s
Validate Helm Charts / Trivy config searxng (pull_request) Successful in 15s
Validate Helm Charts / Trivy config template-chart (pull_request) Successful in 14s
Validate Helm Charts / Build gotenberg (pull_request) Successful in 5s
Validate Helm Charts / Build rss-bridge (pull_request) Successful in 5s
Validate Helm Charts / Build searxng (pull_request) Successful in 5s
Validate Helm Charts / Build ytdlp-web-player (pull_request) Successful in 5s
Validate Helm Charts / Trivy config bentopdf (pull_request) Successful in 14s
Validate Helm Charts / Trivy config cyberchef (pull_request) Successful in 13s
Validate Helm Charts / Trivy config gotenberg (pull_request) Successful in 13s
Validate Helm Charts / Trivy config rss-bridge (pull_request) Successful in 14s
Validate Helm Charts / Trivy config ytdlp-web-player (pull_request) Successful in 15s
bentopdf, apache-tika, gotenberg, rss-bridge, searxng, ytdlp-web-player. One major each, networkPolicy.enabled defaults to true. Three of them differ from the simple case in ways worth naming: GOTENBERG gets DNS-only egress as a deliberate, documented trade. It drives a headless Chromium, and 3000 is its probe port - so it is reachable from the whole cluster by default, and an egress rule for 80/443 would turn a service anyone can POST to into a way of fetching arbitrary URLs. The price is the remote-asset half of HTML conversion: inline content converts, images the page would have fetched silently do not. That degrades a PDF instead of failing a pod, so nothing alerts on it, which is why it is in the template header, in values.yaml and in NOTES.txt, with extraPorts: [80, 443] named as the knowing opt-in. RSS-BRIDGE, SEARXNG and YTDLP-WEB-PLAYER get the open internet on their web ports, because reaching other people's servers IS the application and this object cannot name a host. Said plainly in each, so none of them reads stricter than it is. What the cap still buys is real: no other outbound port, so a compromised pod reaches no database, no mail server and no SSH anywhere. APACHE-TIKA and GOTENBERG render no Ingress - their consumers are other pods, in other namespaces here - so neither gets an ingressController value and both say in NOTES.txt that narrowing probeSources means listing the consumers' namespaces in allowedNamespaces in the same change, or extraction and conversion stop. YTDLP-WEB-PLAYER names the gap this convention has: its oauth2-proxy subchart renders its own Deployment with its own labels and ships no policy, so with the proxy enabled the pod that actually faces the Ingress is unrestricted in both directions. Nothing in this chart can change that - an upstream chart is consumed as it comes - so it is written down instead. ci/outline/test-values.yaml gains egress.extraPorts: [5556]. The CI dex runs there rather than on 443, and Outline fetches the discovery document at boot - so this is the chart's documented escape hatch used for exactly the case it was written for, and the one place in the repo where the cap's upgrade risk is actually exercised. Part of #5
436 lines
22 KiB
YAML
436 lines
22 KiB
YAML
# Scale the whole chart down without uninstalling it: scaleDown: true renders
|
|
# every Deployment/StatefulSet with replicas: 0 (and suspends CronJobs) and
|
|
# takes precedence over any per-workload replicas value. PVCs, Secrets and
|
|
# Services stay in place; scaleDown: false brings the workloads back up.
|
|
scaleDown: false
|
|
|
|
# The bridges RSS-Bridge offers, rendered into the ConfigMap as whitelist.txt
|
|
# and mounted at /app/whitelist.txt.
|
|
#
|
|
# A list rather than a blob of file content: the file format is one bridge name
|
|
# per line, and the application trims and filters every line before use
|
|
# (lib/Configuration.php), so nothing is lost by modelling it as YAML - while a
|
|
# hardcoded file body in the template could not be changed without editing the
|
|
# chart.
|
|
#
|
|
# The single entry "*" is RSS-Bridge's own wildcard and enables every bridge.
|
|
# It is the default here because it is exactly what the image does when no
|
|
# whitelist.txt exists at all, so a default install behaves like stock
|
|
# RSS-Bridge instead of silently serving nothing. Installations that want a
|
|
# narrower set list the bridge names explicitly:
|
|
#
|
|
# whitelist:
|
|
# - Youtube
|
|
# - Heise
|
|
#
|
|
# Changing this value rolls the pod - the deployment carries a checksum over
|
|
# the rendered ConfigMap (see rss-bridge.deployment.yaml). Without that the
|
|
# change would not reach the running container at all: the whitelist is a
|
|
# subPath mount, which the kubelet never refreshes.
|
|
whitelist:
|
|
- "*"
|
|
|
|
rssBridge:
|
|
# Replica count for this workload; 0 is allowed and scales it down.
|
|
# The chart-global scaleDown flag takes precedence.
|
|
replicas: 1
|
|
# Verified against the image, not assumed (issue #128).
|
|
#
|
|
# The image ships no USER and runs everything as root by default. It does,
|
|
# however, run fully hardened once its writable paths are provided: nginx and
|
|
# php-fpm both start, the front page renders and real bridges fetch feeds.
|
|
#
|
|
# uid/gid 33 is www-data, and it is not interchangeable: /app and every file
|
|
# in it is owned by www-data in the image, nginx.conf declares "user
|
|
# www-data" and the php-fpm pool declares "user = www-data". Both emit a
|
|
# harmless notice that those directives are ignored when the master process
|
|
# is not root, and then serve normally as uid 33.
|
|
securityContext:
|
|
pod:
|
|
runAsNonRoot: true
|
|
runAsUser: 33
|
|
runAsGroup: 33
|
|
fsGroup: 33
|
|
fsGroupChangePolicy: Always
|
|
seccompProfile:
|
|
type: RuntimeDefault
|
|
# Why this chart listens on the privileged port 80, and why that is safe.
|
|
#
|
|
# nginx is configured for port 80 inside the image. The only lever the
|
|
# entrypoint offers is HTTP_PORT, which runs a sed against
|
|
# /etc/nginx/sites-enabled/default - impossible with a read-only root
|
|
# filesystem. So the choice is port 80 or readOnlyRootFilesystem, and
|
|
# port 80 is the cheaper of the two. (The Service selects the port by
|
|
# NAME, so the number is invisible to it either way.)
|
|
#
|
|
# Kubernetes sets net.ipv4.ip_unprivileged_port_start=0 in the pod
|
|
# network namespace, so binding 80 needs no capability at all. But that
|
|
# is a runtime default, not a guarantee, and relying on it silently is
|
|
# exactly the trap the template-chart warns about - so the chart pins the
|
|
# value instead of inheriting it.
|
|
#
|
|
# Measured in k3d (k3s v1.35.5), same pod spec, only this value changed:
|
|
# sysctl 1024, capabilities.drop [ALL] -> nginx: bind() to
|
|
# 0.0.0.0:80 failed (13: Permission denied)
|
|
# sysctl 1024, plus NET_BIND_SERVICE added -> identical failure.
|
|
# Adding the capability does NOT help: for a non-root process it
|
|
# lands in the permitted set but not the effective/ambient one, so
|
|
# it buys nothing here. That is why this chart does not add it.
|
|
# sysctl 0 (this default) -> binds, HTTP 200.
|
|
#
|
|
# Note how that failure looks without probes: the entrypoint starts nginx
|
|
# in the background and then execs php-fpm, so a failed bind leaves a
|
|
# container that reports Running with no web server at all. The probes on
|
|
# /?action=health turn that silent failure into a pod that never becomes
|
|
# Ready.
|
|
sysctls:
|
|
- name: net.ipv4.ip_unprivileged_port_start
|
|
value: "0"
|
|
container:
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: true
|
|
runAsNonRoot: true
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
# All three probes hit RSS-Bridge's own health action, which renders a fixed
|
|
# 49-byte JSON document without touching the file cache or any remote site.
|
|
# That keeps liveness free of external dependencies (guideline 3): a scraped
|
|
# website going down, or a cache directory that is not writable, must not
|
|
# restart the pod.
|
|
#
|
|
# Deliberately not "/": the front page enumerates every enabled bridge and
|
|
# answers with roughly 1.5 MB, which is a wasteful thing to fetch every ten
|
|
# seconds forever.
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /?action=health
|
|
port: rss-bridge-port
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /?action=health
|
|
port: rss-bridge-port
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
# The startup probe gates liveness/readiness, so those need no
|
|
# initialDelaySeconds. Startup budget = 5s * 30 = 150s, which is generous:
|
|
# the container is ready in about two seconds (nginx plus php-fpm, no
|
|
# migrations, no warm-up).
|
|
startupProbe:
|
|
httpGet:
|
|
path: /?action=health
|
|
port: rss-bridge-port
|
|
periodSeconds: 5
|
|
timeoutSeconds: 5
|
|
failureThreshold: 30
|
|
# Extra environment variables. Values are rendered through tpl; the value,
|
|
# secretKeyRef and configMapKeyRef forms are supported.
|
|
#
|
|
# RSS-Bridge maps RSSBRIDGE_<section>_<key> onto its config, so for example
|
|
# "RSSBRIDGE_system_timezone: Europe/Berlin" works here.
|
|
env: []
|
|
resources:
|
|
# Limits are optional: memory and ephemeral-storage limits default to
|
|
# limitFactor x the request, an explicitly set limit always wins, and a
|
|
# CPU limit is only set when configured explicitly under "limits".
|
|
limitFactor: 3
|
|
requests:
|
|
cpu: 0.1
|
|
# Measured with the shipped image: about 21 MiB resident at startup and
|
|
# roughly 64 MiB after serving feeds, so the 20Mi the original manifest
|
|
# requested was a third of what the workload occupies around the clock.
|
|
# (Re-measured on the 2025-08-05 image; the 2025-06-03 image came out
|
|
# marginally higher at 24 MiB / 71 MiB under the identical procedure.)
|
|
memory: 128Mi
|
|
# The previous manifest requested 2Gi of ephemeral storage - identical to
|
|
# its limit - and thereby reserved two gigabytes of node scheduling
|
|
# capacity for a workload that does not come close to using it.
|
|
#
|
|
# Everything RSS-Bridge writes was enumerated by running the image with a
|
|
# writable root filesystem, exercising every whitelisted bridge and then
|
|
# reading the container's diff layer. The only path that grows is the
|
|
# feed cache under /app/cache: 17 entries and 2.2 MB after fetching all
|
|
# five bridges, largest single entry 196 KB, and the application purges
|
|
# it on its own (FileCache enable_purge). /run and /var/lib/nginx add
|
|
# under 100 KB together.
|
|
#
|
|
# 64Mi is therefore roughly thirty times the measured footprint while
|
|
# freeing 97% of the old reservation. The limit below stays large, so
|
|
# the decoupling costs no safety margin (same shape as gotenberg, #106).
|
|
ephemeralStorage: 64Mi
|
|
limits:
|
|
# Set explicitly rather than left to limitFactor x request.
|
|
#
|
|
# memory: the manifest this chart replaces capped the container at
|
|
# 100Mi, but a warm container serving five concurrent feed fetches was
|
|
# measured peaking at 119 MiB - the old limit was already below the real
|
|
# peak. php-fpm is configured for up to five workers with a 128M PHP
|
|
# memory_limit each, so the theoretical ceiling is far higher still.
|
|
# 512Mi covers the measured peak with room to spare and still bounds a
|
|
# runaway bridge.
|
|
memory: 512Mi
|
|
# Unchanged from the previous manifest on purpose: a large cap costs
|
|
# nothing (it reserves no capacity) and guarantees this change cannot
|
|
# make eviction more likely than it is today.
|
|
ephemeralStorage: 2Gi
|
|
# No CPU limit by default (repo standard): CPU is compressible, so a limit
|
|
# only throttles. The previous manifest capped CPU at 0.5.
|
|
|
|
ingress:
|
|
# Gates the whole Ingress template. Checked in both directions per guideline
|
|
# 1: nothing outside this template reads an ingress value - the container
|
|
# takes no domain in its environment and nginx serves as default_server
|
|
# without a server_name - so switching the Ingress off frees every value
|
|
# below, and none of them needs a separate required().
|
|
#
|
|
# MUTUALLY EXCLUSIVE WITH httpRoute.enabled (Gitea #114) - the render aborts
|
|
# when both are true, naming both value paths. Note the default here is TRUE,
|
|
# so switching to Gateway mode means setting this to false explicitly.
|
|
#
|
|
# Re-checked for #114, because this is the value that trips charts up in the
|
|
# Gateway mode: anything COMPUTED from ingress.enabled flips when the mode
|
|
# changes, and three charts of the sweep (sure, freesailarr,
|
|
# ytdlp-web-player) had exactly such a value - one of them a silent
|
|
# authentication bypass. This chart has none. The grep was run over the whole
|
|
# chart directory: outside the Ingress template the only readers of an
|
|
# ingress value are NOTES.txt (which knows its own mode) and the tlsGroups
|
|
# helper (called only from behind this switch). RSS-Bridge takes no base URL
|
|
# and no hostname in its environment, so there is nothing here that could
|
|
# come out wrong while the pod stayed Ready - no "published" helper needed.
|
|
enabled: true
|
|
# NOT READ IN GATEWAY MODE: the chart renders no Certificate there, so there
|
|
# is nothing for cert-manager to do on behalf of this release. Required only
|
|
# while ingress.enabled - the single read lives inside the Ingress template,
|
|
# behind that switch.
|
|
clusterIssuer: null
|
|
# NOT READ IN GATEWAY MODE: the class is a property of the Gateway there, and
|
|
# the Gateway belongs to the platform (cluster-config).
|
|
className: nginx
|
|
# Extra annotations for the Ingress; merged with the cert-manager
|
|
# cluster-issuer annotation the chart always sets.
|
|
#
|
|
# NOT READ IN GATEWAY MODE: the Gateway API has no annotation channel for
|
|
# controller behaviour, so anything put here is gone in that mode.
|
|
#
|
|
# Unlike most charts of the sweep, this one loses NOTHING by that today, and
|
|
# it was measured rather than assumed (2026-10-13, read-only kubectl against
|
|
# the live object): the running Ingress carries the cert-manager
|
|
# cluster-issuer annotation plus Helm and Rancher/Fleet bookkeeping, and not
|
|
# one nginx.ingress.kubernetes.io annotation. Group 3 of the sweep found an
|
|
# operator-set annotation filling a chart's gap on four of its six charts -
|
|
# that screen came back empty here. An absence of evidence about THIS
|
|
# installation is not a guarantee about yours: whatever you put here still
|
|
# disappears in Gateway mode.
|
|
annotations: {}
|
|
# The hosts this Ingress serves. Required - the chart ships no default,
|
|
# because hostnames are installation data and have no business in a chart.
|
|
#
|
|
# NOT READ IN GATEWAY MODE, and this is the one value of the block where that
|
|
# needed a decision rather than a note - see httpRoute.hostnames below. The
|
|
# required() on this list lives inside the Ingress template, behind
|
|
# ingress.enabled, so it is already conditional on the mode and demands
|
|
# nothing in Gateway mode.
|
|
#
|
|
# Each entry is a host plus an OPTIONAL tlsSecretName:
|
|
#
|
|
# hosts:
|
|
# - host: rss-bridge.example.com
|
|
# - host: feeds.example.com
|
|
# tlsSecretName: tls-legacy-feeds-ingress
|
|
#
|
|
# Entries sharing a tlsSecretName are grouped into one tls entry, so they
|
|
# share a single certificate with several SANs. Entries with distinct names
|
|
# get one certificate each. Omitting tlsSecretName falls back to the repo
|
|
# convention, tls-<release>-<chart>-ingress.
|
|
#
|
|
# DOCUMENTED DEVIATION - why the secret name is configurable at all:
|
|
#
|
|
# The repo convention (guideline 4) is exactly one TLS secret per Ingress,
|
|
# named tls-<release>-<chart>-ingress. The installation this chart takes over
|
|
# has grown three separate secrets, one per host, from three years of
|
|
# kubectl apply. Renaming them would not be a cosmetic cleanup: cert-manager
|
|
# keys certificates by secret name, so three new names mean three fresh
|
|
# issuances, and the service is unreachable on each host until its
|
|
# certificate is issued. That is a self-inflicted outage plus three
|
|
# avoidable Let's Encrypt issuances, for a deployment that has been running
|
|
# untouched for over a year.
|
|
#
|
|
# Making host and secret name per-entry values keeps the existing names in
|
|
# place today and turns the eventual consolidation onto one certificate - or
|
|
# the retirement of the legacy hostnames - into a values change instead of a
|
|
# template change (the explicit ask from cluster-config#33).
|
|
#
|
|
# tlsSecretName IS MEANINGLESS IN GATEWAY MODE - the certificate sits on the
|
|
# Gateway's listener - which is why httpRoute.hostnames below is a plain list
|
|
# of strings rather than a reuse of this one.
|
|
hosts: null
|
|
|
|
# THE GATEWAY-API ALTERNATIVE TO THE INGRESS ABOVE (Gitea #114), and this chart
|
|
# is the LAST of that sweep - 22 charts carried an Ingress template, 21 an
|
|
# HTTPRoute template, and the difference was this one. It was held back because
|
|
# its install-test had been failing on the Gitea runner (#51), not for anything
|
|
# about its shape - and that test went green in the very PR that converted it,
|
|
# on a render byte-identical to main, which ruled the chart out and left the
|
|
# runner. #51 was closed on that round; the cause was never identified, so a
|
|
# recurrence is a fresh finding rather than a known quirk.
|
|
#
|
|
# Off by default, so an existing release is unaffected. Mutually exclusive with
|
|
# ingress.enabled - the render aborts when both are true, naming both value
|
|
# paths. Note that ingress.enabled DEFAULTS TO TRUE here, so this mode needs
|
|
# ingress.enabled: false set explicitly.
|
|
#
|
|
# The chart renders ONLY an HTTPRoute with parentRefs - no Gateway, no
|
|
# gatewayClassName, no Certificate and no implementation-specific policy
|
|
# object. Class and certificate belong to the Gateway and therefore to the
|
|
# platform (cluster-config), which is what keeps this chart independent of
|
|
# whether the cluster runs nginx-gateway-fabric, Cilium, Envoy Gateway or
|
|
# Istio.
|
|
#
|
|
# ONE OBJECT FOR EVERY HOSTNAME, because nothing differs per host: all three
|
|
# hostnames of the live installation serve the same Service at "/", measured on
|
|
# the running Ingress. spec.hostnames is a list and its rules apply to every
|
|
# hostname of the object, so one object is enough - unlike homeassistant (paths
|
|
# differ per host) or matrix-synapse (different paths and backends).
|
|
#
|
|
# WHAT BECOMES INERT, AND IT IS A SIMPLIFICATION RATHER THAN A LOSS:
|
|
# rss-bridge.tlsGroups, the helper that groups hosts by TLS secret name so the
|
|
# three grown certificates keep their names. With TLS on the listener there is
|
|
# nothing left for it to group, and this mode never calls it.
|
|
#
|
|
# The Gateway-API CRDs must be installed in the cluster: the chart does not and
|
|
# cannot detect them (.Capabilities.APIVersions is unreliable at template
|
|
# time), so with httpRoute.enabled: true and no CRDs the INSTALL fails.
|
|
httpRoute:
|
|
enabled: false
|
|
# The Gateway(s) this route attaches to - a platform object, usually in
|
|
# another namespace, which must allow this namespace in its listener's
|
|
# allowedRoutes. One entry per parent, the fields are the Gateway API's
|
|
# ParentReference (name, and optionally namespace, sectionName, port, group,
|
|
# kind), passed through unchanged:
|
|
#
|
|
# parentRefs:
|
|
# - name: public
|
|
# namespace: gateway
|
|
# sectionName: https
|
|
#
|
|
# REQUIRED while httpRoute.enabled is true - the render aborts on an empty
|
|
# list, because a route without a parent is created, is valid and routes
|
|
# nothing, with no event to say so.
|
|
parentRefs: []
|
|
# The public names of this release in Gateway mode. REQUIRED while
|
|
# httpRoute.enabled is true - the render aborts on an empty list.
|
|
#
|
|
# Its own value, and both halves of that are deliberate:
|
|
#
|
|
# Why not a fallback like the other charts: most of them have an
|
|
# ingress.domain - one public name - and an empty hostnames list falls back
|
|
# to it so there is a single source of truth. This chart has no
|
|
# ingress.domain; it has a LIST of hosts, so there is no single name to fall
|
|
# back to.
|
|
#
|
|
# Why not a reuse of ingress.hosts: those entries carry an optional
|
|
# tlsSecretName, which exists only to keep three grown certificates alive on
|
|
# their existing secret names, and which addresses nothing once TLS sits on
|
|
# the Gateway's listener. Reusing the list would drag a structure whose
|
|
# second field is meaningless into this mode and invite somebody to set it
|
|
# there. (freesailarr and homeassistant REJECT a hostnames key outright, for
|
|
# the opposite reason: a chart-global list could not say which app or which
|
|
# host entry it belonged to. Here there is one Service on one path, so a
|
|
# chart-global list says exactly one thing - which is why this chart gets the
|
|
# key those two refuse.)
|
|
#
|
|
# An empty list does NOT render nothing: an HTTPRoute without hostnames
|
|
# matches every request that reaches its listener, so on a shared Gateway
|
|
# this release would answer for hostnames belonging to other releases. Hence
|
|
# the abort.
|
|
#
|
|
# hostnames:
|
|
# - rss-bridge.example.com
|
|
# - feeds.example.com
|
|
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:
|
|
# WHAT THIS POLICY ALLOWS: inbound 80 only (the container's port), and
|
|
# outbound DNS plus TCP 80 and 443 to ANY destination.
|
|
#
|
|
# WHAT IT DOES NOT DO, and this one needs saying out loud: the egress rule
|
|
# permits the open internet on both web ports, because that IS the
|
|
# application - a feed bridge that cannot reach the sites it bridges does
|
|
# nothing, and a NetworkPolicy cannot express "only these hosts". What the
|
|
# cap still buys is real but narrow: this pod cannot open any OTHER outbound
|
|
# port, so a compromised bridge cannot reach a database, a mail server or an
|
|
# SSH port anywhere in the cluster.
|
|
#
|
|
# Inbound 80 is not restricted by source in the default (it is the probe
|
|
# port), and a policy is only a boundary where the CNI enforces one.
|
|
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 port 80, 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.
|
|
#
|
|
# 80 and 443 are already allowed, so most bridges need nothing here. Add a
|
|
# port only for a source that serves feeds somewhere else.
|
|
extraPorts: []
|