From 66dbe9ffe2799ed1953cf228bd1800fef656b577 Mon Sep 17 00:00:00 2001 From: Konstantin Renner Date: Wed, 20 May 2026 10:50:21 +0200 Subject: [PATCH] network-policies: allow all ICMP types in/out of default-deny namespaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces both the per-namespace ICMP-error addition (3c517a0) and the broad CCNP that broke kube-system (reverted in 3c517a0). Adds a single CCNP that: * Scopes its endpointSelector via `matchExpressions In` to the explicit list of namespaces that already opted into default-deny — so it only widens what's already enforced and CANNOT transition kube-system or any other unmanaged namespace into policy-enforced mode. * Allows the full standard ICMPv4 (0-30) and ICMPv6 (1-4, 128-153) type set in both directions. Cilium's ICMPField requires an explicit type per entry; there is no wildcard, so the list is enumerated. This covers Echo Request/Reply (ping), Destination Unreachable / Port Unreachable, Time Exceeded (traceroute), Packet Too Big (PMTUD), and the full ND/RA/RS set so v6 neighbour discovery works. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../network-policies/allow-icmp.yaml | 205 ++++++++++++++++++ .../network-policies/home-assistant-ns.yaml | 20 -- .../network-policies/kustomization.yaml | 1 + 3 files changed, 206 insertions(+), 20 deletions(-) create mode 100644 kubernetes/infrastructure/network-policies/allow-icmp.yaml diff --git a/kubernetes/infrastructure/network-policies/allow-icmp.yaml b/kubernetes/infrastructure/network-policies/allow-icmp.yaml new file mode 100644 index 00000000..2edaf534 --- /dev/null +++ b/kubernetes/infrastructure/network-policies/allow-icmp.yaml @@ -0,0 +1,205 @@ +# All ICMP types, in/out of every namespace that has a default-deny. +# +# Scoped via `matchExpressions In` to the explicit list of namespaces +# that already opted into policy enforcement, so this CCNP only widens +# what's already enforced — it cannot transition kube-system or any +# other unmanaged namespace into policy-enforced mode (which is what +# broke metrics-server when I previously used `Exists`). +# +# Enumerates every assigned ICMPv4 type (0-30) and ICMPv6 type +# (1-4, 128-153). Cilium's policy schema requires an explicit `type` +# per ICMPField — there is no wildcard. +apiVersion: cilium.io/v2 +kind: CiliumClusterwideNetworkPolicy +metadata: + name: allow-icmp-default-deny-namespaces +spec: + endpointSelector: + matchExpressions: + - key: io.kubernetes.pod.namespace + operator: In + values: + - apps + - audiobookshelf + - authentik + - crowdsec + - database + - home-assistant + - immich + - influxdb + - ingress + - monitoring + - paperless + - rook-ceph + - spegel + - velero + ingress: + - fromEndpoints: + - matchExpressions: + - key: io.kubernetes.pod.namespace + operator: Exists + icmps: + - fields: + - type: 0 # Echo Reply + family: IPv4 + - type: 3 # Destination Unreachable + family: IPv4 + - type: 4 # Source Quench + family: IPv4 + - type: 5 # Redirect + family: IPv4 + - type: 8 # Echo Request + family: IPv4 + - type: 9 # Router Advertisement + family: IPv4 + - type: 10 # Router Solicitation + family: IPv4 + - type: 11 # Time Exceeded + family: IPv4 + - type: 12 # Parameter Problem + family: IPv4 + - type: 13 # Timestamp + family: IPv4 + - type: 14 # Timestamp Reply + family: IPv4 + - type: 15 # Information Request + family: IPv4 + - type: 16 # Information Reply + family: IPv4 + - type: 17 # Address Mask Request + family: IPv4 + - type: 18 # Address Mask Reply + family: IPv4 + - type: 30 # Traceroute + family: IPv4 + - type: 1 # Destination Unreachable + family: IPv6 + - type: 2 # Packet Too Big + family: IPv6 + - type: 3 # Time Exceeded + family: IPv6 + - type: 4 # Parameter Problem + family: IPv6 + - type: 128 # Echo Request + family: IPv6 + - type: 129 # Echo Reply + family: IPv6 + - type: 130 # Multicast Listener Query + family: IPv6 + - type: 131 # Multicast Listener Report + family: IPv6 + - type: 132 # Multicast Listener Done + family: IPv6 + - type: 133 # Router Solicitation + family: IPv6 + - type: 134 # Router Advertisement + family: IPv6 + - type: 135 # Neighbor Solicitation + family: IPv6 + - type: 136 # Neighbor Advertisement + family: IPv6 + - type: 137 # Redirect + family: IPv6 + - type: 138 # Router Renumbering + family: IPv6 + - type: 141 # Inverse Neighbor Discovery Solicitation + family: IPv6 + - type: 142 # Inverse Neighbor Discovery Advertisement + family: IPv6 + - type: 143 # MLDv2 Listener Report + family: IPv6 + - type: 148 # Certification Path Solicitation + family: IPv6 + - type: 149 # Certification Path Advertisement + family: IPv6 + - type: 151 # Multicast Router Advertisement + family: IPv6 + - type: 152 # Multicast Router Solicitation + family: IPv6 + - type: 153 # Multicast Router Termination + family: IPv6 + egress: + - toEndpoints: + - matchExpressions: + - key: io.kubernetes.pod.namespace + operator: Exists + icmps: + - fields: + - type: 0 + family: IPv4 + - type: 3 + family: IPv4 + - type: 4 + family: IPv4 + - type: 5 + family: IPv4 + - type: 8 + family: IPv4 + - type: 9 + family: IPv4 + - type: 10 + family: IPv4 + - type: 11 + family: IPv4 + - type: 12 + family: IPv4 + - type: 13 + family: IPv4 + - type: 14 + family: IPv4 + - type: 15 + family: IPv4 + - type: 16 + family: IPv4 + - type: 17 + family: IPv4 + - type: 18 + family: IPv4 + - type: 30 + family: IPv4 + - type: 1 + family: IPv6 + - type: 2 + family: IPv6 + - type: 3 + family: IPv6 + - type: 4 + family: IPv6 + - type: 128 + family: IPv6 + - type: 129 + family: IPv6 + - type: 130 + family: IPv6 + - type: 131 + family: IPv6 + - type: 132 + family: IPv6 + - type: 133 + family: IPv6 + - type: 134 + family: IPv6 + - type: 135 + family: IPv6 + - type: 136 + family: IPv6 + - type: 137 + family: IPv6 + - type: 138 + family: IPv6 + - type: 141 + family: IPv6 + - type: 142 + family: IPv6 + - type: 143 + family: IPv6 + - type: 148 + family: IPv6 + - type: 149 + family: IPv6 + - type: 151 + family: IPv6 + - type: 152 + family: IPv6 + - type: 153 + family: IPv6 diff --git a/kubernetes/infrastructure/network-policies/home-assistant-ns.yaml b/kubernetes/infrastructure/network-policies/home-assistant-ns.yaml index a8ef690f..2cae52bb 100644 --- a/kubernetes/infrastructure/network-policies/home-assistant-ns.yaml +++ b/kubernetes/infrastructure/network-policies/home-assistant-ns.yaml @@ -36,26 +36,6 @@ spec: - fromEntities: - host - remote-node - # ICMP error class from any cluster pod — covers e.g. coredns sending - # `Destination Unreachable (Port)` back when an HA DNS query lands on - # a draining coredns instance via SO_REUSEPORT. Without this, HA's - # kernel never learns the destination is unreachable and just keeps - # retransmitting; Hubble shows the DU drops as - # `policy-verdict:none DENIED (ICMPv4 DestinationUnreachable(Port))`. - - fromEndpoints: - - matchExpressions: - - key: io.kubernetes.pod.namespace - operator: Exists - icmps: - - fields: - - type: 3 # IPv4 Destination Unreachable - family: IPv4 - - type: 11 # IPv4 Time Exceeded - family: IPv4 - - type: 1 # IPv6 Destination Unreachable - family: IPv6 - - type: 3 # IPv6 Time Exceeded - family: IPv6 # IoT devices reach HA on 10.2.30.80 and mosquitto on 10.2.30.81 # via Cilium-L2 LoadBalancers (externalTrafficPolicy=Local preserves # source IP, so they appear as world identity from the pod's diff --git a/kubernetes/infrastructure/network-policies/kustomization.yaml b/kubernetes/infrastructure/network-policies/kustomization.yaml index 2ec6185c..4f37e8a3 100644 --- a/kubernetes/infrastructure/network-policies/kustomization.yaml +++ b/kubernetes/infrastructure/network-policies/kustomization.yaml @@ -18,3 +18,4 @@ resources: - rook-ceph-ns.yaml - velero-ns.yaml - allow-cilium-health.yaml + - allow-icmp.yaml