Ubuntu 12.04 Active Directory Authentication

4.20 avg. rating (83% score) - 5 votes

Update 2015-06-16: Ubuntu 14.04 Active Directory Authentication

Authenticating Linux users against Active Directory has traditionally been hard. There’s a multitude of HOWTOs on how to do it, and every one of them seems to do it a bit differently. This is because environments and goals vary, and there are many ways to achieve a particular goal. I will add my version to the mix. This one fetches users and groups from Active Directory LDAP using a machine account added using the Samba tools, and authenticates users to the Active Directory Key Distribution Center using Kerberos.

I will use the LDAP schema that comes with the Microsoft Services for Unix Tools which has later been renamed to Subsystem for UNIX-based Applications (SUA).

I will configure the server to fetch user account and group data from Active Directory LDAP using the nss_ldap Name Service Switch module. This information will be used in addition to the data found in local /etc/passwd and /etc/group files. I will also configure the Kerberos authentication client using MIT Kerberos libraries and tools, and configure the pam_ldap Pluggable Authentication Module to utilize it. The Samba tools are used to add a machine account for the host, as well as a keytab file which will be used for querying Active Directory LDAP. No need to add special user accounts for querying AD.

Still, the whole process is not simple by any means. Here’s an outline:

  1. Install and configure the MIT Kerberos client and test that it works
  2. Install and configure the Samba tools
  3. Use the Samba tools to “join” the machine to the domain, or in other words, to create a machine account for it in the AD LDAP
  4. Add forward and reverse DNS records for the machine
  5. Create the host keytab file
  6. Map a suitable Kerberos principal to the new machine account in AD, and test that it works with the keytab file
  7. Make sure there’s a valid ticket for the machine account all the time
  8. Extend AD LDAP schema using the SFU/SUA tools
  9. Install LDAP tools and test connecting to the AD and see the internal structure
  10. Install and configure nss_ldap to fetch user and group information from AD
  11. Install and configure pam_ldap to authenticate to AD
  12. Add a PAM directive to create a home directory for a user logging in the first time if such a directory does not yet exist

Install and configure kerberos

Install the Kerberos library, related PAM library, and also Samba client which we will just use to create a machine account in the domain, and create a keytab file.

Type in your AD Kerberos realm when prompted. It should generally be your domain name in capital letters (“koo.fi” becomes “KOO.FI”). If your DNS is working properly, that should be all that is needed for Kerberos client to work in a basic manner. Otherwise you may need to add your servers to /etc/krb5.conf.

Try getting a ticket:

That shows we now have a valid ticket and the Kerberos authentication is working fine to the domain controller.

