Monday, August 06, 2007

Kerberos Authentication with LDAP Authorization for Linux & Solaris (8 & 10) with Active Directory 2003 R2

This document will show the steps to authenticate (Using Kerberos) and authorize (Using LDAP) Solaris (8 & 10 have been tested, Solaris 9 should work the same as 10) and Linux with Active Directory 2003 R2.

My apology: I used word to create this post and then copy/paste the content to here, so the format has changed a bit... You can download the file from here.

Introduction

Here I'll explain the main components involved in this architecture:

  • Kerberos - The world standard for secured strong network authentication. How it works?
    From wikipedia ( http://en.wikipedia.org/wiki/Kerberos_(protocol) ):

    AS = Authentication Server
    TGS = Ticket Granting Server
    SS = Service Server

    1. A user enters a username and password on the client.
    2. The client performs a one-way hash on the entered password, and this becomes the secret key of the client.
    3. The client sends a clear-text message to the AS requesting services on behalf of the user. Sample Message: "User XYZ would like to request services". Note: Neither the secret key nor the password is sent to the AS.
    4. The AS checks to see if the client is in its database. If it is, the AS sends back the following two messages to the client:
      • Message A: Client/TGS session key encrypted using the secret key of the user.
      • Message B: Ticket-Granting Ticket (which includes the client ID, client network address, ticket validity period, and the client/TGS session key) encrypted using the secret key of the TGS.
    5. Once the client receives messages A and B, it decrypts message A to obtain the client/TGS session key. This session key is used for further communications with TGS. (Note: The client cannot decrypt the Message B, as it is encrypted using TGS's secret key.) At this point, the client has enough information to authenticate itself to the TGS.
    6. When requesting services, the client sends the following two messages to the TGS:
      • Message C: Composed of the Ticket-Granting Ticket from message B and the ID of the requested service.
      • Message D: Authenticator (which is composed of the client ID and the timestamp), encrypted using the client/TGS session key.
    7. Upon receiving messages C and D, the TGS decrypts message D (Authenticator) using the client/TGS session key and sends the following two messages to the client:
      • Message E: Client-to-server ticket (which includes the client ID, client network address, validity period and Client/server session key) encrypted using the service's secret key.
      • Message F: Client/server session key encrypted with the client/TGS session key.
    8. Upon receiving messages E and F from TGS, the client has enough information to authenticate itself to the SS. The client connects to the SS and sends the following two messages:
      • Message E from the previous step (the client-to-server ticket, encrypted using service's secret key).
      • Message G: a new Authenticator, which includes the client ID, timestamp and is encrypted using client/server session key.
    9. The SS decrypts the ticket using its own secret key and sends the following message to the client to confirm its true identity and willingness to serve the client:
      • Message H: the timestamp found in client's recent Authenticator plus 1, encrypted using the client/server session key.
    10. The client decrypts the confirmation using the client/server session key and checks whether the timestamp is correctly updated. If so, then the client can trust the server and can start issuing service requests to the server.
    11. The server provides the requested services to the client.

  • Directory Services – Use to store organization information in a tree hierarchy. The stored information is usually users, groups, computers, resources and more.

  • LDAP – Lightweight Directory Access Protocol is the "SQL language" for querying and modifying directory services data.

  • Active Directory – is Microsoft's implementation for the Kerberos (KDC) and LDAP server in one entity.

  • Active Directory R2 – the release 2 of AD 2003 includes the directory schema extension for UNIX/Linux authorization (compliant with RFC 2307). With this release we can use AD to store information for UNIX like operating systems, this information includes users data like uid, gid, home directory, default shell and more.
    NOTE: Before R2 was released Microsoft created the "
    Microsoft Windows Services for UNIX" that can be downloaded from Microsoft's web site, this schema extension is not compliant with RFC 2307.

Active Directory 2003 R2

To be able to implement this solution we will need a running Active Directory 2003 R2 server, if this is the first R2 server in an existing forest you must first extend the schema with Adprep tool. Here you can find direction on how to correctly install R2.

The schema extension will add/modify the needed objects and attributes to the Active Directory for UNIX/Linux authorization, objects like group and user or attributes like "home directory" and "login shell". We can see the new information as a new tab ("UNIX Attributes") in the user/group dialog box at the "Active Directory Users and Computers" management console. With this dialog we can set the UNIX attributes for each user/group, attributes like uid, gid, home directory and login shell.

Installation and configuration with linux (Redhat ES4 Update 4)

Kerberos

Installing Kerberos

The first step in setting the authentication method to use Kerberos is to install the following RPMs:

· krb5-libs

· pam_krb5

· krb5-workstation

· krb5-auth-dialog

Configuring Kerberos

The second step is to configure the authentication mechanism to use Kerberos, Redhat provides authconfig tool that can be used to do the basic configuration, run this tool and follow the next steps:

· Select "Use Kerberos" in the first dialog and click next

· The next screen will ask for the Kerberos information:

o Realm – Fill the complete domain name in CAPITAL letters, for example: UXDC.CORP

o KDC – Fill the complete domain controller DNS name with port 88, for example: srvuxdc.corp:88

o Admin Server - Fill the complete domain controller DNS name with port 749, for example: srvuxdc.corp:749

o Select both checkboxes:

§ Use DNS to resolve hosts to realms

§ Use DNS to locate KDCs for realms

When you press Ok, authconfig will go back to command line. The files updated by authconfig are:

· /etc/krb5.conf – Kerberos 5 configuration file

· /etc/krb.conf – Kerberos 4 configuration file – This can be remove

· /etc/pam.d/system-auth – PAM configuration file for authentication mechanism

There is one more Kerberos 4 file that can be removed to avoid confusion: /etc/krb.realms, this file is used by Kerberos 4 for the realms map to domain names.

krb5.conf

The next step in the configuration is to edit Kerberos 5 configuration file: /etc/krb5.conf, we will need to change/add few parameters to the file, but before we will do it I'll explain the file structure:

· [logging] – sets the way Kerberos component will perform there logging, the components that use the logging parameters are the KDC and Kerberos Admin Server both are used when you will use Linux as the Kerberos server, our Kerberos server is the Active Directory so we can leave the default for the logging section.

· [libdefaults] - Contains various default values used by the Kerberos V5 library. Values like default encryption type and if to use dns lookups or not.

· [realms] – list of realms and where to find there Kerberos server and some other realm related information.

· [domain_realm] – this file the mapping file from domain names to Kerberos realms.

· [appdefaults] – Contains default values that can be used by Kerberos V5 applications.

Here is an example for krb5.conf file after the needed changes, the main lines are highlighted:

[logging]

default = FILE:/var/log/krb5libs.log

[libdefaults]

default_realm = UXDC.CORP

dns_lookup_realm = true

dns_lookup_kdc = true

default_keytab_name = FILE:/etc/krb5.keytab

default_tkt_enctypes = des-cbc-md5

default_tgs_enctypes = des-cbc-md5

[realms]

UXDC.CORP = {

kdc = SRVUXDC.LCARD.CORP:88

admin_server = SRVUXDC.LCARD.CORP:749

}

[domain_realm]

.uxdc.corp = UXDC.CORP

uxdc.com = UXDC.CORP

[appdefaults]

pam = {

debug = false

ticket_lifetime = 36000

renew_lifetime = 36000

forwardable = true

krb4_convert = false

}

So, what does it means? :

  • default_realm – is the default realm to be used when no realm is specified by using @ for example: user1@UXDC.CORP
  • default_keytab_name – the default path to find the server keytab, a keytab is a file containing pairs of Kerberos principals and DES-encrypted keys based on Kerberos password allowing the server services to access resources based on Kerberos authentication without the need to use a password.
  • default_tkt_enctypes – the default encryption type will be requested by the client.
    • Use des encryption only to support other unix tools, the encryption types can be one of des-cbc-crc or des-cbc-md5
  • default_tgs_enctypes – the default encryption type will be returned by the KDC.
    • Use des encryption only to support other unix tools, the encryption types can be one of des-cbc-crc or des-cbc-md5
  • verify_ap_req_nofail - If this flag is set, then an attempt to get initial credentials will fail if the client machine does not have a keytab. The default for the flag is false. NOTE: For some reason this parameter is not working in linux, that’s why we will use "validate" in the /etc/pam.d/system-auth configuration file.

Configuring PAM

The next file we will change is /etc/pam.d/system-auth, this file is configured by authconfig to use Kerberos as one of the authentication mechanisms (first use Unix and than try Kerberos), the only thing that we will change in the file is adding the validate parameter to each pam_krb5.so line, the validate parameter tells pam to check the server keytab, this can be avoided when the verify_ap_req_nofail parameter in krb5.conf file will work properly in the future release:

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 use_first_pass validate

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 <>

account [default=bad success=ok user_unknown=ignore] /lib/security/$ISA/pam_krb5.so validate

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_krb5.so use_authtok validate

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 optional /lib/security/$ISA/pam_krb5.so validate

try_first_pass – with this parameter PAM will not ask the user to enter the Kerberos password if the Unix authentication failed and will use the first password enter by the user.

If we need to debug the Kerberos 5 pam module you can add "debug" to the end of Kerberos auth line:

auth sufficient /lib/security/$ISA/pam_krb5.so try_first_pass validate debug

Creating the server keytab

The final step is to create the server keytab:

  • Create a domain user for the server, name the user as the name of the server, and use a secured password, also select "Password never expires" and "Use DES ecryption types for this account" in the account tab.
  • Create the account keytab by using the ktpass command line:
    • ktpass.exe princ host/@ mapuser -pass out .keytab
      For example, if my server name is linuxhost01.uxdc.corp:
      ktpass.exe princ host/linuxhost01.uxdc.corp@UXDC.CORP mapuser linuxhost01 -pass TheServerPassw0rd#6 out linuxhost01.keytab
  • Copy the file to the server using secured connection like sftp/scp
  • Connect to the server and run ktutil, and in the ktutil prompt run:
    rkt
    wkt /etc/krb5.keytab
    exit
  • Remove the copied keytab file from the server:
    rm –f
    or the better way is to use shred utility to securely remove the file from the server, for example:
    shred –u linuxhost01.keytab

Testing Kerberos

Now we will try to obtain a Kerberos ticket for an existing domain user, for example:

kinit myuser@UXDC.CORP

Password for myuser@UXDC.CORP:

If no error returned run: "klist -5e" to view the obtained Kerberos ticket!!!!

LDAP

Now that we have Kerberos working we can set the ldap client to get the account information from Active Directory. The configuration files that we will use are:

  • /etc/ldap.conf – LDAP configuration file
  • /etc/nsswitch.conf - Name Service Switch configuration file

Installing LDAP

We will need to install the following RPM's:

  • openldap
  • nss_ldap

ldap.conf

The first file to edit is /etc/ldap.conf, this file contains the defaults to be applied when running ldap clients. The lines that we will need to change/add are:

  • base – specifies the default base DN to use when performing ldap operations:
    base dc=uxdc,dc=corp
  • uri – the way to specify the LDAP server(s) to witch ldap clients should connect. (URI parameter replaced the HOST parameter:
    uri ldap://srvuxdc.corp
  • binddn – the default account to use for binding to ldap server:
    binddn uxldap@uxdc.corp
  • bindpw – the password used for the binding account:
    bindpw Account#Password$
  • scope – the search scope for ldap clients, can be one of:
    • one – one level search
    • sub – subtree search
    • base – base object search

we will use sub option, for example:
scope sub

  • Changing the time limits for ldap operations:
    • timelimit 30 – sets the search time limit to 30 seconds
    • bind_timelimit 30 – sets the binding time limit to 30 seconds
    • idle_timelimit 3600 – the time limit for nss_ldap to close connections if the server has not been connected for this amount of seconds.
  • pam_login_attribute – sets the ID attribute in the ldap server that is equivalent to the Unix uid attribute (uid attribute in unix ldap schema holds the username)
  • Setting where and how to search for specific contexts:
    nss_base_passwd dc=uxdc,dc=corp?sub?&(objectCategory=user)
    nss_base_shadow dc=uxdc,dc=corp?sub
    nss_base_group dc=uxdc,dc=corp?sub?&(objectCategory=group)
  • Now we will set all the other naming contexts from Active Directory to Unix/Linux:
    nss_map_objectclass posixAccount user
    nss_map_objectclass shadowAccount user
    nss_map_objectclass posixGroup group
    nss_map_attribute homeDirectory unixHomeDirectory
    nss_map_attribute gecos cn
    nss_map_attribute uniqueMember member

nsswitch.conf

The next file to configure is /etc/nsswitch.conf file, that file tells linux from where (which database) to get the needed information, all we need to do is to add the word ldap to the passwd, shadow and group databases:

passwd: ldap files

shadow: ldap files

group: ldap files

Testing ldap

After this is done, we can use getent utility to get information for user accound and groups defined in Active Directory but not in /etc/passwd, for example, to get information about the user account ux1 that is defined in Active Directory:

getent passwd ux1

To get information about the group unixgrp, defined in Active Directory:

getent group unixgrp

Now that every thing is set, we can try to login with a user account that is defined in Active Directory.

Installation and configuration with Solaris (8 & 10)

The Solaris configuration is pretty much the same to Linux configuration regarding to Kerberos, the main difference is in the ldap configuration.

Kerberos

Kerberos configuration files saved in /etc/krb5 directory, there are two main configuration files for Kerberos in Solaris:

  • krb5.conf
  • warn.conf – configure the warning massages to display when users Kerberos tickets are about to expire, we will not use this file in this manual.

krb5.conf

There is a difference between the implementation of Kerberos in Solaris 8 and Solaris 10, the main issue is that Solaris 8 does not support the validation of the server keytab!!! Other features that Solaris 8 doesn't support are:

  • dns_lookup_realm
  • dns_lookup_realm
  • default_keytab_name
  • And more…

We will use the same configuration file in both versions. Solaris 8 will ignore the unknown parameters in the configuration file as long as the syntax is correct.

Here is an example for krb5.conf file, there is nothing different here from the Linux configuration:

[libdefaults]

default_realm = UXDC.CORP

default_tkt_enctypes = des-cbc-md5

default_tgs_enctypes = des-cbc-md5

default_keytab_name = /etc/krb5/krb5.keytab

verify_ap_req_nofile = true

dns_lookup_realm = true

dns_lookup_realm = true

[realms]

UXDC.CORP = {

kdc = srvuxdc.corp:88

admin_server = srvuxdc.corp:749

}

[domain_realm]

.uxdc.corp = UXDC.CORP

uxdc.corp = UXDC.CORP

[appdefaults]

kinit = {

renewable = true

forwardable= true

}

Configuring PAM

In contrary to Linux, PAM configuration in Solaris is based on one file:

· /etc/pam.conf

We will need to use different configuration files for Solaris 8 and 10 because the difference between pam_krb5.so implementation in both versions. Solaris 10 version doesn’t support the use of "try_first_pass" because this behavior is implemented by default in the module.

In this file we will add the use of Kerberos authentication if the Unix authentication fails, here is an example:

login auth requisite pam_authtok_get.so.1

login auth required pam_dhkeys.so.1

login auth required pam_unix_auth.so.1

For Solaris 8:

login auth sufficient pam_krb5.so try_first_pass

For Solaris 10:

login auth sufficient pam_krb5.so

login auth required pam_dial_auth.so.1

other auth requisite pam_authtok_get.so.1

other auth required pam_dhkeys.so.1

other auth required pam_unix_auth.so.1

For Solaris 8:

other auth sufficient pam_krb5.so try_first_pass

For Solaris 10:

other auth sufficient pam_krb5.so

other account requisite pam_roles.so.1

other account required pam_projects.so.1

other account required pam_unix_account.so.1

other account required pam_krb5.so

other password required pam_dhkeys.so.1

other password requisite pam_authtok_get.so.1

other password requisite pam_authtok_check.so.1

other password sufficient pam_krb5.so

other password required pam_authtok_store.so.1

If we need to debug the Kerberos 5 pam module we can add "debug" to the end of Kerberos auth lines:

login auth sufficient pam_krb5.so debug

other auth sufficient pam_krb5.so debug

Configuring LDAP

The LDAP configuration in Solaris is done by ldapclient utility, the syntax has been changed between Solaris 8 and Solaris 10 (Solaris 9 syntax is the same as 10).

The files that will be changed by ldapclient are:

  • /etc/defaultdomain – contains the default domain for ldap
  • /var/ldap/ldap_client_cred – contains the account and password that will be used for binding to the ldap server (in our case, the active directory server)
  • /var/ldap/ldap_client_file – the main LDAP configuration file
  • /etc/nsswitch.conf

Solaris 8:

The command that we will run is:

ldapclient -i -a simple -r false \

-b "dc=uxdc,dc=corp" \

-D "cn=uxldap,cn=users,dc=uxdc,dc=corp" -w "Account#Password$" \

-d uxdc.corp -p 192.168.0.122 \

-s sub -o 30 -t 30 \

-R "passwd:gecos=cn" \

-R "passwd:gidnumber=gidNumber" \

-R "passwd:homedirectory=unixHomeDirectory" \

-R "passwd:loginshell=loginShell" \

-R "passwd:uidl=sAMAccountName" \

-R "shadow:uid=sAMAccountName" \

-M "group:posixGroup=group" \

-M "passwd:posixAccount=user" \

-M "shadow:shadowAccount=user" \

-S "passwd:dc=uxdc,dc=corp?sub" \

-S "shadow:dc=uxdc,dc=corp?sub" \

-S "group:dc=uxdc,dc=corp?sub?&(objectCategory=group)"

Here is an explanation for each line:

  • ldapclient -i -a simple -r false
    Will configure ldap to use simple authentication and want follow ldap references,
    ldap references are URI's that could be returned by the ldap server.
  • -b "dc=uxdc,dc=corp"
    sets the base DN to start the search from.
  • -D "cn=uxldap,cn=users,dc=uxdc,dc=corp" -w "Account#Password$"
    sets the account and password that will be used for binding to the LDAP server
  • -d uxdc.corp -p 192.168.0.122
    -d sets the default domain name
    -p sets the LDAP server IP, If we will use the LDAP server DNS name this command may hang
  • -s sub -o 30 -t 30
    -s sets the search scope
    -o and –t sets the LDAP operations timeouts
  • -R "passwd:gecos=cn"
    -R "passwd:gidnumber=gidNumber"
    -R "passwd:homedirectory=unixHomeDirectory"
    -R "passwd:loginshell=loginShell"
    -R "passwd:uidl=sAMAccountName"
    -R "shadow:uid=sAMAccountName"
    sets the attributes mapping
  • -M "group:posixGroup=group"
    -M "passwd:posixAccount=user"
    -M "shadow:shadowAccount=user"

    sets the object class mapping
  • -S "passwd:dc=uxdc,dc=corp?sub"
    -S "shadow:dc=uxdc,dc=corp?sub"
    -S "group:dc=uxdc,dc=corp?sub?&(objectCategory=group)"

    sets the search for each service

Solaris 10:

· ldapclient manual
manually configure LDAP client

· -a authenticationMethod=simple
-a credentialLevel=proxy
Use simple authentication (user and password) for binding to the LDAP server

· -a proxyDN=cn=uxldap,cn=users,dc=uxdc,dc=corp
-a proxyPassword=Account#Password$
sets the account and password for binding to the LDAP server

· -a defaultSearchBase=dc=uxdc,dc=corp
sets the base DN to start the search from.

· -a domainName=uxdc.corp
sets the default domain name

· -a defaultServerList=192.168.0.122
sets the LDAP server IP, If we will use the LDAP server DNS name this command may hang

· -a attributeMap=passwd:uniqueMember=member
-a attributeMap=passwd:gecos=cn
-a attributeMap=passwd:uid=sAMAccountName
-a attributeMap=passwd:homedirectory=unixHomeDirectory
-a attributeMap=passwd:loginshell=loginShell
-a attributeMap=shadow:uid=sAMAccountName
sets the attributes mapping

· -a objectClassMap=group:posixGroup=group
-a objectClassMap=passwd:posixAccount=user
-a objectClassMap=shadow:shadowAccount=user

sets the object class mapping

· -a serviceSearchDescriptor=passwd:dc=uxdc,dc=corp\?sub
-a serviceSearchDescriptor=shadow:dc=uxdc,dc=corp?sub
-a serviceSearchDescriptor=group:dc=uxdc,dc=corp\?sub\&(objectCategory=group)
sets the search for each service

If we would like to edit one of the ldap configuration files directly (without using the ldapclient utility) we would need to stop the ldap_client process before changing anything. ldap_client process role is to cache the ldap configuration for other ldap clients. The way to stop ldap_client process is to run: /etc/init.d/ldap_client stop
NOTE: Do not forget to start the ldap_client process after editing. More information about ldap_client process can be found in the man page of ldap_cachemgr.

Here is the result for /var/ldap/ldap_client_file after running ldapclient utility:

#

# Do not edit this file manually; your changes will be lost.Please use ldapclient (1M) instead.

#

NS_LDAP_FILE_VERSION= 2.0

NS_LDAP_SEARCH_BASEDN= dc=uxdc,dc=corp

NS_LDAP_AUTH= simple

NS_LDAP_SEARCH_REF= FALSE

NS_LDAP_SEARCH_SCOPE= sub

NS_LDAP_SEARCH_TIME= 30

NS_LDAP_SERVER_PREF= 172.16.7.75

NS_LDAP_CACHETTL= 0

NS_LDAP_CREDENTIAL_LEVEL= proxy

NS_LDAP_BIND_TIME= 30

NS_LDAP_ATTRIBUTEMAP= passwd:uniqueMember=member

NS_LDAP_ATTRIBUTEMAP= passwd:gecos=cn

NS_LDAP_ATTRIBUTEMAP= passwd:uid=sAMAccountName

NS_LDAP_ATTRIBUTEMAP= passwd:homedirectory=unixHomeDirectory

NS_LDAP_ATTRIBUTEMAP= passwd:loginshell=loginShell

NS_LDAP_ATTRIBUTEMAP= shadow:uid=sAMAccountName

NS_LDAP_OBJECTCLASSMAP= group:posixGroup=group

NS_LDAP_OBJECTCLASSMAP= passwd:posixAccount=user

NS_LDAP_OBJECTCLASSMAP= shadow:shadowAccount=user

NS_LDAP_SERVICE_SEARCH_DESC= passwd:dc=uxdc,dc=corp?sub

NS_LDAP_SERVICE_SEARCH_DESC= shadow:dc=uxdc,dc=corp?sub

NS_LDAP_SERVICE_SEARCH_DESC= group:dc=uxdc,dc=corp?sub?&(objectCategory=group)

The result for /var/ldap/ldap_client_cred is:

#

# Do not edit this file manually; your changes will be lost.Please use ldapclient (1M) instead.

#

NS_LDAP_BINDDN= cn=uxldap,cn=users,dc=uxdc,dc=corp

NS_LDAP_BINDPASSWD= {NS1}25c945dc7d61e0

You may wish to update /etc/nsswitch.conf file to remove the ldap from all lines excepts for passwd and group, also you would change the hosts entry to "files dns".

Testing ldap

We can use getent utility to test LDAP configuration just like we have done in the Linux machine.

Now that every thing is set, we can try to login with a user account that is defined in Active Directory.

Bibliography

3 comments:

Unknown said...

Wonderful Kerberos article! Thanks a lot Oded!

I do have a couple of questions and I am hoping you would assist. It would really help my understanding of Kerberos.

Assuming a client successfully authenticates to a KDC and obtains a TGT, the client now wishes to engage a registered principle service (e.g. ftp/telnet/secure nfs) on another computer, also in the same Kerberos realm.

Where is the configuration to limit the client access on the server side? Surely not just the service ticket right?

For example, the server principle may be a ftp or telnet daemon or even NFS server and allows only user A and User B from Host X but not User C from host X. Could you advice as to where this access control is done?

Thanks!!!!!

Looking forward to your reply.

Steven Sim
steven.sim@faplccc.net
Singapore

Dikla said...

Thanks a lot!

The first part of you article helped me so much in understanding the scenario of Kerberos.

Thank you.
Dikla

Unknown said...

me gustaria saber si alguien de uds puede decirme como puedo integrar ldap y kerberos5 para un controlador de dominios

??