Secrets on the host
The agent's secrets file — where it lives, what permissions it needs, what happens when a value is missing, and why values never leave the machine.
A secret has two halves. The job in Runjet names what it needs, and the agent on the host fills in the value. This page is that second half; the first — how to add a secret to a job and how it is shown — is on the secrets page.
The values live here and nowhere else in the system. Runjet stores only names, only names travel in a dispatch, and a compromised control plane cannot give up what it never had.
The secrets file
AGENT_SECRETS_FILE in the
configuration points at a
KEY=value file, usually beside agent.env:
# Comments and blank lines are skipped.
DB_PASSWORD=s3cr3t with spaces is fine
S3_TOKEN=AKIA…It is read verbatim: the key is trimmed of spaces, the value is taken as it
stands after the first =. A secret may begin or end with a space, and trimming
it quietly would produce a failure that looks like a wrong password. A line with
no = stops the agent, with the line number.
Permissions 0600, owned by root or by the agent's account. At startup the
agent checks the mode and logs a warning if the file is readable by others —
only it should read the file, and what keeps jobs out of it is
an account of its own. A file named in
AGENT_SECRETS_FILE that does not exist stops the agent; an unset variable
simply means "no file".
The file is read at startup. A new secret takes effect after
systemctl restart runjet-agent.
The fallback to the service's environment
A name that is not in the file is looked for by the agent in its own
environment — so a secret can be supplied by the systemd unit or by -e on a
container without a file at all. The environment is taken once at startup; what
a job is given depends on how the agent was configured, not on when its run
happened to begin.
Two things are lost that way. The agent cannot tell which of its environment variables are secrets, so it will not warn you about a value too short to mask. And the service's environment is visible to anyone who can read the unit. A file is the better choice where you have one.
When a value is missing
A job that names a secret whose value the agent does not have does not run.
The run ends failed with the sentence this agent has no value for DB_PASSWORD
— substituting an empty string would be worse than useless: the backup would be
written somewhere else, the API call would go through quietly without
credentials, and the run would report success.
The agent fills in values after it has reported the run as started, precisely so that a missing secret is a failure with an explanation rather than an orphaned run that a sweep would blame on a silent agent. So a job running on several agents may succeed on one and fail on another — every host has its own secrets.
Short values
Values shorter than five characters are not masked by the agent in the output; for the file, it names them at startup. Why, and why masking is a net rather than a boundary, is in job isolation.