TLS & mTLS
-tls-cert and -tls-key (PEM) enable TLS on the protocol port; they are
only valid together. -tls-client-ca adds a PEM CA pool for client
certificates and enables mTLS: every client must present a certificate
that verifies against the pool, and the connection is rejected at the
handshake otherwise. A client CA without a server certificate and key is a
configuration error.
monolock \ -tls-cert /etc/monolock/server.crt \ -tls-key /etc/monolock/server.key \ -tls-client-ca /etc/monolock/clients-ca.crtThe handshake is completed explicitly before any protocol traffic, bounded by
-io-timeout like any other single read; failures are counted in
monolock_tls_handshake_errors_total.
The three modes
Section titled “The three modes”| Configuration | Transport | Client identity |
|---|---|---|
| no TLS flags | plaintext TCP | empty |
-tls-cert + -tls-key |
encrypted | empty |
… + -tls-client-ca |
encrypted, both sides authenticated | derived from the client certificate |
mTLS is the only source of client identity — there is deliberately no token or password authentication. If you need ACL authorization or identities in the audit log, you need mTLS.
Client identity
Section titled “Client identity”The identity is derived from the verified client certificate:
- the first URI SAN (SPIFFE-friendly), else
- the first DNS SAN, else
- the Common Name.
Every consumer sees the same string: ACL rules match against it, the audit log records it, and the admin API shows it per holder and waiter. Without mTLS the identity is empty.
With a SPIFFE-style PKI a certificate carrying
URI:spiffe://prod/worker/7 yields exactly that string as the identity, which
is what an ACL rule like spiffe://prod/worker/* then matches.
Certificate reload
Section titled “Certificate reload”SIGHUP re-reads all three files, so certificates rotate without a restart
and without dropping existing connections; the new files apply to every
connection accepted after the signal. A file that fails to load keeps its
previous value, so a botched rotation degrades to stale certificates instead
of a broken listener.
A typical rotation is just:
cp new-server.crt /etc/monolock/server.crtcp new-server.key /etc/monolock/server.keykill -HUP "$(pidof monolock)"Long-lived lock connections are a feature here: a session established under the old certificate keeps running — rotation never causes a lock handover.
A lab PKI in four commands
Section titled “A lab PKI in four commands”For local experiments (not production key management):
# CAopenssl req -x509 -newkey ed25519 -nodes -subj "/CN=lab-ca" \ -keyout ca.key -out ca.crt -days 365# server certificateopenssl req -newkey ed25519 -nodes -subj "/CN=monolock" \ -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" \ -keyout server.key -out server.csropenssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \ -copy_extensions copy -out server.crt -days 90# client certificate with a SPIFFE-style identityopenssl req -newkey ed25519 -nodes -subj "/CN=worker" \ -addext "subjectAltName=URI:spiffe://lab/worker/1" \ -keyout client.key -out client.csr && \openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \ -copy_extensions copy -out client.crt -days 90Then run the server with -tls-cert server.crt -tls-key server.key -tls-client-ca ca.crt, and connect with a client configured for
client.crt / client.key and ca.crt as the server CA. The client’s
identity everywhere in monolock is spiffe://lab/worker/1.

