All checks were successful
Update README with ADR Index / update-readme (push) Successful in 6s
New ADRs: - 0043: Cilium CNI and Network Fabric - 0044: DNS and External Access Architecture - 0045: TLS Certificate Strategy (cert-manager) - 0046: Companions Frontend Architecture - 0047: MLflow Experiment Tracking and Model Registry - 0048: Entertainment and Media Stack - 0049: Self-Hosted Productivity Suite - 0050: Argo Rollouts Progressive Delivery - 0051: KEDA Event-Driven Autoscaling - 0052: Cluster Utilities (Spegel, Descheduler, Reloader, CSI-NFS) - 0053: Vaultwarden Password Management README updated with table entries and badge count (53 total).
130 lines
7.2 KiB
Markdown
130 lines
7.2 KiB
Markdown
# DNS and External Access Architecture
|
|
|
|
* Status: accepted
|
|
* Date: 2026-02-09
|
|
* Deciders: Billy
|
|
* Technical Story: Design a multi-layer DNS and ingress architecture providing both public and private access to cluster services
|
|
|
|
## Context and Problem Statement
|
|
|
|
A homelab behind a residential network needs to expose some services publicly (productivity apps, status pages) while keeping others private (admin UIs, AI inference). DNS resolution must work correctly for both external users and LAN clients, avoiding hairpin NAT issues.
|
|
|
|
How do we provide split-horizon DNS, secure external access, and automated DNS management across public and private domains?
|
|
|
|
## Decision Drivers
|
|
|
|
* No public IP dependency — residential NAT, dynamic IP
|
|
* Split-horizon DNS — same domain resolves differently inside vs outside
|
|
* Automated DNS record management from Kubernetes resources
|
|
* External access without opening router ports
|
|
* LAN clients should resolve directly to cluster IPs (no hairpin NAT)
|
|
* Separate gateways for public vs internal services
|
|
|
|
## Decision Outcome
|
|
|
|
A four-component DNS architecture with Cloudflare Tunnel for external access:
|
|
|
|
1. **Cloudflare Tunnel** — encrypted tunnel for external traffic (no open ports)
|
|
2. **Cloudflare DNS (external-dns)** — syncs public DNS records from HTTPRoutes
|
|
3. **k8s-gateway** — internal DNS server for split-horizon resolution
|
|
4. **UniFi DNS (external-dns)** — syncs internal DNS records to home network DNS
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ EXTERNAL ACCESS │
|
|
│ │
|
|
│ Internet → Cloudflare CDN/Proxy │
|
|
│ ↓ │
|
|
│ Cloudflare Tunnel (QUIC + post-quantum encryption) │
|
|
│ ↓ │
|
|
│ envoy-external (192.168.100.210) │
|
|
│ *.daviestechlabs.io (Let's Encrypt wildcard) │
|
|
│ Services: Affine, Immich, Nextcloud, ntfy, Gatus, etc. │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ INTERNAL ACCESS │
|
|
│ │
|
|
│ LAN client → UniFi DNS (home router) │
|
|
│ ↓ (*.lab.daviestechlabs.io → k8s-gateway VIP) │
|
|
│ k8s-gateway (192.168.100.200, port 53) │
|
|
│ ↓ (resolves from HTTPRoutes/Services) │
|
|
│ envoy-internal (192.168.100.201) │
|
|
│ *.lab.daviestechlabs.io (self-signed + LE certs) │
|
|
│ Services: Grafana, Prometheus, MLflow, Companions, etc. │
|
|
│ OIDC auth via Authentik │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ DNS AUTOMATION │
|
|
│ │
|
|
│ HTTPRoute created → external-dns (Cloudflare) syncs public records │
|
|
│ → external-dns (UniFi) syncs LAN records │
|
|
│ │
|
|
│ Split-horizon: external client resolves to Cloudflare proxy IP │
|
|
│ LAN client resolves directly to cluster VIP │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Component Details
|
|
|
|
### Cloudflare Tunnel
|
|
|
|
| | |
|
|
|---|---|
|
|
| **Image** | `cloudflare/cloudflared:2026.1.2` |
|
|
| **Transport** | QUIC with post-quantum encryption |
|
|
|
|
Provides secure ingress without opening any router ports. All external traffic enters via Cloudflare's network and is tunneled to `envoy-external` over an encrypted QUIC connection.
|
|
|
|
- Ingress: `*.daviestechlabs.io` → `https://envoy-external.network.svc.cluster.local:443`
|
|
- HTTP/2 origin, TLS verified against origin server name
|
|
- DNSEndpoint CNAME: `external.daviestechlabs.io` → `<tunnel-id>.cfargotunnel.com`
|
|
- Resources: 10m CPU, 256Mi memory limit
|
|
- Security: non-root (UID 65534), read-only rootfs, capabilities dropped
|
|
|
|
### Cloudflare DNS (external-dns)
|
|
|
|
| | |
|
|
|---|---|
|
|
| **Chart** | `external-dns` v1.20.0 |
|
|
| **Provider** | Cloudflare |
|
|
|
|
Watches `gateway-httproute` and `DNSEndpoint` CRDs, syncs to Cloudflare DNS. Records are Cloudflare-proxied (orange cloud) for DDoS protection. TXT prefix `k8s.` for ownership tracking. Sync policy: full lifecycle management.
|
|
|
|
### k8s-gateway (Internal DNS)
|
|
|
|
| | |
|
|
|---|---|
|
|
| **Chart** | `k8s-gateway` v3.4.1 |
|
|
| **VIP** | `192.168.100.200` (port 53) |
|
|
|
|
CoreDNS-based DNS server that resolves cluster service domains by watching HTTPRoute and Service resources. Provides split-horizon: LAN clients query this server (via UniFi DNS forwarding) and get direct cluster IPs instead of Cloudflare proxy IPs.
|
|
|
|
### UniFi DNS (external-dns)
|
|
|
|
| | |
|
|
|---|---|
|
|
| **Chart** | `external-dns` v1.20.0 |
|
|
| **Webhook** | `ghcr.io/kashalls/external-dns-unifi-webhook:v0.8.1` |
|
|
|
|
Syncs `*.lab.daviestechlabs.io` records to the UniFi controller's DNS server at `192.168.100.254`. This means LAN devices automatically resolve internal services without manual DNS entries. API key from Vault via ExternalSecret.
|
|
|
|
## Domain Strategy
|
|
|
|
| Domain | Gateway | Access | DNS Provider | TLS |
|
|
|--------|---------|--------|-------------|-----|
|
|
| `*.daviestechlabs.io` | envoy-external | Public (Cloudflare Tunnel) | Cloudflare | Let's Encrypt wildcard |
|
|
| `*.lab.daviestechlabs.io` | envoy-internal | LAN only | UniFi DNS | Self-signed + LE |
|
|
|
|
## Links
|
|
|
|
* Related to [ADR-0010](0010-use-envoy-gateway.md) (Envoy Gateway configuration)
|
|
* Related to [ADR-0043](0043-cilium-cni-network-fabric.md) (L2 VIP assignment)
|
|
* Related to [ADR-0045](0045-tls-certificate-strategy.md) (certificate issuance)
|
|
* Related to [ADR-0028](0028-authentik-sso-strategy.md) (OIDC on internal gateway)
|
|
* [Cloudflare Tunnel Docs](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/)
|
|
* [k8s-gateway](https://github.com/k8s-gateway/k8s-gateway)
|