Apache 'Require ldap-group' Limitation
The problem, briefly: Apache configured to authenticate via LDAP and authorize access only to members of a certain group, would not authorize a new user account that was clearly a member of that group.
The solution, briefly: The new user account had its primary group
identifier (GID) set to the authorized group, while all other users
were auxiliary members. The new user account had to be given an
explicit memberUid
entry within the group’s LDAP definition.
The longer story
I and the rest of our team use our regular accounts for both normal
and administrative work on our Unix machines, resorting to separate
admin accounts on Windows only. In the Unix environment, we’re
members of the group admins
, that grants us the rights to log
into infrastructure machines and invoke sudo
when necessary.
Our documentation wiki contains some sensitive information, so we
require that wiki visitors also be a member of the admins
group.
We use Apache’s mod_authnz_ldap:
<Directory />
# everyone authenticates
AuthName "Documentation"
AuthType Basic
AuthBasicProvider ldap
AuthLDAPUrl "ldap://directory.work.com:389/ou=users,dc=work,dc=com?uid?sub"
AuthLDAPGroupAttribute memberUid
AuthLDAPGroupAttributeIsDN off
Require ldap-group cn=admins,ou=groups,dc=work,dc=com
</Directory>
An admin-only account
A colleague within our system administration group—let’s call him
“Skip”—wanted to create a new, separate user account for himself.
He planned to use his regular account for non-administrative functions
only, switching to the new account only when he wanted to invoke
sudo
or do other administrator-level work.
Skip didn’t want his regular account listed in that administrative group, which meant that he’d have to use his new administrative account to access our wiki.
He created the account: skipadm
. He tested login access to machines
that require users to be part of the admins
group. He encountered
no troubles. Unix tools like id
reported that the skipadm
user
was part of the admins
group using
Apache: denied
Despite success with system-level access, Apache wouldn’t authorize
him. We increased Apache’s LogLevel
setting up to trace6
and
watched the error log. We could see that the password was accepted
just fine, but Apache couldn’t map the account to the admins
group.
[Thu Mar 17 10:01:33.809963 2016] [authnz_ldap:debug] [pid 18098] mod_authnz_ldap.c(593): [client 10.11.12.13:46107] AH01697: auth_ldap authenticate: accepting skipadm
[Thu Mar 17 10:01:33.809969 2016] [authnz_ldap:debug] [pid 18098] mod_authnz_ldap.c(879): [client 10.11.12.13:46107] AH01714: auth_ldap authorize: require group: testing for memberUid: skipadm (cn=admins,ou=groups,dc=work,dc=com)
[Thu Mar 17 10:01:33.810001 2016] [authnz_ldap:debug] [pid 18098] mod_authnz_ldap.c(945): [client 10.11.12.13:46107] AH01720: auth_ldap authorize group: authorization denied for user skipadm to /wiki/
Various troubleshooting steps followed, to no avail.
First light
Then Skip sent this to me via chat:
actually, maybe I have a theory
I think I set it as my primary GID
And that freed up the brain cells for me to get to the heart of the problem.
Normal account creation
Here’s our normal procedure for creating new user accounts:
- Create the new user, making
allusers
the primary group - Create a new group with the same name as the new user account
- Add user to the new per-user group
- Create home directory owned by user and per-user group
- Add user to any other pertinent auxiliary groups.
For example, for Skip’s normal account we
- Created user
skip
with GIDallusers
. - Created group
skip
and added userskip
to it. - Made a home directory owned by user
skip
and groupskip
. - Added user
skip
to theadmins
group.
A slight abnormality
When Skip created his admin account, however, he followed a different procedure:
- Created user
skipadm
with GIDadmins
- Created group
skipadm
and added userskipadm
to it. - Made a home directory owned by user
skipadm
and groupskipadm
.
Most user accounts for system administrators have admins
added as an
auxiliary group, but for this account it was the primary group.
The LDAP difference
That difference showed up in our LDAP directory in an unexpected way.
In a normal case, the user’s directory entry has the accounts user ID (UID) listed via uidNumber and the group ID via gidNumber. Auxiliary group membership isn’t listed in the user’s entry but by querying memberUid in a group entry.
In our directory scheme, however, the default group doesn’t get memberUid entry, just the aforementioned gidNumber in the user’s entry.
It can show up via getent
. If we assume that the allusers
group (our default group) has GID 1234, we can see a huge difference in the number of group members seen via getent group allusers
as opposed to via getent passwd
and looking for GID 1234:
[~]$ getent group allusers | cut -d: -f4 | sed 's/,/ /g' | wc
1 61 484
[~]$ getent passwd | grep :1234: | wc
916 917 50790
The group map reports 61 members, while the passwd map reports 916.
When queried on a per-user basis, the system has one view of group membership. That’s what PAM does, and that’s why Skip was able to use his new account to log into systems.
Back to Apache
When viewed on a per-group basis, there’s a different view. That’s what Apache does, and that’s why it didn’t view Skip’s admin account as a group member.
Short of asking Apache to test group membership via PAM by way of
a mechanism like the id
utility, I’m not sure there’s an easy
long-term solution to this problem when the user and group databases
are stored in LDAP.
The fix
The fix was easy, if not really scalable: I manually edited the LDAP
directory, adding a memberUid for skipadm
in the admins
group
entry. Once that was in place, Apache was fine.
Still, it was a weird problem.