Link Search Menu Expand Document

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>>