Hello all,
We're interested in using SSSD to replace our current use of NSS/PAM/NSCD/NSLCD. However, we were curious whether or not SSSD had implemented some critical security checks to protect against malicious remote domains.
- What are the semantics of the local domain: that is, do I have a guarantee that entries in local will never be affected by the network?
- If the answer to the above is true, how does SSSD resolve conflicts between two domains which have entries that claim the same UID? I understand that the max_id/min_id functionality is intended to address this partially, but does SSSD do any further sanity checks, such as refusing information from remote domains that exist in local domains?
- Additionally, users may come with groups, and it is bad if remote domains can spoof ownership in local groups. Is there anyway to lock this down?
- It is frequently useful for applications running on the system to be able to identify nonlocal users as opposed to local users; we had a nsswitch module which identified nonlocal users and added them to their own group. Does this functionality exist in SSSD? (It's also convenient to have another group which contains local users.)
- A nice to have feature (though not strictly necessary), is the ability to pretend that nonlocal users are in some local group. This may be necessary if remote domains cannot dictate ownership in local groups.
In general, we would like to avoid trusting the source of the remote authentication data: local accounts are first class, whereas remote accounts are merely "nice to have". The remote LDAP server may not be held to as high security standards as the machine itself, and if we can achieve isolation at very little cost, we should do so.
The MIT Debathena and Scripts projects would be very interested in seeing this functionality exist, and if it doesn't, we'd be interested in contributing this functionality. We consider this a blocker for moving to SSSD.
Thanks, Edward
On Tue, May 22, 2012 at 10:06:56PM -0400, Edward Z. Yang wrote:
Hello all,
We're interested in using SSSD to replace our current use of NSS/PAM/NSCD/NSLCD. However, we were curious whether or not SSSD had implemented some critical security checks to protect against malicious remote domains.
- What are the semantics of the local domain: that is, do I have a guarantee that entries in local will never be affected by the network?
Yes, the local domain is completely isolated and no entry can reference entries in another domain, local or remote.
The more involved answer is, when the NSS responder process is returning entries from the local domain, it directly shortcuts to the ldb database files where local entries are stored and never contacts the Data Provider process that downloads data from remote domains.
- If the answer to the above is true, how does SSSD resolve conflicts between two domains which have entries that claim the same UID? I understand that the max_id/min_id functionality is intended to address this partially, but does SSSD do any further sanity checks, such as refusing information from remote domains that exist in local domains?
I think the multi domain support in SSSD would help your use case. When the SSSD is configured with multiple domains, it queries them in the order they are defined in the config file and the first match is always[*] returned.
So provided that a given UID exists in both local and remote domains, the NSS responder would search the local domain first, if the UID was found there, the remote domain would not be even checked.
[*] Unless the domain name is specifically part of the query. In other words, if the query would have been 1001@remote, SSSD would only perform the lookup in the domain called "remote".
- Additionally, users may come with groups, and it is bad if remote domains can spoof ownership in local groups. Is there anyway to lock this down?
The current SSSD version would not resolve local memberships in a remote group, it would only query the same remote domain. See also https://fedorahosted.org/sssd/ticket/1020
- It is frequently useful for applications running on the system to be able to identify nonlocal users as opposed to local users; we had a nsswitch module which identified nonlocal users and added them to their own group. Does this functionality exist in SSSD? (It's also convenient to have another group which contains local users.)
I can't think of a nice way of doing this short of ID value checks or querying the local database directly.
- A nice to have feature (though not strictly necessary), is the ability to pretend that nonlocal users are in some local group. This may be necessary if remote domains cannot dictate ownership in local groups.
In general, we would like to avoid trusting the source of the remote authentication data: local accounts are first class, whereas remote accounts are merely "nice to have". The remote LDAP server may not be held to as high security standards as the machine itself, and if we can achieve isolation at very little cost, we should do so.
The MIT Debathena and Scripts projects would be very interested in seeing this functionality exist, and if it doesn't, we'd be interested in contributing this functionality. We consider this a blocker for moving to SSSD.
Thanks, Edward
On Wed, 23 May 2012, Jakub Hrozek wrote:
- If the answer to the above is true, how does SSSD resolve conflicts between two domains which have entries that claim the same UID? I understand that the max_id/min_id functionality is intended to address this partially, but does SSSD do any further sanity checks, such as refusing information from remote domains that exist in local domains?
I think the multi domain support in SSSD would help your use case. When the SSSD is configured with multiple domains, it queries them in the order they are defined in the config file and the first match is always[*] returned.
So provided that a given UID exists in both local and remote domains, the NSS responder would search the local domain first, if the UID was found there, the remote domain would not be even checked.
Hi Jakub, thanks for your reply.
I think this case is a little more subtle than your answer is referring to; namely, how does SSSD handle a lookup for a username in a remote domain that conflicts with a UID from a local domain? For instance, if an LDAP server replies to a passwd-style query with
cn: geofft uidNumber: 0
it should not result in a passwd entry of "geofft:*:0:..." being returned. While for the specific case of 0 this is handled by min_id, it applies equally well to any local account on the system; if I have a local user account with UID 1000 or 20000 or whatever, I wouldn't want a remote account to be able to use that UID on my local system.
- Additionally, users may come with groups, and it is bad if remote domains can spoof ownership in local groups. Is there anyway to lock this down?
The current SSSD version would not resolve local memberships in a remote group, it would only query the same remote domain. See also https://fedorahosted.org/sssd/ticket/1020
Maybe we're not understanding SSSD's model right, but we're curious about (purported) remote memberships in a local group. As above, if a remote user claims in its group list (the return of getgrouplist(3)) to be in a local group like bin or disk or sudo, I wouldn't want that to be respected on my local machine. Again, minimum gids go partway to solving this, but I wouldn't want a remote user who claims to be in gid 1000 or group geofft to be able to access group-readable files I write, etc.
Local memberships in a remote group seem acceptable security-wise; a local system administrator can decide that it's fine for a user account to be in whatever the remote server says a group is. But a remote server should not be able to inject users into local groups.
- It is frequently useful for applications running on the system to be able to identify nonlocal users as opposed to local users; we had a nsswitch module which identified nonlocal users and added them to their own group. Does this functionality exist in SSSD? (It's also convenient to have another group which contains local users.)
I can't think of a nice way of doing this short of ID value checks or querying the local database directly.
Is it not possible for the domain lookup to insert an identifier for that domain in the returned group list on getgrouplist(3)/getgroups(3)? If I create two local groups, say, "local_users" and "remote_users", it seems straightforward to add one of those two groups to group lists before returning them to the NSS client.
Thanks,
On Wed, 2012-05-23 at 03:52 -0400, Geoffrey Thomas wrote:
On Wed, 23 May 2012, Jakub Hrozek wrote:
- If the answer to the above is true, how does SSSD resolve conflicts between two domains which have entries that claim the same UID? I understand that the max_id/min_id functionality is intended to address this partially, but does SSSD do any further sanity checks, such as refusing information from remote domains that exist in local domains?
I think the multi domain support in SSSD would help your use case. When the SSSD is configured with multiple domains, it queries them in the order they are defined in the config file and the first match is always[*] returned.
So provided that a given UID exists in both local and remote domains, the NSS responder would search the local domain first, if the UID was found there, the remote domain would not be even checked.
Hi Jakub, thanks for your reply.
I think this case is a little more subtle than your answer is referring to; namely, how does SSSD handle a lookup for a username in a remote domain that conflicts with a UID from a local domain?
I think we need to get some terminology straight first. There are two kinds of "local" users. There are those users that appear in /etc/passwd and then there are those that can appear in an SSSD domain using the LOCAL provider. They are very different animals.
I'm working under the assumption that when you speak of "local domains" here, you're talking about /etc/passwd. If this is wrong, please correct me.
For instance, if an LDAP server replies to a passwd-style query with
cn: geofft uidNumber: 0
it should not result in a passwd entry of "geofft:*:0:..." being returned. While for the specific case of 0 this is handled by min_id, it applies equally well to any local account on the system; if I have a local user account with UID 1000 or 20000 or whatever, I wouldn't want a remote account to be able to use that UID on my local system.
Ok, let's talk a little bit about the nsswitch interface here. That may clear things up a bit.
Nsswitch ordering is handled by /etc/nsswitch.conf. In most situations, you will have the following specified in that file: passwd: files sss
This means that any lookup calling 'getpwnam()' or 'getpwuid()' will first check to see if it exists in the files map (aka /etc/passwd). If it does, it will return that value and that will be that.
Let's work with the following sample data. (We'll use LDAP as the SSSD domain name, for simplicity) In /etc/passwd: username 'geofft' with UID 2000 in LDAP: username 'geofft' with UID 3000 in LDAP: username 'imposter' with UID 2000
So if you have user 'geofft' in /etc/passwd and also in LDAP, you will get back the information from /etc/passwd for getpwnam("geofft"). So you will get back UID 2000.
If you call getpwnam("geofft@LDAP"), you will bypass the /etc/passwd file and get back UID 3000
If you call getpwuid(2000), you will get back user 'geofft' from /etc/passwd
If you call getpwuid(3000), you will get back user 'geofft' from LDAP
- Additionally, users may come with groups, and it is bad if remote domains can spoof ownership in local groups. Is there anyway to lock this down?
The current SSSD version would not resolve local memberships in a remote group, it would only query the same remote domain. See also https://fedorahosted.org/sssd/ticket/1020
Maybe we're not understanding SSSD's model right, but we're curious about (purported) remote memberships in a local group. As above, if a remote user claims in its group list (the return of getgrouplist(3)) to be in a local group like bin or disk or sudo, I wouldn't want that to be respected on my local machine. Again, minimum gids go partway to solving this, but I wouldn't want a remote user who claims to be in gid 1000 or group geofft to be able to access group-readable files I write, etc.
This cannot happen. Similar to the /etc/passwd example I described above, lookups for a particular group name or GID would stop at /etc/group if the name or GID matched there first. It would not take ANY group membership information for groups in /etc/group from LDAP. If you wanted to add a remote user to a local group, you would need to add that user's name to /etc/group manually.
The one catch is the user's primary group ID. Most of the time, this would be set to a user private group for security reasons, but it's theoretically possible that an LDAP user could have it set to be e.g. 10 ('wheel' on RHEL). In this case, the local system WILL honor it.
That said, I think maybe we want to add an option to filter out certain values for primary group ID in order to avoid this issue. It's a valid concern. Please file an RFE at https://fedorahosted.org/sssd (you can get an account from https://admin.fedoraproject.org/accounts if you do not have one).
Local memberships in a remote group seem acceptable security-wise; a local system administrator can decide that it's fine for a user account to be in whatever the remote server says a group is. But a remote server should not be able to inject users into local groups.
- It is frequently useful for applications running on the system to be able to identify nonlocal users as opposed to local users; we had a nsswitch module which identified nonlocal users and added them to their own group. Does this functionality exist in SSSD? (It's also convenient to have another group which contains local users.)
SSSD does not currently have any such functionality. I'd be interested to see how this module works, as I have a feeling it would be broken by recent changes glibc made to the initgroups interface.
I can't think of a nice way of doing this short of ID value checks or querying the local database directly.
Is it not possible for the domain lookup to insert an identifier for that domain in the returned group list on getgrouplist(3)/getgroups(3)? If I create two local groups, say, "local_users" and "remote_users", it seems straightforward to add one of those two groups to group lists before returning them to the NSS client.
We *could* munge the initgroups() lookup so that it would report membership in those groups, but we couldn't do the reverse, because as mentioned above we don't have the ability (or want to) to add remote users into local groups (except for the primary group loophole that we should close). So I'm not sure this is a wise move. Doing getgrnam("remote_users") would be unable to provide an actual list of users in the group.
I'm not a huge fan of making changes to memberships that aren't reciprocal.
Excerpts from Stephen Gallagher's message of Wed May 23 08:12:33 -0400 2012:
I'm working under the assumption that when you speak of "local domains" here, you're talking about /etc/passwd. If this is wrong, please correct me.
Yes, we are in agreement here.
This means that any lookup calling 'getpwnam()' or 'getpwuid()' will first check to see if it exists in the files map (aka /etc/passwd). If it does, it will return that value and that will be that.
Let's work with the following sample data. (We'll use LDAP as the SSSD domain name, for simplicity) In /etc/passwd: username 'geofft' with UID 2000 in LDAP: username 'geofft' with UID 3000 in LDAP: username 'imposter' with UID 2000
So if you have user 'geofft' in /etc/passwd and also in LDAP, you will get back the information from /etc/passwd for getpwnam("geofft"). So you will get back UID 2000.
If you call getpwnam("geofft@LDAP"), you will bypass the /etc/passwd file and get back UID 3000
If you call getpwuid(2000), you will get back user 'geofft' from /etc/passwd
If you call getpwuid(3000), you will get back user 'geofft' from LDAP
OK, the further case we worry about is as follows: If you call getpwnam("imposter"), will we get back UID 2000, or will this be rejected?
This cannot happen. Similar to the /etc/passwd example I described above, lookups for a particular group name or GID would stop at /etc/group if the name or GID matched there first. It would not take ANY group membership information for groups in /etc/group from LDAP. If you wanted to add a remote user to a local group, you would need to add that user's name to /etc/group manually.
We do not believe the traditional nsswitch semantics work this way. If you look at initgroups(), what will happen is that the lookup for groups of a remote user will fail on the local groups source (/etc/group), and then NSS will consult the remote source for groups, and initgroups_dyn will add them as secondary groups for the user. These groups are not normally distinguished from the normal groups.
It is possible that SSSD has different semantics, but this is not obvious to us.
The one catch is the user's primary group ID. Most of the time, this would be set to a user private group for security reasons, but it's theoretically possible that an LDAP user could have it set to be e.g. 10 ('wheel' on RHEL). In this case, the local system WILL honor it.
That said, I think maybe we want to add an option to filter out certain values for primary group ID in order to avoid this issue. It's a valid concern. Please file an RFE at https://fedorahosted.org/sssd (you can get an account from https://admin.fedoraproject.org/accounts if you do not have one).
Yes, and secondary GIDs have the same problem, unless SSSD does something dramatically different. I will file this report.
SSSD does not currently have any such functionality. I'd be interested to see how this module works, as I have a feeling it would be broken by recent changes glibc made to the initgroups interface.
You can access nss_nonlocal from here:
http://debathena.mit.edu/nss_nonlocal/ git://andersk.mit.edu/nss_nonlocal http://andersk.mit.edu/gitweb/nss_nonlocal.git
It also contains the code for our security checks, so if you're interested in the precise semantics, I suggest taking a look. (And yes, we use internal glibc APIs, check nsswitch-internal.h)
Here is another common security concern we are worried about: many programs (e.g. chown and chgrp, see http://debathena.mit.edu/trac/ticket/367) get confused if you pass them a numeric username, interpreting it as a UID if it exists. So nss_nonlocal also rejects remote users which have numeric IDs that match a local UID, and remote groups that have numeric IDs that match a local GID.
Cheers, Edward
On Fri, 2012-05-25 at 00:11 -0400, Edward Z. Yang wrote:
Excerpts from Stephen Gallagher's message of Wed May 23 08:12:33 -0400 2012:
I'm working under the assumption that when you speak of "local domains" here, you're talking about /etc/passwd. If this is wrong, please correct me.
Yes, we are in agreement here.
This means that any lookup calling 'getpwnam()' or 'getpwuid()' will first check to see if it exists in the files map (aka /etc/passwd). If it does, it will return that value and that will be that.
Let's work with the following sample data. (We'll use LDAP as the SSSD domain name, for simplicity) In /etc/passwd: username 'geofft' with UID 2000 in LDAP: username 'geofft' with UID 3000 in LDAP: username 'imposter' with UID 2000
So if you have user 'geofft' in /etc/passwd and also in LDAP, you will get back the information from /etc/passwd for getpwnam("geofft"). So you will get back UID 2000.
If you call getpwnam("geofft@LDAP"), you will bypass the /etc/passwd file and get back UID 3000
If you call getpwuid(2000), you will get back user 'geofft' from /etc/passwd
If you call getpwuid(3000), you will get back user 'geofft' from LDAP
OK, the further case we worry about is as follows: If you call getpwnam("imposter"), will we get back UID 2000, or will this be rejected?
This cannot happen. Similar to the /etc/passwd example I described above, lookups for a particular group name or GID would stop at /etc/group if the name or GID matched there first. It would not take ANY group membership information for groups in /etc/group from LDAP. If you wanted to add a remote user to a local group, you would need to add that user's name to /etc/group manually.
We do not believe the traditional nsswitch semantics work this way. If you look at initgroups(), what will happen is that the lookup for groups of a remote user will fail on the local groups source (/etc/group), and then NSS will consult the remote source for groups, and initgroups_dyn will add them as secondary groups for the user. These groups are not normally distinguished from the normal groups.
It is possible that SSSD has different semantics, but this is not obvious to us.
Right, this is correct (and is one of the headaches with the libc interface: the behavior of initgroups() and getgrnam() are not reciprocal).
The one catch is the user's primary group ID. Most of the time, this would be set to a user private group for security reasons, but it's theoretically possible that an LDAP user could have it set to be e.g. 10 ('wheel' on RHEL). In this case, the local system WILL honor it.
That said, I think maybe we want to add an option to filter out certain values for primary group ID in order to avoid this issue. It's a valid concern. Please file an RFE at https://fedorahosted.org/sssd (you can get an account from https://admin.fedoraproject.org/accounts if you do not have one).
Yes, and secondary GIDs have the same problem, unless SSSD does something dramatically different. I will file this report.
Yeah, I think I see the issue here now. If there's an LDAP group with ID 10, and they're a member, initgroups() of that user WILL list 10. So you're right here.
SSSD does not currently have any such functionality. I'd be interested to see how this module works, as I have a feeling it would be broken by recent changes glibc made to the initgroups interface.
You can access nss_nonlocal from here:
http://debathena.mit.edu/nss_nonlocal/ git://andersk.mit.edu/nss_nonlocal http://andersk.mit.edu/gitweb/nss_nonlocal.git
It also contains the code for our security checks, so if you're interested in the precise semantics, I suggest taking a look. (And yes, we use internal glibc APIs, check nsswitch-internal.h)
Ok, I get the gist of this. It's pretty hackish though (and will likely only work with glibc, which is a problem because we're at least *trying* to maintain compatibility with any libc in SSSD).
Also, as I originally suspected, I'm pretty sure this code is not going to work with the new initgroups() semantics added to the last two releases of glibc.
The core problem here is that this is basically a hack. The libc interface for initgroups() is intentionally-written to be additive. This is working around that by suppressing some values if they happen to also exist locally. It's not a bad solution, necessarily, but it's against the spirit of the interface.
Basically, the expectation of both SSSD and libc is that if you add a source for NSS data, it's *authoritative*. As in, you're asserting that what's in that central database is the correct answer for your environment. If that's not the case, then it's worth looking into fixing your central store (which is usually easier than futzing with individual clients).
Also, there are valid reasons that you might want to extend local groups from the central server. For example, an application like a database might use a hard-coded group ID to determine which users can access the management console. Being able to add users to this list centrally is a significant advantage.
I'm not sure we want to build a specialized control in SSSD to suppress IDs that exist in /etc/group. For one thing, it's only a stop-gap solution, as a client still might have groups added from other NSS sources that we won't know about.
In recent versions of SSSD (1.7.0 and later), we have added support for more complex group search base filtering. You can now specify an LDAP search filter as part of the group search base to specifically eliminate groups you don't want to make visible to the local machine. For example:
ldap_group_search_base = \ cn=groups,dc=ex,dc=com?subtree?(!(|(gidNumber=10)(gidNumber=11)))
This search base means that we'll look up and use any group in the cn=groups subtree except for those that have gidNumber 10 or 11.
Here is another common security concern we are worried about: many programs (e.g. chown and chgrp, see http://debathena.mit.edu/trac/ticket/367) get confused if you pass them a numeric username, interpreting it as a UID if it exists. So nss_nonlocal also rejects remote users which have numeric IDs that match a local UID, and remote groups that have numeric IDs that match a local GID.
I don't think that's something we're likely to fix, but you're welcome to file an RFE. That really sounds like bugs in chown and chgrp. I'd prefer not to be adding in workarounds for unrelated software.
On the whole, I think we have different concepts about the expectations of a central identity store. Everything we're discussing here suggests that you have concerns about trusting your identity store. That says to me that you're not in control of it, which is a security breach waiting to happen. I think you need to examine why you are relying on identities you don't control.
On Fri, 25 May 2012, Stephen Gallagher wrote:
You can access nss_nonlocal from here:
http://debathena.mit.edu/nss_nonlocal/ git://andersk.mit.edu/nss_nonlocal http://andersk.mit.edu/gitweb/nss_nonlocal.git
It also contains the code for our security checks, so if you're interested in the precise semantics, I suggest taking a look. (And yes, we use internal glibc APIs, check nsswitch-internal.h)
Ok, I get the gist of this. It's pretty hackish though (and will likely only work with glibc, which is a problem because we're at least *trying* to maintain compatibility with any libc in SSSD).
It is very much a hack. :) At this point, though, changing glibc semantics upstream is hard, but SSSD is still young enough that we're hoping we can advocate for such a feature here, should the implementation be elegant and straightforward enough. We're certainly not suggesting that SSSD should incorporate that approach into its NSS module.
One possible way for this to be implemented more elegantly is if SSSD takes responsibility for handling /etc/passwd users too, such that it can implement the filtering logic internally before any data reaches libc (or any other potential consumer). I don't know how involved this change would be, or how compatible it would be with other libcs.
Also, as I originally suspected, I'm pretty sure this code is not going to work with the new initgroups() semantics added to the last two releases of glibc.
Sigh. Our fault for relying on a hack anyway... I've made a note to test it out.
Basically, the expectation of both SSSD and libc is that if you add a source for NSS data, it's *authoritative*. As in, you're asserting that what's in that central database is the correct answer for your environment. If that's not the case, then it's worth looking into fixing your central store (which is usually easier than futzing with individual clients).
So there are two use cases here, which are sufficiently related that we've solved them with the same approach of blacklisting all local uid/gids from the remote source:
1) Some of our systems, e.g. the public workstations we operate, may as well trust the central database, except for a couple of users/groups that overlap with system/local users, and we know those uids and gids. This is more or less solvable with a minimum uid constraint, but also quite solvable by the rule that local uids and gids hide matching remote uids and gids (and somewhat more automatic).
2) We do have privately-owned systems (folks coming in with laptops, etc.) that would like to have remote accounts but that aren't in any sense owned or operated by us, and so it's preferable for us not to require even the theoretical ability to spoof local accounts on their machine. Remote accounts are fine, but they are generally unprivileged and don't have root access. Allowing those accounts to do things like add themselves to the local wheel/sudo/etc. group would be problematic.
This is exacerbated in our environment because for legacy reasons we're using Hesiod, which is over DNS, without DNSSEC. We've been working for the last few years to either get LDAP (over SSL) usable for account lookups, or get DNSSEC on our Hesiod realm, but in a large organization with an overcommitted IT staff, these changes don't happen quickly, and writing a small NSS module let us get on with things. And even if we do get one of these usable (and switching to SSSD seems like the best way to fix the client-side issues we've run into with LDAP), we'd still want the same protection scheme.
Also, there are valid reasons that you might want to extend local groups from the central server. For example, an application like a database might use a hard-coded group ID to determine which users can access the management console. Being able to add users to this list centrally is a significant advantage.
We do have some whitelisting capabilities; for instance, if you add the local (/etc/passwd) user named "nss-nonlocal-users" to a local group, then nss-nonlocal will permit the remote source to claim that users are in that local group. This isn't much used and we don't configure this out-of-the-box, but some of our end users have found this useful and requested it, e.g. to share files in a group-owned/setgid directory on local disk between a set of remote users.
I'm not sure we want to build a specialized control in SSSD to suppress IDs that exist in /etc/group. For one thing, it's only a stop-gap solution, as a client still might have groups added from other NSS sources that we won't know about.
Sure. Note that in our implementation, we do query all NSS sources; something like
passwd: files db nis nonlocal passwd_nonlocal: hesiod ldap
would work, and would allow /etc/passwd, /etc/passwd.db, and NIS to claim whatever they want, and filter all uids and gids in any of those out of Hesiod and LDAP results.
If SSSD takes responsibility for all nameservice sources, then this problem can be solved in SSSD's own configuration in roughly the same way (though with a much less hackish implementation).
In recent versions of SSSD (1.7.0 and later), we have added support for more complex group search base filtering. You can now specify an LDAP search filter as part of the group search base to specifically eliminate groups you don't want to make visible to the local machine. For example:
ldap_group_search_base = \ cn=groups,dc=ex,dc=com?subtree?(!(|(gidNumber=10)(gidNumber=11)))
This search base means that we'll look up and use any group in the cn=groups subtree except for those that have gidNumber 10 or 11.
So this doesn't really work for us because it involves trusting the remote server to do the filtering. In case 1 above that'd be fine, but in case 2 above, a malicious or even just buggy directory server could fail to implement the filtering properly.
It's also somewhat complex to update this to match all local gids, which is a model that's been working well for us.
On the whole, I think we have different concepts about the expectations of a central identity store. Everything we're discussing here suggests that you have concerns about trusting your identity store. That says to me that you're not in control of it, which is a security breach waiting to happen. I think you need to examine why you are relying on identities you don't control.
That's a fair perspective to take. Part of the reason we have concerns is less because _we're_ not in control of it as that our users are not in control of it, and would not be too happy to use a configuration that allows us (theoretically) to silently and remotely control their machines. We don't, for instance, add our SSH keys to people's laptop's /root/.ssh/authorized_keys, convenient as that might be for debugging, so why should we be able to spoof their local accounts that existed before they connected to our domain?
For the scripts.mit.edu project specifically, which is a web hosting environment using multiple servers for redundancy/reliability, one specific reason we have these concerns is to limit the ability of a breach on one server to escape to other servers. We synchronize user accounts through LDAP multimaster replication (using 389); each server's ldap://localhost is protected with nss_nonlocal. Should we accidentally misconfigure one server in a way that's exploitable, it's helpful that it's not trivially easy for the attacker to spoof root (or equivalent) on the rest of our servers. On the one or two occasions we've had security incidents in the last several years, we just took down the one problematic server and the rest of the system could run.
It's also an excellent defense-in-depth strategy for particularly sensitive servers like build machines. It's convenient to have the usual stack installed so e.g. `ls -l` displays useful usernames, but no remote accounts have any form of administrative access on the build server. We've reserved a remote account name and uid for the "builder" user, but the account exists locally, overriding the remote one.
If no account from the remote domain has any sort of administrative access to the local machine, it isn't particularly problematic for those users to exist. And in our scenario of a large environment where it's useful for UIDs to match throughout all systems should they ever need to interoperate -- UNIX machines, Windows boxes, files in networked storage, web applications, etc. etc. -- restricting the ability of the directory server to have a "master key" to every computer on campus that happens to be interacting with it is useful to maintain the principle of least privilege.
On Fri, 2012-05-25 at 00:11 -0400, Edward Z. Yang wrote:
Excerpts from Stephen Gallagher's message of Wed May 23 08:12:33 -0400 2012:
I'm working under the assumption that when you speak of "local domains" here, you're talking about /etc/passwd. If this is wrong, please correct me.
Yes, we are in agreement here.
This means that any lookup calling 'getpwnam()' or 'getpwuid()' will first check to see if it exists in the files map (aka /etc/passwd). If it does, it will return that value and that will be that.
Let's work with the following sample data. (We'll use LDAP as the SSSD domain name, for simplicity) In /etc/passwd: username 'geofft' with UID 2000 in LDAP: username 'geofft' with UID 3000 in LDAP: username 'imposter' with UID 2000
So if you have user 'geofft' in /etc/passwd and also in LDAP, you will get back the information from /etc/passwd for getpwnam("geofft"). So you will get back UID 2000.
If you call getpwnam("geofft@LDAP"), you will bypass the /etc/passwd file and get back UID 3000
If you call getpwuid(2000), you will get back user 'geofft' from /etc/passwd
If you call getpwuid(3000), you will get back user 'geofft' from LDAP
OK, the further case we worry about is as follows: If you call getpwnam("imposter"), will we get back UID 2000, or will this be rejected?
If you set id ranges so that 2000 is not valid in the domain it will be rejected.
This cannot happen. Similar to the /etc/passwd example I described above, lookups for a particular group name or GID would stop at /etc/group if the name or GID matched there first. It would not take ANY group membership information for groups in /etc/group from LDAP. If you wanted to add a remote user to a local group, you would need to add that user's name to /etc/group manually.
We do not believe the traditional nsswitch semantics work this way. If you look at initgroups(), what will happen is that the lookup for groups of a remote user will fail on the local groups source (/etc/group), and then NSS will consult the remote source for groups, and initgroups_dyn will add them as secondary groups for the user. These groups are not normally distinguished from the normal groups.
It is possible that SSSD has different semantics, but this is not obvious to us.
These semantics are not soemthing SSSD can influence, they are internal glibc semantics. On initgroups glibc asks all the group map backends about group memberships. However, recently glibc added an option so that you can segregate initgroups too. In general we try not to use it becaus ein many cases people do want to have the memberships calculated through all group backends. However if you enable "initgroupos: files sss", the getgrouplist call do not continue past files into sss if entries are found in files. I am not sure I like this option, as it is rather new, undocumented, and the semantics may not be really useful, but you may want to experiment with it if you have a new enough glibc. (Was committed to glibc upstream repo on may 10 2011)
The one catch is the user's primary group ID. Most of the time, this would be set to a user private group for security reasons, but it's theoretically possible that an LDAP user could have it set to be e.g. 10 ('wheel' on RHEL). In this case, the local system WILL honor it.
That said, I think maybe we want to add an option to filter out certain values for primary group ID in order to avoid this issue. It's a valid concern. Please file an RFE at https://fedorahosted.org/sssd (you can get an account from https://admin.fedoraproject.org/accounts if you do not have one).
Yes, and secondary GIDs have the same problem, unless SSSD does something dramatically different. I will file this report.
SSSD does not, I think we could do something as we should have access to the list of groups previous nsswitch plugins returned, but we don't, as in many cases users do want the current initgroups semantics.
SSSD does not currently have any such functionality. I'd be interested to see how this module works, as I have a feeling it would be broken by recent changes glibc made to the initgroups interface.
You can access nss_nonlocal from here:
http://debathena.mit.edu/nss_nonlocal/ git://andersk.mit.edu/nss_nonlocal http://andersk.mit.edu/gitweb/nss_nonlocal.git
It also contains the code for our security checks, so if you're interested in the precise semantics, I suggest taking a look. (And yes, we use internal glibc APIs, check nsswitch-internal.h)
Here is another common security concern we are worried about: many programs (e.g. chown and chgrp, see http://debathena.mit.edu/trac/ticket/367) get confused if you pass them a numeric username, interpreting it as a UID if it exists. So nss_nonlocal also rejects remote users which have numeric IDs that match a local UID, and remote groups that have numeric IDs that match a local GID.
IIRC per posix rules usernames cannot start with a digit. Ie they must have at least one non-digit letter in the name, which means a numeric only input to getent passwd should always be considered as a uid number.
Simo.
sssd-devel@lists.fedorahosted.org