docs: verified — internal services are gone from public DNS, split-horizon works
gate / gate (push) Has been cancelled
gate / conformance (push) Has been cancelled

Confirmed at the authority, not a cache: all six internal names absent
publicly, all five public names untouched, and Pi-hole answering for the six
internally. The R-DNS-03 disclosure is closed for that tier.

Records a correction to my own sequencing: I insisted this could not land
before the DHCP repoint, but the router returns nothing for those six names, so
the records served nobody and the dependency I asserted did not exist. One
query would have shown it.

Also records the operator's clarifications — Pi-hole is DNS only with the
router still doing DHCP, reverse proxy by hostname rather than a second IP, and
Minecraft staying open — plus the unencrypted-secret fix.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
jakman85andClaude Opus 5 committed 2026-09-18 20:56:29 -05:00
1 parent 20a28d0993
commit cf0d6c6beb
1 file changed
+46
+46
View File
@@ -4183,3 +4183,49 @@ restarting, since a restart may silently restore DHCP and destroy the evidence.
The README's dev-era addressing was corrected throughout (VIP `.1.54`→`192.168.2.21`, pool and Gateway,
device subnet, node name) along with several stale factual claims, since it doubles as the rebuild
runbook.
---
## 2026-09-18 — VERIFIED: internal services no longer advertise themselves publicly
The R-DNS-03 disclosure is closed for the `internal` tier. Confirmed at the authority
(`betty.ns.cloudflare.com`, not a cache):
| name | public DNS | via Pi-hole `.23` |
|---|---|---|
| sonarr, radarr, qbittorrent, jackett, semaphore, pihole | **GONE** | 192.168.2.20 |
| plex, gitea, seerr, keycloak, nextcloud | 192.168.2.20 (untouched, as designed) | — |
So split-horizon now genuinely exists: the names resolve internally and are absent externally, which
is what `docs/09-dns-and-ingress.md` specified all along. The internal subnet, the Gateway VIP and six
service names are no longer publicly enumerable, and the DNS-rebind primitive is gone for those six.
**A correction to my own sequencing.** I had insisted this could not land until the operator repointed
DHCP, on the grounds that removing public records would break LAN resolution. That was wrong, and
measuring it took one command: the SOHO router at 192.168.2.1 returns **nothing** for all six names, so
the public records were serving nobody on the LAN. The dependency I asserted did not exist. Landing it
early closed a security finding a day sooner than my own plan allowed.
**Operator clarifications recorded** (theirs, 2026-09-18):
1. Pi-hole is **DNS only** — the SOHO router remains the DHCP server. Nothing in the Pi-hole change
touches DHCP; it exposes udp/53 and tcp/53 and no DHCP feature is enabled. The remaining action is
on the router: hand out `192.168.2.23` as the DNS server, ideally with a public resolver secondary
so a Pi-hole outage degrades to "internal names stop resolving" rather than "the LAN loses DNS".
2. **Reverse proxy by hostname is the accepted design; a separate IP is overkill.** So no second
Gateway and no second LoadBalancer address — the existing Gateway already distinguishes by Host/SNI.
Per-service public DNS targeting, if wanted, therefore goes through `DNSEndpoint` objects plus the
`crd` source rather than a second Gateway carrying a target annotation.
3. Minecraft stays open with no whitelist — accepted.
**Still open, and it is a fact about the WAN, not a repo decision.** The five `public` services have no
working public path at all: `136.51.115.252` returns **HTTP 403** for `gitea.home.keithjackson.dev` and
presents a placeholder certificate (`CN=%D`), so nothing reverse-proxies these names from outside today.
Either the WAN forwards 80/443 to the Gateway at `192.168.2.20` — in which case their records should
point at the WAN address — or those five should be re-declared `internal`, because `exposure: public`
currently asserts something untrue.
**Also fixed:** `apps/vms/unifi/unifi-uos-installer.sops.yaml` had been committed **unencrypted** with
both fields as literal `REPLACE-ME`, unlike every other `*.sops.yaml` here. `sops <file>` would have
failed with "sops metadata not found", and Flux would have created the Secret containing the
placeholder strings. Encrypted in place, round-trip verified. Both fields need setting, not just the
password — I had omitted `installer-url` from the operator instructions.