Linux to Active Directory Authentication (Part 1)
For a while now I've been meaning to write an article on how to easily set up your Linux boxes to authenticate against an Active Directory setup. I've had this working in production environments for a while now, having cobbled together bits and pieces from various websites, blogs, and trial and error experimentation.
First of all, you're going to need a Windows 2000 Server or Windows Server 2003 system with Active Directory and Microsoft Services for UNIX installed. SFU provides things like extensions to LDAP to make this work, an NFS server, and bits and pieces of other stuff that you probably wouldn't ever care about. If you're using Windows Server 2003 R2 or Windows 2008 then you don't need to worry about SFU comes as part of the base operating system.
Second of all, you're going to need a Linux system. I have done all of my testing with CentOS 4 and 5, which means that it will work for real Red Hat Enterprise Linux servers as well as Oracle Enterprise Linux, if you're one of the five people out there running it. The configuration files below will work fine for either version, so you won't have any problems there.
I'm going to give you a very, very basic config to look at which, later in the article, I will explain why you won't want to use in production. In a (very) soon to be written follow-up article I'll give you some more information on how to make it production ready.
For your Linux machines, you're going to want to make sure that you have the ncsd and nss_ldap packages installed. OpenLDAP should get installed in a default installation, but if you're using a custom kickstart that does not include it, you'll want to install it. On CentOS systems it's as easy as yum'ming it in. On RedHat systems you'll either need to use up2date (if you have a RHN subscription) or manually install it from your media.
The way that LDAP works is when you log in with a user on your Linux box, it will query your LDAP server (in this case your Domain Controllers) to see if you are a valid user, and if you're providing a valid password. On Linux (OpenLDAP) and Windows 2000 servers, this query can be run anonymously - without having to supply some form of credentials to the server to specify that you have rights to do the lookup. Microsoft (rightly) changed the default behavior in Windows 2003 to require a user to bind to Active Directory to do the lookup. So the first order of business is to create a domain user that can be used to query your Active Directory. This user just needs rights in the Domain Users security group. They should not get Administrator access. In my examples this user is called "binduser" and has a password of "password". You should be able to lock this user down so they can not actually log in from any station. (I'll need to test that.)
On your Linux machine, edit the file /etc/ldap.conf, and replace the contents with this. Note the comments in-line:
host your.domain.controller # If you have multiple LDAP servers, separate them with a space.
base cn=Users,dc=domain,dc=com
# If your AD domain is called "foo.com" then the LDAP base is cn=Users,dc=foo,dc=com
# If you're like me, you store users in various OU's, so you could have your base be something further up or down
# the tree, such as:
# base dc=domain,dc=com (to include everything)
# base cn=Sales,dc=domain,dc=com
# base cn=Development,dc=domain,dc=com
# etc.
binddn cn=binduser,cn=Users,dc=domain,dc=com
# This is the important bit. This is where it's going to look to find that user that it will use to look at your AD.
# I store mine in the default "Users" OU, if you put yours elsewhere, you'll need to adjust that as needed
bindpw password
# Since the password is stored in plaintext on your servers you're going to want to use some throwaway
# password for this user.
scope sub
#
# Active Directory Mappings
#
# Since Microsoft doesn't use the same sort of naming scheme for account names, passwords, or other LDAP
# attributes as OpenLDAP we need to provide some sort of translation. Here's where we tell Linux to look for
# various things in AD. Most importantly the username for the user is found at the attribute sAMAccountName
pam_login_attribute sAMAccountName
pam_filter objectclass=User
pam_password ad
pam_member_attribute msSFU30PosixMember
nss_base_passwd dc=domain,dc=com
nss_base_shadow dc=domain,dc=com
nss_base_group dc=domain,dc=com
nss_map_objectclass posixAccount User
nss_map_objectclass shadowAccount User
nss_map_attribute uid sAMAccountName
nss_map_attribute uidNumber msSFU30UidNumber
nss_map_attribute gidNumber msSFU30GidNumber
nss_map_attribute cn sAMAccountName
nss_map_attribute uniqueMember member
nss_map_attribute userPassword msSFU30Password
nss_map_attribute homeDirectory msSFU30HomeDirectory
nss_map_attribute loginShell msSFU30LoginShell
nss_map_attribute gecos name
nss_map_objectclass posixGroup Group
nss_map_attribute uniqueMember msSFU30PosixMember
nss_map_attribute cn cn
Now, open up the file /etc/openldap/ldap.conf and edit it thusly:
HOST your.domain.controller # If you have multiple LDAP servers, separate them with a space.
BASE dc=domain,dc=com
Now, edit the file /etc/nss/nsswitch.conf. This is going to tell Linux where to look for user authentication. Make sure the passwd, shadow, and group lines look like this. It will check for local users first, and then go to LDAP if there is no local user.
passwd: files ldap compat
shadow: files ldap compat
group: files ldap compat
One handy thing would be to have Linux auto-create a home directory from the /etc/skel templates for a user that logs in via LDAP for the first time. You can edit the /etc/pam.d/system-auth file and edit it so it looks like this:
auth required /lib/security/$ISA/pam_env.so
auth sufficient /lib/security/$ISA/pam_unix.so likeauth nullok
auth sufficient /lib/security/$ISA/pam_ldap.so use_first_pass
auth required /lib/security/$ISA/pam_deny.so
account required /lib/security/$ISA/pam_unix.so broken_shadow
account sufficient /lib/security/$ISA/pam_succeed_if.so uid < 100 quiet
account [default=bad success=ok user_unknown=ignore] /lib/security/$ISA/pam_ldap.so
account required /lib/security/$ISA/pam_permit.so
password requisite /lib/security/$ISA/pam_cracklib.so retry=3
password sufficient /lib/security/$ISA/pam_unix.so nullok use_authtok md5 shadow
password sufficient /lib/security/$ISA/pam_ldap.so use_authtok
password required /lib/security/$ISA/pam_deny.so
session required /lib/security/$ISA/pam_limits.so
session required /lib/security/$ISA/pam_unix.so
session required /lib/security/$ISA/pam_mkhomedir.so skel=/etc/skel/ umask=0077 # sets home dir perms to 700
session optional /lib/security/$ISA/pam_ldap.so
Now, don't rush to log in as a Windows user yet. You'll need to give them access via Services for UNIX. On the domain controller that you have SFU installed on, go to Active Directory Users and Computers and edit the properties for the user. There should be a tab that says "UNIX Attributes." Select that, and then put them in the NIS domain of your organization, assign them a UID, a default shell, and you should be set.
Try logging in as the user. It may be a bit slow depending on your network and the speed of your machines, but if all goes right the user will authenticate and get a home directory made for them (with the proper umask!)
So, remember before when I said that you don't want to use this in production? Well, think of what happens when you log in. The system presents you with a prompt for your username. Fine, you enter that in. Then it asks you for your password. It then takes both of them and goes up to your domain controller and says "Here's user X does he exist? Fine. Here's his password" sent in cleartext over the wire. Fortunately, you can use SSL to encrypt that exchange so your password does not get sent around to the nearest sniffer. I'll be covering that in a (soon to be written) future article as it's a bit tricky to get set up right.
I'd love to hear from other people doing this in their environments. Feel free to send me a comment and let me know if I am missing any information or if there's anything not very clear.
Productive Day
Today I finally managed to get RHEL5 boxes authenticating against Active Directory using secure LDAP. I had no problem getting RHEL4 boxes to do it, or RHEL5 boxes without TLS, but I figured out what the problem was with RHEL5. In my /etc/ldap.conf I had a line:
ssl yes
Which enabled Secure LDAP in RHEL4. In RHEL5 the line needs to be:
ssl start_tls
Incidentally, that line works fine in RHEL4, which means that I can continue using the same config files (and eventually package them up as an RPM or something for when we provision new nodes) across RHEL4 and RHEL5 systems.
Beyond that Chris managed to get two Itanium HPUX servers racked and their console cards configured. He had a nice introduction to Wireshark to get their MAC address, and then arp ping to configure the IP's. Tomorrow I will work with him to get the VLANs set correctly on the switch uplinks, and then I will have to do something to jog my memory to disable Serviceguard on those two nodes.