TLS and mTLS
TLS is off by default. Turn it on and it covers both the client port and the replication port, TLS 1.3 only, with the record layer handed to the kernel (kTLS).
Turning it on
celeriant \
--tls-mode strict \
--tls-ca-cert /etc/celeriant/certs/ca.crt \
--tls-node-cert /etc/celeriant/certs/node.crt \
--tls-node-key /etc/celeriant/certs/node.key \
--tls-client-auth require
--tls-mode is disabled (the default, plaintext only) or strict (TLS only, plaintext refused). There is no mixed mode. With strict, all three paths are required and the server exits at boot if one is missing or unreadable.
The kernel must have TLS support: CONFIG_TLS and the tls module loaded (modprobe tls). The server probes for it at boot and exits if it is absent.
Client auth modes
--tls-client-auth sets what the client port asks of clients:
| Value | Behaviour |
|---|---|
require (default) | Full mTLS. The client must present a certificate signed by the trusted CA. |
optional | Verify a certificate if one is presented; allow anonymous clients. |
none | Server-authenticated TLS only. Client certificates are not requested. |
The replication port always requires a client certificate, whatever this flag says. The nodes authenticate each other with their node certificates.
Splitting client and cluster trust
By default both ports trust --tls-ca-cert and present the node certificate. Two flags separate them:
--tls-intracluster-ca-cert: the replication listener and the outbound replication client trust only this CA. The client listener keeps trusting--tls-ca-cert.--tls-client-cert/--tls-client-key: the certificate the client listener presents in place of the node certificate. Sign it with the client CA.
That gives two trust domains: a client certificate cannot pass as a node, and a node certificate means nothing on the client port. The Pi and EC2 reference clusters both run this way, with --tls-client-auth require.
Hot reload
--tls-cert-reload-interval-secs polls the CA, node and client-facing certificate files every N seconds and reloads on change. New connections get the new certificates; existing ones keep theirs. Reload needs --tls-ca-cert, --tls-node-cert and --tls-node-key all set. Default 0, off.
The same interval drives a reload of api_keys.toml, but only if the file existed at boot.
Generating certificates
The binary ships a cert subcommand. Keys are ECDSA P-256, and every .key file is written with mode 0600.
celeriant cert create-ca --ca-dir /etc/celeriant/ca
celeriant cert create-node node-1.internal 10.0.1.11 \
--ca-dir /etc/celeriant/ca --cert-dir /etc/celeriant/certs
celeriant cert create-client billing \
--ca-dir /etc/celeriant/ca --cert-dir /etc/celeriant/certs
celeriant cert list --cert-dir /etc/celeriant/certs
| Command | Writes | Validity default |
|---|---|---|
create-ca | ca.crt, ca.key | 3650 days |
create-node <hosts...> | node.crt, node.key. Hosts become SANs. Usable as server and client. | 90 days |
create-client <name> | client-<name>.crt, client-<name>.key. CN celeriant-client-<name>. | 90 days |
list | Prints subject, issuer, validity and SANs of every .crt |
Override validity with --validity-days. Ninety days means rotation, so run with hot reload on. For split trust, run create-ca twice into separate directories, sign node certificates with the cluster CA, and sign the client-facing server certificate by running create-node against the client CA into a different directory.
API keys
celeriant keys manages four API keys: a primary and a secondary, each read-write and read-only. Two of each role, so you rotate one while clients use the other.
celeriant keys generate --data-root /var/lib/celeriant
celeriant keys regenerate secondary-rw --data-root /var/lib/celeriant
celeriant keys list --data-root /var/lib/celeriant
generate prints the keys once and writes only their hashes to <data-root>/api_keys.toml (mode 0600). It refuses to overwrite an existing file without --force. Without that file the server does no key checking at all; see Identity.
TLS is not identity
mTLS proves the channel is encrypted and the client holds a trusted certificate. It does not say which client id the client writes as; that is the separate identity handshake, and --require-client-identity enforces less than its name suggests.
API keys and --require-client-identity both need TLS. With either configured and TLS off, the server refuses to start. --insecure-allow-plaintext-auth overrides that for local development and logs a warning.