ADR 0103: what an adopted node holds and what its guard refuses; the node host and connectivity designs name 0102 and 0103
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
---
|
||||
topic: the mesh
|
||||
status: accepted
|
||||
date: 2026-09-22
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
extends: 02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md
|
||||
---
|
||||
|
||||
# 103. What an adopted node holds, and what its guard refuses
|
||||
|
||||
## Context
|
||||
|
||||
[ADR 0100](0100-a-node-in-use-is-adopted-before-it-is-converged.md) holds a found file or
|
||||
container until its module is taken. It also has the mesh guard the store's port and the
|
||||
broker's management port with a table that only refuses. Two independent reviews of the build
|
||||
found both rules drawn too narrowly and, for the guard, in the wrong place:
|
||||
|
||||
1. **Other kinds of resource reach what was found.** An untaken module's directory is re-owned
|
||||
and re-moded if a predecessor's directory is already at its path, and a database refuses to
|
||||
start on a data directory whose mode changed. A service of the same name as a predecessor's
|
||||
unit is started, stopped or re-enabled. An action run *in* a held container runs inside the
|
||||
predecessor's service. A container that is not found under its own name is created, and can
|
||||
mount the predecessor's data beside the predecessor's own container.
|
||||
2. **The guard's two ports are not the only ones a found firewall misses.** A published
|
||||
container port is forwarded, not received, and a firewall that filters only incoming traffic
|
||||
never sees it (ADR 0100's own Context). The broker's plaintext port is published on every
|
||||
interface and admitted by the filter from the private network only. So on an adopted node it
|
||||
is reachable from anywhere. The same holds for any published port a module restricts to the
|
||||
private network.
|
||||
3. **The guard refuses by port alone.** On a machine that routes for others, such as a
|
||||
predecessor's private-network hub, a packet for another machine's database port is refused as
|
||||
well. And a port the guard refuses for a module that is assigned but not taken may still be
|
||||
the predecessor's own, serving the predecessor's other machines.
|
||||
|
||||
## Decision
|
||||
|
||||
**Found covers every kind that can reach what the machine already has.** On an adopted node,
|
||||
for a module not yet taken:
|
||||
|
||||
- a **directory** present with no record is held: its mode and owner are left, and nothing in it
|
||||
is touched;
|
||||
- a **service** whose unit is present with no record is held: its state and whether it starts at
|
||||
boot are left. A reload named by the module still happens, since a reload stops nothing
|
||||
([ADR 0102](0102-the-mesh-writes-into-a-shared-file-never-over-it.md));
|
||||
- a **container** not found by its name is still held if it would mount a path or a volume that
|
||||
is present with no record, because it would share the predecessor's data;
|
||||
- an **action** or one-off step run *in* a held container is held until the module is taken.
|
||||
|
||||
What is held is reported as held and is never removed, as ADR 0100 decides for files and
|
||||
containers.
|
||||
|
||||
**The guard refuses what the found firewall may miss, for taken modules only.** Its ports are
|
||||
derived, not listed. They are every machine port a *taken* module publishes that the filter
|
||||
would admit from the private network only, together with the store's port and the broker's
|
||||
management port. A port of a module that is assigned but not taken is not guarded: it may still
|
||||
be the predecessor's. The guard matches only packets addressed to this machine. Traffic the
|
||||
machine routes for others is never its business.
|
||||
|
||||
**An opening already answered by a found rule is not added.** If the found firewall already
|
||||
admits what an opening says, the opening is reported as satisfied by the found rule, and the
|
||||
mesh adds nothing and later removes nothing. The found firewall treats two rules differing only
|
||||
in their comment as one rule, so adding the mesh's would take over the operator's.
|
||||
|
||||
**A machine raised adopted stays adopted if genesis is run again.** The installer reads the
|
||||
node's mode from what the machine records, not only from the operator's flag. A run without
|
||||
the flag on an adopted machine is refused.
|
||||
|
||||
## Consequences
|
||||
|
||||
- An untaken module on an adopted node can come up only beside what was found, never on top of
|
||||
it: whatever would share the predecessor's data waits for the cutover.
|
||||
- The guard grows with the modules taken, and a module's published private-network port is
|
||||
protected on an adopted node the way the derived filter protects it on a converged one.
|
||||
- Guarding only taken modules means a foundation port on a node joining adopted is guarded once
|
||||
its module is taken, not when it is assigned. Genesis takes the foundation's modules, so the
|
||||
control-node's store is guarded from the first push.
|
||||
|
||||
## How it is checked
|
||||
|
||||
Unit tests hold the host to holding a found directory, a found service and a container that
|
||||
would mount found data, to deferring an action run in a held container, and to adding no
|
||||
opening a found rule answers. They hold the controller to deriving the guard from taken modules'
|
||||
private-network published ports, and the guard's text to matching only this machine's
|
||||
addresses. The installer's tests hold a re-run without the flag on an adopted machine to a
|
||||
refusal. The adoption lab bed asserts that the broker's plaintext port is unreachable from
|
||||
outside the private network, and that an operator's own rule for a port the mesh opens
|
||||
survives the opening being removed.
|
||||
|
||||
## References
|
||||
|
||||
- [ADR 0100](0100-a-node-in-use-is-adopted-before-it-is-converged.md),
|
||||
[ADR 0102](0102-the-mesh-writes-into-a-shared-file-never-over-it.md)
|
||||
@@ -91,6 +91,7 @@ python3 00-META/checks/index.py fail if stale
|
||||
- **0100** — [A node in use is adopted before it is converged](0100-a-node-in-use-is-adopted-before-it-is-converged.md)
|
||||
- **0101** — [A machine's own resolver does not make it in use](0101-a-machines-own-resolver-does-not-make-it-in-use.md)
|
||||
- **0102** — [The mesh writes into a shared file, never over it](0102-the-mesh-writes-into-a-shared-file-never-over-it.md)
|
||||
- **0103** — [What an adopted node holds, and what its guard refuses](0103-what-an-adopted-node-holds-and-what-its-guard-refuses.md)
|
||||
|
||||
### Its tiers, from the bottom up
|
||||
|
||||
|
||||
Reference in New Issue
Block a user