feat: join-key enrollment (v1.5.0, protocol v1.2.0 1.1)

Installing the agent with one key is now all it takes to add a host.

New `join_key` config field, presented while auth_token is empty. The SSO
exchanges it for this agent's own token and the public key it must pin,
both delivered in the config frame; the agent persists them and blanks
the join key. Nothing has to be copied between two machines by hand.

PersistEnrollment rewrites only the credential lines -- line-based rather
than a YAML round-trip -- so operator comments, the capability matrix and
formatting survive. It re-reads afterwards so the credential is live
without a restart, and keeps the file 0600.

The connect URL carries ?hostname= so a self-enrolling host is named
after itself, and the agent refuses to connect at all (with a long
back-off) when it has no credential rather than presenting an empty one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-06 10:34:06 -04:00
parent dc14274edc
commit 0a5011cd42
8 changed files with 296 additions and 18 deletions
+15 -7
View File
@@ -3,18 +3,26 @@
server_url: "https://sso.example.com"
# Issued by the SSO when you enroll this host (Directory -> Install Agent, or
# POST /api/agent/enroll). The server records only its hash and rejects any
# token it did not issue, so a value invented locally will not connect.
auth_token: "REPLACE_WITH_ISSUED_AGENT_TOKEN"
# This agent's own token. Leave EMPTY when installing with a join key -- the
# agent fills it in itself once the SSO enrolls it. The server records only a
# hash and rejects any token it did not issue, so a locally invented value will
# never connect.
auth_token: ""
# Base64 of the SSO's RAW 32-byte Ed25519 public key -- the `publicKey` value
# from enrollment or GET /api/agent/nodes. This is NOT a PEM body.
# The one credential you need to add a host. Used only while auth_token is
# empty: the SSO exchanges it for this agent's own token + public key on first
# connect, and the agent then blanks this line. Get one from the SSO
# (Directory -> Install Agent, or POST /api/agent/join-keys).
join_key: ""
# Base64 of the SSO's RAW 32-byte Ed25519 public key (NOT a PEM body). Filled in
# automatically when enrolling with a join key; set it by hand only if you
# pre-registered this host.
#
# Required for any high-risk command. Without it the agent still reports
# telemetry, but REFUSES reboot / service_restart / configure_ldap /
# arbitrary_bash / update_binary, because it has no way to verify them.
public_key: "REPLACE_WITH_SSO_PUBLIC_KEY"
public_key: ""
location: "default" # Location identifier (e.g., site, datacenter) for naming