Compare commits

..
Author SHA1 Message Date
claude-botandClaude Opus 5.5 570c93559b feat(paperless): restrict FTP and Syncthing LB ingress to their client networks
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
ftp-scanner and syncthing-sync accepted any world source.

- ftp-scanner: IoT and Privat. Over the last 7 days the vsftpd log shows
  uploads from the BR5C scanner via fd02:30:: and the Brother via
  10.2.50.170.
- syncthing-sync: Privat and VPN. Over the last 7 days peers connected
  from 10.2.50.0/24 and fd02:50::/64.

host and remote-node stay allowed. Both LBs are ETP=Local.

Refs S28-19

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 11:18:11 +01:00
k.renner 0ab63f46d4 Merge pull request 'feat(trmnl): restrict device HTTP ingress to the IoT network' (#1584) from feat/trmnl-device-cidr into main
Reviewed-on: #1584
2026-11-07 07:00:20 +00:00
claude-botandClaude Opus 5.5 cbc538ec7d feat(trmnl): restrict device HTTP ingress to the IoT network
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
allow-device-http admitted world on 2345/TCP. The TRMNL panel lives on
IoT (terminus log: GET /api/display from 10.2.30.244 every ~5 min) and
terminus-device is ETP=Local, so the client address reaches the pod.
Source is now net-iot; host/remote-node stay for probes.

Depends on #1583 (CiliumCIDRGroup net-iot).

Refs S28-19

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 15:54:41 +01:00
k.renner c541190e8e Merge pull request 'feat(network-policies): CiliumCIDRGroup per client network' (#1583) from feat/cidr-groups-per-vlan into main
Reviewed-on: #1583
2026-11-06 14:47:46 +00:00
claude-botandClaude Opus 5.5 6de87eba4c feat(network-policies): CiliumCIDRGroup per client network
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
One group per UDM client network (ULA + IPv4; ISP-delegated GUA
prefixes are not stable and are left out), so LoadBalancer CNPs can
restrict sources via fromCIDRSet.cidrGroupRef instead of repeating
subnets. Adds no policy; no traffic changes.

Refs S28-19

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 15:45:15 +01:00
k.renner 2beb9a4e14 Merge pull request 'docs(inventory): ntp_cluster has two members, edge-1 and edge-2' (#1582) from docs/ntp-cluster-edge2 into main
Reviewed-on: #1582
2026-11-06 13:51:17 +00:00
k.renner 767b3cdac4 Merge pull request 'docs(hairpin): list k8s VLANs 46/47/48 as deliberately absent' (#1581) from docs/hairpin-absent-vlans into main
ci/woodpecker/push/deploy-infrastructure Pipeline was successful
Reviewed-on: #1581
2026-11-06 13:50:58 +00:00
claude-botandClaude Opus 5.5 69f7075c7c docs(hairpin): list k8s VLANs 46/47/48 as deliberately absent
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
The nodes hold addresses on 46 (node0), 47 (ingress0) and 48 (pod0),
the same asymmetric-reply reason that excludes 40 and 49. (42) Ingress
no longer exists; its idx slot stays reserved.

Refs S28-13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 14:38:37 +01:00
5 changed files with 199 additions and 15 deletions
@@ -0,0 +1,150 @@
# Client networks as Cilium CIDR groups, referenced from CNPs via
# fromCIDRSet.cidrGroupRef. ULA + IPv4 only: the ISP-delegated GUA prefixes
# change and are not listed.
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-default
spec:
externalCIDRs:
- fd00::/64
- 192.168.8.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-management
spec:
externalCIDRs:
- fd02:10::/64
- 10.2.10.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-radius
spec:
externalCIDRs:
- fd02:11::/64
- 10.2.11.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-video
spec:
externalCIDRs:
- 10.2.20.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-iot
spec:
externalCIDRs:
- fd02:30::/64
- 10.2.30.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-server
spec:
externalCIDRs:
- fd02:40::/64
- fd40::/64
- 10.2.40.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-k8s-node
spec:
externalCIDRs:
- fd02:46::/64
- 10.2.46.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-k8s-ingress
spec:
externalCIDRs:
- fd02:47::/64
- 10.2.47.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-k8s-pod
spec:
externalCIDRs:
- fd02:48::/64
- 10.2.48.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-privat
spec:
externalCIDRs:
- fd02:50::/64
- 10.2.50.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-phone
spec:
externalCIDRs:
- 10.2.60.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-access
spec:
externalCIDRs:
- 10.2.70.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-vpn
spec:
externalCIDRs:
- 10.2.80.0/24
- 192.168.32.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-guest
spec:
externalCIDRs:
- 10.2.90.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-multi-transfer
spec:
externalCIDRs:
- 10.2.122.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-multi-lan
spec:
externalCIDRs:
- 10.2.123.0/24
---
apiVersion: cilium.io/v2
kind: CiliumCIDRGroup
metadata:
name: net-mutti
spec:
externalCIDRs:
- 10.2.200.0/24
@@ -1,6 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cidr-groups.yaml
- default-deny.yaml
- allow-ingress.yaml
- ingress-isolation.yaml
@@ -112,7 +112,7 @@ spec:
- { type: 136, family: IPv6 }
- { type: 143, family: IPv6 }
---
# Allow FTP access (from scanners on the LAN) to the ftp-scanner pod.
# FTP from the scanners (IoT and Privat) to the ftp-scanner pod.
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
@@ -123,8 +123,24 @@ spec:
matchLabels:
app.kubernetes.io/name: ftp-scanner
ingress:
- fromCIDRSet:
- cidrGroupRef: net-iot
- cidrGroupRef: net-privat
toPorts:
- ports:
- port: "21"
protocol: TCP
- port: "21100"
protocol: TCP
- port: "21101"
protocol: TCP
- port: "21102"
protocol: TCP
- port: "21103"
protocol: TCP
- port: "21104"
protocol: TCP
- fromEntities:
- world
- host
- remote-node
toPorts:
@@ -142,7 +158,7 @@ spec:
- port: "21104"
protocol: TCP
---
# Allow Syncthing peer-to-peer sync from the LAN/world.
# Allow Syncthing peer-to-peer sync from Privat and VPN.
# - 22000 TCP+QUIC: actual sync traffic between peers.
# - 21027 UDP: local-discovery broadcast packets from peers on the LAN.
# UI (8384) is intentionally NOT listed — authentik-gate-sync generates the
@@ -157,8 +173,18 @@ spec:
matchLabels:
app.kubernetes.io/name: syncthing
ingress:
- fromCIDRSet:
- cidrGroupRef: net-privat
- cidrGroupRef: net-vpn
toPorts:
- ports:
- port: "22000"
protocol: TCP
- port: "22000"
protocol: UDP
- port: "21027"
protocol: UDP
- fromEntities:
- world
- host
- remote-node
toPorts:
@@ -62,9 +62,10 @@ spec:
# CA, so this bypasses Traefik entirely and the namespace default-deny has
# to be opened for it — same shape as paperless's allow-ftp-scanner.
#
# Scoped to the terminus pods and port 2345 only. Requests still have to
# carry a known device MAC in the `ID` header plus its api_key; this rule
# opens the port, not the application.
# Scoped to the terminus pods, port 2345 and the IoT network (the panel's
# network; the LB is ETP=Local, so the client address reaches the pod).
# Requests still have to carry a known device MAC in the `ID` header plus
# its api_key; this rule opens the port, not the application.
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
@@ -75,8 +76,13 @@ spec:
matchLabels:
app.kubernetes.io/name: terminus
ingress:
- fromCIDRSet:
- cidrGroupRef: net-iot
toPorts:
- ports:
- port: "2345"
protocol: TCP
- fromEntities:
- world
- host
- remote-node
toPorts:
+8 -7
View File
@@ -68,13 +68,14 @@ locals {
# idx is a static per-network slot for rule_index derivation — never
# reuse a freed idx for a new network.
#
# Deliberately absent: (40) Server idx=4, (42) Ingress idx=5, and
# (49) k8s Ceph idx=6. The cluster nodes have interfaces on those VLANs,
# so a DNATed flow's reply would go directly over the shared L2 and
# bypass the UDM's conntrack (asymmetric, connection drops) — and
# clients there are the nodes themselves, whose DNS chain (CoreDNS ->
# k8s_gateway) already resolves the public names in-cluster. Their idx
# slots stay reserved.
# Deliberately absent: (40) Server idx=4, (49) k8s Ceph idx=6,
# (46) k8s Node, (47) k8s Ingress and (48) k8s Pod. The cluster nodes
# have interfaces on those VLANs (mgmt0, node0, ingress0, pod0), so a
# DNATed flow's reply would go directly over the shared L2 and bypass
# the UDM's conntrack (asymmetric, connection drops) — and clients there
# are the nodes themselves, whose DNS chain (CoreDNS -> k8s_gateway)
# already resolves the public names in-cluster. idx=5 stays reserved
# (its network, (42) Ingress, no longer exists).
hairpin_networks = {
"Default" = { id = "5d4fba77ce63ee614841d53d", idx = 0 }
"(10) Management" = { id = "600334abf9ee0c059da6be8f", idx = 1 }