Repository navigation
feat(fleet): switch ACME and EST on a node and show when it needs a reboot - #129
Merged
Merged
Conversation
…eboot SetNodeProtocol reads the node's config, flips one protocol block's enabled flag and applies it back, leaving the block's settings and blank write-only secrets as the node returned them and the other protocol blocks out of the apply. A reboot-required answer is recorded until the node reports the protocol running in the new state, and ListNodes and GetNode carry each node's protocol state and reboot_required. ApplyNodeConfig audits every protocol it switches. Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com>
Bugs5382
added a commit
to CryptOS-PKI/docs
that referenced
this pull request
Sep 30, 2026
Depends on CryptOS-PKI/cryptos-manager#129 and CryptOS-PKI/api#123: the manager's SetNodeProtocol call, the reboot-required flag on ListNodes and GetNode, and the protocol-enabled and protocol-disabled audit entries. The web UI's Protocols page still records intent only, and the manager has no reboot action yet. Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com>
2 tasks done
Bugs5382
marked this pull request as ready for review
September 30, 2026 06:54
This was referenced Sep 30, 2026
Bugs5382
added a commit
to CryptOS-PKI/docs
that referenced
this pull request
Sep 30, 2026
Depends on CryptOS-PKI/cryptos-manager#129 and CryptOS-PKI/api#123: the manager's SetNodeProtocol call, the reboot-required flag on ListNodes and GetNode, and the protocol-enabled and protocol-disabled audit entries. The web UI's Protocols page still records intent only, and the manager has no reboot action yet. Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com>
Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com>
The reboot-required record was keyed by node name, so renaming a node dropped a switch still waiting for its reboot, and protocol audit entries targeted /nodes/<name>. Record switches against the node's stable ID and write protocol-enabled and protocol-disabled entries against /nodes/<id>, from SetNodeProtocol and from ApplyNodeConfig alike. SetNodeProtocol resolves its node through the same lookup as the other node RPCs. Re-pin the api module to api main, which carries the SetNodeProtocol contract and the node ID fields. Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com>
Contributor
Author
|
Closing summary: the per-node ACME and EST switch is real: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
The Fleet Manager's per-protocol "Enabled" switch only records intent in the manager's catalog; nothing reaches a node. Nodes now carry
pki.acmeandpki.estwith an explicitenabledflag (CryptOS-PKI/api#115, CryptOS-PKI/cryptos-node#286), and every switch is reboot-required. This makes the switch real for ACME and EST, through the fleet contract in CryptOS-PKI/api#123.SetNodeProtocol(admin only) fetches the node's config, sets one protocol block'senabledflag and applies the config back through the node'sApplyConfig, the same whole-config pathApplyProfileToNodeuses. The block's other settings go back as the node returned them. EAB keys and EST password digests come back blank fromGetConfigand are sent blank, so the node keeps its stored secret for the samekey_idorusername, and no secret ever reaches the manager. A protocol with no block yet gets a bareenabled: trueblock for the node to validate. A protocol already in the requested state applies and audits nothing.enabled: true, or a block that fails validation, comes back with the node's gRPC code and message (for exampleInvalidArgument) instead ofInternal, so the caller sees why. Nothing is audited or recorded.requires_reboot, the manager records the switch against the node.ListNodesandGetNodenow fillNodeSummary.protocolsfrom the node'sNodeStatus.protocolsand setreboot_requiredwhile the node reportsconfig_reboot_pendingor a protocol'sreboot_pending, or while a recorded switch hasn't shown up as running. A recorded switch clears once the node reports the protocol running in the new state with nothing pending.protocol-enabledorprotocol-disabledentry naming the actor, the node and the protocol, with "(takes effect at the next reboot)" when it does. A whole-configApplyNodeConfigthat turns a protocol on or off now gets the same entry (marked "via config apply") ahead ofconfig-applied. To tell, it reads the node's config first when the incoming config carries a protocol block, and applies nothing if it can't read it.cryptos.v1.ServiceProtocolto thePkiblock name, and the block is read and written through protobuf reflection on itsenabledfield. SCEP (CryptOS-PKI/api#117) is one table entry once the pin carriesPki.scep.SetNodeProtocolis listed as excluded, alongsideApplyNodeConfig.github.com/Bugs5382/go-logv1.3.0 (new dependency: the manager had no logger, and go-log is the owner's logging package). Entry, decisions, node calls with their duration, the reboot record and its confirmation, and every error. No config or secret is logged.task runsetsLOG_LEVEL=trace LOG_FORMAT=console.Design calls:
GetConfigreturns for the others.config_reboot_pendingand per-protocolreboot_pendingcarry the same fact across a manager restart or across replicas. A schema migration would also collide with feat(nodes): stable node IDs and RenameNode #126's migration v6.ActivateImage, which boots a staged image), so a manager-side reboot needs an api and cryptos change first. This PR only surfaces "reboot required".Closes #128
Part of CryptOS-PKI/api#114. Related: #61, #84.
api pin.
go.modpinsgithub.com/CryptOS-PKI/apito9493f86on apimain, which carries CryptOS-PKI/api#115, CryptOS-PKI/api#123 and the node IDs from CryptOS-PKI/api#110.Web. The web half isn't in this PR. The web's switch is fleet-wide with no node dimension, so moving it to a per-node switch with a reboot-required badge is a page redesign, not a wiring change.
Docs: README ("What it does") and
docs/mcp.mdupdated here. Companion docs-site commit on CryptOS-PKI/docs#30 (docs/26-fleet-manager-pages), marked as depending on this PR and CryptOS-PKI/api#123:0d8fe5d(overview: "Switching an enrolment protocol on a node", the admin row, and what is not available; web-ui: the Protocols callout).Verification
golangci-lint2.12.2, gofmt, go vet, golic)go test ./...)How this was verified
internal/fleet/protocols_test.go(12 tests) failed against a stub (Unimplemented, missing fields), then passed. They cover the admin gate, an unswitchable protocol, an unknown node, switching ACME on and EST off with only that block changed and the other block left out, blank secrets kept blank, a missing block, the no-op, a node refusal keeping its code and reason with no audit or record, reboot-required tracking through stored, booted-but-not-running and running states,ListNodesprotocol state, per-protocol audit onApplyNodeConfig, and no apply when the baseline can't be read.TestWireRoundTrip_ProtocolBlocks_KeepEveryFielddrivesGetNodeConfigandApplyNodeConfigover Connect JSON with every ACME and EST field and checks nothing is dropped (with the old pin the fixture doesn't even decode).task ci(gofmt, vet, golangci-lint, test) passes locally. The Postgres store tests ran withoutMANAGER_TEST_DATABASE_URL; the store is untouched here.Overlaps and merge order with the open manager PRs (conflicts checked with
git merge-tree):protocol-enabled/protocol-disabledentry (fromSetNodeProtocoland fromApplyNodeConfig) targets/nodes/<id>.SetNodeProtocolresolves its node through the same lookup as the other node RPCs.SetNodeProtocolRequesthas nonode_idfield on apimain(api#123 was written before api#110), so the RPC is still addressed bynode_name; addingnode_idis an api change. New tests:TestSetNodeProtocol_AuditsAgainstTheNodeID,TestApplyNodeConfig_ProtocolSwitch_AuditsAgainstTheNodeID,TestSetNodeProtocol_RebootRecordSurvivesARename(all three failed on the name-keyed code); the existing assertions on/nodes/issuing-1and the name-keyed reboot record now use the node's ID.mainalready; against this branch it adds the api pin anddocs/mcp.md.main.