Systemd Activatable Responders

Problem statement

SSSD has some responders which don’t have to be running all the time, but could be socket-activated or dbus-activated instead on platforms where it’s supported. That’s the case, for instance, for the IFP, SSH and Sudo responders.

Making these responders socket-activated or dbus-activated would provide a better user experience, as these services could be started on-demand when a client needs them and exit after a period of inactivity.

Currently, the Administrator has to explicitly list all the services that might be potentially needed in the services line of [sssd] section and those processes will be running all the time.

Use cases

  • sssctl: As more and more features had been added depending on the IFP responder being activated, leaving this responder to be started on-demand instead of having the admins explicitly setting them up is desired;
  • KCM: The KCM responder is only seldom needed, when libkrb5 needs to access the credentials store. At the same time, the KCM responder must be running if Kerberos credentials cache defaults to KCM. Socket-activating this responder would solve both of the cases;
  • AutoFS: The AutoFS responder is typically needed only when a shared directory is about to be mounted.

Overview of the solution

The solution agreed on the mailing list is to add a new unit file for each one of the responders. Once a responder is started, it will communicated to the monitor in order to let the monitor know that it’s up and then the monitor will take care of registering the responder, which basically consists in marking the service as started, increasing the services’ counter, getting the responders’ configuration and finally adding the responder to the services’ list. A configurable idle timeout will be implemented the responders, in order to shut the process down in case it becomes idle.

Implementation details

In order to achieve our goal we will need some small modifications in the responders’ common code to make those ready for socket-activation, add a systemd unit file for each of the responders, add a new binary file to ensure that the Administrator won’t mix up those two methods of starting services (for the very same service) and finally do some changes in the monitor code for managing the socket-activated service.

The change in the responders’ common code is quite trivial and goes towards calling activate_unix_sockets() function instead of set_unix_socket(). The important part around this change is to avoid the responders’ file descriptors to be set as -1 in all cases as it would cause the socket to be unreachable in case the Administrator decides to move back from using the socket-activated services to the default way.

