Tuesday, March 10, 2009

Active Directory (AD) Authentication on a Linux Server

Domain Authentication for Linux

I've updated the instructions here to support RHEL 6. I've streamlined things a bit, too, so I'd head over to this page to get the latest on setting up AD authentication for a Linux server. There are a lot of how-tos surrounding the integration of authentication and authorization in Linux through Active Directory domains. I've found a variety of them helpful, and I've found more to be confusing, rather than helpful. Here I'm hoping to put together a start-to-finish process for using your domain to authenticate and authorize users on your linux box. These instructions are written for Red Hat Enterprise Linux v5 (RHEL from now on). That means the file locations should be the same for CENTOS distros (which I highly recommend as a server OS), but that they might move around a bit for others.

A very small bit of background: this system uses winbind and smb to connect to the domain to authenticate users. Kerberos is used to join the system to the domain. The benefit of this system is that it's secure and it's pretty easy to configure. Coupled with PAM (Pluggable Authentication Modules), it's quite flexible, and it's really pretty cool functionality.

Likewise Open

If this looks too daunting (it's not so hard, I promise!), or if you don't want to mess with Samba, take a look at Likewise Open Source. It's a utility that does just what we're doing in this article, but it does it apart from the OS tools we're using here. I've not used it, but I've heard good things about it. It also looks like it's got some neat admin features that could be really useful. If you've had experience with Likewise, I'd love to hear about it.

And now back to the show

To be clear: this isn't utilizing kerberos except for joining the domain; it's using samba (smb) and winbind (which is a part of samba). A note about a particular assumption here: we're using DNS for name resolution. A lot of instructions out there assume you're using a hosts file for name resolution. That's certainly an option, if you're not in an environment where DNS is practical. All that is to say: we're assuming your computers can find each other without special changes to your hosts file. So the first thing we want to do is edit the relevant configuration files.

Edit the configuration Files

Seems like the easiest thing is to include the two most important config files. Critical changes are in blue, and my comments are in orange. Lots of folks are using "example.com" for sample config files, so I'll go with that as well. Substitute your domain name wherever you see example.com. The short name of the domain, then, is "example".

/etc/krb5.conf

Make sure your file reads as follows. Note the capitalization.
default_realm = EXAMPLE.COM
dns_lookup_realm = true
dns_lookup_kdc = true
ticket_lifetime = 24h
forwardable = yes
 [realms]
EXAMPLE.COM = { 
kdc = adserver.example.com:88 
admin_server = adserver.example.com:749 
default_domain = example.com }
 [domain_realm]
.example.com = EXAMPLE.COM 
example.com = EXAMPLE.COM

/etc/samba/smb.conf

#================== Global Settings ===================
[global]
# workgroup = NT-Domain-Name or Workgroup-Name, eg: MIDEARTH
workgroup = example
# server string is the equivalent of the NT Description field
# Which is to say: this can be whatever you want it to be.
server string = My Linux Box
# Security mode. Defines in which mode Samba will operate. Possible
# values are share, user, server, domain and ads. Most people will want
# user level security. See the Samba-HOWTO-Collection for details.
security = ads
# This option is important for security. It allows you to restrict
# connections to machines which are on your local network. The
# following example restricts access to two C class networks and
# the "loopback" interface. For more examples of the syntax see
# the smb.conf man page
# This can be quite useful, if you've got a limited number of users:
# it's difficult to hack in if there only are a couple of gates into the city.

; hosts allow = 192.168.1. 192.168.2. 127.
# The next two lines tell the OS what range of UID and GID (user and group ID numbers)
# to use when creating new accounts. It doesn't really matter terribly what you use, but
# most folks keep it in the high range for clarity.

idmap uid = 10000-20000

idmap gid =
10000-20000
# Don't forget to set this next line

template shell = /bin/bash

#Telling
winbind to use the default domain essentially means there are some situations (like logging in)
# in which you won't have to specify the domain name.
# We use it, but there is a pitfall: domain users don't have to
# specify the domain name when logging in; if there are local
# accounts with the same name, serious confusion can ensue.

winbind use default domain = true
[SNIP]
# DNS Proxy - tells Samba whether or not to try to resolve NetBIOS names
# via DNS nslookups. The default is NO.
# HEADS-UP: the following is case-sensitive: it needs to be all upper-case

realm = EXAMPLE.COM 

encrypt passwords = yes ;
guest ok = no ;
guest account = nobody

# These scripts are used on a domain controller or stand-alone
# machine to add or delete corresponding unix accounts ;
add user script = /usr/sbin/useradd %u ;
add group script = /usr/sbin/groupadd %g ;
add machine script = /usr/sbin/adduser -n -g machines -c Machine -d /dev/null -s /bin/false %u ;
delete user script = /usr/sbin/userdel %u ;
delete user from group script = /usr/sbin/deluser %u %g ;
delete group script = /usr/sbin/groupdel %g

#=================== Share Definitions =====================

Note that I've left the settings in the above file in the locations where you find them in a default smb.conf file. Settings that aren't in there by default are grouped at the top. All of these settings, though, are global, so they all can be clumped together, if you so choose
.

/etc/nsswitch.conf

# 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: compat

group: files winbind

#hosts: db files nisplus nis dns
hosts: files dns
# 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: nisplus [NOTFOUND=return] files
ethers: db files
netmasks: files
networks: files dns
protocols: db files
rpc: db files
services: db files
netgroup: nisplus
publickey: nisplus
automount: files nisplus
aliases: files nisplus

Join the domain

Now we can restart samba to pick up the new settings and join the domain:
service smb restart net ads join -u username
where username is a domain user who has permissions to join a computer to the domain. We should get a response about having joined the domain. Don't worry about errors in updating the DNS; if your server cannot update the DNS, then we don't want it to. Now start winbind:
service winbind start

Test out your settings to make sure you can enumerate the domain groups (I'd use groups instead of users; as a large domain can take a very long time to send over all the users).

wbinfo -g
Now we can edit our PAM configuration:

/etc/pam.d/system-auth

#%PAM-1.0
# User changes will be destroyed the next time authconfig is run.
# Note the above statement. If you run authconfig after manually changing this,

# some of your changes may get dropped.

auth required pam_env.so
auth sufficient pam_unix.so nullok try_first_pass
auth requisite pam_succeed_if.so uid >= 500 quiet
auth sufficient pam_winbind.so use_first_pass

auth required pam_deny.so
account required pam_unix.so
account sufficient pam_succeed_if.so uid < 500 quiet
account required pam_permit.so
password sufficient pam_winbind.so use_authtok

password required pam_deny.so
session optional pam_keyinit.so revoke
session required pam_limits.so
session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session required pam_unix.so

The above is called by most of the other PAM modules, so we should be able to do minimal modifications to other files after having changed this one. We do want the system to create a home directory for people when they log in, so we'll add the following line both to the gdm and sshd files:

session required pam_mkhomedir.so skel=/etc/skel umask=0077

The umask 0077 will give the users full control over their home directory, but no one else will have access. Having added that, we should be able to log in using the username EXAMPLE\username That is, DOMAINNAME\username, to be clear.

Now, since we told winbind to use the default domain, people also should be able to log in using just their domain username. It's probably a good idea, to avoid confusion, to have people use the domain name, too. But there certainly will be situations in which that's not necessary. If you're not able to log in, make sure that your sshd file has calls to system-auth, like in the following example:

#%PAM-1.0
auth include system-auth

account required pam_nologin.so
account include system-auth

account sufficient pam_localuser.so
password include system-auth

session optional pam_keyinit.so force revoke
session include system-auth

session required pam_loginuid.so
session required pam_mkhomedir.so skel=/etc/skel umask=0077

This is the case by default, so all should be fine. Note that this works, too, with the gdm PAM file; that means you can log in to a remote GUI (GDM in this case) on your Linux box with your domain name. Pretty cool.

Restricting Login with Domain Groups

Now that we've set this up, we want to be able to limit the users who can log in to this computer. As it stands right now, any domain user can log in. Usually not the best option (though it may be in your case).
So we'll add a line to the ssh and gdm PAM module configuration files:

account required pam_succeed_if.so user ingroup EXAMPLE\groupname

This line will be the last of the "account" lines. You can stack these, as well as specify users instead of groups, which provides a lot of flexibility. Let's say that we have three groups, linuxusers, webadmins, and domainadmins that we want to be able to log in to our linux server.

Let's say that our domain name is TEST, and let's say that we want, also to allow a user "frank" to be able to log in to our server. We could have a sshd file like this that would allow just that:
#%PAM-1.0
auth include system-auth
account required pam_nologin.so
account include system-auth
account sufficient pam_localuser.so
account sufficient pam_succeed_if.so user = TEST\frank

account sufficient pam_succeed_if.so user ingroup TEST\linuxusers
account sufficient pam_succeed_if.so user ingroup TEST\webadmins1
account required pam_succeed_if.so user ingroup TEST\domainadmins
password include system-auth
session optional pam_keyinit.so force revoke
session include system-auth
session required pam_loginuid.so
session required pam_mkhomedir.so skel=/etc/skel umask=0077
So we've got our user frank allowed (along with all local users on the line above it), and the groups below. Note that the account is "sufficient" until the last group: these are heirarchical, so if the "required" group is first, none of the other groups will be able to log in.

Troubleshooting

One of the most common problems is previous domain joins on the system. One way to take care of that problem is simply to delete the files that are created on the server when joining a domain. Those are (again, on RHEL and CENTOS; other distros have the same files, but in different locations):
/etc/samba/secrets.tdb
/var/cache/samba/*.tdb
remove the above files (perhaps you might make a copy of the secrets.tdb file) and try to join the domain again.

5 comments:

  1. big thanks for this howto! helped me a lot! cheers - Andy

    ReplyDelete
  2. what changes are made with system-auth file,i can not make out that.please,help me as soon as possible

    ReplyDelete
    Replies
    1. Hi, Subhrajit, The changes to the system-auth file are in light blue. In case they're not displaying properly, here they are:
      auth sufficient pam_winbind.so use_first_pass
      password sufficient pam_winbind.so use_authtok

      The above two lines are new additions to the file, and they'd each go before the relevant pam_deny.so line.
      Let us know if you run into problems.

      Delete
  3. but when i opened system-auth fie,the lines which have been given by you,were already there,i only added the mkhomedir.so line at the bottom.what should i do?

    ReplyDelete
    Replies
    1. Are you finding errors in your log? Look specifically at /var/log/messages and /var/log/secure. Samba also has a log file in /var/log. Also, are you getting an error when trying to authenticate as a domain user? These will help us track down the problem.

      Delete

Thanks for leaving a comment!