IPA sudo rules for local users

Central identity management solutions like IPA offer a very nice capability – in addition to storing users and groups on the server, also certain kinds of policies can be defined in one place and used by all the machines in the domain.

Sudo rules are one of the most common policies that administrators define for their domain in place of distributing or worse, hand-editing /etc/sudoers. But what if the administrator would take advantage of the central management of sudo rules, but apply these sudo rules to a user who is not part of the domain, but only exists in the traditional UNIX files, like /etc/passwd?

This blog post illustrates several strategies for achieving that.

Option 1: Move the user to IPA

This might be the easiest solution from the point of view of policy management that allows you to really keep everything in one place. But it might not be always possible to move the user. A common issue arises with UIDs and file ownership. If the UIDs are somewhat consistent on majority of hosts, perhaps it would be possible to use the ID views feature of IPA to present the UID a particular system expects. If it’s not feasible to move the user to the IPA domain, there are other options to consider.

Option 2: Use the files provider of SSSD

One of the core design principles of SSSD is that a user and its policies must both be served from SSSD and even from the same SSSD domain. This prevents unexpected results in case of overlapping user names between SSSD domains or between the data SSSD is handling and the rest of the system.

But at the same time, local users are by definition anchored in /etc/passwd. To be able to serve the local users (and more, for example better performance), SSSD ships a files data provider since its 1.15 release. At the moment (as of 1.16.1), the files release mostly mirrors the contents of /etc/passwd and /etc/groups and presents them via the SSSD interfaces. And that’s precisely what is needed to be able to serve the sudo rules as well.

Let’s consider an example. A client is enrolled in an IPA domain and there is a user called lcluser on the client. We want to let the user run sudo less to be able to display the contents of any file on the client.

Let’s start with adding the sudo rule on the IPA server. First, we add the less command itself:
$ ipa sudocmd-add --desc='For reading log files' /usr/bin/less

Then we add the rule and link the user:
$ ipa sudorule-add readfiles
$ ipa sudorule-add-user --users=lcluser

Note that we lcluser doesn’t exist in IPA, yet we were able to add the user with the regular sudorule-add-user command. When we inspect the sudo rule, we can see that IPA detected that the user is external to its directory and created a special attribute externalUser where the username was added to, unlike the IPA user admin, which is linked to its LDAP object.
$ ipa sudorule-show --all --raw readfiles
dn: ipaUniqueID=31051b50-30d5-11e8-b1a7-5254004e66c1,cn=sudorules,cn=sudo,dc=ipa,dc=test
cn: readfiles
ipaenabledflag: TRUE
hostcategory: all
externaluser: lcluser
memberuser: uid=admin,cn=users,cn=accounts,dc=ipa,dc=test
ipaUniqueID: 31051b50-30d5-11e8-b1a7-5254004e66c1
memberallowcmd: ipaUniqueID=179de976-30d5-11e8-8e98-5254004e66c1,cn=sudocmds,cn=sudo,dc=ipa,dc=test
objectClass: ipaassociation
objectClass: ipasudorule

Finally, let’s link the sudo rule with the host we want to allow the sudo rule at:
ipa sudorule-add-host readfiles --hosts ipa.client.test

Now, we can configure the IPA client. We being by defining a new SSSD domain that will mirror the
local users, but we also add a ‘sudo_provider’:
id_provider = files
sudo_provider = ldap
ldap_uri = ldap://unidirect.ipa.test

The reason it is preferable to use the IPA sudo provider over the LDAP provider is that the LDAP provider relies on schema conversion on the IPA server from IPA’s own schema into the schema normally used when storing sudo rules in LDAP as described in man sudoers.ldap. This conversion is done by the slapi-nis plugin and can be somewhat costly in large environments.

Finally, we enable the domain in the [sssd] section:
services = nss, pam, ssh, sudo, ifp
domains = files, ipa.test

Now, we should be able to run sudo as “lcluser”:
$ su - lcluser
[lcluser@client ~]$ sudo -l
[sudo] password for lcluser:
Matching Defaults entries for lcluser on client:
XAUTHORITY", secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin

User lcluser may run the following commands on client:
(root) /usr/bin/less

Woo, it works!

Option 3: Use the proxy SSSD provider proxying to files

The files provider was introduced to SSSD in the 1.15 version. If you are running an older SSSD version, this provider might not be available. Still, you can use SSSD, just with somewhat more convoluted configuration using id_provider=proxy. All the server-side steps can be taken from the previous paragraph, just the client-side configuration will look like this:

id_provider = proxy
proxy_lib_name = files
proxy_pam_target = none

sudo_provider = ldap
ldap_uri = ldap://unidirect.ipa.test

Using the files provider is preferable, because it actively watches the changes to /etc/passwd and group using inotify, so the provider receives any change done to the files instantly. The proxy provider reaches out to the files as if it were a generic data source. Also, as you can see, the configuration is not as nice, but it’s a valid option for older releases.

Option 4: Use the LDAP connector built into sudo

If using SSSD is not an option at all, because perhaps you are configuring a non-Linux client, you can still point sudo to the IPA LDAP server manually. I’m not going to go into details, because the setup is nicely described in “man sudoers.ldap”.

Unlike all the above options, this doesn’t give you any caching, though.

Restrict the set of groups the user is a member of with SSSD

