Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1640,10 +1640,27 @@ rules", and of doing that discovery with an audit device rather than a grep. The
found 19 files and could not have found this, because **the fact is not in the files** —
it is a property of the running host.

**Pin the address before writing rules.** An allowlist naming both is correct but papers
over the cause; the real fix is deciding what `enp1s0` is for and either giving it a
losing route metric or taking it off that subnet. See §4.12 — same configuration, and
this is its second distinct symptom.
**PINNED 2026-09-06, not yet applied.** `h4-dns-resolvers.yml` now emits
`route-metric: 200` on the non-primary link, so `enp2s0` (.160) wins deterministically
and the H4's source address stops depending on what the kernel felt like.

**Hung off the variable that already decides which link is primary.** `h4_dns_link:
enp2s0` governed the resolver list; it now governs the route metric too. The resolver
link and the preferred-route link must be the *same* link, and two independent knobs
would eventually disagree in a way nothing would notice.

**It does not remove `.156` or down the link** — only which route is preferred. And
nothing is bound to `.156` any more in any case: the unconfigured dnsmasq holding it was
disabled in §2.14, found during this same investigation.

**Applying is still manual**, as this playbook has always been: it writes the override
and stops. `netplan try` gives a 120-second auto-revert, and unlike the N150s it should
work here — that refusal was specific to a bridge carrying `parameters:`, and the H4 has
plain ethernets. Confirm it actually offers the prompt rather than assuming; the
`systemd-run` revert timer from `kvm-netplan-fix.yml` is the fallback if it refuses.

An allowlist naming both addresses would still have been *correct*; this makes it
unnecessary. See §4.12 — same configuration, and this was its second distinct symptom.

### 2.10 `.claude/settings.json` is a MicroShift-era artifact
`docs/REVIEW-2026-07-24.md:310` (H30)
Expand Down
36 changes: 36 additions & 0 deletions ansible/playbooks/h4-dns-resolvers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,36 @@
# its applied line. Right servers, wrong count.
#
# enp2s0 is the primary: it carries 192.168.1.160 and the kube-vip VIPs .200/.201.
#
# THIS VARIABLE NOW GOVERNS ROUTING AS WELL AS DNS, deliberately. The resolver link
# and the preferred-route link must be the same link; two independent knobs would
# eventually disagree, and the disagreement would be invisible.
h4_dns_link: enp2s0

# ---- route metric — BACKLOG §2.9, added 2026-09-06 -----------------------
# Both interfaces are on the SAME /24 and both take DHCP, so both installed a
# default route at metric 100:
#
# default via 192.168.1.1 dev enp1s0 proto dhcp src 192.168.1.156 metric 100
# default via 192.168.1.1 dev enp2s0 proto dhcp src 192.168.1.160 metric 100
#
# Equal metric means the kernel picks one and nothing pins the choice. It had
# picked enp1s0, so the H4 was sourcing LAN traffic from **192.168.1.156** — an
# address referenced nowhere in this repo. Found in Vault audit logs (§2.6), where
# the H4's own requests arrived from an address no document knew about.
#
# WHY THIS MATTERS BEYOND TIDINESS. §2.9's firewall allowlist would have been built
# from the repo, which says the H4 is .160. It would have worked — until a reboot
# flipped the source address and locked out the machine that runs every playbook,
# including the one needed to undo the rule. A failure arriving hours or weeks
# after the change, looking unrelated to it.
#
# A higher metric loses. 200 on the secondary leaves enp2s0's 100 winning, and does
# NOT remove .156 or take the link down — it only decides which route is preferred.
# Nothing is bound to .156 any more in any case: the unconfigured dnsmasq that held
# it was disabled in §2.14, found during this same investigation.
h4_secondary_route_metric: 200

tasks:
- name: Confirm the expected links exist before touching anything
ansible.builtin.command: "ip -o link show {{ item }}"
Expand Down Expand Up @@ -265,6 +293,14 @@
dhcp4: true
dhcp4-overrides:
use-dns: false
{% if link != h4_dns_link %}
# Both links are on the same /24 and both take DHCP, so both
# installed a default route at metric 100 and the kernel picked
# whichever it liked — which made the H4's source address for LAN
# traffic non-deterministic. A higher metric loses. This does not
# remove the address or down the link. BACKLOG §2.9.
route-metric: {{ h4_secondary_route_metric }}
{% endif %}
{% if link == h4_dns_link %}
# Resolver list lives on this link only. Repeating it on the other
# link doubles the entries in resolv.conf — resolved does not dedupe
Expand Down