Securing the sudo to sudo_logsrvd connection

Using sudo_logsrvd to centrally collect sudo session recordings from your network is a huge step forward in security: users cannot delete or modify session recordings locally. However, by default, transmission of recordings is not encrypted, making it open to modifications and eavesdropping. Encrypting the connection between sudo and sudo_logsrvd can eliminate these problems. Larger environments usually either have in-house PKI tooling in place, or colleagues who know all openssl options off the top of their heads. However, small and medium enterprises often lack the infrastructure or knowledge to work with TLS certificates.

This blog can help you to secure connections between sudo and sudo_logsrvd when there is no PKI tooling available to you, or you want to create all the certificates yourself using openssl. It is based on the sudo_logsrvd manual, but changed in such a way that all information is entered on the command line. While interactive certificate generation works fine for a single cert, generating multiple client certificates is easier when everything is on the command line.

Before you begin

To collect sudo recordings you need to use at least sudo version 1.9.0. There were many minor bug fixes related to this feature, so it is recommended to use the latest version available. At the time of writing, this is version 1.9.7p2. Another requirement is to have OpenSSL support enabled in sudo and sudo_logsrvd. Fedora merged my request, so Rawhide has the latest sudo version with OpenSSL support enabled. OpenSUSE Tumbleweed has an up-to-date version and OpenSSL support is expected to be enabled soon. Sudo in FreeBSD works out of box.

For other distributions you can either try to download a binary package from the sudo website, or compile sudo on your own.

You will also need the openssl command line utility to generate the certificates. It is installed by default on most systems.

Note: this blog assumes that OpenSSL configuration is stored in the /etc/ssl directory. If it is not the case, you will have to adjust the path names in configuration files and command line examples.

Creating the certificates

We do everything under the /etc/ssl/sudo directory. As a first step we set up a few files and directories and fix their permissions.

mkdir /etc/ssl/sudo
cd /etc/ssl/sudo
mkdir certs csr newcerts private
chmod 700 private
touch index.txt
echo 1000 > serial

Now copy the openssl configuration file over here and open it in your favorite text editor:

cp ../openssl.cnf .
vi openssl.cnf

Edit the openssl.cnf file in the current directory. Most likely it already has a [CA] and a [CA_default] section, similar to this:

[ ca ]
default_ca      = CA_default

[ CA_default ]
dir             = /etc/ssl/sudo
certs           = $dir/certs
database        = $dir/index.txt
certificate     = $dir/cacert.pem
serial          = $dir/serial

In this case, all you have to change is to make sure that “dir” points to the newly created /etc/ssl/sudo directory. Otherwise, copy the example into your openssl.cnf.

Creating the CA key and certificate

In order to create and sign our own certificates, we need to create a private key and a certificate for the root of the CA. First, create the private key and protect it with a pass phrase:

openssl genrsa -aes256 -out private/cakey.pem 4096
chmod 400 private/cakey.pem

Next, generate the root certificate. While doing it interactively might be easier at first, we provide all values on the command line. You can check the list below to see what the different fields mean:

  • “C” stands for country
  • “L” for location, usually city name
  • “ST” for state (we do not use that here in Hungary, but openssl sometimes complains if it is missing)
  • “O” organization
  • “OU” organizational unit (or department)
  • “CN” stands for common name. In case of a CA, it is the name displayed when you list certificate authorities. In case of client or server certificates, it is the FQDN of the host or its IP address.

Note that from now on you cannot blindly copy and paste command lines from this blog. The command line contains organization and site specific information as well. Change the values according to your environment as necessary.

openssl req -config openssl.cnf -key private/cakey.pem -new -x509 -days 7300 -sha256 -extensions v3_ca -out cacert.pem -subj '/C=HU/L=Budapest/ST=Budapest/O=My Home Ltd/OU=sudo/CN=sudo Root CA'
chmod 444 cacert.pem
openssl x509 -noout -text -in cacert.pem

The last command is not strictly necessary. However it helps you to verify if you entered all information as intended. Here is an example:

localhost:/etc/ssl/sudo # openssl x509 -noout -text -in cacert.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            78:af:5a:28:fa:1c:e2:07:2c:44:4a:17:28:60:00:01:5c:86:27:26
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = HU, L = Budapest, ST = Budapest, O = My Home Ltd, OU = sudo, CN = sudo Root CA
        Validity
            Not Before: Aug  6 11:23:49 2021 GMT
            Not After : Aug  1 11:23:49 2041 GMT
        Subject: C = HU, L = Budapest, ST = Budapest, O = My Home Ltd, OU = sudo, CN = sudo Root CA
        Subject Public Key Info:
[...]

Creating and signing certificates

The server and client certificates will be signed by the previously created root CA. Usually, the root CA is not used to sign server/client certificates directly. Instead, intermediate certificates are created and signed with the root CA and the intermediate certs are used to sign CSRs (Certificate Signing Request). In this example we’ll skip this part for simplicity’s sake and sign the CSRs with the root CA.

First, generate the private key without a pass phrase.

openssl genrsa -out private/logsrvd_key.pem 2048
chmod 400 private/logsrvd_key.pem

Next, create a certificate signing request (CSR) for the server’s certificate and sign it. The organization name must match the name given in the root certificate. The common name should be either the server’s IP address or a fully qualified domain name. The abbreviation of field names is the same as in the previous section, you can check them there.

