Rotate a node's key without a flag day shipped
This guide replaces the transport key of one node, drone, in a four-node record fleet. Nothing changes on the other nodes' configurations, nobody restarts but the drone and the node you publish the list through, and the drone keeps its node id, its routes and its place in every peer table throughout.
[auth] provider = "fleet" (see the node record), the authoring copy of its fleet list on the operator host, and the config-author key that signs it. To rotate on a schedule the whole fleet acts on — with the retire step gated on the nodes that matter, the mesh secret included — use Rotate keys and the mesh secret without stranding anyone.The rotation runs in four steps, and the node is reachable through all of them:
| Step | Record lists | Drone initiates with | Drone answers on |
|---|---|---|---|
| Before | 6142ed49 | 6142ed49 | 6142ed49 |
| 1–2 List and load | 6142ed49, 5123339a | 6142ed49 | either |
| 3 Activate | 6142ed49, 5123339a | 5123339a | either |
| 4 Retire | 5123339a | 5123339a | 5123339a |
1 — List the next key in the record
Mint the next keypair on the drone, or in whatever system produces your keys; only the public half leaves the node.
$ atlasd keygen
✓ Keypair generated (Curve25519)
⚷ Private Key (keep secret)
private_key = "…"
⚷ Public Key (share with peers)
public_key = "0gmysyqqf3f6vVOsqi4/u7ufJq6+DS4gQuAHP0fLQgI="
On the operator host, add the public key to the drone's record as a second transport key. A window is optional; valid_from = 0 makes it valid at once.
[[node.keys.transport]]
key = "aC+J3tbTGW+7vBHMWMDbeCnjdsFxCxNS4W5gCmxAHWk=" # current, 6142ed49
valid_from = 0
valid_to = 0
[[node.keys.transport]]
key = "0gmysyqqf3f6vVOsqi4/u7ufJq6+DS4gQuAHP0fLQgI=" # next, 5123339a
valid_from = 0
valid_to = 0
Check and sign. The edit invalidated the old signature; signing bumps the sequence number and signs again.
$ atlasd fleet check --file fleet-list.toml
fleet `field-1` seq 1: 4 records, 0 error(s), 0 warning(s), signature does not verify against the anchors
$ atlasd fleet sign --file fleet-list.toml
fleet `field-1` seq 2 signed by 3c24f045 (4 records, ffc955e8)
Publish it: copy the signed file to the [auth] fleet_list path of one node, typically the ground station, and restart that daemon. Every session it brings up carries the list onward, hop by hop. The journal on each node records identity.fleet_list_adopted, and the Fleet tab and atlasd fleet show -c /etc/atlas/config.toml on any node show seq 2.
2 — Load the next key on the node
Add the private half to the drone's [interface] as next_private_key and restart the drone. It now answers handshakes addressed to either key, and opens end-to-end sealed traffic on either.
$ atlasd identity show
interface atlas0
mode record fleet
node id e191..81b6 (af2e580d-5365-4b5f-acfa-9a9da1f69e73)
record drone
capabilities relay=true classes=[Control,Voice,Position,Telemetry,Video,Bulk] config_author=false dashboard=own
transport 6142ed49 valid · held here
transport 5123339a valid · held here
signing e5c003f3 valid · held here
fleet list `field-1` seq 2
3 — Activate the next key
Swap the two values: the new key becomes private_key and the old one moves to next_private_key, so a peer still addressing the old key is answered. Restart the drone. It now initiates with the new key; each peer finds the key in the drone's record and rebinds its existing peer entry, logging:
identity.peer_key_changed node e191..81b6 now presents its key 5123339a (was 6142ed49)
The node id is unchanged in every snapshot, the routes through and to the drone stay where they were, and the Fleet tab still shows the drone as one row.
4 — Retire the old key
Remove the old entry from the drone's record (or set its valid_to to the moment it should stop), then check, sign and publish as in step 1. Once a node holds the new list, it seals end-to-end traffic for the drone to the new key and no longer accepts the old one in a handshake.
$ atlasd fleet sign --file fleet-list.toml
fleet `field-1` seq 3 signed by 3c24f045 (4 records, 9dad4498)
When the Fleet tab shows seq 3 on every node, remove next_private_key from the drone at its next restart. Until then it does no harm: the drone simply holds a key nobody uses.
Rotating the signing key
The same order applies to the Ed25519 key that signs the drone's dashboard token: add the new public key as a second [[node.keys.signing]] entry, sign and publish, replace signing_key on the node and restart, then remove the old entry and sign again. Tokens minted with either key verify while both are listed.
If something is off
- The node refuses to start with "this node's transport key … has no valid record": its
private_keyandnext_private_keyare both missing from the list it holds. Publish the list that lists the key first. fleet checkreports three keys valid at once: close the old key's window or remove it before adding another.- A node still shows the old sequence number: it has no live session to a node holding the new list. The list reaches it on its next session; nothing needs copying by hand.