Some extra configuration at this point in krb5.conf. The appdefaults/pam configuration section is where pam_krb5 module gets its configuration from (see for example http://linux.die.net/man/5/pam_krb5).

The auth_to_local rule will try to parse the local username from the Kerberos principal name, otherwise it will use the principal name itself (see http://linux.die.net/man/5/krb5.conf).

Configure Samba

We only need the Samba client because it is a convenient tool to create a machine account in Active Directory. Configure Samba client using /etc/samba/smb.conf:

The “system keytab” kerberos method states that the Kerberos system is used to find the keytab file (see http://www.samba.org/samba/docs/man/manpages-3/smb.conf.5.html#KERBEROSMETHOD). We defined it in krb5.conf above.

Join to Domain

Join the machine to the domain. This command creates a machine account in AD:

If you get the “DNS update failed” error message, you just need to create a host record in DNS manually (both forward and reverse).

After this, you should basicly be able to remove smbclient should you wish to do so. I didn’t bother.

Create a Keytab file

A keytab file should automatically be created by net ads join as /etc/krb5.keytab. This was stated earlier in krb5.conf. You can also create the keytab file manually with the following command (from the smbclient package):

Test the keytab with this command:

That means you are able to authenticate with the keytab file using principal UBUNTU$. If you have error messages, you may turn on debug output in krb5.conf:

The next step is to go to your Active Directory domain controller and use the ktpass.exe tool to create a host principal (“host/ubuntu.koo.fi”) and map it to the machine account that was created (“UBUNTU$”).

Now you should be able to run:

Make Sure There’s a Valid Machine Account Ticket all the time

Now that we have a working keytab file, we’ll have to make sure we have a valid ticket all the time, and that it can be accessed by every user who needs it. Active Directory has a maximum ticket lifetime of 10 hours. The keytab file by itself will not be enough to authenticate, but it can be used to get a ticket from a KDC. We can do it with a cron job (“sudo crontab -e”):

That will run kinit every hour as root, and save the host credentials in the Kerberos credentials cache file /etc/krb5cc_host. This file contains the live tickets, and needs to be refreshed periodically. It also needs to be readable by all users who need to read information from the LDAP directory. That is why we add world-readable permissions to it.

Security-wise, it is important to remember, that anyone who has read permissions to the credentials cache can pose as the principal whose keys are in the file. In our case, it is the AD machine account. You may wish to restrict who has access to the file using groups or acls. You could revoke access from nobody:nogroup like this:

All that has to be on one line in the crontab. Or you could create a shell script for it. You also need to install the “acl” package to get the setfacl command.

To see what credentials are currently in the file, run:

Install OpenLDAP tools

While not strictly necessary, it is helpful at this point to test authentication to AD and fetching stuff from it, usind ldap-utils and SASL module:

Edit /etc/ldap/ldap.conf (the OpenLDAP tools configuration file) and put your own details there:

Now, after fetching a ticket with the command “kinit username@REALM” you should be able to run plain “ldapsearch” and see the contents of your whole Active Directory (or up to about a thousand entries) using that Kerberos ticket. This will turn out handy in the next section.

You should also be able to authenticate using the principal in your keytab file at this point. Destroy your ticket by running kdestroy. After fetching a ticket with the keytab file by running kinit -V -k ‘host/ubuntu.koo.fi@KOO.FI’, you should also be able to ldapsearch without problems.

The Active Directory Schema

The Active Directory LDAP Schema must be extended by installing the Microsoft Services For Unix on an Active Directory Domain controller. The schema extension adds some extra attributes to the directory that allow you to specify user’s ID number, home directory, shell etc. You can edit them in a new tab which should appear in the Active Directory Users and Computers snap-in. It looks something like this:

 

The attribute names and objectclasses used in the following discussion have been taken from my setup. They may vary depending on which MS SFU version you have installed at the moment, or which version you installed the first time. It is therefore advisable to take a look at your own directory and take the correct attribute names from there. To do that, go to AD Users and Computers, add UNIX attributes for one user with UNIX attributes set up, and also one such group, and then run ldapsearch to see the attributes:

That whill search by the username and should return a list of attributes saved for the user. My attributes look like this (I removed a lot of stuff from here, only relevant attrs showed):

Let’s look at the group “UNIX users”:

The msSFU30PosixMember attributes contain references to the member user accounts. That will be used to map users to groups.

Install and configure nss_ldap and pam_ldap

Now, let’s install nss_ldap (the name service switch ldap module) and pam_ldap (the PAM ldap module):

Dpkg will ask questions to do some preconfiguring. This configuration will use the Kerberos host keytab:

Next, let’s configure /etc/ldap.conf some more. This configuration file is for both the pam_ldap and nss_ldap. You will need to substitute your own values here. Let’s go through it piece by piece.

First some basic information on how to connect to the directory, and timeouts, option to not to be fussy over SSL/TLS certificates and to ignore referrals. If your directory is partitioned you will have to enable referrals. In that case be sure to have connectivity to all domain controllers, as well as a working DNS. The use_sasl on option will change to using Kerberos through SASL. The sasl_auth_id must be the same which you mapped to your machine account with the ktpass Windows command earlier.

The krb5_ccname tells where to find the Kerberos credentials cache file.  The file must be readable by any user you wish to be able to read information from AD. It must also be refreshed periodically. This was configured as a cron job earlier in this article.

The nss_base_ attributes tell where to look for particular types of objects in the directory. We will simply give the root object with subtree scope so that the whole directory is checked. You may want to restrict this for performance reasons if you have a huge directory, or for security reasons if you have strict permissions in your directory.

The nss_map_attribute is used to map an ldap attribute to a Linux NSS property. The first argument is the NSS property, and the second argument is the LDAP attribute from which to fetch the value. Be sure to double-check the attribute names that they match the ones in your directory.

The pam_login_attribute is used as the user name for the PAM authentication process. The pam_password says which kind of a protocol to use for changing user passwords if that is needed. You need to install libpam-ldap to take advantage of it.

The last change is needed to the file /etc/nsswitch.conf so that the Name Service Switch knows it should be querying AD:

Only those three lines need editing.

At this stage, you should be able to list users from Active Directory using “getent passwd”, and groups using “getent group”. If you can’t, add line “debug 1” to /etc/ldap.conf and try re-running “getent passwd”. It should give you a pretty verbose log of what’s going on. You can set the verbosity up to 10 if you like.

If you want to cache the results, you can install the “unscd” package. That will cache users and groups, so that they are not asked from LDAP every time, which makes things faster. You can tune the settings in /etc/nscd.conf.

PAM configuration

Now that the NSS part is working properly, let’s configure PAM. It should mostly be done automatically already, just double-check it.

This is what my /etc/pam.d/common-auth looks like:

That will enable Kerberos, LDAP and Unix passwd file authentication.

This is /etc/pam.d/common-account:

/etc/pam.d/common-password:

/etc/pam.d/common-session:

The only thing I had to change was to add the pam_mkhomedir.so line, which creates a home directory automatically for any user logging in the first time.

The End Result

After all that is in place, you should be able to log in locally, or remotely with ssh, using a user account from AD, authenticating to AD with Kerberos, and get your home directory created automatically for you should it not exist already.

Useful links

22 thoughts on “Ubuntu 12.04 Active Directory Authentication”

  1. Hi,

    Thanks a lot for this tutorial, really appreciate it.
    I’ve tried your instructions on both windows 2003 and 2008. In 2008, when I try:

    # kinit -V -k ‘UBUNTU$’

    I get:

    kinit: Generic preauthentication failure while getting initial credentials

    error. It doesn’t happen on 2003 however. I’ve been beating my head to figure out what’s different, but can’t figure it out. Can you help?

    But the bigger problem is that once I do:

    # kinit

    I can see AD users using ‘getent passwd’, and am able to login via ssh as any AD user, since I have a ticket. But until then I can’t log on except using local user credentials.

    Is there any way to automatically get a ticket, say during boot, or during login, so I don’t have to manually get a kerberos ticket first before I can log on using AD credentials?

    Thanks again.

  2. That line should’ve said:

    sudo kinit -V -k ‘UBUNTU$’

    I forgot the sudo there. That’s because your’re using the /etc/krb5.keytab, to which only root has access.

    And yes, you need to refresh the ticket for the root user every once in a while. If I remember correctly AD KDC gives maximum of 10 hours. So if you put something like this in root’s crontab, you’ll refresh the ticket every hour:

    0 * * * * kinit -k ‘host/ubuntu.koo.fi@KOO.FI’

    That way root has a ticket all the time, meaning users can log in. And when a user logs in using Kerberos, they will get a fresh ticket at login. Non-kerberos logins will not get a ticket automatically.

    Seems like I have a bit of article updating to do. Thanks for the feedback!

  3. I updated the article a bit and it now describes a better method for keeping a valid ticket for all users. In a nutshell:

    Add this to root’s crontab:

    0 * * * * kinit -k ‘host/ubuntu.koo.fi@KOO.FI’ -c /tmp/krb5cc_host; chmod +r /tmp/krb5cc_host

    And this to /etc/ldap.conf:

    krb5_ccname FILE:/tmp/krb5cc_host

    Now there’s a credentials cache file which can be read by all users, and it will have a valid ticket all the time.

    Just remember that when this file is world-readable, any user can authenticate themselves as the host principal or “machine account” using it.

  4. I get the following error when I try to join the machine to the domain:
    “Joined ‘CLIENTVM’ to realm ‘testsupsi.ch’
    No DNS domain configured for clientvm. Unable to perform DNS Update.
    DNS update failed!”

    What do you mean by “you just need to create a host record in DNS manually (both forward and reverse)”?

    Thank you, I appreciate your guide very much!

    1. You should go to the Active Directory DNS and add a new host (A) to the DNS Forward Lookup Zone. It is also advisable, although I guess not strictly necessary, to add a reverse record (PTR) to the Reverse Lookup Zone.

      1. Thank’s for your reply. I added the new Host (A) as you said, but now I get:

        kinit succeeded but ads_sasl_spnego_krb5_bind failed: Server not found in Kerberos database
        Failed to join domain: failed to connect to AD: Server not found in Kerberos database

  5. Is this working with a forest level of 2008 R2?
    Because I can’t get past this section:

    sudo kinit -V -k ‘UBUNTU$’
    Using default cache: /tmp/krb5cc_0
    Using principal: UBUNTU$@WINUX.LOCAL
    kinit: Generic preauthentication failure while getting initial credentials

    I’ve checked every setting I can think.

    1. The one place I have it working is forest and domain level 2003. I haven’t tested it with 2008. Have you tried mapping with ktpass and authenticating with the mapped principal? Do you see anything in the windows server event log?

      1. Yes I’ve tried that too.

        On the AD Server (2008 R2)
        ktpass /princ host/ubuntu.winux.local@WINUX.LOCAL /mapuser UBUNTU$@WINUX.LOCAL
        Targeting domain controller: ADSrv.winux.local
        Using legacy password setting method
        Successfully mapped host/ubuntu.winux.local to ubuntu$.

        …and the Ubuntu Server (12.04)
        @ubuntu:~$ sudo kinit -V -k ‘host/ubuntu.winux.local@WINUX.LOCAL’
        Using default cache: /tmp/krb5cc_0
        Using principal: host/ubuntu.winux.se@WINUX.LOCAL
        kinit: Generic preauthentication failure while getting initial credentials

        No errors in windows event log.
        DNS is working ok.

        Is there anything wrong with my krb5.conf?
        Nothing shows up in the specified logfile.

        [appdefaults]
        pam = {
        realm = WINUX.LOCAL
        ticket_lifetime = 1d
        renew_lifetime = 1d
        forwardable = true
        proxiable = false
        retain_after_close = false
        minimum_uid = 2
        try_first_pass = true
        ignore_root = true
        }
        [libdefaults]
        default_realm = WINUX.LOCAL
        default_keytab_name = FILE:/etc/krb5.keytab
        [realms]
        WINUX.LOCAL = {
        auth_to_local = DEFAULT
        }
        [domain_realm]
        .winux.local = WINUX.LOCAL
        winux.local = WINUX.LOCAL
        [logging]
        default = FILE:/var/log/krb5.log

        Any suggestions?

        1. I solved my problem in a almost-too-good-to-be-true kind of way.
          It’s very easy to join an AD server with the use Centrify Direct Control.

          Ubuntu 12.04
          sudo add-apt-repository “deb http://archive.canonical.com/ precise partner”
          sudo apt-get update
          sudo apt-get install centrifydc

          Join AD
          sudo adjoin -w domain.name
          reboot

          Check that everything went well with the command “adinfo”
          In my case it looks likes this:

          Local host name: adbuntu
          Joined to domain: winux.local
          Joined as: adbuntu.winux.local
          Pre-win2K name: adbuntu
          Current DC: adsrv.winux.local
          Preferred site: Default-First-Site-Name
          Zone: Auto Zone
          Last password set: 2013-05-14 14:37:20 CEST
          CentrifyDC mode: connected
          Licensed Features: Disabled

          Enable sudo for an ADgroup in /etc/sudoers
          %adgroup ALL=(ALL) ALL

          Everything just works including ssh.

          Read more here
          https://help.ubuntu.com/community/DirectControl

  6. Hey, I got your same issue, and joined the domain with centrify.

    Is a workaround to the “Create a Keytab”? I didn’t quite understand how the keytab works here. After joining the domain and running kpass.exe I launch “kinit -k ‘host/ubuntu2.testsupsi.ch@TESTSUPSI.CH’ -c /tmp/krb5cc_host” and it replies:

    kinit: Cannot resolve servers for KDC in realm “TESTSUPSI.CH” while getting initial credentials

    Still not going anywere.

    1. That probably indicates that name resolution is not working properly. I would recommend that you use an Active Directory DNS server for name resolution on the host.

      Make sure you are able to resolve DNS SRV records like these from your host:

      _kerberos._tcp.testsupsi.ch
      _kerberos._udp.testsupsi.ch

      Another option is to configure the KDC server(s) manually in the realms section of krb5.conf.

  7. hi,

    Has somebody found a solution for the error:
    “kinit: Generic preauthentication failure while getting initial credentials”

    I cannot rely on centrify’s join since it changes locally the uidNumbers of the Users.

    my configuration is:

    Ubuntu 12.04.03 LTS
    AD: 2008 R2

    Would be very thankful for every tip!

    Cheers

    1. hi again,

      I did find a solution. Add these 3 lines to your krb5.conf in the [libdefaults] section:

      default_tgs_enctypes = arcfour-hmac-md5 des-cbc-md5 des-cbc-crc
      default_tkt_enctypes = arcfour-hmac-md5 des-cbc-md5 des-cbc-crc
      permitted_enctypes = arcfour-hmac-md5 des-cbc-md5 des-cbc-crc

      This did the magic!

      Cheers

  8. I ran into a “Generic preauthentication failure while getting initial credentials” error message while installing a new server today. I think what fixed it was adding these two lines in /etc/krb5.conf under the libdefaults stanza.

    default_tkt_enctypes = rc4-hmac des-cbc-crc des-cbc-md5
    default_tgs_enctypes = rc4-hmac des-cbc-crc des-cbc-md5

    I had to re-create the keytab with “net ads keytab flush; net ads keytab create”. After that I was able to authenticate.

    1. Update: it seems that you can set Active Directory’s supported Kerberos encryption types by editing Group Policy, under:

      Computer Configuration
      – Policies
      — Windows Settings
      — Security Settings
      —- Local Policies
      —– Securty Options
      ——> Network Security: Configure encryption types allowed for Kerberos

      It can also be set for one particular host by using ADSI Edit, finding the host entry and setting the value for the attribute “msDS-SupportedEncryptionTypes” as a logical combination of these possible values:

      0x01 DES-CBC-CRC
      0x02 DES-CBC-MD5
      0x04 RC4-HMAC
      0x08 AES128-CTS-HMAC-SHA1-96
      0x10 AES256-CTS-HMAC-SHA1-96

      I haven’t tested either method yet.

      See this page for a lot of info on the subject:

      http://blogs.msdn.com/b/openspecification/archive/2011/05/31/windows-configurations-for-kerberos-supported-encryption-type.aspx

  9. Nice post. Very helpful . Thanks for taking time.

    I setup netbios name same as hostname and unable to set mapping data for . Appreciate the advise.

    C:\Users\Administrator.KOO>ktpass /princ “host/hostname.domain.org@DOMAIN.ORG” /mapuser hostname$@DOMAIN.ORG

  10. Thank you for sharing your knowledge!

    I followed the tutorial to the end, did not get any error message. But ssh is trying to connect I get the message “error: PAM: pam_open_session (): Permission denied” and then I am disconnected from the session.
    Can you help me solve this problem?

    Thank you again.

    1. Ersan: there could be a number of things wrong. Did you change the PAM files under /etc/pam.d?

      I would suggest adding more verbose logging for sshd in /etc/ssh/sshd_config, and watching the log file while you log in with ssh.

      You can also yank up the logging of the ssh client with “ssh -vvvv your_server”.

      1. Thanks for the feedback!

        It worked by changing the common-session file as below.

        session [default=1] pam_permit.so
        session requisite pam_deny.so
        session required pam_permit.so
        session optional pam_umask.so
        session optional pam_krb5.so minimum_uid=1000
        session required pam_unix.so
        session optional pam_ldap.so
        session required pam_mkhomedir.so skel=/etc/skel/ umask=0077

        have a nice day 🙂

  11. Hi,
    I am not able to login in ssh and even in consol
    using any Active Directory user.

Leave a Reply