Networking Architecture¶
The cluster's networking is built on several layers that work together to route traffic from the internet to your apps, and between apps themselves.
Network Stack Overview¶
graph TB
Internet[Internet] --> CF[Cloudflare]
CF --> Tunnel[cloudflared tunnel]
Tunnel --> EnvoyExt[envoy-external Gateway]
EnvoyExt --> Service[Kubernetes Service]
Service --> Cilium[Cilium Load Balancer]
Cilium --> Pods[Application Pods]
LAN[Home Network] --> UnifiDNS[unifi-dns<br/>External-DNS]
UnifiDNS --> UniFi[UniFi Controller<br/>DNS Records]
UniFi --> ServiceLB[Service LoadBalancer IP]
ServiceLB --> Cilium Core Components¶
Cilium: CNI & Load Balancing¶
Cilium is the Container Network Interface (CNI) that connects pods. It replaces kube-proxy with eBPF-based networking for better performance.
Key features configured in kubernetes/apps/kube-system/cilium/app/helmrelease.yaml:
- Native routing: Pods communicate directly without overlay networking
- L2 announcements: Broadcasts LoadBalancer IPs via ARP on your home LAN
- kube-proxy replacement: Uses eBPF instead of iptables (faster, more efficient)
- Maglev hashing: Consistent load balancing across pods
How Cilium LoadBalancer Works
When you create a Service with type: LoadBalancer:
- Cilium allocates an IP from
CiliumLoadBalancerIPPool(range: part of 192.168.5.0/24) CiliumL2AnnouncementPolicybroadcasts the IP via ARP- Devices on your LAN see the IP as reachable on the network
- Traffic hits the IP → Cilium routes it to healthy pods
No external load balancer needed—Cilium handles it all.
DNS Resolution¶
CoreDNS¶
Internal cluster DNS at 10.43.0.10. Configured in kubernetes/apps/kube-system/coredns/.
- Resolves
*.cluster.local(internal service discovery) - Falls through to upstream DNS for external queries
- Pods use this automatically via
kubeletconfiguration
Service DNS Pattern
Services are automatically resolvable:
Examples: - postgresql.database.svc.cluster.local - PostgreSQL database - dragonfly-cluster.database.svc.cluster.local - Redis cache - authentik.default.svc.cluster.local - Authentik SSO
unifi-dns (external-dns with UniFi provider)¶
Syncs DNS records from Kubernetes to your UniFi Controller. Configured in kubernetes/apps/network/unifi-dns/.
- Watches HTTPRoute and Service resources
- Automatically creates/updates/deletes A records in UniFi
- Domain filter:
${SECRET_DOMAIN}(your domain) - TXT record prefix:
k8s.main.for ownership tracking
When you create an HTTPRoute for sonarr.yourdomain.com, external-dns automatically creates the DNS record in UniFi pointing to the Service's LoadBalancer IP.
external-dns (Cloudflare provider)¶
Syncs HTTPRoutes to Cloudflare DNS for external access. Configured in kubernetes/apps/network/external-dns/.
- Watches
envoy-externalGateway HTTPRoutes - Creates DNS records in Cloudflare with
--cloudflare-proxied(orange cloud) - Routes marked for external access get synced; internal-only routes are ignored
Envoy Gateway: Ingress Controller¶
Envoy Gateway routes HTTP/HTTPS traffic to services. Two gateways:
envoy-external: Internet-facing (receives traffic from Cloudflare tunnel)envoy-internal: LAN-only (for internal services)
Configured in kubernetes/apps/network/envoy-gateway/.
HTTPRoutes define routing rules:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: sonarr
spec:
parentRefs:
- name: envoy-external # Use external gateway
hostnames:
- sonarr.${SECRET_DOMAIN}
rules:
- backendRefs:
- name: sonarr
port: 80
This routes sonarr.yourdomain.com → sonarr Service → Sonarr pods.
SecurityPolicy: Forward Auth
Apps protected by Authentik use a SecurityPolicy:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
name: sonarr
spec:
extAuth:
http:
backendRefs:
- name: authentik-outpost-external
port: 9000
path: /outpost.goauthentik.io/auth/envoy
targetRefs:
- kind: HTTPRoute
name: sonarr
Before forwarding traffic, Envoy calls Authentik to validate the session. If unauthorized, Envoy redirects to the Authentik login page.
See the ext-auth component for details.
Cloudflared Tunnel¶
Cloudflared establishes a secure tunnel from Cloudflare to your cluster. Configured in kubernetes/apps/network/cloudflared/.
- Runs as a Deployment in the
networknamespace - QUIC tunnel to Cloudflare (encrypted, no inbound firewall rules needed)
- Routes
*.${SECRET_DOMAIN}→envoy-external.network.svc.cluster.local:443
Traffic flow:
- User visits
sonarr.yourdomain.com - Cloudflare DNS resolves to Cloudflare edge
- Cloudflare edge forwards via tunnel to
cloudflaredpod cloudflaredforwards toenvoy-externalgateway- Envoy routes based on HTTPRoute rules
No port forwarding, no exposing your home IP. Everything goes through Cloudflare's secure tunnel.
Traffic Flows¶
External Access (Internet → App)¶
graph LR
A[User Browser] --> B[Cloudflare Edge]
B --> C[Cloudflared Tunnel]
C --> D[Envoy Gateway<br/>envoy-external]
D --> E[Kubernetes Service]
E --> F[Pod] - DNS resolves
sonarr.yourdomain.comto Cloudflare - Cloudflare tunnels request to
cloudflaredpod cloudflaredforwards toenvoy-external:443- Envoy Gateway checks HTTPRoute, applies SecurityPolicy (Authentik auth)
- Envoy forwards to
sonarrService - Cilium load balances to healthy
sonarrpods
Internal Access (LAN → App)¶
graph LR
A[LAN Device] --> B[UniFi DNS]
B --> C[Service LoadBalancer IP]
C --> D[Cilium]
D --> E[Pod] - DNS query to UniFi controller resolves
sonarr.yourdomain.com - UniFi returns Service LoadBalancer IP (managed by external-dns)
- Traffic hits LoadBalancer IP on the cluster network
- Cilium routes to healthy pods
Inter-Pod Communication¶
Pods talk directly via cluster DNS:
Cilium routes traffic using native routing over bond0 (no overlay/tunneling). Pods get IPs from 10.42.0.0/16 (defined in talos/machineconfig.yaml.j2).
Certificate Management¶
TLS certificates are handled by cert-manager. Certificates live in kubernetes/apps/network/certificates/.
How it Works¶
- Envoy Gateway HTTPRoutes reference
certificateRef(a Secret) - cert-manager watches Certificate CRDs
- cert-manager requests certificates from Let's Encrypt via DNS-01 challenge (Cloudflare)
- Certificates are automatically renewed before expiration
No manual certificate management. Just define the Certificate CRD and cert-manager does the rest.
Cross-Namespace Access¶
By default, Kubernetes blocks cross-namespace references. To allow it, use a ReferenceGrant.
Example from kubernetes/apps/default/authentik/app/resources/referencegrant.yaml:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: authentik-outpost
namespace: default
spec:
from:
- group: gateway.envoyproxy.io
kind: SecurityPolicy
namespace: network
to:
- group: ""
kind: Service
This allows SecurityPolicies in the network namespace to reference Authentik's outpost Service in default.
Network Policies¶
Cilium enforces NetworkPolicies (Kubernetes standard) and CiliumNetworkPolicies (Cilium-specific). These control which pods can talk to each other.
By default, all traffic is allowed. To restrict, create NetworkPolicy CRDs.
Multus VPN for Media Apps¶
Select media applications (qBittorrent, Prowlarr) use Multus CNI to attach to a secondary VPN network interface while maintaining cluster connectivity.
How it works:
- Pod has two network interfaces:
- Primary (eth0): Cilium-managed cluster network (for internal services)
- Secondary (net1): VPN network (192.168.99.0/24) for external traffic
- VPN network routes specific traffic through UniFi VPN gateway
- Apps can simultaneously access cluster services and route downloads through VPN
Configuration: - NetworkAttachmentDefinition creates secondary interface - VLAN 99 tagged on bond0 for VPN network - Apps using VPN: qBittorrent, Prowlarr
Benefits:
- Download traffic isolated to VPN without affecting internal cluster communication
- No need for sidecar VPN containers
- Native Kubernetes networking with secondary interfaces
See VPN Networking Guide for detailed configuration.
Observability¶
Network metrics are collected by:
- Unpoller: Scrapes UniFi Controller for network stats (bandwidth, clients, etc.)
- Cilium Hubble: eBPF-based flow observability (see traffic between pods)
- Prometheus: Stores time-series metrics from both
See the Observability Guide for details.
Common Networking Tasks¶
Exposing a New App Externally¶
-
Create an HTTPRoute in the app's
resources/: -
Include
ext-auth-externalcomponent inks.yamlif you want SSO protection - Push to Git; Flux applies it
- external-dns creates DNS records in Cloudflare automatically
Exposing a New App Internally (LAN Only)¶
Same process, but use envoy-internal gateway and don't include ext-auth component.
Debugging Network Issues¶
# Check Cilium status
cilium status
# View Cilium connectivity
cilium connectivity test
# Check LoadBalancer IPs
kubectl get svc -A | grep LoadBalancer
# View HTTPRoutes
kubectl get httproute -A
# Check Envoy Gateway status
kubectl get gateway -n network
# Test DNS resolution from a pod
kubectl run -it --rm debug --image=nicolaka/netshoot --restart=Never -- nslookup postgresql.database.svc.cluster.local
Next Steps¶
- Storage Guide: Persistent volumes and backups
- Operations Guide: Day-to-day maintenance