Recently I undertook the very daunting task of integrating a Red Hat Enterprise Linux 5 server in a Windows Server 2003 RC2 Active Directory environment.
As enterprise networks go, single sign-on between operating systems from all walks of life is sort-of a holy grail of achievement, and with good reason, it was by no means obvious or easy to make it happen! But with some determination, lots of Google searching, trial and error, and a desk to bang your head against, it is ultimately possible.
In Linux-land, those nifty GUI tools for doing this sort of thing are completely worthless. On the Windows side Microsoft isn't exactly the biggest help either. The web and various man pages are your only friends. I spent the better part of two weeks searching the web, reading documentation, ant attempting to follow in the footsteps of those that came before me.
You see, I wanted to make AD login happen on a Linux server, but I did not want to become an expert in Kerberos, LDAP, Windows Active Directory, or networking in general. Unfortunately, you're much better off if you are an expert. Linux does not forgive the weak or the naive. And AD login on Linux doesn't look like it will ever be as easy as integrating a Windows client on a Windows domain. That is to say, set your domain, enter the Administrator password, and you're good to go. No, no, no, that's far too easy. OK, enough whining, let's get on with it.
Here are the goals I set out with:
That's the synopsis, currently my integration of Linux in a Windows AD environment fulfills all of those requirements but the last, and with some further research and experimentation, I believe I can fulfill all of those requirements. Now a word of warning.
DISCLAIMER: I am not an Active Directory expert. Neither am I an expert on the various technologies that Linux uses to perform authentication. There may be flaws in my configurations. I MAY NOT BE ABLE TO ASSIST YOU WITH YOUR PARTICULAR CONFIGURATION. I CANNOT GUARANTEE SECURITY. PROCEED AT YOUR OWN RISK.
The following configuration is specific to my company's particular implementation of a Windows Server 2003 (RC2) domain running Active Directory. Your results may vary, God help you in your quest.
So, without further delay, here are the configuration instructions.
In order to configure Linux for AD authentication, you must configure PAM (Pluggable Authentication Modules), nsswitch (Name Service Switch), LDAP, Kerberos, Samba, and Winbind. I present two different methods of AD authentication simultaneously, that is to say authentication via LDAP, and authentication via Winbind. These instructions are based on personal experience with the help of the following online resources/blogs.
# man ldap.conf
# man smb.conf
# man nsswitch.conf
# man pam
# man krb5.conf
# man wbinfo
Read the manual!
Again, my configuration is specific to Red Hat Enterprise Linux 5, certain bits may need to be tweaked for your particular distribution of Linux.
First up is LDAP. Make the following configuration changes to /etc/ldap.conf
bind_policy soft
host 192.168.1.10
base dc=example,dc=com
uri ldap://dc.example.com/
binddn adquery@EXAMPLE.COM
bindpw adquerypassword
scope sub
ssl no
referrals no
nss_base_passwd dc=example,dc=com?sub
nss_base_shadow dc=example,dc=com?sub
nss_base_group dc=example,dc=com?sub?&(objectCategory=group)(gidnumber=*)
nss_map_objectclass posixAccount user
nss_map_objectclass shadowAccount user
nss_map_objectclass posixGroup group
nss_map_attribute gecos cn
nss_map_attribute homeDirectory unixHomeDirectory
nss_map_attribute uniqueMember member
In the LDAP configuration, the configuration is set for a domain called example.com. The domain controller has the host name dc.example.com. The domain controller is located at the IP address 192.168.1.10.
If your domain is called something.example.com, and your domain controller is called dc.something.example.com you'd change the configuration like so where only the domain is referenced: dc=something,dc=example,dc=com
Active Directory also does not allow anonymous queries. Each query made must be associated with a valid domain user. Therefore, you must create a new user in Active Directory for this purpose. In the example configuration, this user is adquery@EXAMPLE.COM, and the user's password is adquerypassword. This user should have no privileges, in fact you should make this user a member of Domain Guests.
The remainder of the file has to do with mapping Microsoft's Services for Unix (SFU) snapin to Linux user attributes. My configuration ultimately does not utilize SFU at all, though it could with some experimentation.
The configurations I present allow two different ways of authenticating a domain user, via LDAP and Kerberos, or via Winbind. The former configuration does not allow Linux SMB shares to mount on Windows clients, while the latter does, at least in this particular Windows AD domain.
# An example Name Service Switch config file. This file should be
# sorted with the most-used services at the beginning.
#
# The entry '[NOTFOUND=return]' means that the search for an
# entry should stop if the search in the previous entry turned
# up nothing. Note that if the search failed due to some other reason
# (like no NIS server responding) then the search continues with the
# next entry.
#
# Legal entries are:
#
# nisplus or nis+ Use NIS+ (NIS version 3)
# nis or yp Use NIS (NIS version 2), also called YP
# dns Use DNS (Domain Name Service)
# files Use the local files
# db Use the local database (.db) files
# compat Use NIS on compat mode
# hesiod Use Hesiod for user lookups
# [NOTFOUND=return] Stop searching if not found so far
#
# To use db, put the "db" in front of "files" for entries you want to be
# looked up first in the databases
#
# Example:
#passwd: db files nisplus nis
#shadow: db files nisplus nis
#group: db files nisplus nis
passwd: files winbind
shadow: files
group: files winbind
#hosts: db files nisplus nis dns
hosts: files dns wins
# Example - obey only what nisplus tells us...
#services: nisplus [NOTFOUND=return] files
#networks: nisplus [NOTFOUND=return] files
#protocols: nisplus [NOTFOUND=return] files
#rpc: nisplus [NOTFOUND=return] files
#ethers: nisplus [NOTFOUND=return] files
#netmasks: nisplus [NOTFOUND=return] files
bootparams: files
ethers: files
netmasks: files
networks: files
protocols: files
rpc: files
services: files
netgroup: files
publickey: nisplus
automount: files
aliases: files nisplus
In the preceding block you see the standard nsswitch.conf file that's shipping with Red Hat (and presumably Fedora and CentOS). This is the only important modification to make:
passwd: files winbind
shadow: files
group: files winbind
You're telling Linux to look at winbind as a source of authentication information, in addition to the Linux files /etc/passwd and /etc/group.
I could use the following configuration for LDAP, instead of Winbind. If only AD authentication is required (but no file shares), that would be the way to go. If going that method, you'll need that Microsoft Services for Unix snapin to be installed, and you'll have to configure the UID, GID, Home Directory, and Login Shell attributes for each domain user logging into Linux.
passwd: files ldap
shadow: files
group: files ldap
#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
#auth required /lib/security/$ISA/pam_env.so
#auth sufficient /lib/security/$ISA/pam_unix.so likeauth nullok
#auth sufficient /lib/security/$ISA/pam_krb5.so
#auth required /lib/security/$ISA/pam_deny.so
auth sufficient /lib/security/$ISA/pam_winbind.so
auth sufficient /lib/security/$ISA/pam_unix.so nullok_secure use_first_pass
auth required /lib/security/$ISA/pam_deny.so
#account sufficient /lib/security/$ISA/pam_unix.so
#account sufficient /lib/security/$ISA/pam_krb5.so
#account sufficient /lib/security/$ISA/pam_succeed_if.so uid < 100 quiet
#account required /lib/security/$ISA/pam_deny.so
account sufficient /lib/security/$ISA/pam_winbind.so
account required /lib/security/$ISA/pam_unix.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 required /lib/security/$ISA/pam_deny.so
session required /lib/security/$ISA/pam_mkhomedir.so skel=/etc/skel umask=0077
session required /lib/security/$ISA/pam_limits.so
session required /lib/security/$ISA/pam_unix.so
PAM is configured to use winbind for authentication in this example, if going the LDAP route, remove the "auth" and "account" blocks, and uncomment the corresponding "auth" and "account" lines containing references to krb5.
# Do not remove the following line, or various programs
# that require network functionality will fail.
127.0.0.1 NETBIOS.EXAMPLE.COM NETBIOS localhost
192.168.1.10 DC.EXAMPLE.COM DC
In the hosts configuration, you're doing two things. One, you're setting the Fully-Qualified Domain Name (FQDN) of the server or workstation, and two, you're hard-coding a DNS entry for the location of the domain controller. For good measure.
[logging]
default = FILE:/var/log/krb5libs.log
kdc = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmind.log
[libdefaults]
default_realm = EXAMPLE.COM
dns_lookup_realm = true
dns_lookup_kdc = true
[realms]
EXAMPLE.COM = {
kdc = dc.example.com
admin_server = dc.example.com:749
default_domain = example.com
}
[domain_realm]
example.com = EXAMPLE.COM
.example.com = EXAMPLE.COM
[kdc]
profile = /var/kerberos/krb5kdc/kdc.conf
[appdefaults]
pam = {
debug = false
ticket_lifetime = 36000
renew_lifetime = 36000
forwardable = true
krb4_convert = false
}
WARNING: The case of the domain names in krb5.conf is important. You will fail if this is not configured correctly.
At this point, you should be able to do a kerberos authentication. At the command line, cross your fingers and type the following:
# kinit user@EXAMPLE.COM
The above command obtains a new kerberos ticket. You do not have to be joined to the domain to obtain a kerberos ticket. Joining to the domain is necessary for mutual authentication, and is required for Linux SMB shares. Again, the case is important. The domain must be typed in all uppercase, or this command will fail. See if you have obtained a kerberos ticket by running the following command:
# klist
You should see a valid kerberos ticket.
Don't forget that the clock of the Linux client must be within the range allowed by the Windows server. Typically this is a skew of plus or minus five minutes. The best way to handle this is to set your clock to automatically synchronize to an NTP server, such as time.redhat.com.
If they are running, stop the smb and winbind services.
# /sbin/service smb stop
# /sbin/service winbind stop
Now, configure /etc/samba/smb.conf.
[global]
workgroup = EXAMPLE
realm = EXAMPLE.COM
netbios name = NETBIOS
server string =
security = ads
use kerberos keytab = true
hosts allow = 192.168. 127. 10.
load printers = no
log file = /var/log/samba/%m.log
client use spnego = yes
max log size = 50
log level = 1
password server = DC.EXAMPLE.COM
idmap uid = 10000 - 20000
idmap gid = 10000 - 20000
winbind enum users = yes
winbind enum groups = yes
winbind cache time = 10
winbind nested groups = yes
;winbind nss info = template sfu
winbind use default domain = no
wins server = 192.168.1.15 192.168.1.16
template homedir = /home/%U
template shell = /bin/bash
;idmap backend = idmap_ad
dns proxy = no
domain master = no
preferred master = no
[www]
comment = www on NETBIOS
path = /home/www
valid users = @EXAMPLEweb
force user = www
force group = EXAMPLEweb
public = no
writable = yes
printable = no
Although I haven't tested it yet, I believe it is possible to use both winbind and Windows Services for Unix to generate Unix account attributes, UID, GID, login shell, and home directory. man smb.conf leads me to believe this is possible, but more tinkering is required. Additionally, smb.conf can be configured to store the winbind-generated attributes in an LDAP container, which is useful for synchronizing these attributes among multiple Linux clients.
Test the samba configuration.
# testparm /etc/samba/smb.conf
With regards to share definitions, group membership can be tested as criteria
valid users = @EXAMPLEweb
The above says that anyone in the group EXAMPLEweb is allowed access to the share.
Spaces in group names must be accounted for specially, just enclose the name in quotes.
valid users = @"EXAMPLEgroup name"
Now make sure that winbind and samba are set to start at boot, and that samba starts before winbind. Do this from the webmin console or the services console.
Now, start Winbind and Samba services, samba sbould be started first.
# /sbin/service smb start
# /sbin/service winbind start
Obtain a kerberos ticket for the domain Administrator
# kinit Administrator@EXAMPLE.COM
Verify that you have a ticket.
# klist
Join the workstation to the domain.
# net ads join
Alternatively, you can also join using the following command, which supersedes the need to pull a kerberos ticket for the domain Administrator.
# net ads join -U Administrator
As I explained previously in the configuration for LDAP, Windows Server 2003 does not allow anonymous queries, so you'll have to assign winbind a domain user, again this domain user does not need any privileges, in fact it's better if it is a member of domain guests.
# wbinfo --set-auth-user adquery%adquerypassword
The modulus separates the username and password, for a more complex password that may have characters that have special meaning in the BASH terminal, enclose the password in single (or double) quotes.
# wbinfo --set-auth-user adquery%'adquerypassword'
In Active Directory, the user lookup should be a member of Domain Guests. Verify that you have set the user with the following
# wbinfo --get-auth-user
The above should print the username and password.
Verify that you are joined by testing the join
# wbinfo -t
# net ads testjoin
Now, test that you have domain users and groups available.
# wbinfo -u
The above should print every domain user as EXAMPLEuser.
# wbinfo -g
The above should print every domain group as EXAMPLEgroup.
Test that you have merged domain users and local users with the following.
# getent passwd
The same for groups
# getent group
Domain users should be appended to the results of each of those commands.
Test a login with a domain user account.
# ssh -l EXAMPLEuser localhost
If the above is successful, you should see "Directory created for user", and have a login by SSH.
Operations like chown and chgrp should now work with domain users. At the command line, and in most other operations, any user or group name containing spaces must be enclosed in quotations. Additionally, the backslash character must be escaped like you see above in the SSH login.
If you are not able to login via a domain user, or if getent passwd / getent group does not return domain users, it may be necessary to clear the winbind cache.
# /sbin/service smb stop
# /sbin/service winbind stop
Delete the winbind cache.
# rm -f /var/cache/samba/winbindd_idmap.tdb
# /sbin/service smb start
# /sbin/service winbind start
For debugging, change the log level in smb.conf to 10, and look for the log for the client you are attempting to connect with in /var/log/samba. Logs are kept by netbios name and IP address.
Before attempting to connect to a Linux SMB share from a Window client, it may be necessary to logout and login on the client. It may also be necessary to wait a little time for propagation.
You may also find that the testparm /etc/samba/smb.conf command complains about the winbind separator. It's supposed to be a backslash by default. If this is a problem for you, you may want to change the separator to a plus sign instead. That change might look like this:
winbind enum users = yes
winbind enum groups = yes
winbind cache time = 10
winbind nested groups = yes
winbind separator = +
# net ads changetrustpw
The above changes the machine's kerberos password, and updates the samba-maintained Kerberos keytab. This hangs when I do it, so CTRL + C to cancel out of it.
Once done, you have logout and login to any machines you're using to test.
Test the join.
# net ads testjoin
Leave the domain.
# net ads leave
Print out the workgroup of the kerberos realm.
# net ads workgroup
Print out the workgroup of the kerberos realm.
Cleanup, before logging off the server run the following command:
# kdestroy
This will remove any active kerberos tickets, including any obtained for the domain Administrator.
The domain Administrator can be given root access to the Linux server by editing the /etc/sudoers file.
# visudo -f /etc/sudoers
Make the following modification around the "root" line.
root ALL=(ALL) ALL
%Domain_Admins All=(ALL)ALL
I have not yet tested granting the domain administrator root privileges via sudo, so I'm not certain if that works.
There are no comments posted at this time.
* All comments are moderated and are subject to approval.
Your comment will appear once it has been approved.
Posting multiple times will not expedite the approval process.