Canonfig
Reference

Security and credentials

Look up what Canonfig signs and sends between machines, where it stores credentials on each platform, and how to revoke a Follower Machine.

What leaves each machine

DataWhere it goesHow it travels
Profile Revisions and the files they nameSource Machine to Follower MachinesHTTPS pinned at enrollment, signed by the Source Machine
Shared secrets (opt-in only)Source Machine to Follower Machines in the canonfig:secrets groupThe same pinned HTTPS connection
Follower Machine status and run resultsStay on the Follower MachineNot sent
Local Overlay keys and local append-local textStay on the Follower MachineNot sent
credential resource valuesNever sent; the profile holds only a referenceNot sent
Command logStays on the machineNot sent

Everything in a profile, including inline content and every source file, is published to every Follower Machine that selects the profile. Do not put tokens, passwords, private keys, or cookies in profile content.

Canonfig signs Profile Revisions and pins the connection; it does not encrypt profile content at rest. Follower Machines write applied files with the modes the profile declares (0600 by default).

Source keys

canonfig source init creates the Source Machine's signing key, HTTPS private key, and certificate, and stores them in the native credential store. Anyone who can read them, or copy ~/.canonfig/state.sqlite together with them, can publish Profile Revisions your Follower Machines accept. Protect the Source Machine's user account accordingly.

Each Canonfig state directory has its own key names, so two Source Machines under one OS account do not overwrite each other's keys.

Running canonfig source init again never creates another identity. It checks that the stored keys match the fingerprints recorded at initialization. If they do not, Canonfig signs and serves nothing and fails with exit 4:

The native credential store no longer holds this Source's own credentials: <which>. They were not used, so nothing was signed or served as another Source. This Source's keys cannot be recovered from the store: move this state directory aside, run canonfig source init to create a new Source identity, then enroll its followers again with new invitations.

Transport trust

canonfig source serve listens on a loopback address only (127.0.0.1 or ::1). A Follower Machine on another host connects through the managed SSH tunnel, canonfig tunnel start.

Trust is set on first use, at enrollment. The invitation file carries the Source Machine's HTTPS certificate fingerprint and signing key fingerprint, and the Follower Machine pins both. Treat the invitation file as a secret: anyone who holds it before it expires can enroll one machine. It is single-use, valid for 15 minutes unless you pass --expires (at most 24 hours), and written with mode 0600. Move it over a private channel.

After enrollment, the Follower Machine rejects:

  • a different HTTPS certificate;
  • a Profile Revision with an invalid signature, or a file whose digest does not match;
  • a reused invitation;
  • a revoked Follower Identity (exit 5).

The tunnel also pins the SSH host key you pass with --ssh-host-key-file, and refuses options that turn off host key checking or add forwards.

The Source Machine and each Follower Machine must run the same major.minor release. A mismatch fails with a "source/follower version mismatch" error (exit 2), never a signature error.

Follower credentials

Each Follower Machine gets its own credential at enrollment, its Follower Identity, stored in its native credential store. Follower Machines never share a token, so revoking one does not affect the others.

OSCredential store
LinuxSecret Service (for example GNOME Keyring), when it can be used without a prompt
macOSThe login Keychain
WindowsCredential Manager
AnyA plaintext file with mode 0600, only when you choose it with CANONFIG_LOCAL_CREDENTIAL_ROOT

Canonfig never falls back to a plaintext file on its own. When no secure store is usable, enrollment fails with Human Action Required, before it uses up the invitation. The store a Follower Machine enrolled with is recorded and used by later runs, including scheduled ones.

Credential lifecycle

EventWhat happens
Enrollment fails or you cancel itThe credentials it created are removed on both machines.
You enroll a name that is already activeRefused with "the follower identity is already enrolled". The existing credential is unchanged. Revoke the name on the Source Machine first.
canonfig follower enroll --replace with a different nameThe identity under the other name is enrolled first, then the old one is revoked and its local credential deleted. The output lists every local setting that was reset.
canonfig source revoke <follower-id> on the Source MachineThe Follower Machine is revoked. Its next request fails with exit 5.
canonfig follower unenroll on the Follower MachineThe identity is revoked on the Source Machine, then the local credential, received shared secrets, and enrollment record are deleted.

canonfig follower unenroll deletes the local credential even when the Source Machine is unreachable. The output then shows sourceRevoked: false and the canonfig source revoke <id> command to run on the Source Machine. Applied files, the schedule, and the tunnel record stay; remove the last two with:

