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.