refactor(orchestrator): uniform control-plane auth provisioning per trust domain #482
Reference in New Issue
Block a user
Delete Branch "didericis/refactor/control-plane-auth-provisioning-476"
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?
Closes #476.
Hoists control-plane auth provisioning out of the per-backend launchers into one shared contract, parameterized per trust domain (
bot_bottle/trust_domain.py):TrustDomain— one credential boundary (host-canonical key file + role set + env vars).mint/verifyare scoped to the domain's roles, so a future host-controller domain (#468) uses its own key/verifier/roles rather than ahostrole on the control plane's frozenset.ControlPlaneProvisioning— the single seam answering the four invariants: host-canonical key, split key-vs-token credential, CLI token valid across co-running backends, and fail-closed (no open mode) for any co-located topology.Topology— the backend declares what it is; default is co-located + fail-closed, so a backend need not redeclare it.The
OrchestratorABC getscontrol_plane_key()(fail-closed) and routesmint_gateway_token()through the contract; the docker/macOS/firecracker orchestrators, the server (verify), and the host CLI client (mintcli) all go through the domain instead of reading the host key directly.orchestrator_authgains an optionalroles=arg (default unchanged) andpaths.host_signing_key(filename)generalizeshost_orchestrator_token.Durable rationale in
docs/prds/prd-new-control-plane-auth-provisioning.md. Based onfix/db-off-data-plane-469(#471), which #476 depends on.@didericis-claude the wording in the PRD and in the comments is very generic and verbose. Can you tighten it up and talk about the specific SERVICES (orchestrator, host controller) instead of using generic terms, and what specifically this buys us?
The main reason I approved this is I didn't want the orchestrator minting the keys it uses to communicate with the host controller. That's a good change. But the way this is described is confusing.
Good call — reworded the PRD and the docstrings around the concrete services and lead with the specific win.
The framing is now: the orchestrator holds the control-plane key and mints the gateway's/CLI's tokens; the host controller (#468) gets a separate key the orchestrator never holds — so the orchestrator can't mint the credentials it uses to talk to the host controller that starts and stops it. The PRD's Problem section opens with exactly that (adding a
hostrole to the orchestrator's key is the anti-pattern this rules out), and the second win — retiring the hand-rolled per-backend provisioning behind PR #471 — is stated as secondary.Cut the generic "credential boundary" language throughout
trust_domain.py,orchestrator_auth.mint, andpaths.host_signing_keyin favor of "the orchestrator's key" / "a separate service's key". No behaviour change — docs and comments only (784e492).784e49239dto8f6148d571The current backends are wired consistently and the focused auth/backend tests pass, but I think the new topology opt-out weakens the invariant it is meant to encode.
Blocking:
ControlPlaneProvisioning.orchestrator_key()allows an empty key wheneverdata_plane_shares_control_host=False, andtest_orchestrator_key_allows_empty_when_isolatedmakes that behavior contractual. Being on a different host does not prevent the gateway from reaching the orchestrator—in fact the gateway must reach/resolve—so an open orchestrator would still treat that gateway asROLE_CLIand expose CLI-only routes. The safety condition is network isolation/authorization, not host co-location.Please either remove the empty-key opt-out and always fail closed for provisioned deployments, or model and enforce a stronger condition that proves untrusted/data-plane callers cannot reach the control-plane listener. Merely declaring a separate host should not disable authentication.
Verification:
python3 -m unittest -v tests.unit.test_trust_domain tests.unit.test_orchestrator_auth tests.unit.test_orchestrator_client tests.unit.test_docker_orchestrator tests.unit.test_macos_orchestrator tests.unit.test_firecracker_orchestrator(91 tests, all passed).@didericis-claude remove the empty-key opt-out @didericis-codex identified
Done — removed the empty-key opt-out entirely (
e53104d).ControlPlaneProvisioning.orchestrator_key()now fail-closes unconditionally: no signing key →ProvisioningError, for every backend. @didericis-codex was right that host separation is not the safety condition — the gateway must reach the control plane for/resolve, so an open orchestrator would still hand any caller that reaches it fullcli. Declaring a separate host no longer disables auth.Since the
Topology/data_plane_shares_control_hostmachinery existed only to gate that opt-out (no backend ever declared a non-default topology), I dropped it along with the contractualtest_orchestrator_key_allows_empty_when_isolated. PRD invariant 4 and the lifecycle docstring now state the key is mandatory with no topology opt-out. Auth/backend suite: 90 tests, all pass.Re-reviewed at
e53104d. The previous blocking issue is resolved: the topology-based empty-key opt-out has been removed, andControlPlaneProvisioning.orchestrator_key()now fails closed unconditionally. The corresponding unsafe test contract was removed and replaced with coverage for the unconditional failure.I found no further actionable issues.
Verification:
git diff --check origin/main...HEADpython3 -m unittest -v tests.unit.test_trust_domain tests.unit.test_orchestrator_auth tests.unit.test_orchestrator_client tests.unit.test_docker_orchestrator tests.unit.test_macos_orchestrator tests.unit.test_firecracker_orchestrator(90 tests, all passed)Re-reviewed at
e53104d. The previous blocking issue is resolved: the topology-based empty-key opt-out has been removed, andControlPlaneProvisioning.orchestrator_key()now fails closed unconditionally. The corresponding unsafe test contract was removed and replaced with coverage for the unconditional failure.I found no further actionable issues.
Verification:
git diff --check origin/main...HEADpython3 -m unittest -v tests.unit.test_trust_domain tests.unit.test_orchestrator_auth tests.unit.test_orchestrator_client tests.unit.test_docker_orchestrator tests.unit.test_macos_orchestrator tests.unit.test_firecracker_orchestrator(90 tests, all passed)