canonfig schedule remove
canonfig tunnel stop --forget

Local credential-store failures

When Canonfig cannot read or write this machine's own credential store, the command fails with exit 3 (Human Action Required), not exit 5, and prints the store's own recovery text. For example, during canonfig sync:

the follower credential could not be read from this machine's credential store: …

Linux. Canonfig reaches Secret Service through DBUS_SESSION_BUS_ADDRESS, or the socket at $XDG_RUNTIME_DIR/bus. From a background shell, set XDG_RUNTIME_DIR=/run/user/$(id -u). If that socket does not exist, no user session manager is running; sudo loginctl enable-linger <user> starts one. The login keyring must also be unlocked, which a password login does. A private dbus-run-session bus does not work. Run canonfig secrets bootstrap to check the store end to end; see Headless Linux credential storage.

macOS. Over SSH or in the background, the login Keychain is often locked:

The login Keychain is locked in this SSH or background session. To continue in this session, run security unlock-keychain ~/Library/Keychains/login.keychain-db and retry; the unlock lasts only for this session and does not carry over to new SSH sessions, the desktop session, or scheduled runs. Scheduled runs need the logged-in desktop session (launchd domain gui/<uid>).

Windows. An OpenSSH session that signed in with a public key may have no access to Credential Manager. Set up credentials from the signed-in desktop session. On Windows 10 ARM64, install PowerShell 7 in %ProgramFiles%\PowerShell\7\pwsh.exe, or set CANONFIG_POWERSHELL to its path.

Opt-in shared secrets

Canonfig sends secret values to a Follower Machine only when you enroll it with the canonfig:secrets group:

canonfig source invite --endpoint https://127.0.0.1:17342 --output ./canonfig-invite --group canonfig:secrets

Set a secret on the Source Machine through standard input, so the value never appears in the process list or shell history:

printf '%s' "$GITHUB_TOKEN" | canonfig secrets set github-token

A successful canonfig sync --apply then copies the authorized secrets to the Follower Machine. canonfig secrets sync retries the copy on its own.

  • Values travel only over the pinned HTTPS connection and are written straight to the Follower Machine's native credential store. The state database, Profile Revisions, and canonfig secrets list hold only names and origins.
  • Canonfig reads every stored value back and compares it before reporting success. If the store returns different bytes, Canonfig deletes the item and fails with exit 3.
  • Follower Machines never pass the Source Machine's secrets on to other machines.
  • When you remove a secret on the Source Machine, Follower Machines delete their copy on the next apply.
  • canonfig secrets set and secret transfer require a secure store. A plaintext CANONFIG_LOCAL_CREDENTIAL_ROOT file is not accepted for shared secrets.

Value limits

  • At most 16384 bytes of valid UTF-8, not empty, with no NUL byte.
  • Piped input is stored exactly, including a trailing newline. Use printf '%s', not echo.
  • At a terminal, input is hidden and the final Enter is not stored.
  • A pipe must end within 10 seconds.

Secret ownership

On a Follower Machine, canonfig secrets set refuses to overwrite a name the Source Machine owns. Change the value on the Source Machine, or pick another local name.

If another Canonfig process is changing secrets, the command fails with exit 3 before changing anything; a Follower Machine's fetch from a busy Source Machine fails with exit 6. Wait for the other process to finish and retry.

Secrets in output and logs

Canonfig removes configured secret values from captured command arguments, output, and JSON results before it stores or prints them. Treat this as a safety net: keep secrets off command lines and out of profiles in the first place.

The command log, ~/.canonfig/canonfig.log, records only the command name, time, process ID, duration, and exit code. It never records arguments, output, invitations, or secret values. It is readable only by your user (mode 0600, or a user-only ACL on Windows). Set CANONFIG_LOG=off to turn it off, or CANONFIG_LOG_FILE to write it elsewhere.

CANONFIG_DEBUG=1 adds error details to the output of an internal failure (exit 1). Read that text before sharing it; it can include paths.

Agent limits

A Configuration Agent runs only inside the paths, programs, HTTPS origins, and capabilities you allow with canonfig agent harness. Canonfig starts programs directly, without a shell. An agent's report never counts as success; the resource's own verification does. See Let a Configuration Agent resolve work.

Audit a machine

canonfig doctor --no-input
canonfig status --json
canonfig secrets list --json

doctor checks the credential store and the connection to the Source Machine, status shows the applied Profile Revision and the last run, and secrets list shows secret names and where each came from.

On this page