Security review — finding #sec-2 (MED-HIGH). First of the one-PR-per-point series.
The home-assistantdefault-deny-ingress CNP grants fromEntities: worldnamespace-wide (endpointSelector: {}), so the untrusted IoT VLAN / any BGP-routed source can reach every pod in the namespace on every port — not just the broker. That includes the VSCode editor (:8080), zone-configurator (:42069), otbr web, whisper, matter-server, speech-to-phrase, etc. Only Mosquitto's own auth stands in front of most of them (and the others have no auth at all). I confirmed live that :1883 is reachable from my workstation.
Change
Replace the blanket rule with two endpoint+port-scoped policies (added as multi-doc in the same file; no kustomization change):
mosquitto-world-ingress: world → mosquitto :1883, :8883
home-assistant-world-ingress: world → home-assistant :8123
Why it's safe
Verified against live Services — the only LoadBalancers in the namespace are home-assistant-bgp (targetPort 8123) and mosquitto-iot (1883/8883); nothing else is world-fronted. External clients can only reach a pod via an LB/NodePort, so no non-LB pod needs world ingress. matter-server's IoT VIP arrives on a multus net1 interface that bypasses Cilium policy, so it's unaffected either way.
kubectl kustomize builds clean. Additive-safe: removes a blanket allow, adds scoped allows covering the same two real paths. Revert = restore the namespace-wide world rule.
Post-merge watch: after Flux reconciles, confirm IoT devices still reach HA:8123 and the broker (Hubble / a quick MQTT connect), and that the other ns pods are no longer world-reachable.
Next in the series: #2 ACL tightening (shellies off homeassistant/#, publishers → write-only), then #3 TLS cutover to :8883 (staged, edge-1 first).
**Security review — finding #sec-2 (MED-HIGH).** First of the one-PR-per-point series.
The `home-assistant` `default-deny-ingress` CNP grants `fromEntities: world` **namespace-wide** (`endpointSelector: {}`), so the untrusted IoT VLAN / any BGP-routed source can reach **every pod in the namespace on every port** — not just the broker. That includes the **VSCode editor (:8080)**, zone-configurator (:42069), otbr web, whisper, matter-server, speech-to-phrase, etc. Only Mosquitto's own auth stands in front of most of them (and the others have no auth at all). I confirmed live that :1883 is reachable from my workstation.
## Change
Replace the blanket rule with **two endpoint+port-scoped** policies (added as multi-doc in the same file; no kustomization change):
- `mosquitto-world-ingress`: world → mosquitto **:1883, :8883**
- `home-assistant-world-ingress`: world → home-assistant **:8123**
## Why it's safe
Verified against live Services — the **only** LoadBalancers in the namespace are `home-assistant-bgp` (targetPort 8123) and `mosquitto-iot` (1883/8883); nothing else is world-fronted. External clients can only reach a pod via an LB/NodePort, so no non-LB pod needs world ingress. `matter-server`'s IoT VIP arrives on a multus `net1` interface that bypasses Cilium policy, so it's unaffected either way.
`kubectl kustomize` builds clean. Additive-safe: removes a blanket allow, adds scoped allows covering the same two real paths. **Revert** = restore the namespace-wide `world` rule.
**Post-merge watch:** after Flux reconciles, confirm IoT devices still reach HA:8123 and the broker (Hubble / a quick MQTT connect), and that the other ns pods are no longer world-reachable.
Next in the series: **#2 ACL tightening** (shellies off `homeassistant/#`, publishers → write-only), then **#3 TLS cutover to :8883** (staged, edge-1 first).
The home-assistant default-deny-ingress CNP granted `fromEntities: world`
namespace-wide (endpointSelector:{}), so the untrusted IoT VLAN / any
BGP-routed source could reach EVERY pod in the namespace on every port —
vscode (:8080), zone-configurator (:42069), otbr, whisper, matter-server,
speech-to-phrase, etc. — when only two pods are actually fronted by
world-facing LoadBalancers.
Replace the blanket rule with two endpoint+port-scoped CiliumNetworkPolicies:
- world -> mosquitto :1883, :8883
- world -> home-assistant :8123
Verified against live Services: home-assistant-bgp (targetPort 8123) and
mosquitto-iot (1883/8883) are the only LoadBalancers in the namespace;
matter-server's IoT VIP rides a multus net1 interface that bypasses Cilium
policy entirely, so it is unaffected.
Security review finding #sec-2. Additive-safe (removes a blanket allow, adds
scoped allows covering the same two real ingress paths); revert = restore the
namespace-wide world rule.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Security review — finding #sec-2 (MED-HIGH). First of the one-PR-per-point series.
The
home-assistantdefault-deny-ingressCNP grantsfromEntities: worldnamespace-wide (endpointSelector: {}), so the untrusted IoT VLAN / any BGP-routed source can reach every pod in the namespace on every port — not just the broker. That includes the VSCode editor (:8080), zone-configurator (:42069), otbr web, whisper, matter-server, speech-to-phrase, etc. Only Mosquitto's own auth stands in front of most of them (and the others have no auth at all). I confirmed live that :1883 is reachable from my workstation.Change
Replace the blanket rule with two endpoint+port-scoped policies (added as multi-doc in the same file; no kustomization change):
mosquitto-world-ingress: world → mosquitto :1883, :8883home-assistant-world-ingress: world → home-assistant :8123Why it's safe
Verified against live Services — the only LoadBalancers in the namespace are
home-assistant-bgp(targetPort 8123) andmosquitto-iot(1883/8883); nothing else is world-fronted. External clients can only reach a pod via an LB/NodePort, so no non-LB pod needs world ingress.matter-server's IoT VIP arrives on a multusnet1interface that bypasses Cilium policy, so it's unaffected either way.kubectl kustomizebuilds clean. Additive-safe: removes a blanket allow, adds scoped allows covering the same two real paths. Revert = restore the namespace-wideworldrule.Post-merge watch: after Flux reconciles, confirm IoT devices still reach HA:8123 and the broker (Hubble / a quick MQTT connect), and that the other ns pods are no longer world-reachable.
Next in the series: #2 ACL tightening (shellies off
homeassistant/#, publishers → write-only), then #3 TLS cutover to :8883 (staged, edge-1 first).The home-assistant default-deny-ingress CNP granted `fromEntities: world` namespace-wide (endpointSelector:{}), so the untrusted IoT VLAN / any BGP-routed source could reach EVERY pod in the namespace on every port — vscode (:8080), zone-configurator (:42069), otbr, whisper, matter-server, speech-to-phrase, etc. — when only two pods are actually fronted by world-facing LoadBalancers. Replace the blanket rule with two endpoint+port-scoped CiliumNetworkPolicies: - world -> mosquitto :1883, :8883 - world -> home-assistant :8123 Verified against live Services: home-assistant-bgp (targetPort 8123) and mosquitto-iot (1883/8883) are the only LoadBalancers in the namespace; matter-server's IoT VIP rides a multus net1 interface that bypasses Cilium policy entirely, so it is unaffected. Security review finding #sec-2. Additive-safe (removes a blanket allow, adds scoped allows covering the same two real ingress paths); revert = restore the namespace-wide world rule. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>