From e4f70bc8564ec7efed18794b5438a2b223f2eb61 Mon Sep 17 00:00:00 2001 From: jklein Date: Mon, 24 Aug 2026 14:38:03 +0200 Subject: [PATCH] Correct two firewall claims the runtime test disproved FIREWALL_INPUT_PORTS does not open the app ports inside a pod network. gluetun detects the pod's own subnet and inserts an INPUT accept for it ahead of the per-port rules, and every packet arriving at the pod IP matches that rule by destination. Measured with the packet counters: 50 fresh requests moved the subnet rule from 306 to 356 packets while every --dport rule stayed at 0 since container start. A port that listens but is not in the list (gluetun's control server on 8000) is reachable from another pod all the same. The variable is kept - it is the explicit statement of which ports are meant to be reachable, and the subnet detection is gluetun's behaviour rather than a guarantee of this chart - but the comments no longer claim the traffic would be dropped without it. Second correction, same run: the /tmp/gluetun emptyDir fixed the "open ... permission denied" failure, but gluetun also chowns the file, which needs CAP_CHOWN. With all capabilities but NET_ADMIN dropped that logs "chown /tmp/gluetun/ip: operation not permitted" on every VPN restart. The file is written and the public IP is persisted, so this is a log line rather than a failure, and granting CHOWN to silence it would widen the container's capabilities for nothing. Noted where the mount is declared. --- freesailarr/templates/_helpers.tpl | 14 ++++++++++++-- freesailarr/templates/freesailarr.sfs.yaml | 17 ++++++++++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/freesailarr/templates/_helpers.tpl b/freesailarr/templates/_helpers.tpl index 2c92c6a..64e7a41 100644 --- a/freesailarr/templates/_helpers.tpl +++ b/freesailarr/templates/_helpers.tpl @@ -197,8 +197,18 @@ ingress block with enabled: true. Used by the ingress template. {{/* Comma-separated FIREWALL_INPUT_PORTS for gluetun: the ports of the enabled app containers (ingress traffic and the kubelet probes both arrive on the pod IP) -plus 9999 for gluetun's own health server. Without these the gluetun firewall -drops the traffic. +plus 9999 for gluetun's own health server. + +Measured caveat: inside a pod network these rules never actually match. gluetun +detects the pod's own subnet and inserts +"-A INPUT -d -i eth0 -j ACCEPT" ahead of the per-port rules, and +every packet arriving at the pod IP matches it by destination - the packet +counters on the --dport rules stayed at 0 while the subnet rule absorbed the +traffic. The declaration is kept as an explicit statement of which ports are +meant to be reachable, and because that subnet detection is gluetun's, not a +guarantee of the chart's: a CNI that hands out a /32 or a future gluetun that +drops the rule would make these the only thing keeping probes and ingress +alive. It is not what opens the ports today. */}} {{- define "freesailarr.firewallInputPorts" -}} {{- $ports := list -}} diff --git a/freesailarr/templates/freesailarr.sfs.yaml b/freesailarr/templates/freesailarr.sfs.yaml index 9eff982..d2d220e 100644 --- a/freesailarr/templates/freesailarr.sfs.yaml +++ b/freesailarr/templates/freesailarr.sfs.yaml @@ -133,9 +133,12 @@ spec: - name: FIREWALL_OUTBOUND_SUBNETS value: {{ . | quote }} {{- end }} - # Open the firewall for the UI/probe ports of the enabled apps and - # the health server - kubelet probes and ingress traffic arrive on - # the pod IP and would be dropped otherwise. + # Declare the UI/probe ports of the enabled apps and the health + # server as reachable. Note that inside a pod network gluetun's own + # pod-subnet rule already accepts this traffic and these per-port + # rules never match (measured - see the helper's comment); they are + # the explicit statement of intent and the fallback if that subnet + # detection ever stops covering the pod IP. - name: FIREWALL_INPUT_PORTS value: {{ include "freesailarr.firewallInputPorts" . | quote }} # Bind the health server to all interfaces so the kubelet HTTP @@ -169,6 +172,14 @@ spec: # and every write fails with "clearing public IP data: open # /tmp/gluetun/ip: permission denied". An emptyDir provides the # path with usable permissions. + # Remaining, cosmetic: gluetun also chowns the file, which needs + # CAP_CHOWN. With all capabilities but NET_ADMIN dropped that call + # is denied and logs "clearing public IP data: chown + # /tmp/gluetun/ip: operation not permitted" on every VPN restart. + # The file itself is written and the public IP is persisted + # (verified at runtime), so this is a log line, not a failure - + # granting CHOWN just to silence it would widen the container's + # capabilities for nothing. - mountPath: /tmp/gluetun name: gluetun-tmp {{- if .Values.qbittorrent.enabled }}