Hi,
we'd like the SSSD in 1.12.1 to run as a non-privileged user. To summarize the discussions we had, I created the following design page: https://fedorahosted.org/sssd/wiki/DesignDocs/NotRootSSSD
For your convenience, the text of the page is also included below.
I'll be glad for comments and another round of discussion.
= Running SSSD as a non-root user =
Related ticket(s): * https://fedorahosted.org/sssd/ticket/2370
=== Problem statement === Currently, all SSSD processes run as the root user. However, if one of the processes was compromised, this might lead to compromising the whole system, especially if additional measures like SELinux were not enabled. It would improve security if instead SSSD was running as its own private user, This design page summarizes what would be needed to run sssd as a non-privileged user and all the cases that currently require a root user.
== Scope of the changes == At a higher level, the changes would amount to: * A new system user would be created. This user must be added in sssd.spec during the `%pre` section. * Files that were used by sssd and previously owned by root should now be owned as the sssd user. This includes the LDB databases. * It is important that no code linked from libkrb5 runs as root. This has consequences for accessing the system keytab, which must be readable by the sssd user. * Responders and back ends would drop privileges and become the sssd user as soon as possible, ideally as the first action after startup. * Short-lived processes that are spawned by `sssd_be` but might still require elevated privileges would be setuid root. * Places that blindly check for UID==0 must be converted to handling EPERM/EACCESS gracefully.
The changes to individual binaries and files are described in more detail below. After the changes are implemented, the code that runs as root will be reduced to the monitor process and the krb5_child.
== A new system user == The sssd will run as a new system user called simply `sssd`. We do not need to have the UID fixed across systems as no files owned by SSSD are shared among different systems. The user will be simply added during the `%pre` phase: {{{ %pre getent group sssd >/dev/null || groupadd -r sssd getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd }}} As it's common practice for system users, the shell will be `/sbin/nologin` so the user cannot log in into the system.
The name of the user should be configurable at configure-time as different distributions might decide on using different users.
== Dropping privileges of the SSSD processes == The goal is for the "worker" processes (that is, both responders and providers) to drop the root privileges as soon as possible - typically right after startup, or alternatively after completing any work that requires root privileges such as opening a file. Because the processes might have to keep the root privileges after startup, the monitor process would still be running as root.
=== Using libcap-ng to drop the privileges === Even though we already have some code to drop privileges in the `krb5`provider, we should leverage the [https://people.redhat.com/sgrubb/libcap-ng/ libcap-ng] project for privilege drop. The added benefits over doing the privilege drop ourselves are: * libcap-ng is tested and used by many other packages already. For security-sensitive code, it's advisable to re-use existing code rather than hit the same mistakes someone else did already. * libcap-ng also allows to work with capabilities. For some cases, this might be beneficial in future, for instance, we might need to retain the auditing capability.
The downside is obviously the extra dependency, but libcap-ng has a small footprint and is already used by packages that are present on most, if not all, modern Linux installations, such as dbus.
We should keep the existing code around as a fallback for environments that don't have the libcap-ngs library available, such as non-Linux systems or embedded systems. Because the code wouldn't be enabled by default, it's important to have unit tests for the privilege drop. For unit testing both options (libcap-ng and our own code), [http://cwrap.org/uid_wrapper.html uid_wrapper] and [http://cwrap.org/nss_wrapper.html nss_wrapper] are the best choice.
=== Monitor (sssd) === The monitor process would keep running as root. This is in order to be able to fork and exec processes that are initially privileged without making them all setuid. As a future enhancement, the process management functionality of the monitor will be delegated to systemd (see ticket #2243).
=== Responders === The responder processes are by nature 'readers' that mostly read data from cache and request cache updates from the back end processes.
==== NSS responder ==== The NSS responder can drop privileges after startup. The files that the NSS responder reads (sysdb, confdb, NSS pipe) and writes (memory cache, debug logs, NSS pipe) will be owned by the sssd user.
==== PAM responder ==== The PAM responder can drop privileges after startup. The files that the PAM responder reads (sysdb, confdb, PAM public pipe) and writes (debug logs, PAM pipe) will be owned by the sssd user.
In order to keep the privileged pipe only owned by the root user, we would open the pipe prior to becoming user and pass the file descriptor.
==== !InfoPipe responder ==== The !InfoPipe responder can drop privileges after startup. The files that the !InfoPipe responder reads (sysdb, confdb) and writes (debug logs, PAM pipe) will be owned by the sssd user.
Contrary to other responders, the !InfoPipe responder doesn't have a public pipe. The !InfoPipe responder also binds to the system bus, we must also convert the bus policy file to allow the sssd user to bind to the bus.
Moreover, as the !InfoPipe responder allows to change the configuration (this functionality is used by the OpenLMI SSSD provider), the !InfoPipe responder should be able to write to the `sssd.conf` file. Therefore, the `sssd.conf` file should be writable by the sssd user, too. Alternatively, another setuid helper can be created to write the configuration changes with augeas calls.
==== Autofs, SUDO and SSH responders ==== The Autofs, SUDO and SSH responders only read from the sysdb, confdb and their respective UNIX public pipes. These responders also only write to the debug logs and the public pipe, all of which would be owned by the sssd user. This means the Autofs, SUDO and SSH responders can drop privileges right after startup.
=== Providers === The providers are dynamically loadable libraries that are loaded by the `sssd_be` process. After startup, the sssd_be process dlopens the provider library and dlsyms the handlers. During sssd operation, the `sssd_be` process mostly unpacks requests arriving on the SBUS and calls the provider-specific handlers.
We have two options here - either drop the privileges in the provider library itself or directly in the `sssd_be` process. Dropping privileges in the `sssd_be` process has the advantage of modifying only one place and being sure that no matter the back end, the privileges would always be dropped.
On the other hand, becoming user in the library itself might be beneficial for scenarios where the back end requires root access for initialization. Also, if some third-party proprietary module absolutely requires to run as root, we shouldn't enforce the privilege drop.
If we don't care about the third party modules, we could take an approach where the provider would drop privilege as soon as it can and after all the initialization was completed, the sssd_be process would ensure the privileges are indeed dropped. Because there are no third party back ends so far and there was no attempt to write one, this is currently safe.
=== Short-lived processes === The purpose of the short-lived processes is to avoid blocking calls by performing an otherwise blocking action in a completely separate process.
==== ldap_child ==== The ldap_child subprocess primes the credential cache used to establish GSSAPI-encrypted connection. In order to do so, the ldap_child process needs to be able to read the keytab, which needs to have its group ownership set to the sssd group and have the appropriate access rights. The ldap_child process does not have to be setuid. The resulting ccache would be owned by the sssd user and thus accessible to the rest of the SSSD.
==== krb5_child ==== The krb5_child would be split into two parts - one that would perform most of the Kerberos-related tasks, such as reading the keytab or creating the ccache on behalf of the sssd user. Another part, that would be setuid root would change the ccache ownership to the user who logs in. The new process (krb5_child_user perhaps) would have the permissions and ownership set to 4750 and root.sssd respectively. That way only the sssd user would be able to run the new helper.
==== proxy_child ==== The proxy child performs the PAM conversation with the module being proxied. Normally there is no restriction on the UID to initiate the PAM conversation, so the proxy child can run unprivileged.
==== gpo_child ==== The gpo_child process connects to a SMB share, downloads a GPO policy file and stores it locally, by default in `/var/lib/sss/gpo_cache`. The gpo_child authenticates to the SMB share using Kerberos; the ccache, as created by ldap_child is already accessible to the sssd user. Since that directory would be owned by the sssd user, the gpo_child could run unprivileged.
==== ssh helpers ==== The SSH helpers already run non-privileged. `sss_ssh_knownhostsproxy` runs as the user who initiated the SSH session. `sss_ssh_authorizedkeys` runs as the user specified with the !AuthorizedKeysCommandUser directive in sshd_config.
=== Command line tools === There are two general kinds of command line tools we ship with the SSSD - tools that manage accounts in the local backend and SSSD management tools. All tools check if they are executed by root currently. I think this check makes sense and should stay because all the tool are intended for administrative purposes only.
==== Local back end tools ==== The tools either write (`sss_useradd, userdel, usermod, sss_groupadd, groupdel, groupmod`) or read (`sss_groupshow`) the `sssd.ldb` file. Since the file will be owned by the sssd user, the tools can also run as sssd.
==== sss_seed and sss_cache ==== These two tools function similarly to the local backend management tools, except they manipulate the domain cache. The cache is also owned and writable by the sssd user, so it's safe to drop privileges here, too.
==== sss_debuglevel ==== The sss_debuglevel tool changes the debug level of sssd on the fly. The tool writes new debug level values to the confdb (owned by sssd) and touches sssd.conf (owned and writable by sssd as well). The tool can drop privileges to sssd after startup.
==== sss_obfuscate ==== The sss_obfuscate tool is written in Python and manipulates the sssd.conf file by obfuscating the input and using it as a value of the `ldap_default_authtok` configuration option. For dropping privileges of the sss_obfuscate tool, we can use the python bindings of libcap-ng.
== External resources currently requiring root access == This part of the design page summarizes which external resources, typically file system objects currently require SSSD to have elevated privileges.
For filesystem objects, we can either change their owner to the sssd local user, add an ACL or open them as the privileged process and pass the file descriptor.
=== SSSD configuration file === * Filesystem path: `/etc/sssd/sssd.conf` * Current owner and permissions: root.root 0600 * Read by: The monitor process * Written to by: The !InfoPipe responder and users of the configAPI, such as sss_obfuscate or authconfig * ''Change: In order to allow the !InfoPipe responder to make changes to the config file, the file must be owned by sssd.sssd and made writable by the sssd user'' * ''New owner and permissions: sssd.sssd 0600''
=== Debug logs === * Filesystem path: `/var/log/sssd/*.log` * Current owner and permissions: root.root 0600 * Read by: N/A, only externally by admin * Written to by: monitor, providers, responders, child processes * ''New owner and permissions: sssd.sssd 0600''
=== The configuration database === * Filesystem path: `/var/lib/sss/db/config.ldb` * Current owner and permissions: root.root 0600 * Read by: responders, providers, monitor, command-line tools * Written to by: The monitor process, sssd-ad (a single confdb_set call), sss_debuglevel, sssd_ifp * ''New owner and permissions: sssd.sssd 0600''
=== The on-disk cache (sysdb) === * Filesystem path: `/var/lib/sss/db/cache_$domain.ldb` * Current owner and permissions: root.root 0600 * Read by: responders, providers, command-line tools * Written to by: sssd_be, the CLI tools * ''New owner and permissions: sssd.sssd 0600''
=== Memory Cache === * Filesystem path: `/var/lib/sss/mc/{passwd,group}` * Current owner and permissions: root.root 0644 * Read by: The SSS NSS module * Written to by: The NSS responder * ''New owner and permissions: sssd.sssd 0600''
=== Kerberos keytab === * Filesystem path: configurable, `/etc/krb5.keytab` by default * Current owner and permissions: root.root 0600 * Read by: LDAP, KRB5, IPA, AD providers, krb5_child, ldap_child * Written to by: sssd_be, the CLI tools * ''Change: Since no Kerberos code should run as root, the keytab must be readable by the sssd group'' * ''New owner and permissions: root.sssd 0640'' * Special care must be taken to make sure other the keytabs as specified in sssd.conf have the right ownership. We already have an upgrade script in %post, we can use it to chown the keytabs
=== Kerberos user credential cache === * Filesystem path: Configurable, only if FILE or DIR based cache is used, which is not the default anymore * Current owner and permissions: the user who logged in, 0600 * Read by: KRB5, AD, IPA, krb5_child, libkrb5 externally * Written to by: krb5_child * ''Change: No change, the credential cache will still be written as the user in question''
=== Kerberos LDAP credential cache === * Filesystem path: `/var/lib/sss/db/ccache_$domain` * Current owner and permissions: root.root 0600 * Read by: AD, IPA and LDAP providers (coded up in LDAP provider tree) * Written to by: ldap_child * No change needed since ldap_child will run as the sssd user in the new design * ''New owner and permissions: sssd.sssd 0600''
=== Kerberos kdcinfo files === * Filesystem path: `/var/lib/sss/pubconf/*` * Current owner and permissions: root.root. The directory has permissions of 0755, the files 0644 * Read by: libkrb5 * Written to by: LDAP, KRB5, IPA, AD providers, krb5_child, ldap_child * ''New owner and permissions: Both directory and files will be owned by sssd.sssd, the permissions will stay the same''
=== SELinux user mappings === * Filesystem path: `/etc/selinux/targeted/logins` * Current owner and permissions: root.root. The directory has permissions of 0755, the files 0644 * Read by: pam_selinux * Written to by: IPA provider * ''Change: We need to see if we can use libselinux to set the label first. Either way, the code to set the label needs to run privileged, the SELinux policy mainainer didn't like the idea of changing permissions of the directory''
=== UNIX pipes === * Filesystem path: `/var/lib/sss/pipes/` * Current owner and permissions: root.root. The directory has permissions of 0755, the files 0666. There is one pipe per responder. * Read by: client modules, all responders except !InfoPipe * Written to by: client modules, responders * ''New owner and permissions: Both directory and files will be owned by sssd.sssd, the permissions will stay the same''
=== UNIX PAM private pipe === * Filesystem path: `/var/lib/sss/pipes/private/pam` * Current owner and permissions: root.root. The directory has permissions of 0700, the files 0600. Only the PAM responder uses the private pipe. * Read by: PAM responder * Written to by: PAM client module * ''New owner and permissions: The directory will be owned by sssd.sssd, the file will stay the same''
=== Data Provider private pipes === * Filesystem path: `/var/lib/sss/pipes/private/sbus-dp_$domain` * Current owner and permissions: root.root. The directory has permissions of 0700, the files 0600. Only the PAM responder uses the private pipe. * Read by: Responders * Written to by: Data Provider * ''New owner and permissions: Both directory and files will be owned by sssd.sssd, the permissions will stay the same''
== Kerberos configuration file == * Filesystem path: `/etc/krb5.conf` * Read by: libkrb5 * Written to by: The IPA and AD providers "touch" the file in order to make libkrb5 re-read it * ''Change: The file can be opened before dropping privileges and we can keep the fd around. Alternatively, the modification can be performed with a setuid helper''
== How to test == Test ordinary SSSD operations. Everything must work as it used to before. Pay special attention to operations that involve the short-lived processes, like GSSAPI LDAP provider authentication or Kerberos user authentication.
Upgrade testing must be performed as well.
== Authors == * Sumit Bose sbose@redhat.com * Jakub Hrozek jhrozek@redhat.com * Simo Sorce <simo@redhat.com
On Wed, Jul 23, 2014 at 03:38:13PM +0200, Jakub Hrozek wrote:
Hi,
we'd like the SSSD in 1.12.1 to run as a non-privileged user. To summarize the discussions we had, I created the following design page: https://fedorahosted.org/sssd/wiki/DesignDocs/NotRootSSSD
For your convenience, the text of the page is also included below.
I'll be glad for comments and another round of discussion.
= Running SSSD as a non-root user =
Related ticket(s):
=== Problem statement === Currently, all SSSD processes run as the root user. However, if one of the processes was compromised, this might lead to compromising the whole system, especially if additional measures like SELinux were not enabled. It would improve security if instead SSSD was running as its own private user, This design page summarizes what would be needed to run sssd as a non-privileged user and all the cases that currently require a root user.
Thank you Jakub for setting up this page and collecting all the details.
I have a couple of general comments which you might want to put on this page or can be added to a 'Running SSSD as a non-root user - Step 2' page later. As a first step we should try to make SSSD able to run as unprivileged user but do not do it by default. This means that e.g. we do not change the permissions of the host keytab but describe on a wiki page what has to be done to run SSSD as non-root user. Additionally this page will be our task list about which setuid helpers are still needed or which permission have to be set during installation.
We should try to be more ambitious here and say that SSSD can be started as unprivileged user i.e. none of the long running daemons run as root at any time. systemd offer option like User= and Group= start start daemons as any use, additionally it offers Capabilities= so the we can keep some capabilities, e.g. to send audit messages.
Small and simple helper binary with setuid bit set will do any task that require root privileges like touching file like /etc/krb5.conf or changing the ownership of credential caches.
A helper for accessing the host keytab would be nice as well. But I think we need a bit of additional support in libkrb5 for this. There already is a MEMORY keytab type which can be used inside the unprivileged processes instead of the FILE type. The helper can just read the content of the and pass it back to the caller. But there is no libkrb5 call to pass a memory copy of the keytab file content into the related structs or into a MEMORY type keytab (at least I haven't found a way so far). So the for the time being the host keytab should be made available to the sssd user if SSSD should run unprivileged.
About the sssd users. If SSSD can be started unprivileged the user basically does not matter. We should only check in SSSD if the ownership of the files and directories SSSD is using have save permissions, i.e. belong to the user sssd is started as and have permissions set as you described below. If SSSD stops or just logs a warning if some of the permissions are unsafe can be configurable. Distributions most certainly will create a special user for SSSD as upstream we should only make sure that it is possible the 'make install' creates files and directories with a configurable owner other than root where needed.
Allow SSSD to run as the user as it is started would make testing easier as well because we can just start SSSD as the current user during make test (uid_wrapper would help here as well).
About the PAM privileged pipe. I think we can remove it at least on platform where the SO_PEERCRED option for getsockopt() is available. With this we can reliable determine the UID of the caller, with the pipe in the private directory we depend on correctly set file system permissions. Maybe we can use the private pipe conditionally on platforms where SO_PEERCRED is not available (if any)?
About the proxy child. Some PAM modules, like e.g. pam_unix require root access, so I guess the proxy_child has to get a setuid bit.
bye, Sumit
== Scope of the changes == At a higher level, the changes would amount to: * A new system user would be created. This user must be added in sssd.spec during the `%pre` section. * Files that were used by sssd and previously owned by root should now be owned as the sssd user. This includes the LDB databases. * It is important that no code linked from libkrb5 runs as root. This has consequences for accessing the system keytab, which must be readable by the sssd user. * Responders and back ends would drop privileges and become the sssd user as soon as possible, ideally as the first action after startup. * Short-lived processes that are spawned by `sssd_be` but might still require elevated privileges would be setuid root. * Places that blindly check for UID==0 must be converted to handling EPERM/EACCESS gracefully.
The changes to individual binaries and files are described in more detail below. After the changes are implemented, the code that runs as root will be reduced to the monitor process and the krb5_child.
== A new system user == The sssd will run as a new system user called simply `sssd`. We do not need to have the UID fixed across systems as no files owned by SSSD are shared among different systems. The user will be simply added during the `%pre` phase: {{{ %pre getent group sssd >/dev/null || groupadd -r sssd getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd }}} As it's common practice for system users, the shell will be `/sbin/nologin` so the user cannot log in into the system.
The name of the user should be configurable at configure-time as different distributions might decide on using different users.
== Dropping privileges of the SSSD processes == The goal is for the "worker" processes (that is, both responders and providers) to drop the root privileges as soon as possible - typically right after startup, or alternatively after completing any work that requires root privileges such as opening a file. Because the processes might have to keep the root privileges after startup, the monitor process would still be running as root.
=== Using libcap-ng to drop the privileges === Even though we already have some code to drop privileges in the `krb5`provider, we should leverage the [https://people.redhat.com/sgrubb/libcap-ng/ libcap-ng] project for privilege drop. The added benefits over doing the privilege drop ourselves are:
- libcap-ng is tested and used by many other packages already. For security-sensitive code, it's advisable to re-use existing code rather than hit the same mistakes someone else did already.
- libcap-ng also allows to work with capabilities. For some cases, this might be beneficial in future, for instance, we might need to retain the auditing capability.
The downside is obviously the extra dependency, but libcap-ng has a small footprint and is already used by packages that are present on most, if not all, modern Linux installations, such as dbus.
We should keep the existing code around as a fallback for environments that don't have the libcap-ngs library available, such as non-Linux systems or embedded systems. Because the code wouldn't be enabled by default, it's important to have unit tests for the privilege drop. For unit testing both options (libcap-ng and our own code), [http://cwrap.org/uid_wrapper.html uid_wrapper] and [http://cwrap.org/nss_wrapper.html nss_wrapper] are the best choice.
=== Monitor (sssd) === The monitor process would keep running as root. This is in order to be able to fork and exec processes that are initially privileged without making them all setuid. As a future enhancement, the process management functionality of the monitor will be delegated to systemd (see ticket #2243).
=== Responders === The responder processes are by nature 'readers' that mostly read data from cache and request cache updates from the back end processes.
==== NSS responder ==== The NSS responder can drop privileges after startup. The files that the NSS responder reads (sysdb, confdb, NSS pipe) and writes (memory cache, debug logs, NSS pipe) will be owned by the sssd user.
==== PAM responder ==== The PAM responder can drop privileges after startup. The files that the PAM responder reads (sysdb, confdb, PAM public pipe) and writes (debug logs, PAM pipe) will be owned by the sssd user.
In order to keep the privileged pipe only owned by the root user, we would open the pipe prior to becoming user and pass the file descriptor.
==== !InfoPipe responder ==== The !InfoPipe responder can drop privileges after startup. The files that the !InfoPipe responder reads (sysdb, confdb) and writes (debug logs, PAM pipe) will be owned by the sssd user.
Contrary to other responders, the !InfoPipe responder doesn't have a public pipe. The !InfoPipe responder also binds to the system bus, we must also convert the bus policy file to allow the sssd user to bind to the bus.
Moreover, as the !InfoPipe responder allows to change the configuration (this functionality is used by the OpenLMI SSSD provider), the !InfoPipe responder should be able to write to the `sssd.conf` file. Therefore, the `sssd.conf` file should be writable by the sssd user, too. Alternatively, another setuid helper can be created to write the configuration changes with augeas calls.
==== Autofs, SUDO and SSH responders ==== The Autofs, SUDO and SSH responders only read from the sysdb, confdb and their respective UNIX public pipes. These responders also only write to the debug logs and the public pipe, all of which would be owned by the sssd user. This means the Autofs, SUDO and SSH responders can drop privileges right after startup.
=== Providers === The providers are dynamically loadable libraries that are loaded by the `sssd_be` process. After startup, the sssd_be process dlopens the provider library and dlsyms the handlers. During sssd operation, the `sssd_be` process mostly unpacks requests arriving on the SBUS and calls the provider-specific handlers.
We have two options here - either drop the privileges in the provider library itself or directly in the `sssd_be` process. Dropping privileges in the `sssd_be` process has the advantage of modifying only one place and being sure that no matter the back end, the privileges would always be dropped.
On the other hand, becoming user in the library itself might be beneficial for scenarios where the back end requires root access for initialization. Also, if some third-party proprietary module absolutely requires to run as root, we shouldn't enforce the privilege drop.
If we don't care about the third party modules, we could take an approach where the provider would drop privilege as soon as it can and after all the initialization was completed, the sssd_be process would ensure the privileges are indeed dropped. Because there are no third party back ends so far and there was no attempt to write one, this is currently safe.
=== Short-lived processes === The purpose of the short-lived processes is to avoid blocking calls by performing an otherwise blocking action in a completely separate process.
==== ldap_child ==== The ldap_child subprocess primes the credential cache used to establish GSSAPI-encrypted connection. In order to do so, the ldap_child process needs to be able to read the keytab, which needs to have its group ownership set to the sssd group and have the appropriate access rights. The ldap_child process does not have to be setuid. The resulting ccache would be owned by the sssd user and thus accessible to the rest of the SSSD.
==== krb5_child ==== The krb5_child would be split into two parts - one that would perform most of the Kerberos-related tasks, such as reading the keytab or creating the ccache on behalf of the sssd user. Another part, that would be setuid root would change the ccache ownership to the user who logs in. The new process (krb5_child_user perhaps) would have the permissions and ownership set to 4750 and root.sssd respectively. That way only the sssd user would be able to run the new helper.
==== proxy_child ==== The proxy child performs the PAM conversation with the module being proxied. Normally there is no restriction on the UID to initiate the PAM conversation, so the proxy child can run unprivileged.
==== gpo_child ==== The gpo_child process connects to a SMB share, downloads a GPO policy file and stores it locally, by default in `/var/lib/sss/gpo_cache`. The gpo_child authenticates to the SMB share using Kerberos; the ccache, as created by ldap_child is already accessible to the sssd user. Since that directory would be owned by the sssd user, the gpo_child could run unprivileged.
==== ssh helpers ==== The SSH helpers already run non-privileged. `sss_ssh_knownhostsproxy` runs as the user who initiated the SSH session. `sss_ssh_authorizedkeys` runs as the user specified with the !AuthorizedKeysCommandUser directive in sshd_config.
=== Command line tools === There are two general kinds of command line tools we ship with the SSSD - tools that manage accounts in the local backend and SSSD management tools. All tools check if they are executed by root currently. I think this check makes sense and should stay because all the tool are intended for administrative purposes only.
==== Local back end tools ==== The tools either write (`sss_useradd, userdel, usermod, sss_groupadd, groupdel, groupmod`) or read (`sss_groupshow`) the `sssd.ldb` file. Since the file will be owned by the sssd user, the tools can also run as sssd.
==== sss_seed and sss_cache ==== These two tools function similarly to the local backend management tools, except they manipulate the domain cache. The cache is also owned and writable by the sssd user, so it's safe to drop privileges here, too.
==== sss_debuglevel ==== The sss_debuglevel tool changes the debug level of sssd on the fly. The tool writes new debug level values to the confdb (owned by sssd) and touches sssd.conf (owned and writable by sssd as well). The tool can drop privileges to sssd after startup.
==== sss_obfuscate ==== The sss_obfuscate tool is written in Python and manipulates the sssd.conf file by obfuscating the input and using it as a value of the `ldap_default_authtok` configuration option. For dropping privileges of the sss_obfuscate tool, we can use the python bindings of libcap-ng.
== External resources currently requiring root access == This part of the design page summarizes which external resources, typically file system objects currently require SSSD to have elevated privileges.
For filesystem objects, we can either change their owner to the sssd local user, add an ACL or open them as the privileged process and pass the file descriptor.
=== SSSD configuration file ===
- Filesystem path: `/etc/sssd/sssd.conf`
- Current owner and permissions: root.root 0600
- Read by: The monitor process
- Written to by: The !InfoPipe responder and users of the configAPI, such as sss_obfuscate or authconfig
- ''Change: In order to allow the !InfoPipe responder to make changes to the config file, the file must be owned by sssd.sssd and made writable by the sssd user''
- ''New owner and permissions: sssd.sssd 0600''
=== Debug logs ===
- Filesystem path: `/var/log/sssd/*.log`
- Current owner and permissions: root.root 0600
- Read by: N/A, only externally by admin
- Written to by: monitor, providers, responders, child processes
- ''New owner and permissions: sssd.sssd 0600''
=== The configuration database ===
- Filesystem path: `/var/lib/sss/db/config.ldb`
- Current owner and permissions: root.root 0600
- Read by: responders, providers, monitor, command-line tools
- Written to by: The monitor process, sssd-ad (a single confdb_set call), sss_debuglevel, sssd_ifp
- ''New owner and permissions: sssd.sssd 0600''
=== The on-disk cache (sysdb) ===
- Filesystem path: `/var/lib/sss/db/cache_$domain.ldb`
- Current owner and permissions: root.root 0600
- Read by: responders, providers, command-line tools
- Written to by: sssd_be, the CLI tools
- ''New owner and permissions: sssd.sssd 0600''
=== Memory Cache ===
- Filesystem path: `/var/lib/sss/mc/{passwd,group}`
- Current owner and permissions: root.root 0644
- Read by: The SSS NSS module
- Written to by: The NSS responder
- ''New owner and permissions: sssd.sssd 0600''
=== Kerberos keytab ===
- Filesystem path: configurable, `/etc/krb5.keytab` by default
- Current owner and permissions: root.root 0600
- Read by: LDAP, KRB5, IPA, AD providers, krb5_child, ldap_child
- Written to by: sssd_be, the CLI tools
- ''Change: Since no Kerberos code should run as root, the keytab must be readable by the sssd group''
- ''New owner and permissions: root.sssd 0640''
- Special care must be taken to make sure other the keytabs as specified in sssd.conf have the right ownership. We already have an upgrade script in %post, we can use it to chown the keytabs
=== Kerberos user credential cache ===
- Filesystem path: Configurable, only if FILE or DIR based cache is used, which is not the default anymore
- Current owner and permissions: the user who logged in, 0600
- Read by: KRB5, AD, IPA, krb5_child, libkrb5 externally
- Written to by: krb5_child
- ''Change: No change, the credential cache will still be written as the user in question''
=== Kerberos LDAP credential cache ===
- Filesystem path: `/var/lib/sss/db/ccache_$domain`
- Current owner and permissions: root.root 0600
- Read by: AD, IPA and LDAP providers (coded up in LDAP provider tree)
- Written to by: ldap_child
- No change needed since ldap_child will run as the sssd user in the new design
- ''New owner and permissions: sssd.sssd 0600''
=== Kerberos kdcinfo files ===
- Filesystem path: `/var/lib/sss/pubconf/*`
- Current owner and permissions: root.root. The directory has permissions of 0755, the files 0644
- Read by: libkrb5
- Written to by: LDAP, KRB5, IPA, AD providers, krb5_child, ldap_child
- ''New owner and permissions: Both directory and files will be owned by sssd.sssd, the permissions will stay the same''
=== SELinux user mappings ===
- Filesystem path: `/etc/selinux/targeted/logins`
- Current owner and permissions: root.root. The directory has permissions of 0755, the files 0644
- Read by: pam_selinux
- Written to by: IPA provider
- ''Change: We need to see if we can use libselinux to set the label first. Either way, the code to set the label needs to run privileged, the SELinux policy mainainer didn't like the idea of changing permissions of the directory''
=== UNIX pipes ===
- Filesystem path: `/var/lib/sss/pipes/`
- Current owner and permissions: root.root. The directory has permissions of 0755, the files 0666. There is one pipe per responder.
- Read by: client modules, all responders except !InfoPipe
- Written to by: client modules, responders
- ''New owner and permissions: Both directory and files will be owned by sssd.sssd, the permissions will stay the same''
=== UNIX PAM private pipe ===
- Filesystem path: `/var/lib/sss/pipes/private/pam`
- Current owner and permissions: root.root. The directory has permissions of 0700, the files 0600. Only the PAM responder uses the private pipe.
- Read by: PAM responder
- Written to by: PAM client module
- ''New owner and permissions: The directory will be owned by sssd.sssd, the file will stay the same''
=== Data Provider private pipes ===
- Filesystem path: `/var/lib/sss/pipes/private/sbus-dp_$domain`
- Current owner and permissions: root.root. The directory has permissions of 0700, the files 0600. Only the PAM responder uses the private pipe.
- Read by: Responders
- Written to by: Data Provider
- ''New owner and permissions: Both directory and files will be owned by sssd.sssd, the permissions will stay the same''
== Kerberos configuration file ==
- Filesystem path: `/etc/krb5.conf`
- Read by: libkrb5
- Written to by: The IPA and AD providers "touch" the file in order to make libkrb5 re-read it
- ''Change: The file can be opened before dropping privileges and we can keep the fd around. Alternatively, the modification can be performed with a setuid helper''
== How to test == Test ordinary SSSD operations. Everything must work as it used to before. Pay special attention to operations that involve the short-lived processes, like GSSAPI LDAP provider authentication or Kerberos user authentication.
Upgrade testing must be performed as well.
== Authors ==
- Sumit Bose sbose@redhat.com
- Jakub Hrozek jhrozek@redhat.com
- Simo Sorce <simo@redhat.com
sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
On Wed, Jul 23, 2014 at 04:47:58PM +0200, Sumit Bose wrote:
On Wed, Jul 23, 2014 at 03:38:13PM +0200, Jakub Hrozek wrote:
Hi,
we'd like the SSSD in 1.12.1 to run as a non-privileged user. To summarize the discussions we had, I created the following design page: https://fedorahosted.org/sssd/wiki/DesignDocs/NotRootSSSD
For your convenience, the text of the page is also included below.
I'll be glad for comments and another round of discussion.
= Running SSSD as a non-root user =
Related ticket(s):
=== Problem statement === Currently, all SSSD processes run as the root user. However, if one of the processes was compromised, this might lead to compromising the whole system, especially if additional measures like SELinux were not enabled. It would improve security if instead SSSD was running as its own private user, This design page summarizes what would be needed to run sssd as a non-privileged user and all the cases that currently require a root user.
Thank you Jakub for setting up this page and collecting all the details.
I have a couple of general comments which you might want to put on this page or can be added to a 'Running SSSD as a non-root user - Step 2' page later. As a first step we should try to make SSSD able to run as unprivileged user but do not do it by default. This means that e.g. we do not change the permissions of the host keytab but describe on a wiki page what has to be done to run SSSD as non-root user. Additionally this page will be our task list about which setuid helpers are still needed or which permission have to be set during installation.
So you think the default for F-21 and RHEL-7.1 should still be root user? Or are you describing a first step in development?
We should try to be more ambitious here and say that SSSD can be started as unprivileged user i.e. none of the long running daemons run as root at any time. systemd offer option like User= and Group= start start daemons as any use, additionally it offers Capabilities= so the we can keep some capabilities, e.g. to send audit messages.
Yes, if the monitor can run as non-root, too. Currently I think the only reason to run as root is to be able to spawn worker processes that start as root.
Small and simple helper binary with setuid bit set will do any task that require root privileges like touching file like /etc/krb5.conf or changing the ownership of credential caches.
If we keep the backend as root after startup, then I would argue it's easier to open krb5.conf as root and pass on a fd. If the backend starts as the sssd user already, the yes, we need the setuid helper.
A helper for accessing the host keytab would be nice as well. But I think we need a bit of additional support in libkrb5 for this. There already is a MEMORY keytab type which can be used inside the unprivileged processes instead of the FILE type. The helper can just read the content of the and pass it back to the caller. But there is no libkrb5 call to pass a memory copy of the keytab file content into the related structs or into a MEMORY type keytab (at least I haven't found a way so far). So the for the time being the host keytab should be made available to the sssd user if SSSD should run unprivileged.
Ah, thanks, I remember you mentioned this earlier.
About the sssd users. If SSSD can be started unprivileged the user basically does not matter. We should only check in SSSD if the ownership of the files and directories SSSD is using have save permissions, i.e. belong to the user sssd is started as and have permissions set as you described below. If SSSD stops or just logs a warning if some of the permissions are unsafe can be configurable. Distributions most certainly will create a special user for SSSD as upstream we should only make sure that it is possible the 'make install' creates files and directories with a configurable owner other than root where needed.
Is this a common practice? In some of the deamons I checked (chrony, 389-ds) the Makefile.am installed files always as root and the files were owned by the user only in the specfile..
Allow SSSD to run as the user as it is started would make testing easier as well because we can just start SSSD as the current user during make test (uid_wrapper would help here as well).
Sure!
About the PAM privileged pipe. I think we can remove it at least on platform where the SO_PEERCRED option for getsockopt() is available. With this we can reliable determine the UID of the caller, with the pipe in the private directory we depend on correctly set file system permissions. Maybe we can use the private pipe conditionally on platforms where SO_PEERCRED is not available (if any)?
About the proxy child. Some PAM modules, like e.g. pam_unix require root access, so I guess the proxy_child has to get a setuid bit.
Ah, I thought pam_unix had some setuid helper? But I haven't checked the code (yet).
bye, Sumit
On Wed, Jul 23, 2014 at 06:21:06PM +0200, Jakub Hrozek wrote:
On Wed, Jul 23, 2014 at 04:47:58PM +0200, Sumit Bose wrote:
On Wed, Jul 23, 2014 at 03:38:13PM +0200, Jakub Hrozek wrote:
Hi,
we'd like the SSSD in 1.12.1 to run as a non-privileged user. To summarize the discussions we had, I created the following design page: https://fedorahosted.org/sssd/wiki/DesignDocs/NotRootSSSD
For your convenience, the text of the page is also included below.
I'll be glad for comments and another round of discussion.
= Running SSSD as a non-root user =
Related ticket(s):
=== Problem statement === Currently, all SSSD processes run as the root user. However, if one of the processes was compromised, this might lead to compromising the whole system, especially if additional measures like SELinux were not enabled. It would improve security if instead SSSD was running as its own private user, This design page summarizes what would be needed to run sssd as a non-privileged user and all the cases that currently require a root user.
Thank you Jakub for setting up this page and collecting all the details.
I have a couple of general comments which you might want to put on this page or can be added to a 'Running SSSD as a non-root user - Step 2' page later. As a first step we should try to make SSSD able to run as unprivileged user but do not do it by default. This means that e.g. we do not change the permissions of the host keytab but describe on a wiki page what has to be done to run SSSD as non-root user. Additionally this page will be our task list about which setuid helpers are still needed or which permission have to be set during installation.
So you think the default for F-21 and RHEL-7.1 should still be root user? Or are you describing a first step in development?
If you think it would be possible in the given time-frame it would be great to run as non-root user by default. But I think being able to run as non-root user in most of the use-cases is a sufficiently high goal.
We should try to be more ambitious here and say that SSSD can be started as unprivileged user i.e. none of the long running daemons run as root at any time. systemd offer option like User= and Group= start start daemons as any use, additionally it offers Capabilities= so the we can keep some capabilities, e.g. to send audit messages.
Yes, if the monitor can run as non-root, too. Currently I think the only reason to run as root is to be able to spawn worker processes that start as root.
Small and simple helper binary with setuid bit set will do any task that require root privileges like touching file like /etc/krb5.conf or changing the ownership of credential caches.
If we keep the backend as root after startup, then I would argue it's easier to open krb5.conf as root and pass on a fd. If the backend starts as the sssd user already, the yes, we need the setuid helper.
Yes, but it will still miss cases where krb5.conf is replaced with a different version.
A helper for accessing the host keytab would be nice as well. But I think we need a bit of additional support in libkrb5 for this. There already is a MEMORY keytab type which can be used inside the unprivileged processes instead of the FILE type. The helper can just read the content of the and pass it back to the caller. But there is no libkrb5 call to pass a memory copy of the keytab file content into the related structs or into a MEMORY type keytab (at least I haven't found a way so far). So the for the time being the host keytab should be made available to the sssd user if SSSD should run unprivileged.
Ah, thanks, I remember you mentioned this earlier.
About the sssd users. If SSSD can be started unprivileged the user basically does not matter. We should only check in SSSD if the ownership of the files and directories SSSD is using have save permissions, i.e. belong to the user sssd is started as and have permissions set as you described below. If SSSD stops or just logs a warning if some of the permissions are unsafe can be configurable. Distributions most certainly will create a special user for SSSD as upstream we should only make sure that it is possible the 'make install' creates files and directories with a configurable owner other than root where needed.
Is this a common practice? In some of the deamons I checked (chrony, 389-ds) the Makefile.am installed files always as root and the files were owned by the user only in the specfile..
ah, ok, then it is even easier.
Allow SSSD to run as the user as it is started would make testing easier as well because we can just start SSSD as the current user during make test (uid_wrapper would help here as well).
Sure!
About the PAM privileged pipe. I think we can remove it at least on platform where the SO_PEERCRED option for getsockopt() is available. With this we can reliable determine the UID of the caller, with the pipe in the private directory we depend on correctly set file system permissions. Maybe we can use the private pipe conditionally on platforms where SO_PEERCRED is not available (if any)?
About the proxy child. Some PAM modules, like e.g. pam_unix require root access, so I guess the proxy_child has to get a setuid bit.
Ah, I thought pam_unix had some setuid helper? But I haven't checked the code (yet).
you are right, I just remembered someone saying the pam_unix will only work when called by root, but this might be outdated.
bye, Sumit
bye, Sumit
sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
On Wed, Jul 23, 2014 at 06:39:40PM +0200, Sumit Bose wrote:
On Wed, Jul 23, 2014 at 06:21:06PM +0200, Jakub Hrozek wrote:
On Wed, Jul 23, 2014 at 04:47:58PM +0200, Sumit Bose wrote:
On Wed, Jul 23, 2014 at 03:38:13PM +0200, Jakub Hrozek wrote:
Hi,
we'd like the SSSD in 1.12.1 to run as a non-privileged user. To summarize the discussions we had, I created the following design page: https://fedorahosted.org/sssd/wiki/DesignDocs/NotRootSSSD
For your convenience, the text of the page is also included below.
I'll be glad for comments and another round of discussion.
= Running SSSD as a non-root user =
Related ticket(s):
=== Problem statement === Currently, all SSSD processes run as the root user. However, if one of the processes was compromised, this might lead to compromising the whole system, especially if additional measures like SELinux were not enabled. It would improve security if instead SSSD was running as its own private user, This design page summarizes what would be needed to run sssd as a non-privileged user and all the cases that currently require a root user.
Thank you Jakub for setting up this page and collecting all the details.
I have a couple of general comments which you might want to put on this page or can be added to a 'Running SSSD as a non-root user - Step 2' page later. As a first step we should try to make SSSD able to run as unprivileged user but do not do it by default. This means that e.g. we do not change the permissions of the host keytab but describe on a wiki page what has to be done to run SSSD as non-root user. Additionally this page will be our task list about which setuid helpers are still needed or which permission have to be set during installation.
So you think the default for F-21 and RHEL-7.1 should still be root user? Or are you describing a first step in development?
If you think it would be possible in the given time-frame it would be great to run as non-root user by default. But I think being able to run as non-root user in most of the use-cases is a sufficiently high goal.
Yeah, unfortunately maintenance is taking most of the time :-/
That brings one question -- should the user to run as be configurable during runtime, too? Most deamons allow this and perhaps being able to specify something like:
[sssd] user = sssd group = sssd
or conversely:
[sssd] user = root group = root
Might be a good way to have a workaround if we missed some corner case that doesn't work with unprivileged process. Then, after we are confident that all use cases work fine we could "just" flip the defaults.
We should try to be more ambitious here and say that SSSD can be started as unprivileged user i.e. none of the long running daemons run as root at any time. systemd offer option like User= and Group= start start daemons as any use, additionally it offers Capabilities= so the we can keep some capabilities, e.g. to send audit messages.
Yes, if the monitor can run as non-root, too. Currently I think the only reason to run as root is to be able to spawn worker processes that start as root.
Small and simple helper binary with setuid bit set will do any task that require root privileges like touching file like /etc/krb5.conf or changing the ownership of credential caches.
If we keep the backend as root after startup, then I would argue it's easier to open krb5.conf as root and pass on a fd. If the backend starts as the sssd user already, the yes, we need the setuid helper.
Yes, but it will still miss cases where krb5.conf is replaced with a different version.
True. This sounds like a bit of a corner case, though.
In general, my concern is that any setuid binary raises a flag for security teams in most distributions so I would prefer to keep their number at a minimum. I guess if the binary did one thing only (like touch /etc/krb5.conf here) and didn't accept any input, then it would be easier to review for the security teams..I will try to gather some input from the Fedora security team.
A helper for accessing the host keytab would be nice as well. But I think we need a bit of additional support in libkrb5 for this. There already is a MEMORY keytab type which can be used inside the unprivileged processes instead of the FILE type. The helper can just read the content of the and pass it back to the caller. But there is no libkrb5 call to pass a memory copy of the keytab file content into the related structs or into a MEMORY type keytab (at least I haven't found a way so far). So the for the time being the host keytab should be made available to the sssd user if SSSD should run unprivileged.
Ah, thanks, I remember you mentioned this earlier.
About the sssd users. If SSSD can be started unprivileged the user basically does not matter. We should only check in SSSD if the ownership of the files and directories SSSD is using have save permissions, i.e. belong to the user sssd is started as and have permissions set as you described below. If SSSD stops or just logs a warning if some of the permissions are unsafe can be configurable. Distributions most certainly will create a special user for SSSD as upstream we should only make sure that it is possible the 'make install' creates files and directories with a configurable owner other than root where needed.
Is this a common practice? In some of the deamons I checked (chrony, 389-ds) the Makefile.am installed files always as root and the files were owned by the user only in the specfile..
ah, ok, then it is even easier.
I will double check what is the best practice on other lists, too.
Allow SSSD to run as the user as it is started would make testing easier as well because we can just start SSSD as the current user during make test (uid_wrapper would help here as well).
Sure!
About the PAM privileged pipe. I think we can remove it at least on platform where the SO_PEERCRED option for getsockopt() is available. With this we can reliable determine the UID of the caller, with the pipe in the private directory we depend on correctly set file system permissions. Maybe we can use the private pipe conditionally on platforms where SO_PEERCRED is not available (if any)?
About the proxy child. Some PAM modules, like e.g. pam_unix require root access, so I guess the proxy_child has to get a setuid bit.
Ah, I thought pam_unix had some setuid helper? But I haven't checked the code (yet).
you are right, I just remembered someone saying the pam_unix will only work when called by root, but this might be outdated.
This is something we should double check with the PAM maintainer.
Thank you for the review of the design page!
On Wed, 2014-07-23 at 20:52 +0200, Jakub Hrozek wrote:
On Wed, Jul 23, 2014 at 06:39:40PM +0200, Sumit Bose wrote:
Yeah, unfortunately maintenance is taking most of the time :-/
That brings one question -- should the user to run as be configurable during runtime, too?
I'd prefer this, I see no reason to hardcode it at build time.
Most deamons allow this and perhaps being able to specify something like:
[sssd] user = sssd group = sssd
or conversely:
[sssd] user = root group = root
Might be a good way to have a workaround if we missed some corner case that doesn't work with unprivileged process. Then, after we are confident that all use cases work fine we could "just" flip the defaults.
Sounds a good cautious approach, and allows users to flip back to root, should some corner case fail still.
We should try to be more ambitious here and say that SSSD can be started as unprivileged user i.e. none of the long running daemons run as root at any time. systemd offer option like User= and Group= start start daemons as any use, additionally it offers Capabilities= so the we can keep some capabilities, e.g. to send audit messages.
Yes, if the monitor can run as non-root, too. Currently I think the only reason to run as root is to be able to spawn worker processes that start as root.
We may need some capability to monitor interfaces/files ?
Small and simple helper binary with setuid bit set will do any task that require root privileges like touching file like /etc/krb5.conf or changing the ownership of credential caches.
If we keep the backend as root after startup, then I would argue it's easier to open krb5.conf as root and pass on a fd. If the backend starts as the sssd user already, the yes, we need the setuid helper.
Yes, but it will still miss cases where krb5.conf is replaced with a different version.
True. This sounds like a bit of a corner case, though.
In general, my concern is that any setuid binary raises a flag for security teams in most distributions so I would prefer to keep their number at a minimum. I guess if the binary did one thing only (like touch /etc/krb5.conf here) and didn't accept any input, then it would be easier to review for the security teams..I will try to gather some input from the Fedora security team.
Why do we need to touch krb5.conf ? Isn't the version of libkrb5 we'll have in F21 going to have plugins for all the things we needed and we can stop including files in krb5.conf at runtime ?
Allow SSSD to run as the user as it is started would make testing easier as well because we can just start SSSD as the current user during make test (uid_wrapper would help here as well).
Sure!
About the PAM privileged pipe. I think we can remove it at least on platform where the SO_PEERCRED option for getsockopt() is available. With this we can reliable determine the UID of the caller, with the pipe in the private directory we depend on correctly set file system permissions. Maybe we can use the private pipe conditionally on platforms where SO_PEERCRED is not available (if any)?
About the proxy child. Some PAM modules, like e.g. pam_unix require root access, so I guess the proxy_child has to get a setuid bit.
Ah, I thought pam_unix had some setuid helper? But I haven't checked the code (yet).
you are right, I just remembered someone saying the pam_unix will only work when called by root, but this might be outdated.
This is something we should double check with the PAM maintainer.
pam_unix does use a setuid helper, it is necessary for the password change case. However exclusively password changes are allowed, any other operation is not.
I would also like to make a point I do not like making the system keytab directly accessible to the sssd user.
There are only 2 cases when access to the keytab is needed. 1 is obtaining credentials to access LDAP servers using the host/ identity 2 is verification of authentication requests.
Both can be performed by a helper. For (1) the helper creates a private ccache file, which will be good until credentials expire. For (2) we need a root helper to write ccache files as users, so validation can be done in the same helper as part of authentication. This means running some code as root, but it is nothing that involves network communication, as the ticket validity is checked locally against the keytab directly.
Simo.
On Mon, Jul 28, 2014 at 06:29:39AM -0400, Simo Sorce wrote:
On Wed, 2014-07-23 at 20:52 +0200, Jakub Hrozek wrote:
On Wed, Jul 23, 2014 at 06:39:40PM +0200, Sumit Bose wrote:
Yeah, unfortunately maintenance is taking most of the time :-/
That brings one question -- should the user to run as be configurable during runtime, too?
I'd prefer this, I see no reason to hardcode it at build time.
Most deamons allow this and perhaps being able to specify something like:
[sssd] user = sssd group = sssd
or conversely:
[sssd] user = root group = root
Might be a good way to have a workaround if we missed some corner case that doesn't work with unprivileged process. Then, after we are confident that all use cases work fine we could "just" flip the defaults.
Sounds a good cautious approach, and allows users to flip back to root, should some corner case fail still.
We should try to be more ambitious here and say that SSSD can be started as unprivileged user i.e. none of the long running daemons run as root at any time. systemd offer option like User= and Group= start start daemons as any use, additionally it offers Capabilities= so the we can keep some capabilities, e.g. to send audit messages.
Yes, if the monitor can run as non-root, too. Currently I think the only reason to run as root is to be able to spawn worker processes that start as root.
We may need some capability to monitor interfaces/files ?
Small and simple helper binary with setuid bit set will do any task that require root privileges like touching file like /etc/krb5.conf or changing the ownership of credential caches.
If we keep the backend as root after startup, then I would argue it's easier to open krb5.conf as root and pass on a fd. If the backend starts as the sssd user already, the yes, we need the setuid helper.
Yes, but it will still miss cases where krb5.conf is replaced with a different version.
True. This sounds like a bit of a corner case, though.
In general, my concern is that any setuid binary raises a flag for security teams in most distributions so I would prefer to keep their number at a minimum. I guess if the binary did one thing only (like touch /etc/krb5.conf here) and didn't accept any input, then it would be easier to review for the security teams..I will try to gather some input from the Fedora security team.
Why do we need to touch krb5.conf ? Isn't the version of libkrb5 we'll have in F21 going to have plugins for all the things we needed and we can stop including files in krb5.conf at runtime ?
Yes, but the same version might be used on RHEL-6 as well..I really think RHEL-6 is a reasonable version to support upstream, Fedora is too bleeding edge for many users.
However you do have a point, we can avoid touching /etc/krb5.conf when possible.
Allow SSSD to run as the user as it is started would make testing easier as well because we can just start SSSD as the current user during make test (uid_wrapper would help here as well).
Sure!
About the PAM privileged pipe. I think we can remove it at least on platform where the SO_PEERCRED option for getsockopt() is available. With this we can reliable determine the UID of the caller, with the pipe in the private directory we depend on correctly set file system permissions. Maybe we can use the private pipe conditionally on platforms where SO_PEERCRED is not available (if any)?
About the proxy child. Some PAM modules, like e.g. pam_unix require root access, so I guess the proxy_child has to get a setuid bit.
Ah, I thought pam_unix had some setuid helper? But I haven't checked the code (yet).
you are right, I just remembered someone saying the pam_unix will only work when called by root, but this might be outdated.
This is something we should double check with the PAM maintainer.
pam_unix does use a setuid helper, it is necessary for the password change case. However exclusively password changes are allowed, any other operation is not.
OK, thank you, I admit I still haven't checked the details.
I would also like to make a point I do not like making the system keytab directly accessible to the sssd user.
There are only 2 cases when access to the keytab is needed. 1 is obtaining credentials to access LDAP servers using the host/ identity 2 is verification of authentication requests.
Both can be performed by a helper. For (1) the helper creates a private ccache file, which will be good until credentials expire.
Do you propose the helper runs as root here?
For (2) we need a root helper to write ccache files as users, so validation can be done in the same helper as part of authentication. This means running some code as root, but it is nothing that involves network communication, as the ticket validity is checked locally against the keytab directly.
I need to bring this up on one of our internal lists. One of the reasons for doing this exercise is to avoid any libkrb5 code to be run as root. If we were building a solution just for upstream, I would agree, but this is something other groups wold consume and I would like to make sure whatever we do us usable by others, or we risk doing the same work twice.. I will CC you on that mail..
On Mon, Jul 28, 2014 at 06:29:39AM -0400, Simo Sorce wrote:
On Wed, 2014-07-23 at 20:52 +0200, Jakub Hrozek wrote:
On Wed, Jul 23, 2014 at 06:39:40PM +0200, Sumit Bose wrote:
Yeah, unfortunately maintenance is taking most of the time :-/
That brings one question -- should the user to run as be configurable during runtime, too?
I'd prefer this, I see no reason to hardcode it at build time.
Most deamons allow this and perhaps being able to specify something like:
[sssd] user = sssd group = sssd
or conversely:
[sssd] user = root group = root
Might be a good way to have a workaround if we missed some corner case that doesn't work with unprivileged process. Then, after we are confident that all use cases work fine we could "just" flip the defaults.
Sounds a good cautious approach, and allows users to flip back to root, should some corner case fail still.
OK, thanks, added to the design page as well as your IRC notes about merging ldap_child and krb5_child.
We should try to be more ambitious here and say that SSSD can be started as unprivileged user i.e. none of the long running daemons run as root at any time. systemd offer option like User= and Group= start start daemons as any use, additionally it offers Capabilities= so the we can keep some capabilities, e.g. to send audit messages.
Yes, if the monitor can run as non-root, too. Currently I think the only reason to run as root is to be able to spawn worker processes that start as root.
We may need some capability to monitor interfaces/files ?
Currently we monitor the resolv.conf and the netlink socket, none of which requires root privileges. If we need to keep the root privs for the proxy backend, though, it's just an academic discussion..
On Mon, 2014-07-28 at 13:59 +0200, Jakub Hrozek wrote:
On Mon, Jul 28, 2014 at 06:29:39AM -0400, Simo Sorce wrote:
Currently we monitor the resolv.conf and the netlink socket, none of which requires root privileges. If we need to keep the root privs for the proxy backend, though, it's just an academic discussion..
Yes the proxy backend needs to run as root or have helpers, so does the monitor I guess.
On 07/23/2014 03:38 PM, Jakub Hrozek wrote:
Hi,
we'd like the SSSD in 1.12.1 to run as a non-privileged user. To summarize the discussions we had, I created the following design page: https://fedorahosted.org/sssd/wiki/DesignDocs/NotRootSSSD
Hi, this is a very thorough design page, good job!
On Wed, Jul 23, 2014 at 03:38:13PM +0200, Jakub Hrozek wrote:
==== PAM responder ==== The PAM responder can drop privileges after startup. The files that the PAM responder reads (sysdb, confdb, PAM public pipe) and writes (debug logs, PAM pipe) will be owned by the sssd user.
In order to keep the privileged pipe only owned by the root user, we would open the pipe prior to becoming user and pass the file descriptor.
As we're testing the patches with Michal, we realized one thing that I didn't check when creating the design.
The pam_sss.so module explicitly checks if the PAM pipe (private or not) is owned by UID 0. Because we initially wanted to let the non-private PAM pipe be owned by the SSSD user, this check fails. Please note the public pipe has permissions 0666, so the ownership doesn't matter that much, 'others' are always allowed to read and write to the pipe.
So we have two options: 1) Let the public PAM pipe be owned by root and create it prior to dropping privileges + No changes to the client code - a bit messy responder initialization where the PAM responder would create both pipes itself. All other responders could still rely on the shared setup code.
2) Extend the check in the PAM module so that both UID 0 and UID of the SSSD user are allowed. + Nicer responder code - Touches client code. Please note that I'm not sure if PAM modules are loaded on every PAM conversation or not. If they stay loaded for the duration of the application (like the NSS module), then this option is not viable at all.
Thanks for your opinions.
On Mon, 13 Oct 2014 17:59:45 +0200 Jakub Hrozek jhrozek@redhat.com wrote:
On Wed, Jul 23, 2014 at 03:38:13PM +0200, Jakub Hrozek wrote:
==== PAM responder ==== The PAM responder can drop privileges after startup. The files that the PAM responder reads (sysdb, confdb, PAM public pipe) and writes (debug logs, PAM pipe) will be owned by the sssd user.
In order to keep the privileged pipe only owned by the root user, we would open the pipe prior to becoming user and pass the file descriptor.
As we're testing the patches with Michal, we realized one thing that I didn't check when creating the design.
The pam_sss.so module explicitly checks if the PAM pipe (private or not) is owned by UID 0. Because we initially wanted to let the non-private PAM pipe be owned by the SSSD user, this check fails. Please note the public pipe has permissions 0666, so the ownership doesn't matter that much, 'others' are always allowed to read and write to the pipe.
So we have two options: 1) Let the public PAM pipe be owned by root and create it prior to dropping privileges + No changes to the client code - a bit messy responder initialization where the PAM responder would create both pipes itself. All other responders could still rely on the shared setup code.
I'd prefer 1, it insures the pipe can only be created by a high privileged process so no takeover is possible.
2) Extend the check in the PAM module so that both UID 0 and UID
of the SSSD user are allowed. + Nicer responder code - Touches client code. Please note that I'm not sure if PAM modules are loaded on every PAM conversation or not. If they stay loaded for the duration of the application (like the NSS module), then this option is not viable at all.
Pam modules are reloaded at each use, but you do not know how long an authentication take, I am not sure what happens with login applications that sit there for a long time awaiting for input from a terminal.
Simo.
On Wed, Jul 23, 2014 at 03:38:13PM +0200, Jakub Hrozek wrote:
=== Providers === The providers are dynamically loadable libraries that are loaded by the `sssd_be` process. After startup, the sssd_be process dlopens the provider library and dlsyms the handlers. During sssd operation, the `sssd_be` process mostly unpacks requests arriving on the SBUS and calls the provider-specific handlers.
We have two options here - either drop the privileges in the provider library itself or directly in the `sssd_be` process. Dropping privileges in the `sssd_be` process has the advantage of modifying only one place and being sure that no matter the back end, the privileges would always be dropped.
On the other hand, becoming user in the library itself might be beneficial for scenarios where the back end requires root access for initialization. Also, if some third-party proprietary module absolutely requires to run as root, we shouldn't enforce the privilege drop.
If we don't care about the third party modules, we could take an approach where the provider would drop privilege as soon as it can and after all the initialization was completed, the sssd_be process would ensure the privileges are indeed dropped. Because there are no third party back ends so far and there was no attempt to write one, this is currently safe.
After some experimentation and poking at the krb5 code, I think a different route is needed. We can't reasonably drop the privileges in the provider's setup routines themselves, because we don't know if another provider needs root privileges or not. For example consider a LDAP + Kerberos combination, the LDAP ID provider can't drop privileges until Kerberos provider initializes because the Kerberos provider might need root privileges to check exisiting ccaches for renewal after startup.
We can drop privileges after the whole initialization finishes, but we should strive to reduce the privileged code even further.
Michal had an idea of adding another function to the providers that would perform privileged init, then sssd_be would drop privs and proceed with the rest of the init.
So the initialization would change from: id_provider = dlopen() id_init = dlsym(id_provider) id_init()
auth_provider = dlopen() auth_init = dlsym(auth_provider) auth_init()
[...]
become_user(sssd)
to something like: id_provider = dlopen() auth_provider = dlopen() privileged_id_init = dlsym(id_provider) privileged_auth_init = dlsym(auth_provider) privileged_id_init() privileged_auth_init()
become_user(sssd)
id_init() auth_init()
The privileged init would initialize private data the provider needs and pass it on to the non-privileged init code.
There are some other alternatives, like a setuid setup process or performing the initialization in the monitor, but I like this option the best because passing on complex data structures between processes is tricky. This way we also keep no knowledge about provider internals outside the provider code.
Simo, I CC-ed you directly because I know you prefer to be aware of changes to the data_provider_be.c module. Do you agree with this plan?
On Sat, 1 Nov 2014 17:24:53 +0100 Jakub Hrozek jhrozek@redhat.com wrote:
On Wed, Jul 23, 2014 at 03:38:13PM +0200, Jakub Hrozek wrote:
=== Providers === The providers are dynamically loadable libraries that are loaded by the `sssd_be` process. After startup, the sssd_be process dlopens the provider library and dlsyms the handlers. During sssd operation, the `sssd_be` process mostly unpacks requests arriving on the SBUS and calls the provider-specific handlers.
We have two options here - either drop the privileges in the provider library itself or directly in the `sssd_be` process. Dropping privileges in the `sssd_be` process has the advantage of modifying only one place and being sure that no matter the back end, the privileges would always be dropped.
On the other hand, becoming user in the library itself might be beneficial for scenarios where the back end requires root access for initialization. Also, if some third-party proprietary module absolutely requires to run as root, we shouldn't enforce the privilege drop.
If we don't care about the third party modules, we could take an approach where the provider would drop privilege as soon as it can and after all the initialization was completed, the sssd_be process would ensure the privileges are indeed dropped. Because there are no third party back ends so far and there was no attempt to write one, this is currently safe.
After some experimentation and poking at the krb5 code, I think a different route is needed. We can't reasonably drop the privileges in the provider's setup routines themselves, because we don't know if another provider needs root privileges or not. For example consider a LDAP + Kerberos combination, the LDAP ID provider can't drop privileges until Kerberos provider initializes because the Kerberos provider might need root privileges to check exisiting ccaches for renewal after startup.
We can drop privileges after the whole initialization finishes, but we should strive to reduce the privileged code even further.
Michal had an idea of adding another function to the providers that would perform privileged init, then sssd_be would drop privs and proceed with the rest of the init.
So the initialization would change from: id_provider = dlopen() id_init = dlsym(id_provider) id_init()
auth_provider = dlopen() auth_init = dlsym(auth_provider) auth_init() [...] become_user(sssd)
to something like: id_provider = dlopen() auth_provider = dlopen() privileged_id_init = dlsym(id_provider) privileged_auth_init = dlsym(auth_provider) privileged_id_init() privileged_auth_init()
become_user(sssd) id_init() auth_init()
The privileged init would initialize private data the provider needs and pass it on to the non-privileged init code.
There are some other alternatives, like a setuid setup process or performing the initialization in the monitor, but I like this option the best because passing on complex data structures between processes is tricky. This way we also keep no knowledge about provider internals outside the provider code.
Simo, I CC-ed you directly because I know you prefer to be aware of changes to the data_provider_be.c module. Do you agree with this plan?
Are we sure we will be able to meaningfully separate "privileged initialization" from non-privileged items ?
My fear is that we complicate the init system and end up having all initialization in privileged_*_init() anyway, and *_init() become empty shells.
I am comfortable with keeping the whole init privileged TBH.
Simo.
On Sat, Nov 01, 2014 at 05:21:51PM -0400, Simo Sorce wrote:
On Sat, 1 Nov 2014 17:24:53 +0100 Jakub Hrozek jhrozek@redhat.com wrote:
On Wed, Jul 23, 2014 at 03:38:13PM +0200, Jakub Hrozek wrote:
=== Providers === The providers are dynamically loadable libraries that are loaded by the `sssd_be` process. After startup, the sssd_be process dlopens the provider library and dlsyms the handlers. During sssd operation, the `sssd_be` process mostly unpacks requests arriving on the SBUS and calls the provider-specific handlers.
We have two options here - either drop the privileges in the provider library itself or directly in the `sssd_be` process. Dropping privileges in the `sssd_be` process has the advantage of modifying only one place and being sure that no matter the back end, the privileges would always be dropped.
On the other hand, becoming user in the library itself might be beneficial for scenarios where the back end requires root access for initialization. Also, if some third-party proprietary module absolutely requires to run as root, we shouldn't enforce the privilege drop.
If we don't care about the third party modules, we could take an approach where the provider would drop privilege as soon as it can and after all the initialization was completed, the sssd_be process would ensure the privileges are indeed dropped. Because there are no third party back ends so far and there was no attempt to write one, this is currently safe.
After some experimentation and poking at the krb5 code, I think a different route is needed. We can't reasonably drop the privileges in the provider's setup routines themselves, because we don't know if another provider needs root privileges or not. For example consider a LDAP + Kerberos combination, the LDAP ID provider can't drop privileges until Kerberos provider initializes because the Kerberos provider might need root privileges to check exisiting ccaches for renewal after startup.
We can drop privileges after the whole initialization finishes, but we should strive to reduce the privileged code even further.
Michal had an idea of adding another function to the providers that would perform privileged init, then sssd_be would drop privs and proceed with the rest of the init.
So the initialization would change from: id_provider = dlopen() id_init = dlsym(id_provider) id_init()
auth_provider = dlopen() auth_init = dlsym(auth_provider) auth_init() [...] become_user(sssd)
to something like: id_provider = dlopen() auth_provider = dlopen() privileged_id_init = dlsym(id_provider) privileged_auth_init = dlsym(auth_provider) privileged_id_init() privileged_auth_init()
become_user(sssd) id_init() auth_init()
The privileged init would initialize private data the provider needs and pass it on to the non-privileged init code.
There are some other alternatives, like a setuid setup process or performing the initialization in the monitor, but I like this option the best because passing on complex data structures between processes is tricky. This way we also keep no knowledge about provider internals outside the provider code.
Simo, I CC-ed you directly because I know you prefer to be aware of changes to the data_provider_be.c module. Do you agree with this plan?
Are we sure we will be able to meaningfully separate "privileged initialization" from non-privileged items ?
Right now we've identified the places that need root access during initialization because we crawled the whole SSSD codebase while making it rootless -- they're the keytab processing after startup of IPA and AD providers and reading the ccaches of users when initializing the renewal. In general, the only access where we might fail unprivileged atm is keytab access or ccache access.
I can't guarantee other problems in the future, true, but that's not a problem limited to initialization, but we might run into a similar problem during runtime as well.
My fear is that we complicate the init system and end up having all initialization in privileged_*_init() anyway, and *_init() become empty shells.
I am comfortable with keeping the whole init privileged TBH.
Right, the initialization is a small window, at least time-wise, compared to the code that runs during regular SSSD execution. Separating the privileged init would have two benefits from my point of view. 1) Making the surface of the code that runs as root smaller in general. This is mostly interested in downstream groups that aim at limiting the root code.
2) Being able to separate the code that we know is required to run privileged and be able to unit test SSSD as a whole during make check, using wrappers.
With 1) we can wait for some feedback from downstream. 2) is more of a convenience -- in order for SSSD to run as a completely different user, we need to do changes in the monitor (like stop requiring that monitor runs as root)
In conclusion, for now maybe we can file a ticket describing the privileged init, defer it and wait for downstream feedback as well as see how our testing with a custom destdir goes. Revive this ticket if we see a need and keep the backend init privileged now.
On Mon, 3 Nov 2014 16:08:16 +0100 Jakub Hrozek jhrozek@redhat.com wrote:
On Sat, Nov 01, 2014 at 05:21:51PM -0400, Simo Sorce wrote:
On Sat, 1 Nov 2014 17:24:53 +0100 Jakub Hrozek jhrozek@redhat.com wrote:
On Wed, Jul 23, 2014 at 03:38:13PM +0200, Jakub Hrozek wrote:
=== Providers === The providers are dynamically loadable libraries that are loaded by the `sssd_be` process. After startup, the sssd_be process dlopens the provider library and dlsyms the handlers. During sssd operation, the `sssd_be` process mostly unpacks requests arriving on the SBUS and calls the provider-specific handlers.
We have two options here - either drop the privileges in the provider library itself or directly in the `sssd_be` process. Dropping privileges in the `sssd_be` process has the advantage of modifying only one place and being sure that no matter the back end, the privileges would always be dropped.
On the other hand, becoming user in the library itself might be beneficial for scenarios where the back end requires root access for initialization. Also, if some third-party proprietary module absolutely requires to run as root, we shouldn't enforce the privilege drop.
If we don't care about the third party modules, we could take an approach where the provider would drop privilege as soon as it can and after all the initialization was completed, the sssd_be process would ensure the privileges are indeed dropped. Because there are no third party back ends so far and there was no attempt to write one, this is currently safe.
After some experimentation and poking at the krb5 code, I think a different route is needed. We can't reasonably drop the privileges in the provider's setup routines themselves, because we don't know if another provider needs root privileges or not. For example consider a LDAP + Kerberos combination, the LDAP ID provider can't drop privileges until Kerberos provider initializes because the Kerberos provider might need root privileges to check exisiting ccaches for renewal after startup.
We can drop privileges after the whole initialization finishes, but we should strive to reduce the privileged code even further.
Michal had an idea of adding another function to the providers that would perform privileged init, then sssd_be would drop privs and proceed with the rest of the init.
So the initialization would change from: id_provider = dlopen() id_init = dlsym(id_provider) id_init()
auth_provider = dlopen() auth_init = dlsym(auth_provider) auth_init() [...] become_user(sssd)
to something like: id_provider = dlopen() auth_provider = dlopen() privileged_id_init = dlsym(id_provider) privileged_auth_init = dlsym(auth_provider) privileged_id_init() privileged_auth_init()
become_user(sssd) id_init() auth_init()
The privileged init would initialize private data the provider needs and pass it on to the non-privileged init code.
There are some other alternatives, like a setuid setup process or performing the initialization in the monitor, but I like this option the best because passing on complex data structures between processes is tricky. This way we also keep no knowledge about provider internals outside the provider code.
Simo, I CC-ed you directly because I know you prefer to be aware of changes to the data_provider_be.c module. Do you agree with this plan?
Are we sure we will be able to meaningfully separate "privileged initialization" from non-privileged items ?
Right now we've identified the places that need root access during initialization because we crawled the whole SSSD codebase while making it rootless -- they're the keytab processing after startup of IPA and AD providers and reading the ccaches of users when initializing the renewal. In general, the only access where we might fail unprivileged atm is keytab access or ccache access.
I can't guarantee other problems in the future, true, but that's not a problem limited to initialization, but we might run into a similar problem during runtime as well.
Given keytabs can be rotated during the lifetime of sssd I think we should rather have a suid helper (or use gss-proxy in conjuction with sssd) to access the keytab, or sssd_be will fail to handle keyroation in future.
My fear is that we complicate the init system and end up having all initialization in privileged_*_init() anyway, and *_init() become empty shells.
I am comfortable with keeping the whole init privileged TBH.
Right, the initialization is a small window, at least time-wise, compared to the code that runs during regular SSSD execution. Separating the privileged init would have two benefits from my point of view. 1) Making the surface of the code that runs as root smaller in general. This is mostly interested in downstream groups that aim at limiting the root code.
This sounds like it would be better served by a helper though.
2) Being able to separate the code that we know is required to run privileged and be able to unit test SSSD as a whole during make check, using wrappers.
Same as above.
With 1) we can wait for some feedback from downstream. 2) is more of a convenience -- in order for SSSD to run as a completely different user, we need to do changes in the monitor (like stop requiring that monitor runs as root)
Hopefully this will not cause issues in monitoring network or resolv.conf and other files that is done there.
In conclusion, for now maybe we can file a ticket describing the privileged init, defer it and wait for downstream feedback as well as see how our testing with a custom destdir goes. Revive this ticket if we see a need and keep the backend init privileged now.
+1
Simo.
On Mon, Nov 03, 2014 at 10:29:41AM -0500, Simo Sorce wrote:
On Mon, 3 Nov 2014 16:08:16 +0100 Jakub Hrozek jhrozek@redhat.com wrote:
On Sat, Nov 01, 2014 at 05:21:51PM -0400, Simo Sorce wrote:
On Sat, 1 Nov 2014 17:24:53 +0100 Jakub Hrozek jhrozek@redhat.com wrote:
On Wed, Jul 23, 2014 at 03:38:13PM +0200, Jakub Hrozek wrote:
=== Providers === The providers are dynamically loadable libraries that are loaded by the `sssd_be` process. After startup, the sssd_be process dlopens the provider library and dlsyms the handlers. During sssd operation, the `sssd_be` process mostly unpacks requests arriving on the SBUS and calls the provider-specific handlers.
We have two options here - either drop the privileges in the provider library itself or directly in the `sssd_be` process. Dropping privileges in the `sssd_be` process has the advantage of modifying only one place and being sure that no matter the back end, the privileges would always be dropped.
On the other hand, becoming user in the library itself might be beneficial for scenarios where the back end requires root access for initialization. Also, if some third-party proprietary module absolutely requires to run as root, we shouldn't enforce the privilege drop.
If we don't care about the third party modules, we could take an approach where the provider would drop privilege as soon as it can and after all the initialization was completed, the sssd_be process would ensure the privileges are indeed dropped. Because there are no third party back ends so far and there was no attempt to write one, this is currently safe.
After some experimentation and poking at the krb5 code, I think a different route is needed. We can't reasonably drop the privileges in the provider's setup routines themselves, because we don't know if another provider needs root privileges or not. For example consider a LDAP + Kerberos combination, the LDAP ID provider can't drop privileges until Kerberos provider initializes because the Kerberos provider might need root privileges to check exisiting ccaches for renewal after startup.
We can drop privileges after the whole initialization finishes, but we should strive to reduce the privileged code even further.
Michal had an idea of adding another function to the providers that would perform privileged init, then sssd_be would drop privs and proceed with the rest of the init.
So the initialization would change from: id_provider = dlopen() id_init = dlsym(id_provider) id_init()
auth_provider = dlopen() auth_init = dlsym(auth_provider) auth_init() [...] become_user(sssd)
to something like: id_provider = dlopen() auth_provider = dlopen() privileged_id_init = dlsym(id_provider) privileged_auth_init = dlsym(auth_provider) privileged_id_init() privileged_auth_init()
become_user(sssd) id_init() auth_init()
The privileged init would initialize private data the provider needs and pass it on to the non-privileged init code.
There are some other alternatives, like a setuid setup process or performing the initialization in the monitor, but I like this option the best because passing on complex data structures between processes is tricky. This way we also keep no knowledge about provider internals outside the provider code.
Simo, I CC-ed you directly because I know you prefer to be aware of changes to the data_provider_be.c module. Do you agree with this plan?
Are we sure we will be able to meaningfully separate "privileged initialization" from non-privileged items ?
Right now we've identified the places that need root access during initialization because we crawled the whole SSSD codebase while making it rootless -- they're the keytab processing after startup of IPA and AD providers and reading the ccaches of users when initializing the renewal. In general, the only access where we might fail unprivileged atm is keytab access or ccache access.
I can't guarantee other problems in the future, true, but that's not a problem limited to initialization, but we might run into a similar problem during runtime as well.
Given keytabs can be rotated during the lifetime of sssd I think we should rather have a suid helper (or use gss-proxy in conjuction with sssd) to access the keytab, or sssd_be will fail to handle keyroation in future.
My fear is that we complicate the init system and end up having all initialization in privileged_*_init() anyway, and *_init() become empty shells.
I am comfortable with keeping the whole init privileged TBH.
Right, the initialization is a small window, at least time-wise, compared to the code that runs during regular SSSD execution. Separating the privileged init would have two benefits from my point of view. 1) Making the surface of the code that runs as root smaller in general. This is mostly interested in downstream groups that aim at limiting the root code.
This sounds like it would be better served by a helper though.
That was my first instinct, too, and for keytab access it's certainly doable, I even started to refactor the code that checks the keytab, so it's reusable, other tasks just bubbled up.
However, for gathering the list of ccaches that need to be renewed after startup, I'm not so sure a helper is a good idea. The output from the renewal function is currently a hash table in the form of: user -> struct renew_data
where renew_data contains stuff like ccache end-time but also the pam_data structure which then contains authtok. Such complex data is not easy to transfer between processes, that's why I initially opted for gathering the renew_data while privileged, store it in the global krb5 context and then drop privs (and proceed with the rest of the initialization)
2) Being able to separate the code that we know is required to run privileged and be able to unit test SSSD as a whole during make check, using wrappers.
Same as above.
With 1) we can wait for some feedback from downstream. 2) is more of a convenience -- in order for SSSD to run as a completely different user, we need to do changes in the monitor (like stop requiring that monitor runs as root)
Hopefully this will not cause issues in monitoring network or resolv.conf and other files that is done there.
Yes, currently I think both these cases would work, but I agree there is a chance that something might not. For regular operation, the monitor will keep running as root now, it would drop (or rather never acquire root..) only when unit testing.
In conclusion, for now maybe we can file a ticket describing the privileged init, defer it and wait for downstream feedback as well as see how our testing with a custom destdir goes. Revive this ticket if we see a need and keep the backend init privileged now.
+1
Simo.
-- Simo Sorce * Red Hat, Inc * New York
On Wed, Jul 23, 2014 at 03:38:13PM +0200, Jakub Hrozek wrote:
=== Using libcap-ng to drop the privileges === Even though we already have some code to drop privileges in the `krb5`provider, we should leverage the [https://people.redhat.com/sgrubb/libcap-ng/ libcap-ng] project for privilege drop. The added benefits over doing the privilege drop ourselves are:
- libcap-ng is tested and used by many other packages already. For security-sensitive code, it's advisable to re-use existing code rather than hit the same mistakes someone else did already.
- libcap-ng also allows to work with capabilities. For some cases, this might be beneficial in future, for instance, we might need to retain the auditing capability.
The downside is obviously the extra dependency, but libcap-ng has a small footprint and is already used by packages that are present on most, if not all, modern Linux installations, such as dbus.
We should keep the existing code around as a fallback for environments that don't have the libcap-ngs library available, such as non-Linux systems or embedded systems. Because the code wouldn't be enabled by default, it's important to have unit tests for the privilege drop. For unit testing both options (libcap-ng and our own code), [http://cwrap.org/uid_wrapper.html uid_wrapper] and [http://cwrap.org/nss_wrapper.html nss_wrapper] are the best choice.
Hi,
this is another aspect of the original design that I'm no longer sure is valid.
I have prepared the patches that use libcap-ng by default: https://fedorapeople.org/cgit/jhrozek/public_git/sssd.git/commit/?h=nonroot-...
But I'm not sure we need to merge them at this point, because: 1) Since uid_wrapper doesn't support faking capabilities (yet!), it's hard to unit test the uid dropping using libcap-ng 2) We actually don't use capabilities (again..yet, maybe we'll use CAP_AUDIT_WRITE in the future)
So the only advantage we'd gain is that code that drops privileges could be offloaded to libcap that is used and tested by other projects, too. But given that we'd keep our code around, too, for minimal environments (we have users running sssd on embedded systems where every extra dependency counts..) I'm not convinced there is too much value in merging the libcap-ng support now.
Thoughts?
On Sat, 1 Nov 2014 17:29:47 +0100 Jakub Hrozek jhrozek@redhat.com wrote:
On Wed, Jul 23, 2014 at 03:38:13PM +0200, Jakub Hrozek wrote:
=== Using libcap-ng to drop the privileges === Even though we already have some code to drop privileges in the `krb5`provider, we should leverage the [https://people.redhat.com/sgrubb/libcap-ng/ libcap-ng] project for privilege drop. The added benefits over doing the privilege drop ourselves are:
- libcap-ng is tested and used by many other packages already. For
security-sensitive code, it's advisable to re-use existing code rather than hit the same mistakes someone else did already.
- libcap-ng also allows to work with capabilities. For some cases,
this might be beneficial in future, for instance, we might need to retain the auditing capability.
The downside is obviously the extra dependency, but libcap-ng has a small footprint and is already used by packages that are present on most, if not all, modern Linux installations, such as dbus.
We should keep the existing code around as a fallback for environments that don't have the libcap-ngs library available, such as non-Linux systems or embedded systems. Because the code wouldn't be enabled by default, it's important to have unit tests for the privilege drop. For unit testing both options (libcap-ng and our own code), [http://cwrap.org/uid_wrapper.html uid_wrapper] and [http://cwrap.org/nss_wrapper.html nss_wrapper] are the best choice.
Hi,
this is another aspect of the original design that I'm no longer sure is valid.
I have prepared the patches that use libcap-ng by default: https://fedorapeople.org/cgit/jhrozek/public_git/sssd.git/commit/?h=nonroot-...
But I'm not sure we need to merge them at this point, because: 1) Since uid_wrapper doesn't support faking capabilities (yet!), it's hard to unit test the uid dropping using libcap-ng 2) We actually don't use capabilities (again..yet, maybe we'll use CAP_AUDIT_WRITE in the future)
So the only advantage we'd gain is that code that drops privileges could be offloaded to libcap that is used and tested by other projects, too. But given that we'd keep our code around, too, for minimal environments (we have users running sssd on embedded systems where every extra dependency counts..) I'm not convinced there is too much value in merging the libcap-ng support now.
Thoughts?
We can wait indeed. +1 to defer it.
Simo.
On Sat, Nov 01, 2014 at 05:24:57PM -0400, Simo Sorce wrote:
On Sat, 1 Nov 2014 17:29:47 +0100 Jakub Hrozek jhrozek@redhat.com wrote:
On Wed, Jul 23, 2014 at 03:38:13PM +0200, Jakub Hrozek wrote:
=== Using libcap-ng to drop the privileges === Even though we already have some code to drop privileges in the `krb5`provider, we should leverage the [https://people.redhat.com/sgrubb/libcap-ng/ libcap-ng] project for privilege drop. The added benefits over doing the privilege drop ourselves are:
- libcap-ng is tested and used by many other packages already. For
security-sensitive code, it's advisable to re-use existing code rather than hit the same mistakes someone else did already.
- libcap-ng also allows to work with capabilities. For some cases,
this might be beneficial in future, for instance, we might need to retain the auditing capability.
The downside is obviously the extra dependency, but libcap-ng has a small footprint and is already used by packages that are present on most, if not all, modern Linux installations, such as dbus.
We should keep the existing code around as a fallback for environments that don't have the libcap-ngs library available, such as non-Linux systems or embedded systems. Because the code wouldn't be enabled by default, it's important to have unit tests for the privilege drop. For unit testing both options (libcap-ng and our own code), [http://cwrap.org/uid_wrapper.html uid_wrapper] and [http://cwrap.org/nss_wrapper.html nss_wrapper] are the best choice.
Hi,
this is another aspect of the original design that I'm no longer sure is valid.
I have prepared the patches that use libcap-ng by default: https://fedorapeople.org/cgit/jhrozek/public_git/sssd.git/commit/?h=nonroot-...
But I'm not sure we need to merge them at this point, because: 1) Since uid_wrapper doesn't support faking capabilities (yet!), it's hard to unit test the uid dropping using libcap-ng 2) We actually don't use capabilities (again..yet, maybe we'll use CAP_AUDIT_WRITE in the future)
So the only advantage we'd gain is that code that drops privileges could be offloaded to libcap that is used and tested by other projects, too. But given that we'd keep our code around, too, for minimal environments (we have users running sssd on embedded systems where every extra dependency counts..) I'm not convinced there is too much value in merging the libcap-ng support now.
Thoughts?
We can wait indeed. +1 to defer it.
Simo.
I filed: https://fedorahosted.org/sssd/ticket/2482 and edited the design page to list libcap-ng as a future enhancement: https://fedorahosted.org/sssd/wiki/DesignDocs/NotRootSSSD?action=diff&ve...
sssd-devel@lists.fedorahosted.org