protection of NSS DB content


This document describes how Directory Server will protect NSS database access. Using Keyring or Clevis/Tang we can prevent NSS sensitive files (passwords, extracted keys and certificates) to be compromised.

Overview

Directory servers installation contains some sensitive files. Relying on the rights of the files looks as a weak protection in case of an attack. The idea is either to remove those files or to make the content of those files useless if compromised. This document details two different approaches Keyring and Clevis/Tang.

Use Cases

DS is configured with secure port. The administrator wants DS be start without being prompted for NSS password. To do So he creates a pin file (pin.txt) that is used to initialize the NSS database and extract key/certs. Someone connected on the Directory server host, with the appropriate rights, can use the pin.txt file to read/write NSS database.

Design


Directory server is a service of systemd, so if it terminates abrutly (a crash) systemd may restart it automatically. In such case the administrator does not want to be prompted for a NSS password and so registers the NSS password in pin.txt file. In order to protect the file we evaluate two options:

Several components are impacted with this change:

The following figure shows the global architecture of systemd/DS using keyring. Clevis and Tang is not the chosen option

Svrcore

principle

Directory servers retrieves NSS password using svrcore framework. This framework call a retrieving method and if the method fails then it calls a fallback. The fallback also registers a method/fallback etc.. Svrcore basically contains a ordered list of retrieval method and fallback. Each method/fallback is registered in a so called plugin. Each DS instance has its own svrcore list method/fallback. The ordered list of retrieval method is:

New plugin

DS retrieves NSS password using svrcore. In order to take into account a new retrieval method (keyring or Clevis/Tang) we need to create a new svrcore plugin (keyring or clevisTang). The plugin defines the retrieval method (using standard callback getPin) and insert it at the appropriate place in the retrieval method/fallback ordered list. With keyring the plugin method is in keyring-ask-password.c and the insertion in std-keyring.c. With ClevisTang the plugin method is in clevistang-ask-password.c and the insertion in std-clevistang.c.

Using keyring or alternatively ClevisTang the resulting ordered list is

setup / getPin

Because the password is stored while being root and needed while being <nsslapd-localuser> (aka as dirsrv) it requires an intermediate step. The password is stored once prompted by systemd. Before the DS deamon calls setuid (detach), DS running as root retrieves the password using keyctl_search/keyctl_read and stores it in a local variable. Then DS starts running as dirsrv and copy the password from the local variable to svrcore keyring plugin during svrcore_setup. Finally when DS needs the password, for NSS/SSL initialization, it calls svrcore getPin (during slapd_ssl_init/slapd_pk11_authenticate.

DS retrieves the password from keyring at the condition security is enabled (nsslapd-security). If nsslapd-security: off NSS password is NULL and during svrcore_setup the svrcore keyring plugin does not register the keyring getPin callback.

Keyring

provisioning

After a reboot of a box hosting the directory server, the keyring does not contain any data. To be provisioned, the first time the directory instance is started (via systemd), the system administrator is prompted (systemd-ask-password) for the NSS password. Then the password is stored (in clear text) in keyring.

At this time the administrator is logged as root and stores the password in ‘@u’ keyring with ‘user’ keytype.

retrieval

Later the password is retrieved by directory server (using svrcore and keyring plugin).

An important point is that keyring provisioning is done by systemd so by root user. The retrieval is done by directory server, that is launched as root but later setuid to <nsslapd-localuser> (aka as dirsrv).

key name

Keyring is a shared repository, so it will contains all the NSS passwords of all instances running on the box. The keyname must differentiate each individual instance. So the keyname has the format: <fixed name><instance_serverid><info_type>, where

Core server

using keyring

It exists two phases that register and later retrieve the password:

If the core server (main.c) uses keyring then it requires the link option -lkeyutils and define build option -DWITH_KEYRING. Indeed core server calls keyctl_search/keyctl_read to retrieve the password from keyring. It does this while the DS deamon is running as root (before detach). When retrieved, it provides the password to NSS/SSL setup rountine (slapd_do_all_nss_ssl_init). This routine first registers (svrcore_setup) the password into the svrcore plugin that handle keyring (std-keyring.c) then later retrieved from svrcore (getPin) during slapd_ssl_init/slapd_pk11_authenticate.

In the first phase, when DS started by systemd retrieves password from keyring, it calls keyctl_read that triggers a Selinux AVC. A new policy is required TBD.

using Clevis/Tang

The idea would be to let a systemd script (in systemd template ExecStartPre) to test if it exists encrypted_pin.txt JSON file. If it does not exist either prompt or read the pin.txt file, encode the password, store it into encrypted_pin.txt and remove pin.txt file.

Tang server

We need a tang server to encrypt and decrypt. If each host has its local own Tang server it is a bit generous. The advantage is it simplifes the process of key rotation and only local instance are impacted in case of problem on the Tang server. If we have a centralized Tang server, it becomes a SPOF and its key rotation will impact all instance using it. It requires to

Clevis client

The Clevis client is used to translate a clear text password file pin.txt into an encrypted one: clevis encrypt tang ‘{“url”, “http://<tang_server_hostname>[:<tang_server_ListenStream>]”}’ < pin.txt > encrypted_pin.txt.

Clevis/Tang not used

Once encrypted into encrypted_pin.txt, the clear text password can be retrieve using clevis descripte command. It requires the rights to access the encrypted_pin.txt file and the access to the tang server. So an attacker logged on the host and having the appropriate access, can decrypt the password and read the NSS database. It adds an additional step (vs pin.txt) but the original concern is the same: It exists a file that gives access to NSS database.

For this reason, Clevis/Tang is not used.

systemd

With keyring a ExecStartPre script must fetch (keyctl search @u user <key_name>) the NSS instance password. If it does not exist (and is required nsslapd-security: on), the script prompts (systemd-ask-password) the administrator and store the password in keyring (keyctl padd user <key_name> @u).

The script (currently ds-keyring.pl) should be integrated into dsctl with new command (dsctl <instance> keyring …)

To allow DS to read the keyring password (keyctl_read), the systemd template must define KeyringMode=shared

Once stored into keyring the password is available until next reboot. That means that if the instance is restarted, it will fetch the password directly from keyring. If it is required to prompt the password at each restart, it is possible to add a ExecStopPost directive to clear/unlink the password.

Selinux

When the core server, running as root, reads keyring (keyctl_read) it triggers an Selinux AVC. The bugzilla #1782896 track the required selinux policy.

container consideration

Keyring is not namespaced and containers are sharing the kernel keyring of the same user. As a consequence the description of the stored key ( Internal (Software) Token:inst_name:password) can be identical on several containers. For containers the description should be enhanced to something like Internal (Software) Token:inst_name:containerId:password.

A workaround, to run DS with security in containers, is that all instances on a box (in a container or not) are defining pin.txt file.

The proposed solution. This may include but is not limited to:

-   new schema
-   syntax of commands
-   logic flow
-   access control considerations

Implementation
--------------

Any additional requirements or changes discovered during the implementation phase.

Major configuration options and enablement
------------------------------------------

Any configuration options? Any commands to enable/disable the feature or turn on/off its parts?

Replication
-----------

Any impact on replication?

Updates and Upgrades
--------------------

Any impact on updates and upgrades?

Dependencies
------------

Any new package and library dependencies.

External Impact
---------------

Impact on other development teams and components

Origin
-------------

A link to the trac ticket or bugzilla

Author
------

<you@redhat.com>
Last modified on 1 March 2024