Registered ca-trust from the catalogue — it was merged and had never been registered, which is why "assign it to one machine" had no module to name — assigned it to the workstation, and verified. Verified in the form ADR 0147 prescribes, against the authority's own API so the handshake needs nothing else in the mesh to be right: 200, issuer Mesh Internal CA, Verify return code 0. Four routed internal names verify too, and `git ls-remote https://…` works, which is the consequence the report named. Removal exercised for the first time. Unassign and push removes the anchor, empties the trust store of the mesh's authority, and returns the plain client to the original error; assigning again restores it. That is the half 0147 claimed and nothing had shown. One thing it found that is not in the module: removal works only because the host removes the service before the script. Stopping the unit is what deletes the certificate and refreshes the bundles, and it needs the script to still exist. The symmetry rests on an ordering nothing states. 0147's "written, and not yet run" now carries a progressive insight saying it has run, where, and that it ran on one machine of four.
64 lines
3.6 KiB
Markdown
64 lines
3.6 KiB
Markdown
---
|
|
status: resolved
|
|
opened: 2026-09-26
|
|
located-in: [mesh-catalog modules/ca-trust]
|
|
fixed-by: the ca-trust module registered from the catalogue and assigned to a workstation; verified in both directions 2026-09-30 (02-resolution.md)
|
|
---
|
|
|
|
# 129 — nothing makes a machine trust the mesh's own certificate authority
|
|
|
|
## What was observed
|
|
|
|
On an enrolled, adopted workstation — on the private network, resolving the mesh's names
|
|
through the mesh's resolver — every HTTPS name the mesh serves internally fails verification:
|
|
|
|
```
|
|
curl https://<a name the mesh routes internally>/
|
|
curl: (60) SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
|
|
```
|
|
|
|
The route proxy presents a certificate issued by the mesh's internal authority (step-ca, the
|
|
`internal-acme-ca` provision). The machine's trust store holds the **predecessor's** authority
|
|
and a developer tool's local root, and nothing of the mesh's. No module installs the mesh's
|
|
root, and no fact carries it: step-ca's only consumers are proxies, which obtain certificates
|
|
over ACME and never need the root on the machine they run on.
|
|
|
|
[Issue 048](../048-nothing-makes-a-machine-trust-the-mesh-registry/00-report.md) found the same
|
|
shape for the mesh's registry and resolved it by treating the private network as the transport
|
|
security ([ADR 0082](../../02-DECISIONS/0082-the-registry-is-reached-by-name-and-trusted-by-the-overlay.md)):
|
|
the runtime pulls in the clear, over the tunnel. That answer does not carry over. A browser, git
|
|
over HTTPS, a package manager and every TLS client a person or a module uses verify the
|
|
certificate chain, and there is no "insecure registries" for them — nor should there be.
|
|
|
|
Consequences today, all silent until someone tries:
|
|
|
|
- a person on a workstation cannot open any internal HTTPS name without a warning;
|
|
- git over HTTPS to the mesh's forge fails, so the working clone URL is ssh-only;
|
|
- a module on a non-hub machine that calls another module's internal HTTPS name fails
|
|
verification unless its image happens to carry the root;
|
|
- the predecessor's authority cannot be retired from any machine while anything there still
|
|
speaks TLS to a mesh name, because it is the only authority those machines trust.
|
|
|
|
## What would have prevented it
|
|
|
|
- A **mesh fact carrying the internal authority's root** (public material; the controller or
|
|
the step-ca module is its source), written onto every machine on the private network — the
|
|
same reasoning that has the private network write the registry trust and the names: being on
|
|
the network is what makes a machine one that speaks to the mesh's names.
|
|
- A resource that puts it where the machine's TLS clients look — on Arch,
|
|
`/etc/ca-certificates/trust-source/anchors/` — and **refreshes the extracted bundles**
|
|
(`update-ca-trust`). The refresh is the open design question: it is a command, and the link
|
|
may not carry an action ([ADR 0005](../../02-DECISIONS/0005-the-node-host.md)). A declared
|
|
one-shot unit, or a host primitive for "trust this anchor", are the obvious candidates.
|
|
- Removal symmetric to arrival: undeclared, the anchor goes and the bundles are refreshed again,
|
|
so a machine leaving the mesh stops trusting it.
|
|
|
|
## Evidence to carry into diagnosis
|
|
|
|
- `step-ca` module: provides `acme-ca` / `internal-acme-ca`, listens on 9000 for proxies; no
|
|
resource writes its root anywhere but its own state directory.
|
|
- The private network's generator writes `/etc/hosts` and the registry trust, and nothing
|
|
about certificates.
|
|
- On the workstation, the trust anchors present are the predecessor's authority and a local
|
|
development root; `trust list` shows no entry for the mesh.
|