The systemd units for the responders will look like:
  • NSS responder: NSS is a really special case as it cannot have be run as unprivileged user. It happens because libc does initgroups on pretty much any account and initgroups checks all NSS modules in order to be precise, causing nss_sss to trigger the NSS responder … so a cycle dependency would happen.

    • sssd-nss.service:

      [Unit]
      Description=SSSD NSS Service responder
      Documentation=man:sssd.conf(5)
      After=sssd.service
      BindsTo=sssd.service
      RefuseManualStart=true
      
      [Install]
      Also=sssd-nss.socket
      
      [Service]
      ExecStart=@libexecdir@/sssd/sssd_nss --debug-to-files --socket-activated
      Restart=on-failure
      
    • sssd-nss.socket:

      [Unit]
      Description=SSSD NSS Service responder socket
      Documentation=man:sssd.conf(5)
      After=sssd.service
      BindsTo=sssd.service
      Before=sssd-autofs.socket sssd-pac.socket sssd-pam.socket sssd-ssh.socket sssd-sudo.socket
      DefaultDependencies=no
      Conflicts=shutdown.target
      
      [Socket]
      ExecStartPre=@libexecdir@/sssd/sssd_check_socket_activated_responders -r nss
      ListenStream=@pipepath@/nss
      
      [Install]
      WantedBy=sssd.service
      
  • PAM responder: PAM is a little bit special as it has two sockets associated to itself.

    • sssd-pam.service:

      [Unit]
      Description=SSSD PAM Service responder
      Documentation=man:sssd.conf(5)
      After=sssd.service
      BindsTo=sssd.service
      RefuseManualStart=true
      
      [Install]
      Also=sssd-pam.socket sssd-pam-priv.socket
      
      [Service]
      ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_pam.log
      ExecStart=@libexecdir@/sssd/sssd_pam --debug-to-files --socket-activated
      Restart=on-failure
      User=@SSSD_USER@
      Group=@SSSD_USER@
      PermissionsStartOnly=true
      
    • sssd-pam.socket:

      [Unit]
      Description=SSSD PAM Service responder socket
      Documentation=man:sssd.conf(5)
      After=sssd.service
      BindsTo=sssd.service
      BindsTo=sssd-pam-priv.socket
      DefaultDependencies=no
      Conflicts=shutdown.target
      
      [Socket]
      ExecStartPre=@libexecdir@/sssd/sssd_check_socket_activated_responders -r pam
      ListenStream=@pipepath@/pam
      SocketUser=root
      SocketGroup=root
      
      [Install]
      WantedBy=sssd.service
      
    • sssd-pam-private.socket:

      [Unit]
      Description=SSSD PAM Service responder private socket
      Documentation=man:sssd.conf(5)
      After=sssd.service
      BindsTo=sssd.service
      BindsTo=sssd-pam.socket
      DefaultDependencies=no
      Conflicts=shutdown.target
      
      [Socket]
      ExecStartPre=@libexecdir@/sssd/sssd_check_socket_activated_responders -r pam
      Service=sssd-pam.service
      ListenStream=@pipepath@/private/pam
      SocketUser=root
      SocketGroup=root
      SocketMode=0600
      
      [Install]
      WantedBy=sssd.service
      
  • AutoFS, PAC, Ssh and Sudo responders:

    • sssd-@responder@.service:

      [Unit]
      Description=SSSD @responder@ Service responder
      Documentation=man:sssd.conf(5)
      After=sssd.service
      BindsTo=sssd.service
      RefuseManualStart=true
      
      [Install]
      Also=sssd-@responder@.socket
      
      [Service]
      ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_autofs.log
      ExecStart=@libexecdir@/sssd/sssd_@responder@ --debug-to-files --socket-activated
      Restart=on-failure
      User=@SSSD_USER@
      Group=@SSSD_USER@
      PermissionsStartOnly=true
      
    • sssd-@responder@.socket:

      [Unit]
      Description=SSSD @responder@ Service responder socket
      Documentation=man:sssd.conf(5)
      After=sssd.service
      BindsTo=sssd.service
      DefaultDependencies=no
      Conflicts=shutdown.target
      
      [Socket]
      ExecStartPre=@libexecdir@/sssd/sssd_check_socket_activated_responders -r @responder@
      ListenStream=@pipepath@/@responder@
      SocketUser=@SSSD_USER@
      SocketGroup=@SSSD_USER@
      
      [Install]
      WantedBy=sssd.service
      
  • IFP responder: While the other responders are going to be socket-activated, IFP will be dbus-activated:

    • sssd-ifp.service:

      [Unit]
      Description=SSSD IFP Service responder
      Documentation=man:sssd-ifp(5)
      After=sssd.service
      BindsTo=sssd.service
      
      [Service]
      Type=dbus
      BusName=org.freedesktop.sssd.infopipe
      ExecStart=@libexecdir@/sssd/sssd_ifp --uid 0 --gid 0 --debug-to-files --dbus-activated
      Restart=on-failure
      

The newly added binary does nothing but check in the config files whether the responder that is about to be activated is also listed in the services of the configuration file. In case it’s there, the services’ socket is not started, fallbacking to the default way.

And, finally, the code on the monitor side will have to have some adjustments in order to properly deal with an empty list of services and, also, to register the service when it is stated.

As just the responders will be socket-activated (for now), the service type will have to be exposed and passed through sbus when calling the RegistrationService method and then the monitor will properly do the services’ registration when the method’s callback is triggered. As mentioned before, the registration that has to be done consists in:

  • Marking the service as started;
  • Increasing the services’ counter;
  • Getting the services’ configuration;
  • Setting the services’ restart number;
  • Adding the service to the services’ list;

Unregistering a socket-activated responder will also be done by the monitor when the connection between the service and the monitor is closed.

Configuration changes

After this design is implemented, the services line in sssd.conf will become optional for platforms where systemd is present. Note that in order to keep backward compatibility, if the services line is present, the services will behave exactly as they did before these changes.

How To Test

The easiest way to test is removing the service from sssd.conf’s services line, enabling the service’s socket and trying to use SSSD normally.

See below an example of how to enable NSS and PAM sockets:

# systemctl enable sssd-nss.socket sssd-pam.socket
# systemctl start sssd-nss.socket sssd-pam.socket

Using sssctl tool without having the IFP responder set in the services line is another way to test.

How To Debug

The easiest way to debug this new feature is taking a look on the responders’ common initialization code and in the monitors’ client registration code.

Is worth to mention that disabling the systemd’s sockets will prevent the responders’ services to be started.

Authors

Fabiano Fidencio <fidencio@redhat.com>