fix: every member learns the root CA's holder from a notice the root signed (keel#105) #112
No reviewers
Labels
No labels
accessibility
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Keel-Linux/keel!112
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/root-holder-for-every-member"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #105 (bug B1 of the real-node MariaDB pair test, Keel-Linux/handbook#60).
Stacked on #111 (both bump
debian/changelog): this branch is rebased on it and its base is #111's branch. GitHub moves the base tomainwhen #111 merges.Problem
In a mesh whose root CA is held by a cloud advanced node (web-1) that is not a pair member, a cloud simple pair cannot get its database certificate. Only etcd members write
/var/lib/keel/etcd/holder, so each pair member asks the other one, which refuses:this node does not hold the mesh's root CA. The tester wrote web-1's address into that file by hand.Which source is trusted
Decision 0051: "The holder's address is not in the bundle ... it is a short notice signed by that root's key alone". The root certificate is the anchor (the trust bundle of epoch 1).
The notice (mesh id, holder's overlay address, time) is signed by the root's key. Any roster may carry it, the holder's own or relayed, because only the root's key makes one. A member takes it only when it is for its mesh, newer than the one it keeps, and verifies with the root certificate it holds. A member that does not hold the root's key cannot send certificate requests to another address.
A member that holds no root certificate (no etcd member) takes one only from a roster it fetched from a trust root's own overlay address, as docs/mesh.md says a trust root's signing key is learned; never from an announcement. It must be a self-signed CA named for the mesh, and it is never replaced (a new root is 0051's bundle, by a majority).
A notice dated more than 5 minutes ahead of the local clock is refused: a notice dated far ahead would make every later one "older" and pin the address. A time and not a sequence number, because 0051 names the time and a counter would have to move with the root's key when the holder moves.
The notice has a
regionfield (0051); absent means the first region. A notice of another region is not taken until the bundle exists.Open points (old notice replayed to a new node, a trust root that gives a fake root, the root in the join answer): #114.
Change
keel/mesh/rootholder.py(new): the notice, made once on the holder and kept;learnverifies and keeps it, writesholder,holder.noticeandroot-anchor.crt;askedfetches the peers' rosters.keel/mesh/members.py: the roster carriesrootandholder; a value that cannot be read is left out. Older members ignore the new fields.keel/mesh/sync.py: the roster offers them;keel mesh syncand announcements take them.keel/system/dbtls.py: a node that knows no holder fetches its peers' rosters before it asks, and asks the other pair member only when no roster names the holder. The leaf is checked against the learned root.docs/mesh.md,docs/replication.md.debian/changelog,pyproject.toml,keel/__init__.py: 0.23.5.Tests
tests/test_mesh_rootholder.py: a pair of two cloud simple nodes, the root held by a third node, gets both database leaves with no file written by hand (through the roster wire format);keel mesh synclearns it, also relayed by the other pair member; a forged root with the mesh root's name and a notice signed by it are refused; a root from a member that is no trust root, or from an announcement, is not taken; a leaf under another root is refused; an older notice, one of another mesh, one more than 5 minutes ahead, and one of another region are not taken; the region is signed.Test plan
CI record
First run:
vip / trixiefailed atg_promote_b(etcdctl get: context deadline exceeded, as in main's run 37833124848),tests / coveragefailed intests/test_cli_channel.py(a gpg call, not this change), andmariadb / trixiefailed in #111's case (fixed there). No job was rerun: the rebase on #111 ran all checks again, all green.