Browse the docs
Command line
Enroll a machine and run the service
How crunu enroll registers a server with a single-use code and prints its fingerprint, and how the crunu daemon service keeps environments in memory.
Last updated
On this page
A machine is a server with the crunu agent. It gets its own keys at enrollment and then runs the crunu-agent service, which keeps the granted environments decrypted in memory and serves them to crunu run and crunu pull. For the full flow in the web app, see Install the agent.
crunu enroll
crunu enroll [--server URL] [--name NAME] -An owner or admin creates the machine in the web app and gets a single-use enrollment code that starts with crunu_enr_. The code is valid for 15 minutes by default and at most 24 hours, and it can be tied to specific addresses. Pass it on one line through stdin, or in CRUNU_ENROLL_CODE:
printf '%s\n' "$CODE" | sudo crunu enroll --server https://app.crunu.com -crunu enroll refuses a code given as an argument. Arguments are visible to every user of the machine in the process list, so it exits with code 2 before contacting the server and without repeating the code. Giving the code both ways at once is also an error.
What happens next:
crunuchecks that the organization key on the server matches the fingerprint inside the code. If it doesn't match, the code is not presented.- It creates the machine keys and sends their public parts, authenticated with a MAC derived from the code.
- It prints the machine fingerprint on the first line of its output, then says that the machine is waiting for approval. An owner or admin compares this fingerprint with the one in the web app before approving.
Run it as the service user or as root, so the files get the owner of the state directory. The server address comes from --server, then CRUNU_SERVER, then server in agent.json. --name sets the host name the admin will see, which defaults to the system host name. The machine's own name is set by the admin when creating it.
If the connection drops during enrollment
If the server answered 409 because data changed at the same time, crunu enroll retries the same request up to 3 times with a growing pause. If no answer came at all, the outcome is unknown: the keys are kept, no enrollment record is written, and the exit code is 1. Run crunu enroll again with the same code. crunu signs in with the saved keys and learns from the server whether the enrollment went through, without presenting the code a second time. If the server rejected the request outright, nothing was enrolled and the keys are deleted.
crunu daemon
The service runs under systemd as crunu-agent.service. Start it with:
sudo systemctl enable --now crunu-agentIt opens its socket with mode 0660 for the crunu group, then tells systemd it's ready. It signs in with the machine key, checks the server every minute and renews its lease every 5 minutes. Decrypted environments are kept only in memory. Without an enrollment it doesn't start, and the unit checks for one.
| What happened | What the service does | What crunu run gets |
|---|---|---|
| The machine isn't approved yet | Keeps trying at each check | Exit code 5 and a hint to verify the fingerprint |
| The machine was revoked or its lease expired | Wipes the environments from memory | Exit code 4 |
| No connection or a server error | Retries with a growing pause and serves the last verified state until the lease ends | The last verified variables, then exit code 4 after the lease ends |
| Organization data failed verification | Doesn't apply it, logs an alert, serves nothing | Exit code 6 |
| One environment failed verification | Doesn't serve that environment, logs an alert, serves the others | Exit code 6 for that environment |
| The machine's address is outside an environment's network rule | Stops serving that environment at once, unless the machine has a valid machine pass | Exit code 7 for that environment |
crunu is older than the server's minimum agent version | Doesn't sync and explains why in its log | Exit code 1 |
state.json can't be written | Keeps serving the last saved state, no longer than its saved lease | The last saved variables, then exit code 4 |
The service saves its rollback-protection state to state.json before it serves newly verified data. After a restart, the server can't quietly bring back anything older than what the service already served.
SIGHUP makes the service check the server now:
sudo systemctl kill -s HUP crunu-agentSIGTERM wipes the environments from memory and stops the service with exit code 0. systemctl status crunu-agent shows the number of environments, how many are closed by network rules, and when the lease ends.
Service settings
/etc/crunu/agent.json is optional. Without it the service uses the server address from its enrollment and the defaults below. The file is strict JSON, and an unknown key is an error. Updating the agent doesn't change it.
| Key | Default | Meaning |
|---|---|---|
server | the enrollment address | The server address, if the server moved. It must match the server's public address. |
pollInterval | "1m" | How often to check the server. |
renewInterval | "5m" | How often to renew the lease. |
socket | /run/crunu/agent.sock | Socket path. CRUNU_SOCKET takes priority. |
socketGroup | crunu | Group of the socket. Without a group, only root and the service user can connect. |
releasesUrl | built into the release | Release directory for crunu self-update. |
Durations are Go strings such as "30s", "5m" or "1h":
{ "server": "https://vault.company.example", "pollInterval": "30s" }A shorter pollInterval means the service notices a revocation sooner. With the default of one minute, revocation reaches an online machine within minutes. An offline machine keeps serving what it has until its lease ends, 24 hours by default. Programs that are already running keep their variables until they restart.