Files
home-network-k3s-impl/platform/cloudflared/README.md
T
jakman85andClaude Opus 5.5 8fe8d5df8a
gate / gate (pull_request) Successful in 1m14s
gate / conformance (pull_request) Skipped
feat(dns): PiHole answers an explicit LAN name list, not a zone wildcard
Public names are proxied CNAMEs to the Cloudflare Tunnel since PR #156 and
work from the LAN, so they should resolve publicly there too. Replace the
address=/${BASE_DOMAIN}/ wildcard with explicit entries: the LAN-only names
(derived from every controller:none HTTPRoute), gitea/nextcloud (off
Cloudflare's 100 MB / 100 s limits), keycloak/auth, and the L4 VIPs.

Add L0 check pihole-lan-names, mutation-tested. Correct docs that still
described public names as CNAME to wan. and the cloudflared entrypoint comment.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-08 19:51:49 -06:00

25 lines
2.0 KiB
Markdown

# platform/cloudflared
**Cloudflare Tunnel connector**: inbound HTTPS from the Cloudflare edge to the shared Gateway,
outbound-only from the cluster (no router port forward, no hairpin, no split-DNS dependency).
- **Flux tier:** `clusters/base/cloudflared.yaml` — its own Kustomization, `dependsOn: [platform-config]`,
`wait: false`, and nothing depends on it. A missing or invalid credential can affect only the tunnel.
- **Runbook (enrolment, canary, alerts, rollback):** `runbooks/cloudflare-tunnel.md`
- **Design record:** `decisions/2026-11-08-cloudflare-tunnel.md`
- **Guard:** `conformance/tests/l0-static/cloudflared-ingress-rules`
| File | What it is |
|---|---|
| `config.yaml` | The locally-managed tunnel: literal tunnel UUID + ingress rules. LAN/VPN-only hosts → 404, apex + wildcard → `https://cilium-gateway-shared.gateway.svc.cluster.local:443` with `matchSNItoHost`, catch-all 404. Never the Kubernetes API. |
| `cloudflared-credentials.sops.yaml` | SOPS-encrypted tunnel credentials JSON. Ships with `REPLACE-ME`; the operator fills it. |
| `deployment.yaml` | 2 replicas, hard spread across nodes, non-root, read-only root fs, pinned digest; PDB `minAvailable: 1`. |
| `networkpolicy.yaml` | default-deny (single owner — not an app namespace) + Prometheus scrape allow + egress CNP: world 7844 tcp/udp and 443, the Gateway (`ingress` entity), and Gateway backends by `gateway-access=shared` minus the LAN-only namespaces. |
| `servicemonitor.yaml`, `alerts.yaml` | Headless metrics Service + ServiceMonitor scraping :2000, and the two alerts, both written to fire (not go quiet) when their series vanish. |
Cloudflare sends a hostname through the tunnel only when its DNS record is a proxied CNAME to
`<UUID>.cfargotunnel.com`; nothing in this directory creates one. Those records are published by
external-dns from the shared Gateway's target annotation (Phase 2, PR #156; see
`platform/externaldns/README.md`). LAN resolution: `catalog/pihole.yaml` (explicit names only since
2026-11-09), so public names reach Cloudflare from the LAN too.