Network Policies¶
HomeKube uses Kubernetes NetworkPolicy objects enforced by Cilium to implement zero-trust network segmentation. Each namespace has a default-deny baseline, with explicit allow rules for only the traffic that must flow.
Design Principles¶
- Default deny — every namespace starts with a
deny all ingresspolicy - Explicit allow — traffic is permitted only by named policies with specific selectors
- Namespace isolation — pods in one namespace cannot reach pods in another unless a policy says so
- In-cluster DNS always allowed — all namespaces allow egress to
kube-systemon UDP/TCP 53
Per-Namespace Summary¶
| Namespace | Default Deny | Allowed Ingress | Allowed Egress |
|---|---|---|---|
default |
✅ Ingress | Prometheus scrape (port 9090, 8080) | DNS only |
identity |
✅ Ingress | ingress-nginx → port 80; monitoring Prometheus → port 8080 | DNS only |
monitoring |
✅ Ingress | ingress-nginx → Grafana port 3000; Grafana → Keycloak (identity) | DNS only |
identity Namespace (Keycloak)¶
default-deny-ingress¶
Blocks all ingress by default. No pod in identity is reachable unless an explicit allow policy matches.
allow-ingress-nginx¶
Permits ingress-nginx to forward HTTP traffic to Keycloak on port 80 (the ingress controller terminates TLS externally).
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- port: 80
allow-prometheus-scrape¶
Permits Prometheus (running in monitoring) to scrape Keycloak metrics on port 8080 (if a metrics endpoint is exposed).
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
podSelector:
matchLabels:
app.kubernetes.io/name: prometheus
ports:
- port: 8080
allow-dns-egress¶
All pods in identity may send DNS queries to kube-system (CoreDNS) on UDP/TCP 53. Required for in-cluster service discovery.
monitoring Namespace (Grafana + Prometheus)¶
default-deny-ingress¶
Blocks all ingress to monitoring pods by default.
allow-ingress-nginx¶
Permits ingress-nginx to forward HTTP to Grafana on port 3000.
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- port: 3000
allow-grafana-to-keycloak¶
Permits Grafana to reach Keycloak's HTTP service in identity on port 80. This is the egress side of the OIDC token exchange (token_url and api_url use keycloak.identity.svc.cluster.local).
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: identity
ports:
- port: 80
allow-dns-egress¶
All pods in monitoring may send DNS queries to CoreDNS.
default Namespace¶
Covers any ad-hoc pods. Default deny ingress is in place. DNS egress and Prometheus scrape are permitted so that any workload deployed here can be observed.
Files¶
| File | Namespace |
|---|---|
infrastructure/network-policies/default-deny-ingress.yaml |
default |
infrastructure/network-policies/allow-dns-egress.yaml |
default |
infrastructure/network-policies/allow-monitoring-scrape.yaml |
default |
identity/network-policies.yaml |
identity |
observability/network-policies.yaml |
monitoring |
Verifying with Hubble¶
# Open the Hubble flow visualiser
cilium hubble ui
# CLI: watch live flows in the identity namespace
hubble observe --namespace identity --follow
# CLI: check if a specific flow is allowed or dropped
hubble observe --namespace monitoring --to-namespace identity --verdict FORWARDED
hubble observe --namespace monitoring --to-namespace identity --verdict DROPPED
A DROPPED verdict from monitoring → identity on port 80 means the allow-grafana-to-keycloak egress policy is missing or not applied yet. Wait for Flux to reconcile or run: