From af170e3a67108a97cf0814ba3678e7a31dc33a07 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 30 Sep 2026 15:20:26 +0200 Subject: [PATCH] Issue 171: a module that names its own resolver knows no mesh name Found and fixed the afternoon ADR 0148 landed: mailu-admin lost its database behind Mailu's own resolver. Two catalogue PRs; an insight on 0148 that a container's dns is a decision, not a preference. --- ...are-resolved-not-copied-into-containers.md | 10 +++ .../00-report.md | 78 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 04-ISSUES/171-a-modules-own-resolver-knows-no-mesh-name/00-report.md diff --git a/02-DECISIONS/0148-the-meshs-names-are-resolved-not-copied-into-containers.md b/02-DECISIONS/0148-the-meshs-names-are-resolved-not-copied-into-containers.md index 5858f31..11dbfb2 100644 --- a/02-DECISIONS/0148-the-meshs-names-are-resolved-not-copied-into-containers.md +++ b/02-DECISIONS/0148-the-meshs-names-are-resolved-not-copied-into-containers.md @@ -150,6 +150,16 @@ closed by this record, only answered by it. resolvable inside the mesh — holds unchanged and by the same means the machine already uses. - **Issue 110 stops being a container-DNS inconvenience and becomes a prerequisite** for the mesh not restarting itself whenever it learns a name. +- **A container that names a resolver of its own has opted out of the machine's**, and the copy this + record removes was the only reason such a container could reach anything by a mesh name. + + > **Progressive insight — 2026-09-30, the afternoon this landed. Found the hard way.** The mail + > system's admin, behind Mailu's own resolver, lost its database the moment the copy went + > ([issue 171](../04-ISSUES/171-a-modules-own-resolver-knows-no-mesh-name/00-report.md)). A `dns` on + > a container is a decision about whether mesh names exist inside it, not a preference; the module + > was corrected, and whether the controller should refuse the contradiction is that issue's open + > question. + - **A container started by hand gets the mesh's names too**, where before only declared containers did. Design 08 drew that boundary deliberately, on the grounds that reaching into every container is what a nameserver would be for. This record accepts that consequence rather than working around it: a diff --git a/04-ISSUES/171-a-modules-own-resolver-knows-no-mesh-name/00-report.md b/04-ISSUES/171-a-modules-own-resolver-knows-no-mesh-name/00-report.md new file mode 100644 index 0000000..d9b5ac5 --- /dev/null +++ b/04-ISSUES/171-a-modules-own-resolver-knows-no-mesh-name/00-report.md @@ -0,0 +1,78 @@ +--- +status: resolved +opened: 2026-09-30 +located-in: + - mesh-catalog modules/mailu (eight containers name Mailu's own resolver, and one of them binds a mesh name) + - mesh-catalog modules/dnsmasq (dropped the DNSSEC bit its upstreams set) +fixed-by: mesh-catalog PR 178 (mailu-admin uses the machine's resolver) and PR 179 (the machine's resolver passes the DNSSEC bit down) — 2026-09-30, the same afternoon +amended-design: +--- + +# 171 — A module that names its own resolver knows no mesh name + +## What was observed + +The afternoon [ADR 0148](../../02-DECISIONS/0148-the-meshs-names-are-resolved-not-copied-into-containers.md) +landed — no container is given the mesh's names any more; it asks the machine's resolver — the mail +system's admin container began logging, 523 times in three minutes: + +``` +psycopg2.OperationalError: could not translate host name "novox.internal" to address: Name does not resolve +``` + +Mail was accepted on every port and the web front answered; the admin and the spam filter beside it +were unhealthy, and anything that needed the database — a mailbox change through the API, the spam +filter's domain list — failed. Found by the operator asking whether mail was back, forty minutes in. + +Mailu ships its own resolver, an unbound in a container, and every other Mailu container is told to +use it — the module carries `dns: [192.168.203.254]` on eight containers. That resolver recurses from the +root and knows nothing under `.internal`. Until that afternoon the admin container had the database's +name anyway, because the mesh wrote every name into every container at creation; the copy was the only +reason a container behind its own resolver could reach anything by a mesh name, and nobody knew it was +load-bearing. + +**Removing the override was not enough.** Given the machine's resolver instead, the admin refused to +start: `Your DNS resolver at 127.0.0.11 isn't doing DNSSEC validation`. Mailu checks, at start, that +its resolver returns the Authenticated Data bit for a signed name. The mesh's resolver forwards to two +upstreams that validate and set the bit, and dropped it on the way down — dnsmasq does unless told +otherwise. Mailu's own unbound has no hook to forward a zone elsewhere, so it could not be taught the +mesh's names either. + +## Why it matters beyond this instance + +**A container with a resolver of its own has opted out of the machine's, and nothing says so.** 0148 +made the machine's resolver load-bearing for every container; a `dns` on a container is a quiet +exception to that, and the exception used to be papered over by the copy the record removed. The +manifest field reads like a preference and is a decision about whether mesh names exist inside the +container. + +**A resolver that forwards to validating upstreams and hides the fact is less useful than it could +be**, and the first program to check found out. + +**The mesh reported nothing.** Every container ran; the failing one accepted connections; the report +was about bytes. It is [issue 145](../145-a-machine-reads-healthy-while-its-modules-cannot-reach-each-other/00-report.md) +again, and the check that would have caught it is the same unbuilt one. + +## What was done + +- The one Mailu container that binds a mesh name — the admin, through the database it is granted — + no longer names Mailu's resolver and uses the machine's, like every container without a `dns` of + its own (mesh-catalog PR 178). The other seven keep unbound: the spam filter needs a validating + resolver for its blocklist lookups, and none of them asks for a mesh name. +- The machine's resolver passes the DNSSEC bit down from its upstreams, `proxy-dnssec` (PR 179). It + does not validate itself; the trust is the upstream's and the path to it, as a forwarding resolver's + always was, and the configuration says so. + +## What checks it + +The admin container's own start-up check, which is what failed, and the mesh's status once it reads +healthy. A container-level check that a mesh name resolves from inside every declared container is +the one 110 and 145 both ask for and is not built. + +## Open questions + +- Should a container's `dns` be refused, or made to say what it gives up? A module that names its + own resolver and binds a mesh name is a contradiction the controller can see at composition — the + grant hands it a name its resolver will not answer. +- Should the machine's resolver validate rather than proxy? It would cost a trust anchor on every + machine and make the resolver slower to start; proxying was enough for the one program that asked.