Skip to content

TLS & mTLS

-tls-cert and -tls-key (PEM) enable TLS on the protocol port. The two flags are valid only together. -tls-client-ca adds a PEM certificate-authority (CA) pool for client certificates and enables mutual TLS (mTLS). Each client must show a certificate. The server verifies the certificate against the pool. If the verification fails, the server rejects the connection at the handshake. A client CA without a server certificate and key is a configuration error.

Terminal window
monolock \
-tls-cert /etc/monolock/server.crt \
-tls-key /etc/monolock/server.key \
-tls-client-ca /etc/monolock/clients-ca.crt

The server completes the handshake explicitly before protocol traffic starts. The -io-timeout deadline limits the handshake, the same as each other single read. The server counts failures in monolock_tls_handshake_errors_total.

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. By design, there is no token authentication and no password authentication. If you need ACL (access-control list) authorization or identities in the audit log, then you need mTLS.

The server derives the identity from the verified client certificate. The server uses the first item that is available:

  1. the first URI SAN (Subject Alternative Name; compatible with SPIFFE); if this is not present,
  2. the first DNS SAN; if this is not present,
  3. the Common Name.

Each consumer sees the same string. ACL rules match against the string. The audit log records the string. The admin API shows the string for each holder and each waiter. Without mTLS, the identity is empty.

An example with a SPIFFE-style public-key infrastructure (PKI): a certificate that contains URI:spiffe://prod/worker/7 gives exactly this string as the identity. An ACL rule such as spiffe://prod/worker/* then matches this identity.

SIGHUP reads the three files again. Thus certificates rotate without a restart and without a loss of the open connections. The new files apply to each connection that the server accepts after the signal. A file that does not load keeps its previous value. Thus an unsatisfactory rotation causes stale certificates, not a broken listener.

A typical rotation is only:

Terminal window
cp new-server.crt /etc/monolock/server.crt
cp new-server.key /etc/monolock/server.key
kill -HUP "$(pidof monolock)"

Long lock connections are an advantage here. A session that started under the old certificate continues to operate. A rotation never causes a lock handover.

  1. Create a CA.

    Terminal window
    openssl req -x509 -newkey ed25519 -nodes -subj "/CN=lab-ca" \
    -keyout ca.key -out ca.crt -days 365
  2. Issue the server certificate.

    Terminal window
    openssl req -newkey ed25519 -nodes -subj "/CN=monolock" \
    -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" \
    -keyout server.key -out server.csr
    openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
    -copy_extensions copy -out server.crt -days 90
  3. Issue a client certificate with a SPIFFE-style identity.

    Terminal window
    openssl 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 90
  4. Start the server and connect.

    Start the server with -tls-cert server.crt -tls-key server.key -tls-client-ca ca.crt. Connect with a client that uses client.crt / client.key, and that uses ca.crt as the server CA. The identity of the client everywhere in monolock is spiffe://lab/worker/1.