feat: etcd's certificates are the root's, and etcd's auth is on (#83) #90
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!90
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/etcd-root-issued-rbac"
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?
Implements #83, which the maintainer approved on 2026-10-07. Packaging: Keel-Linux/common#48. Handbook amendment: Keel-Linux/handbook#56.
What changes
The root signs every etcd certificate itself. The inviter relays the request at a join (
issue), and the member sends its own at a renewal. The CN is the member's mesh identity (keel-<address>) and the SANs are its /128 and::1. The root sets both, whatever the request asks. The member checks key, name, address, CA:FALSE and the chain to the root. No member holds a CA key. Renewal (with 10 of 30 days left) and new memberships wait, with an alert, while the holder is unreachable. Issuance goes through the holder named in the member's state, which leaves room for 0051's other roots.Who gets a certificate (
keel.mesh.etcdproof, after the security review). The root signs only a request shown to be the member's own. The CSR's own signature is proof of possession of the CSR key (checked before signing); the member's Ed25519 signature over the CSR with its mesh signing key binds that key to the member. A member renews its own address itself (sender = that address's key, proof verified with the trust store's signing key for it). A node being admitted is relayed by its inviter with the admission evidence it signed (names the node, address and signing key; signed by the sender's trusted key); the proof must verify with the evidence's signing key. Evidence naming the inviter's own or any other member's signing key is refused; where the trust store knows the node, the evidence must name the same key; a certificate issued under a signing key the trust store later disowns is revoked attend(etcdca.impostors). The holder records the signing key and the relaying member with each certificate, and the relay may revoke it, soabandoned()gives a failed join's certificate and learner back.tests/test_mesh_etcd_root.pynow refuses B for C's address in every form;tests/etcd_auth_netns.pydoes the same on the real cluster.etcd auth. Users are the CNs.
keel-member/keel/<mesh>/, write/keel/<mesh>/etcd/(the mesh's own keys, e.g. #87's restart lock)keel-vip-<vip>/keel/<mesh>/vip/<vip>/The holder manages users and roles with an admin certificate (CN
root) that only it holds (keel.mesh.etcdauth). Whether auth is on is read from etcd (auth status, cached 5 s), never from a file; every step afterauth enablein reissue is idempotent, so a crash between them resumes on rerun.keel vip pairandtendsend a pair's record to the holder, which checks it like any node does. Membership changes need root once auth is on, so they now run on the holder: learner promote and remove intend, and member removal insiderevoke.etcdctl instead of the JSON gateway (
keel.mesh.etcdclient). The gateway cannot carry a client's CN (etcd's docs, and tested on trixie's 3.5.16). Details:/proc/self/fd/Nviapass_fds;PATHandGOMAXPROCS(fits the controller's TasksMax);-w json, etcd's own timeouts, plus a process kill at +0.5 s;The gateway is now off (
ETCD_ENABLE_GRPC_GATEWAY=false). keel-vip.service's helper rewrites the controller's memfds when the certificate changes (renewal, reissue). Before this, a controller running past 30 days kept a stale certificate.CRL: still signed with the root key on the holder and distributed as before. Members sign nothing. The 0051 note is in handbook#56.
Migration of the live layout:
keel mesh etcd reissue(on the root holder)--dry-runstops here and prints the plan.enroll, then the root signs, thenreissue. The member drops its intermediate. etcd reads the new certificate at its next handshake, so nothing restarts. The next step waits until that member serves the new certificate and every voter is healthy (3 min max, then it stops with the reason; rerun continues).crl).auth enableas root, then reads the mesh as itself to check.Rollback:
keel mesh etcd reissue --rollbackdisables auth. Certificates stay root-issued: the intermediates are revoked, which is the point. A run that stopped part way needs no rollback: both certificate kinds work together until step 4, and a rerun finishes the job.Upgrade order: upgrade keel and keel-overlay-etcd on every node first, one node at a time (applying the new config restarts etcd once for the gateway change). keel
Breaks: keel-overlay-etcd (<< 0.4.0~)so etcdctl comes with keel. Then run reissue once.Known limits
/keel/<mesh>/etcd/, which every member may write. This is keel 0.22.0.Tests
Unit: recording etcdctl, fake etcd with auth, reissue on a cluster of the old layout including every refusal path, receiver kinds, memfd refresh. Coverage stays above the 95% gate.
etcd / trixieandvip / trixienow run on etcdctl.New
etcd-auth / trixie(tests/test_etcd_auth_netns.py): 250 ms ±25 ms with 2% loss, measured first. Three members start in the live layout while the VIP is held at A, and reissue runs. It asserts:permission deniedon put, delete, revoke and txn of the VIP keys, while B passes;It also measures etcdctl's overhead against the controller's 2 s call timeout.
CodeQL / Clear-text storage of sensitive information
This expression stores sensitive data (secret) as clear text.
Show more details