openssl req -config openssl.cnf -key private/logsrvd_key.pem -new -sha256 -out csr/logsrvd_csr.pem -subj '/C=HU/L=Budapest/ST=Budapest/O=My Home Ltd/OU=sudo/CN=172.16.167.164'
openssl ca -config openssl.cnf -days 375 -notext -md sha256 -in csr/logsrvd_csr.pem -out certs/logsrvd_cert.pem

You can verify the results using:

# openssl verify -CAfile cacert.pem certs/logsrvd_cert.pem
certs/logsrvd_cert.pem: OK

If you want to use peer authentication, you also need to create client certificates. Otherwise, you can skip ahead to configuring TLS in sudo_logsrvd.

Creating the client certificates is practically the same as for sudo_logsrvd. You only need to change the file names and the CN (Common Name) on the command lines. Here are the command lines for your first sudo client:

openssl genrsa -out private/client_key.pem 2048
chmod 400 private/logsrvd_key.pem
openssl req -config openssl.cnf -key private/client_key.pem -new -sha256 -out csr/client_csr.pem -subj '/C=HU/L=Budapest/ST=Budapest/O=My Home Ltd/OU=sudo/CN=172.16.167.153'
openssl ca -config openssl.cnf -days 375 -notext -md sha256 -in csr/client_csr.pem -out certs/client_cert.pem

Copying the certificates

While not strictly part of certificate creation, copying the right files to the right host is important. Here is an example command sequence helping you to figure out which files to copy when you setup a client:

cd ..
tar cvf sudo_client_certs.tgz sudo/cacert.pem sudo/certs/client_cert.pem sudo/private/client_key.pem
scp sudo_client_certs.tgz user@172.16.167.153:

So, we changed to the /etc/ssl directory, created a tar archive from the three necessary files and copied the file to the host, where we configure sudo to forward session recordings to sudo_logsrvd through a TLS encrypted connection.

Configuring sudo and sudo_logsrvd

Now that we have the freshly generated certificates available on the server and possibly also on the client, it is time to configure sudo_logsrvd and sudo. The configuration examples assume that you use the directory structure from the certificate generation command line examples.

I learned the hard way: /etc/sudo_logsrvd.conf, the configuration file for sudo_logsrvd, has several different sections in it. Make sure that you edit the [server] section when you enable TLS, otherwise you will receive some frightening error messages. The content of some sections is similar, so double-check that you are in the right section.

# Listen on port 30344 for TLS connections to any address.
listen_address = *:30344(tls)
# Path to the certificate authority bundle file in PEM format.
tls_cacert = /etc/ssl/sudo/cacert.pem
# Path to the server's certificate file in PEM format.
tls_cert = /etc/ssl/sudo/certs/logsrvd_cert.pem
# Path to the server's private key file in PEM format.
tls_key = /etc/ssl/sudo/private/logsrvd_key.pem

With these settings you should already be able to receive TLS encrypted connections from sudo clients. You can configure two additional settings to further secure communications:

  • tls_verify - sudo_logsrvd will validate its own certificate at startup
  • tls_checkpeer - sudo_logsrvd will validate the certificates of clients that connect to it

If peer authentication is enabled on the client, a copy of cacert.pem must be present on the client system too. And this leads us to client configuration. Here is a minimal configuration:

Defaults log_servers = 172.16.167.164:30344(tls)
Defaults log_output

This configuration enables session recording and sends the results to the given address using TLS encryption. There is no peer verification, but at least the data is not clear text on the wire. There are many more possible configuration options:

Defaults ignore_iolog_errors
Defaults log_servers = 172.16.167.164:30344(tls)
Defaults log_output
Defaults log_input
Defaults log_server_cabundle = /etc/ssl/sudo/cacert.pem
Defaults log_server_peer_cert = /etc/ssl/sudo/certs/client_cert.pem
Defaults log_server_peer_key = /etc/ssl/sudo/private/client_key.pem
Defaults log_server_verify

The names are pretty self-explanatory, but let me give you a quick explanation for each of them.

  • By default sudo does not authorize commands to execute when sudo_logsrvd is inaccessible; ignore_iolog_errors makes sure that sudo works even in this situation
  • log_server_cabundle / log_server_peer_cert / log_server_peer_key point to the various certificates enabling peer authentication
  • log_server_verify instructs the client to verify the server’s certificate

Testing

If you configured everything properly, using sudo should not be any different. Just enter commands as usual and they should work just as they did before. The difference is that you should now be able to see your session recordings on the host running sudo_logsrvd.

Here is the output of sudoreplay on an openSUSE host running sudo_logsrvd, showing recordings from sudo running on a Fedora 34 host:

Aug  3 14:31:50 2021 : czanik : TTY=/dev/pts/0 ; CWD=/home/czanik ; USER=root ; HOST=fedora34.localdomain ; TSID=000015 ; COMMAND=/usr/bin/ls /root/
Aug  6 13:49:17 2021 : czanik : TTY=/dev/pts/0 ; CWD=/home/czanik ; USER=root ; HOST=fedora34.localdomain ; TSID=000016 ; COMMAND=/bin/bash

If you would like to be notified about new posts and sudo news, sign up for the sudo blog announcement mailing list.