Certificate Agent
A small daemon-less program that keeps TLS certificates current on a host: renews them before they expire, writes the bundle where your service expects it, and reloads that service — only when something actually changed.
It closes the last gap in certificate automation. ScaiVault already renews certificates on a schedule, but until now getting the renewed material onto the machine that serves it was manual.
Install#
1 | |
Get the wheel from https://www.scailabs.ai/downloads under ScaiVault.
It depends on cryptography and httpx and nothing else — it does not require the ScaiVault server, so installing it on a web server does not put a secrets manager's database drivers in your DMZ. Python 3.11+, Linux/systemd.
Enrol the host#
Rather than copying a long-lived API key onto every machine, mint a short-lived token and let the host trade it for its own credential:
1 2 3 4 5 6 7 | |
The host receives its own service account, named after its hostname, so it can be revoked individually. See Enrollment for the full API.
A long-lived key still works if you prefer: write it to /etc/scaivault/agent.key with mode 0600.
Add a certificate#
1 | |
This infers the four things you would otherwise have to look up — the certificate path, the CA to sign against, the output directory, and the correct reload command — then prints the config to paste:
1 2 3 4 5 6 7 8 9 10 11 12 | |
Then:
1 2 3 | |
scaivault-agent services lists the services it knows and marks the ones installed on this host.
Key modes#
Set per certificate, because not every certificate type can use a locally generated key.
| Mode | Key handling | Scope needed |
|---|---|---|
csr (default) |
Generated on the host; only a CSR is sent. The private key never crosses the network. | pki:write |
managed |
Key lives in ScaiVault and is downloaded. Needed where the key is not the agent's to generate — ACME above all. | pki:export-key |
Prefer csr. A stolen agent credential can then request certificates but cannot exfiltrate existing private keys. Scope managed service accounts to only the paths that host serves.
The agent will not silently fall back from csr to managed: a CSR that will not sign is an error to report, not to work around.
Supported services#
Each profile knows how to reload safely and which files the service wants.
| Service | Files it uses | Reload |
|---|---|---|
| nginx | fullchain.pem + privkey.pem |
nginx -t && systemctl reload nginx |
| Apache | certificate.pem + chain.pem + privkey.pem |
apachectl configtest && systemctl reload apache2 |
| HAProxy | combined haproxy.pem (built by the hook) |
haproxy -c -f … && systemctl reload haproxy |
| Postfix | fullchain.pem + privkey.pem (group-readable) |
postfix check && systemctl reload postfix |
| Dovecot | fullchain.pem + privkey.pem (group-readable) |
doveconf -n && systemctl reload dovecot |
Every reload validates the configuration first. That turns "the reload broke the site" into "the reload refused, the old certificate is still serving".
Postfix and Dovecot run unprivileged, so those profiles set a group and a 0640 key mode automatically — a root-only 0600 key would silently break them.
Files written#
| File | Contents |
|---|---|
certificate.pem |
leaf only |
chain.pem |
issuer chain |
fullchain.pem |
leaf + chain |
privkey.pem |
private key, 0600 unless the service needs otherwise |
Writes are atomic: each file goes to a temporary file in the same directory with ownership and mode already applied, then rename(). A service reloading concurrently never reads a half-written PEM.
Scheduling#
The agent is a one-shot process, not a daemon. The bundled systemd timer runs it twice daily with up to an hour of jitter so a fleet does not stampede the API. A run with nothing due makes no API calls at all.
Exit codes#
| Code | Meaning |
|---|---|
0 |
everything current, or renewed and reloaded cleanly |
1 |
configuration error |
2 |
a certificate failed to renew, or a reload hook failed |
3 |
ScaiVault unreachable |
2 and 3 are distinct on purpose: "one host's reload hook is broken" is a different alert from "the CA is down".
Fleet visibility#
After each run the agent reports what it manages, so you can see which hosts are about to break without ssh-ing into each one. See Fleet.
Set report_status = false under [agent] for hosts that must not phone home. A check-in failure never affects renewal — by that point the certificates are already deployed.
Other platforms#
Linux/systemd today. The wire contract — config schema, state file, exit codes, reload semantics — is specified language-agnostically in PROTOCOL.md inside the distribution, so a Go or C# build for Windows/IIS is a port rather than a redesign.
What's next#
- Enrollment — minting and redeeming tokens.
- Fleet — which hosts are about to break.
- PKI — the certificate API the agent uses.