Written by Jakub Hrozek and Sumit Bose

One of the frequent requests we receive for a future enhancement for the SSSD project is one where admins would like to restrict the list of groups users on a host are a member of. We currently don’t offer this functionality and in this blog post I would like to explain why it’s not a completely trivial thing to implement correctly (and therefore why it’s not implemented already..) and offer a workaround that can be used for many environments as long as the administrator understands its limitations.

The administrator typically wants to restrict the list of groups the uses are a member of on the host for either (or both) of these reasons:

  • to limit access to resources beyond what the users are normally privileged to access
  • to provide a performance boost where sssd wouldn’t even attempt to resolve groups that are not listed in the configured group list

The vast majority of administrators are actually asking to improve performance, especially in High Performance Computing environments where users are part of a huge domain, but the client machine is only interested in a subset of the groups that give access to some resource. At the same time, avoiding the group resolution completely is significantly less trivial than the first case where SSSD would resolve all the groups and then only present a subset to the system.

Resolving the list of groups the user is a member of is a complex task, which can query different resources or interfaces depending on how the user logs in or what kind of command the administrator invokes. In the simplest case, where SSSD is connected to a generic LDAP server and the admin calls the “id” utility, SSSD would search the LDAP directory for groups the user is a member of. This scenario is actually possible to restrict already (and we’ll show how later in the post), but there are more ways to resolve a user’s group memberships. For example, in an Active Directory domain, the group membership might come from the PAC data blob attached to the Kerberos ticket acquired during authentication in the form of a list of SIDs which must be resolved into either a POSIX ID or a name before to be filtered later – and this SID-to-name/SID-to-ID resolution would negate any performance benefit in most cases.

Similarly, when an IPA client is resolving groups for an AD user from a trusted directory, it would ask one of the IPA masters for a list of groups the user belongs to. These two examples hopefully illustrate that there are many code paths to consider to make this feature work as expected in all possible scenarios. While implementing this feature is something we have on our roadmap, it will take time to get there.

With that said, SSSD already provides a way to only include certain groups as long as only the generic LDAP lookups are used to resolve group memberships. As an example, we’ll illustrate how to restrict the client to only search and return two groups. We’ll start with a setup where SSSD is connected to an Active Directory domain and returns the full list of group memberships, for example:

$ id sssduser@win.trust.test
uid=679801116(sssduser@win.trust.test) gid=679800513(domain users@win.trust.test) groups=679800513(domain users@win.trust.test),679801117(global_group@win.trust.test),679801105(sudogroup@win.trust.test),679801118(universal_group@win.trust.test)

The client uses a fairly default configuration where the domain section of sssd.conf looks like this:

id_provider = ad
access_provider = ad
ad_domain = win.trust.test
krb5_realm = WIN.TRUST.TEST
realmd_tags = manages-system joined-with-adcli

Let’s say that in our environment, we only care about the “sudogroup” so that the user can elevate her privileges with sudo and the “Domain Users” group to access shared resources.

The first step is to make the client look up the groups the user is a member of using plain LDAP lookups instead of looking up the AD-specific tokenGroups attribute. Normally, if all groups are to be returned, using the tokenGroups attribute provides a significant performance benefit, because the list of all groups is a member of can be returned with a single BASE-scoped search of the user entry. However, the tokenGroups attribute is a multi-valued list of SIDs the user is a member of and as said earlier, all the SIDs would have to be resolved into group names anyway. Therefore we disable the tokengroups support in the [domain] section of the sssd.conf config file by adding this parameter:

ldap_use_tokengroups = false

Then, we need to instruct SSSD to only look for the two groups we care about on the client. We include the names of the two groups as an extension of the LDAP group search base, which can optionally also include the scope and the filter to search with:

ldap_group_search_base = CN=Users,DC=win,DC=trust,DC=test?sub?(|(cn=domain users)(cn=sudogroup))

Please note that the group search base is not required to be set unless in the typical case, because SSSD infers its value from the domain name of the AD domain it is joined to.

Finally, we restart the SSSD service:

# systemctl restart sssd
Make sure we pull data from AD and not the cache on the next lookup:
# sss_cache -E
And resolve the user entry again:

id sssduser@win.trust.test
uid=679801116(sssduser@win.trust.test) gid=679800513(domain users@win.trust.test) groups=679800513(domain users@win.trust.test),679801105(sudogroup@win.trust.test)

This lookup only includes the domain users group and the sudogroup. Inspecting the SSSD debug logs would show that the client only attempted to fetch group names that include the “domain users” or the “sudogroup”.

This configuration workaround would work only if the client lookups the entries in an LDAP tree directly – so it wouldn’t work in cases where an IPA client is looking up groups of a user who comes from a trusted AD domain or in the case where the user logs in without a password using her Kerberos ticket from a Windows machine and expects SSSD to read the group memberships from the PAC blob attached to the Kerberos ticket. Similarly, this workaround only works for the joined domain, because at the moment (at least until the trusted domains can be made configurable), the trusted domains only use the default search base. These cases will be covered when the upstream ticket https://fedorahosted.org/sssd/ticket/3249 is implemented in one of the future SSSD releases.

We also believe that, since this feature is often asked for performance reasons, we should focus on improving SSSD performance in the general case instead of providing workarounds.