diff --git a/README.md b/README.md index 9b95e47..4388011 100644 --- a/README.md +++ b/README.md @@ -92,8 +92,8 @@ documents for different readers. the Makefile, the scripts, the workflow and the runbooks resolves its image from `compose.yaml` too, so an image that is not pinned there cannot be run at all. -- **Documented decisions and runbooks.** 41 ADRs covering what was chosen - and what was rejected — including the costs accepted knowingly; 26 +- **Documented decisions and runbooks.** 42 ADRs covering what was chosen + and what was rejected — including the costs accepted knowingly; 27 runbooks for the operations that are easy to get wrong at 1am, one of which is the handover page a successor reads first. diff --git a/docs/adr/0008-place-services-by-data-trust.md b/docs/adr/0008-place-services-by-data-trust.md index 25cc60c..2523004 100644 --- a/docs/adr/0008-place-services-by-data-trust.md +++ b/docs/adr/0008-place-services-by-data-trust.md @@ -121,7 +121,7 @@ earned its place. This leaves the "no MFA on the internal services" gap in access*. When that premise changes, so does the decision. > *The second half of that premise changed in 2026-09. - > [ADR-0041](0041-terminate-the-remote-path-on-the-lab-and-route-it.md) opens + > [ADR-0042](0042-terminate-the-remote-path-on-the-lab-and-route-it.md) opens > a WireGuard path that terminates on the lab and reaches the lab only, so > "no remote access" becomes "no remote access to the house". It fires > [ADR-0022](0022-expire-the-sso-deferral-when-the-tier-holds-real-data.md)'s diff --git a/docs/adr/0011-keep-the-wiki-internal.md b/docs/adr/0011-keep-the-wiki-internal.md index 2e9076f..6c8b9cb 100644 --- a/docs/adr/0011-keep-the-wiki-internal.md +++ b/docs/adr/0011-keep-the-wiki-internal.md @@ -60,12 +60,12 @@ machinery for publishing a service exists and reusing it would be cheap. > entry"* is the live state of the firewall, not only an intention. > > **Update · 2026-09.** The measurement above is now dated. -> [ADR-0041](0041-terminate-the-remote-path-on-the-lab-and-route-it.md) decides +> [ADR-0042](0042-terminate-the-remote-path-on-the-lab-and-route-it.md) decides > a WireGuard endpoint on the lab jumpbox, and building it makes `morpheus` > carry exactly one `rdr` and one inbound WAN pass. **The decision below is > unchanged and so is its reasoning**: the wiki is still not published, still > has no external hostname and still sits behind no reverse proxy, and reaching -> it still means being inside the house — or, from ADR-0041 onward, on a tunnel +> it still means being inside the house — or, from ADR-0042 onward, on a tunnel > that terminates on VLAN 30 and cannot route to `oracle` at all. What expires > is the estate-wide claim that nothing is reachable from outside, not this > ADR's answer for this service. diff --git a/docs/adr/0014-put-ifrit-on-imaginationlan-and-give-the-targets-no-route.md b/docs/adr/0014-put-ifrit-on-imaginationlan-and-give-the-targets-no-route.md index 428843b..5899912 100644 --- a/docs/adr/0014-put-ifrit-on-imaginationlan-and-give-the-targets-no-route.md +++ b/docs/adr/0014-put-ifrit-on-imaginationlan-and-give-the-targets-no-route.md @@ -16,10 +16,10 @@ > > **The last Consequence below names remote access into VLAN 30 as something > that reopens this decision. It has been wanted, and -> [ADR-0041](0041-terminate-the-remote-path-on-the-lab-and-route-it.md), +> [ADR-0042](0042-terminate-the-remote-path-on-the-lab-and-route-it.md), > 2026-09, is the ADR that answers it.** What moved is the premise, not the > decision: `ifrit` stays on ImaginationLAN, its targets still have no route, -> and every constraint below still holds. What ADR-0041 adds to this segment is +> and every constraint below still holds. What ADR-0042 adds to this segment is > a second source subnet — `172.31.0.0/24`, the WireGuard peers — which is why > it also widens the tripwire this ADR decided. `172.30.` is the range; > `172.31.` is the tunnel. Nothing here is amended. diff --git a/docs/adr/0022-expire-the-sso-deferral-when-the-tier-holds-real-data.md b/docs/adr/0022-expire-the-sso-deferral-when-the-tier-holds-real-data.md index 8f97f94..72211cc 100644 --- a/docs/adr/0022-expire-the-sso-deferral-when-the-tier-holds-real-data.md +++ b/docs/adr/0022-expire-the-sso-deferral-when-the-tier-holds-real-data.md @@ -5,7 +5,7 @@ > [!NOTE] > **Trigger 2 fired in 2026-09, and the deferral was re-accepted rather than > ended.** -> [ADR-0041](0041-terminate-the-remote-path-on-the-lab-and-route-it.md) opens a +> [ADR-0042](0042-terminate-the-remote-path-on-the-lab-and-route-it.md) opens a > WireGuard path terminating on the lab, which takes ADR-0008's *no external > exposure* premise — the thing this trigger makes testable. It is recorded as > fired there rather than argued around, and re-accepted on the grounds this diff --git a/docs/adr/0041-terminate-the-remote-path-on-the-lab-and-route-it.md b/docs/adr/0042-terminate-the-remote-path-on-the-lab-and-route-it.md similarity index 99% rename from docs/adr/0041-terminate-the-remote-path-on-the-lab-and-route-it.md rename to docs/adr/0042-terminate-the-remote-path-on-the-lab-and-route-it.md index 19e106b..096a1e0 100644 --- a/docs/adr/0041-terminate-the-remote-path-on-the-lab-and-route-it.md +++ b/docs/adr/0042-terminate-the-remote-path-on-the-lab-and-route-it.md @@ -1,4 +1,4 @@ -# ADR-0041: Terminate the remote path on the lab, and route it +# ADR-0042: Terminate the remote path on the lab, and route it **Status:** Accepted · 2026-09 diff --git a/docs/network.md b/docs/network.md index 26d371f..0f40369 100644 --- a/docs/network.md +++ b/docs/network.md @@ -85,7 +85,7 @@ truth for what a box actually does. - The gateway runs in bridge mode; its own Wi-Fi radio stays operational but is unused. All wireless is handled by eero units on tagged VLANs. - **One inbound pass, and one only** — the WireGuard endpoint decided by - [ADR-0041](adr/0041-terminate-the-remote-path-on-the-lab-and-route-it.md): a + [ADR-0042](adr/0042-terminate-the-remote-path-on-the-lab-and-route-it.md): a UDP `rdr` to the lab jumpbox, terminating on ImaginationLAN and reaching the lab only. The endpoint hostname and the listen port are withheld with the WAN address ([`security.md`](security.md#what-this-repository-deliberately-does-not-publish)). @@ -303,8 +303,8 @@ Televisions and consoles. Internet only. not exist yet and neither does `stacks/media`; what exists is a host on its address. **It does not change the *Reaches* column**, and that is the point ADR-0016 made in advance: nothing on this segment initiates anywhere, and the - four rules created that day all let a more trusted segment reach **in**. - That is the direction this row records, and it is the one that is unchanged. + rules created that day all let a more trusted segment reach **in**. That is + the direction this row records, and it is the one that is unchanged. - **Inbound is no longer nothing, and that is deliberate.** Since 2026-09-16 Hicks reaches `10.0.40.30` on `443` and `8096`, and `10.0.99.20` reaches it on `9100` and `22` — four host-scoped, port-scoped passes above *Block access @@ -393,7 +393,7 @@ Where things get broken on purpose. - **The WireGuard peers live on `172.31.0.0/24`, and it is routed rather than translated** - ([ADR-0041](adr/0041-terminate-the-remote-path-on-the-lab-and-route-it.md)). + ([ADR-0042](adr/0042-terminate-the-remote-path-on-the-lab-and-route-it.md)). `morpheus` carries one static route for it toward the jumpbox, so a peer's own address is what arrives on this interface and what a firewall log carries — which is what lets a rule name a peer and an alert say which one. diff --git a/docs/observability.md b/docs/observability.md index 884eeb7..630277b 100644 --- a/docs/observability.md +++ b/docs/observability.md @@ -297,7 +297,7 @@ packet anyway, so nothing is weakened by it being there. The terminal three feed a destination. **That alert reads two source subnets, not one.** -[ADR-0041](adr/0041-terminate-the-remote-path-on-the-lab-and-route-it.md) routes +[ADR-0042](adr/0042-terminate-the-remote-path-on-the-lab-and-route-it.md) routes the WireGuard peers on `172.31.0.0/24` rather than masquerading them, so a peer's own address reaches `igc0.30` and appears in `filterlog`. That is the point of routing rather than translating — a peer is nameable in a rule and in diff --git a/docs/roadmap.md b/docs/roadmap.md index dbd89d1..90c8307 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -1073,12 +1073,12 @@ them name the condition that would change the answer. the estate, and it stores connection credentials to do it. The estate already has a KVM in U6 for physical console access. Declined. **The remote-access question it gestured at is answered differently** by - [ADR-0041](adr/0041-terminate-the-remote-path-on-the-lab-and-route-it.md): + [ADR-0042](adr/0042-terminate-the-remote-path-on-the-lab-and-route-it.md): WireGuard to the lab jumpbox, terminating on ImaginationLAN and reaching the lab only. That is not a softening of this decline — it stores no connection credentials at a gateway, it never touches Winterfell, and the boundary is the firewall's rather than an application's. Guacamole's objection was about - the management segment, and nothing about ADR-0041 goes near it. + the management segment, and nothing about ADR-0042 goes near it. - **Frigate** — locally-processed object detection on camera streams, and the one service on the shortlist that would change the network's shape rather than its population: continuous RTSP from every camera through the `99 → 20` diff --git a/docs/runbooks/build-the-nas.md b/docs/runbooks/build-the-nas.md index 86a8887..e46b4e1 100644 --- a/docs/runbooks/build-the-nas.md +++ b/docs/runbooks/build-the-nas.md @@ -174,7 +174,7 @@ the box and in the firewall, not here. The static is set on the host and the reservation is set on the server, and both are done because either alone is a single point of drift. -### §0.5 — Create the three rules, in order and in position +### §0.5 — Create the four rules, in order and in position **Position is the whole difficulty.** Two of these sit above a deny that has been in place since 2025; appended where new rules naturally land they would @@ -183,14 +183,20 @@ reason. | On interface | Protocol / source → destination | Position | | --- | --- | --- | -| Hicks (50) | `tcp` `vlan50 net` → `10.0.40.30` ports `443,8096` | **above** *Block access to CasaBonita* | +| Hicks (50) | `tcp` `vlan50 net` → `10.0.40.30` port `443` | **above** *Block access to CasaBonita* | +| Hicks (50) | `tcp` `vlan50 net` → `10.0.40.30` port `8096` | **above** *Block access to CasaBonita* | | Winterfell (99) | `tcp` `10.0.99.20` → `10.0.40.30` port `9100` | **above** *Block access to CasaBonita* | | Winterfell (99) | `tcp` `10.0.99.20` → `10.0.40.30` port `22` | **above** *Block access to CasaBonita* | -**The Hicks rule's ports differ from ADR-0016's table, and deliberately.** That -table says `22,8096`, which assumed a box administered over SSH — ADR-0016 -decided Ubuntu Server. `smaug` runs TrueNAS, which is administered over HTTPS, -so the admin port is **443** and not 22. +**Four rules and not ADR-0016's three.** That table wrote the Hicks pass as a +single row carrying a port list; what was created on 2026-09-16 is one rule per +port, which is what this table now describes. Three was a count of the rows the +ADR wrote, not of rules that exist. + +**The Hicks ports differ from ADR-0016's table, and deliberately.** That table +says `22,8096`, which assumed a box administered over SSH — ADR-0016 decided +Ubuntu Server. `smaug` runs TrueNAS, which is administered over HTTPS, so the +admin port is **443** and not 22. [ADR-0040](../adr/0040-run-truenas-on-smaug-and-keep-the-media-stack-in-this-repository.md) records the correction; it had originally claimed the rules were untouched by the operating-system change, and the ports were the part of them that was not. diff --git a/docs/runbooks/open-the-remote-path.md b/docs/runbooks/open-the-remote-path.md index b3d1c93..df8ba81 100644 --- a/docs/runbooks/open-the-remote-path.md +++ b/docs/runbooks/open-the-remote-path.md @@ -8,7 +8,7 @@ enrol, and **an endpoint** — see §0, which is the step this runbook cannot do for you **Before this:** the jumpbox exists ([#436](https://github.com/Gerrrt/HomeLab/issues/436)), and -[ADR-0041](../adr/0041-terminate-the-remote-path-on-the-lab-and-route-it.md) +[ADR-0042](../adr/0042-terminate-the-remote-path-on-the-lab-and-route-it.md) is read rather than skimmed This opens the estate's **first inbound path from the internet**. It terminates @@ -20,7 +20,7 @@ lab, and a `MASQUERADE` rule copied in from a tutorial. > [!CAUTION] > **There is no `MASQUERADE` in this design, anywhere.** Every guide you will -> find while doing this has one. ADR-0041 §2 is why this one does not: NAT +> find while doing this has one. ADR-0042 §2 is why this one does not: NAT > would make every peer indistinguishable from the jumpbox, which holds a > Proxmox token and an SSH key, and would hand every peer the jumpbox's > standing at the firewall. If you find yourself adding `-j MASQUERADE` to make @@ -47,7 +47,7 @@ key that has been on two machines is a key you cannot reason about later. WireGuard needs a stable address and port to dial. This estate has neither: the WAN address is ISP-assigned by DHCP, and there is no dynamic DNS anywhere in -it. ADR-0041 §4 records that deliberately as a separate decision — a static +it. ADR-0042 §4 records that deliberately as a separate decision — a static address is a recurring purchase, and a dynamic DNS provider is a third party handed a continuously-updated pointer to the house. @@ -124,7 +124,7 @@ ListenPort = PrivateKey = # Forwarding is a capability scoped to the tunnel's lifetime, not a permanent -# property of the host (ADR-0041). Nothing here is in /etc/sysctl.conf, and +# property of the host (ADR-0042). Nothing here is in /etc/sysctl.conf, and # nothing here translates an address. PostUp = sysctl -w net.ipv4.ip_forward=1 PostDown = sysctl -w net.ipv4.ip_forward=0 @@ -162,7 +162,7 @@ Endpoint = : # On the CLIENT, AllowedIPs is a ROUTE: the CIDRs that go down the tunnel. # This is the lab and nothing else. 0.0.0.0/0 here would pull all of the # device's traffic through the house, which is not what this is for and is the -# failure ADR-0041 says will not announce itself. +# failure ADR-0042 says will not announce itself. AllowedIPs = 10.0.30.0/24 PersistentKeepalive = 25 ``` @@ -197,7 +197,7 @@ Then *System → Routing → Static Routes → Add*: | --- | --- | | Destination network | `172.31.0.0/24` | | Gateway | `JUMPBOX_TUNNEL` | -| Description | `WireGuard peers — ADR-0041` | +| Description | `WireGuard peers — ADR-0042` | **Save**, then **Apply Changes**. @@ -213,7 +213,7 @@ Then *System → Routing → Static Routes → Add*: | Destination port range | the listen port, from and to | | Redirect target IP | the jumpbox's lab address | | Redirect target port | the same listen port | -| Description | `WireGuard — ADR-0041` | +| Description | `WireGuard — ADR-0042` | | Filter rule association | **Add associated filter rule** | **Save**, then **Apply Changes**. This is the `rdr` and the WAN pass that @@ -236,7 +236,7 @@ First, *Firewall → Aliases → IP → Add*: | Name | `Tunnel_Peers` | | Type | Network(s) | | Network | `172.31.0.0/24` | -| Description | `WireGuard peers — ADR-0041` | +| Description | `WireGuard peers — ADR-0042` | Then on *Firewall → Rules → ImaginationLAN*, mirror the existing lab rules for this source, keeping the established order — blocks, then the tripwire, then @@ -364,7 +364,7 @@ is strictly more closed than after it. 6. `sudo shred -u /etc/wireguard/server.key /etc/wireguard/wg0.conf`. Removing **one peer** rather than the tunnel is a `wg0.conf` edit and -`sudo systemctl reload wg-quick@wg0`. ADR-0041 records that this does not scale +`sudo systemctl reload wg-quick@wg0`. ADR-0042 records that this does not scale and that the first lost device is when it stops being proportionate. ## If something goes wrong diff --git a/docs/runbooks/restore-the-firewall.md b/docs/runbooks/restore-the-firewall.md index 4883e68..3dd5bf3 100644 --- a/docs/runbooks/restore-the-firewall.md +++ b/docs/runbooks/restore-the-firewall.md @@ -267,10 +267,10 @@ ssh root@10.0.99.1 'pfctl -sr \ # latter names 10.0.30.0/24 itself, and against it every DNS query from the lab # to its own gateway logs as a crossing. ssh root@10.0.99.1 'pfctl -sr | grep -E "^pass in log quick on igc0\.30 " | grep -c ""' -# expect 2 once ADR-0041's tunnel exists: the lab's own tripwire and the +# expect 2 once ADR-0042's tunnel exists: the lab's own tripwire and the # WireGuard peers'. Before it is built, expect 1. -# 6. ADR-0041's rules, if the tunnel has been built. The check above counts +# 6. ADR-0042's rules, if the tunnel has been built. The check above counts # tripwires by their shape and the four in step 5 are sourced from an # interface network macro, which the tunnel's is not — so the tunnel's # tripwire and its blocks need asking after separately, or a restore drops diff --git a/docs/security.md b/docs/security.md index 334d946..8df1e4c 100644 --- a/docs/security.md +++ b/docs/security.md @@ -37,7 +37,7 @@ state rather than leaving it open: the first real secret, photo or document in the sensitive tier, any reachability from outside the house, or a third account holder — whichever comes first. **The second of those has now fired and the deferral was re-accepted**, not ended: -[ADR-0041](adr/0041-terminate-the-remote-path-on-the-lab-and-route-it.md) opens +[ADR-0042](adr/0042-terminate-the-remote-path-on-the-lab-and-route-it.md) opens a WireGuard path terminating on the lab, which takes ADR-0008's *no external exposure* premise with it. Nothing in the tier became reachable — it is unbuilt, and on Winterfell when it is built — but the lab's own Grafana on @@ -731,7 +731,7 @@ fingerprint of a house is not. Withheld on purpose: the same instinct: a repository that withholds the WAN address and then publishes the port a VPN answers on has withheld nothing. The design, the peer subnet and the rules are published - ([ADR-0041](adr/0041-terminate-the-remote-path-on-the-lab-and-route-it.md)); + ([ADR-0042](adr/0042-terminate-the-remote-path-on-the-lab-and-route-it.md)); where to send a packet is not. The public IP was already redacted in the original inventory — the rest of this