The mesh certifies names inside it

08-connectivity keeps two authorities apart on purpose: a public one for
names the outside world reaches, and the mesh's own for names only the
mesh knows. Nothing implemented the second, so anything between machines
was plaintext or trust-on-first-use — which the design refuses everywhere
else.

A node now generates a fourth key at enrolment and reports the public
half. A fourth, because a key used for two purposes is one rotation away
from breaking the other: the identity key signs messages to the mesh and
would do for TLS, and reusing it would mean rotating a node's identity
every time its certificate is replaced.

**Nothing secret travels and nothing is sealed.** A certificate authority
says "this name belongs to the holder of this key", so the mesh signs a
public half it cannot use, and the certificate it issues is public. A
module asks for one and is given the certificate and, if it wants,
the mesh's own — the private key is a path to a file the machine already
has, the same arrangement the private network's key uses.

Asserted by verifying rather than inspecting, because a certificate that
parses and does not chain fails at the moment something connects:

- what the mesh issues verifies against the mesh, for the name asked for
- the name is in the subject alternative names, since a certificate
  carrying it only in the common name is refused by every modern client
- it certifies the key the node generated and no other
- another mesh's certificate does not verify, which is the whole point of
  two authorities being separate
- the authority cannot sign another authority — one that could is one
  that can be delegated without anybody deciding to
- two control planes starting together agree on one authority, or a mesh
  has certificates half its machines refuse

Certificates last ten years, which is a choice: a short life needs
something to renew it, and a renewal that fails silently is a mesh that
stops trusting itself on a date nobody wrote down. What makes one
replaceable is that the mesh reissues on demand, not that it expires.
This commit is contained in:
2026-08-31 00:09:13 +02:00
parent 0262873254
commit 646609c1b2
8 changed files with 570 additions and 1 deletions
+71 -1
View File
@@ -1280,8 +1280,78 @@ func declarationWith(ctx context.Context, inv *inventory.Inventory, node string,
needed[m.Module][name] = sealed
}
}
// And a certificate for this machine's name inside the mesh, when anything on it asks. Issued
// rather than stored: the node's key does not change, so signing again produces an equally
// valid certificate and there is nothing to keep in step.
var certificate, authority string
for _, m := range plan.Modules {
if m.Certificate == nil {
continue
}
issued, meshCA, err := certificateFor(ctx, inv, node)
if err != nil {
return nil, err
}
certificate, authority = issued, meshCA
break
}
return plan.Declaration(catalogue.Rendering{
Settings: settings, Generators: gens, Grants: grants, Needed: needed})
Settings: settings, Generators: gens, Grants: grants, Needed: needed,
Certificate: certificate, Authority: authority})
}
// certificateFor is what the mesh certifies about one machine's internal name.
//
// It reaches across two contexts and reads neither one's store from the other: `inventory` knows
// the machine and whether it is on the private network, `identity` holds the authority and the
// key that machine reported. The process holding both grants asks each for its part
// (novox/hq ADR 0008).
func certificateFor(ctx context.Context, inv *inventory.Inventory, node string) (string, string, error) {
ident, err := openIdentity(ctx)
if err != nil {
return "", "", err
}
defer ident.Close()
record, err := inv.NodeByName(ctx, node)
if err != nil {
return "", "", err
}
serving, err := ident.ServingKeyOf(ctx, record.ID)
if err != nil {
return "", "", err
}
if serving == "" {
// The machine joined before it had one, or never reported it. Said plainly, because the
// remedy is on the machine and no amount of pushing from here will produce one.
return "", "", fmt.Errorf(
"%s wants a certificate and has never told the mesh what key it serves with; it "+
"joins again to report one", node)
}
// The name it is certified for. Only a machine on the private network has one — a certificate
// for a name nothing resolves is a certificate nothing can check.
where, err := whereEveryoneIs(ctx, inv, nil)
if err != nil {
return "", "", err
}
name := where[node]
if name == "" {
return "", "", fmt.Errorf(
"%s wants a certificate and is not on the private network, so it has no name inside "+
"the mesh to be certified for", node)
}
issued, err := ident.Certify(ctx, node, name, serving)
if err != nil {
return "", "", err
}
authority, err := ident.EstablishAuthority(ctx)
if err != nil {
return "", "", err
}
return issued, authority.Certificate, nil
}
// grantsFor is every credential this node must create, because something elsewhere uses it.