Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ac77e3cef | ||
|
|
a619022c35 | ||
|
|
49c065c204 | ||
|
|
ddb3980f09 | ||
|
|
75a8f6abc7 |
@@ -99,6 +99,31 @@ composed, so it is not certified.
|
||||
binding. The per-node source override becomes its reach, widened from the filter alone to the names
|
||||
and the certificate as well.
|
||||
|
||||
## Progressive insight — 2026-09-29, from building it
|
||||
|
||||
**Reach does not mean the same thing to the filter for an endpoint the proxy serves.** The decision
|
||||
above says `internal` means "the filter opens the machine port to the private network" and `public`
|
||||
means "the filter opens it to anywhere". For a routed endpoint the second half is wrong, and
|
||||
[ADR 0045](0045-a-machine-firewall-is-the-sum-of-what-it-listens-on.md) already said so before this
|
||||
record was written: *a public service is exposed through the proxy, not by opening its own port* — it
|
||||
listens `from: mesh`, only the proxy reaches it, and it is exposed by name.
|
||||
|
||||
Found by trying to express one real module, not by review. Its routed name must be public, because
|
||||
browsers post to it; its machine-side port must not be, because that port serves the dashboard in
|
||||
cleartext. Under one value driving both, saying "public" would have reopened a port an operator had
|
||||
just closed. Measured the same evening: that module's routed name answered from the internet over TLS
|
||||
while its machine-side port was refused from the same place. The port is not the path.
|
||||
|
||||
So the reach of a **routed** endpoint asks for names, and its port keeps what the manifest said. The
|
||||
reach of an **unrouted** endpoint — git over ssh, a mail port, the bus — governs the port, because
|
||||
there is no name and the port is the only way in. That is the same split this record already draws in
|
||||
*an endpoint that is not routed is reached but never named*; what it got wrong was carrying the filter
|
||||
across it.
|
||||
|
||||
This corrects a fact, not the decision: one statement per endpoint, three things derived from it and
|
||||
none of them deciding on its own, all stand. The table in the decision should be read with the filter
|
||||
column applying to an unrouted endpoint.
|
||||
|
||||
## Consequences
|
||||
|
||||
- **A manifest gains endpoint names, and a route contribution names an endpoint instead of a port.**
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
status: located
|
||||
opened: 2026-09-29
|
||||
located-in:
|
||||
- mesh-controller internal/catalogue (a converged node's declaration)
|
||||
- mesh-host internal/apply/opening.go
|
||||
- mesh-host internal/apply/opening.go (retireFirewall)
|
||||
- mesh-host internal/apply/apply.go (the condition it is called under)
|
||||
fixed-by:
|
||||
amended-design:
|
||||
---
|
||||
@@ -31,9 +31,29 @@ systemctl is-enabled ufw -> enabled
|
||||
systemctl is-active ufw -> active
|
||||
```
|
||||
|
||||
And the declaration that was sent carries no resource that would disable it. A converged node's
|
||||
declaration has no adoption block at all, and nothing in its 372 resources names the found firewall.
|
||||
The sentence is printed by the command; no resource implements it.
|
||||
*Corrected 2026-09-29, an hour later, from reading the host rather than the declaration.* **The first
|
||||
account of this was wrong.** It said the declaration carries no resource that would disable the found
|
||||
firewall, and that the sentence was printed by the command with nothing implementing it. The
|
||||
declaration indeed carries no such resource — but the mechanism was never meant to be one. It is a
|
||||
step in the host's own apply, `retireFirewall`, and it exists, is careful, and is strict: it refuses to
|
||||
retire anything until it has read back from the machine that the mesh's own table is loaded, it records
|
||||
the forward policies first so a half-done retirement can be retried, and it verifies ufw reports
|
||||
inactive afterwards.
|
||||
|
||||
What is established is narrower and stranger than "nothing implements it":
|
||||
|
||||
- ufw was **active and enabled two minutes after the flip**, and the flip had reported the node
|
||||
converged with 372 resources applied and nothing failed.
|
||||
- The machine's own record now reads `disabled_by_mesh: true` — but it was written by a reconcile
|
||||
*after* an operator disabled ufw by hand, roughly fifty minutes later. A reconcile found ufw already
|
||||
inactive, asked it to be inactive, read that back, and recorded that the mesh had done it.
|
||||
- So the step did not take effect at the flip, and the machine's record now says it did.
|
||||
|
||||
The candidates are named rather than chosen, because the evidence does not separate them: the step is
|
||||
called only when the apply had no failures, and a skipped step is silent; the mesh's table is loaded by
|
||||
a service in the same apply, so whether it was loaded *at the moment the step asked* is an ordering
|
||||
question; and the host's own detail lines do not reach the journal, so what it decided is not
|
||||
recoverable after the fact.
|
||||
|
||||
## Why it matters beyond this instance
|
||||
|
||||
@@ -69,5 +89,14 @@ harmless, but the mesh's belief about which firewall is in force has been wrong
|
||||
Convergence is a state, so presumably re-disable it and say so.
|
||||
- Should the preview say what it *will* do rather than what it does, until a step exists that does it?
|
||||
The wording was read as evidence twice in one session.
|
||||
- Is there a check that a sentence the mesh prints corresponds to a resource it sends? This is the
|
||||
second time today that a printed claim and a sent declaration disagreed.
|
||||
- Is there a check that a sentence the mesh prints corresponds to something that happened? This is the
|
||||
second time in one session that a printed claim and the machine disagreed.
|
||||
- **Why did the step not take effect?** It is called only when the apply had no failures, and being
|
||||
skipped is silent. The mesh's table is loaded by a service in the same apply, so whether it was
|
||||
loaded when the step asked is an ordering question — and ADR 0100 makes loading it first a
|
||||
precondition rather than an expectation.
|
||||
- **A step that records the mesh as having done what an operator did is worse than the omission.** The
|
||||
record now says the mesh disabled ufw. Nothing distinguishes "we did this" from "we found it already
|
||||
so". Should it?
|
||||
- Why do the host's own detail lines not reach the journal? Everything it decided during the flip is
|
||||
unrecoverable, which is why this account has candidates instead of a cause.
|
||||
|
||||
Reference in New Issue
Block a user