Friday, September 14, 2012

LINUX MANAGING /etc/hosts WITH LDAP

Managing the /etc/hosts File Across Multiple Servers With LDAP (Microsoft Windows Active Directory 2008 R2)

 :: PURPOSE ::


Managing the /etc/hosts file across more than a handful of servers can quickly become more trouble than it’s worth.  There are many solutions that could be leveraged to manage this; like Puppet, Chef, or Cfengine.  A cron job tied to rsync could be made to work with little effort.  A SysAdmin with a lot of time on his hands who enjoys performing repetitive tasks better suited to shell scripts…

There are also many problem associated with trying to maintain identical yet separate copies of the /etc/hosts file across multiple servers.  All of the solutions listed above depend on the time between when the problem is first encountered and how soon the solution is scheduled to run.

But, if you’re like me, and you are already leveraging an LDAP (Microsoft Windows 2008 R2 Active Directory) environment for user and group information as well as Kerberos authentication, why not leverage it to provide /etc/hosts information as well?  For starters, changes to /etc/hosts entries in LDAP are available across all servers as soon as they are made (barring replication times between Domain Controllers).  A solid second reason is that LDAP-provided hosts data can serve as a fail-safe in the event that your DNS becomes unavailable.  Or, you may have a situation like mine where you want only a couple of entries in the local /etc/hosts file, then the majority of static host entries available from LDAP, and then, finally, some critical servers and services provided by DNS.  You might also be operating in an environment with less than stellar DNS management and you’d like to circumvent a problem you cannot resolve directly…not that I’ve ever heard of such a place.

A word of thanks to Kar Ellen and Karellen’s Unix Blog for providing the most clear information to this problem.  This post is almost wholly inspired by a similar one on Kar Ellen' blog; I've just adapted it to Microsoft Windows Active Directory 2008 R2.  Lots of really good information there.

I'd like to point out that sometimes we do things simply because we can.  This is one of those cases.  Do I have a driving need to provide /etc/hosts information from LDAP?  No.  But it's cool, so I did it.  Also, the Active Directory admins are fond of telling me what can and cannot be done with LDAP.  I am fond of proving them wrong.

The best thing about this is that only those individual servers that are configured to query LDAP for hosts information will be affected by this.  So you can have one or two servers running this just to try it out without impacted name resolution for the other servers in your domain. 

:: EXAMINE CURRENT /etc/hosts FILE ::


Let’s take a look at the current /etc/hosts file and see what we can work with.

As root first make a back-up of the existing /etc/hosts file:
# cp /etc/hosts /etc/hosts.backup
Now, cat the contents to see what we have:
# cat /etc/hosts
127.0.0.1       lux001.test.internal lux001 localhost.localdomain localhost
::1             localhost6.localdomain6 localhost6
10.0.0.50 dc01.test.internal dc01 # ACTIVE DIRECTORY DOMAIN CONTROLLER
10.0.0.51 dc02.test.internal dc02 # ACTIVE DIRECTORY DOMAIN CONTROLLER
10.0.0.60 lux001.test.internal lux001 # TEST.INTERNAL RHEL 5
10.0.0.61 lux002.test.internal lux002 # TEST.INTERNAL RHEL 5 HOME DIRECTORY SERVER

Comment out the entries for lux001.test.internal and lux002.test.internal and save /etc/hosts:
# vim /etc/hosts
127.0.0.1       lux001.test.internal lux001 localhost.localdomain localhost
::1             localhost6.localdomain6 localhost6
10.0.0.50 dc01.test.internal dc01 # ACTIVE DIRECTORY DOMAIN CONTROLLER
10.0.0.51 dc02.test.internal dc02 # ACTIVE DIRECTORY DOMAIN CONTROLLER
#10.0.0.60 lux001.test.internal lux001 # TEST.INTERNAL RHEL 5
#10.0.0.61 lux002.test.internal lux002 # TEST.INTERNAL RHEL 5 HOME DIRECTORY SERVER
 

:: CREATING THE LDIF FILE ::


We’re going to create the entries for lux001, lux001.test.internal, lux002, and lux002.test.internal in LDAP.  We’re also going to create a new OU called HOSTS to store these objects. 

NOTE:  You can either create an LDIF file to perform these steps or you can manually create the OU, then use ADSIEdit to create the device object and, finally, add the objectClass “ipHost” and description through the Attribute Editor tab of the new device object.  I have found that trying to add the objectClass “ipHost” while creating the initial object manually seems to fail.  I do not know why.  It does not fail when being created by LDIF. 

NOTE:  Please remove the top-most section of this LDIF file if you have manually created the OU into which you will be storing these device entries.

On your Windows Domain Controller, create a file called “hosts.ldif” and save it.
Edit the “hosts.ldif” file with Notepad and add the following (remember to change this to suit your requirements…):

dn: ou=HOSTS,ou=servers,dc=test,dc=internal
objectClass: organizationalUnit
objectClass: top
ou: HOSTS

dn: cn=lux001,ou=hosts,ou=servers,dc=test,dc=internal
ipHostNumber: 10.0.0.60
objectClass: top
objectClass: ipHost
objectClass: device
description: /ETC/HOSTS SERVER IP: 10.0.0.60
cn: lux001

dn: cn=lux001.test.internal,ou=hosts,ou=servers,dc=test,dc=internal
ipHostNumber: 10.0.0.60
objectClass: top
objectClass: ipHost
objectClass: device
description: /ETC/HOSTS SERVER IP: 10.0.0.60
cn: lux001.test.internal

dn: cn=lux002,ou=hosts,ou=servers,dc=test,dc=internal
ipHostNumber: 10.0.0.61
objectClass: top
objectClass: ipHost
objectClass: device
description: /ETC/HOSTS SERVER IP: 10.0.0.61
cn: lux002

dn: cn=lux002.test.internal,ou=hosts,ou=servers,dc=test,dc=internal
ipHostNumber: 10.0.0.61
objectClass: top
objectClass: ipHost
objectClass: device
description: /ETC/HOSTS SERVER IP: 10.0.0.61
cn: lux002.test.internal

NOTE:  If you want your HOSTS OU to be lowercase or just not all uppercase than you must change it to the appearance you want on both the “cn:” and “dn:” lines.

Process the LDIF from the Domain Controller as a user with administrator rights for the domain as follows:
<PATH TO HOST.LDIF>:\> ldifde -i -f hosts.ldif

The ldifde command is pretty good about telling you what part of the command failed; most of the time it’s a syntax error in your file.  Double-check you work, remove any objects that ldifde may have created before failing and try running the command again.

Once it’s complete, you should see a new OU called “HOSTS” and the device objects you created in it.  If not, refresh Active Directory Users and Computers (ADUC) and they will appear.  It should look something like this:


The next steps will happen on the RHEL server.

:: CONFIGURING THE /etc/ldap.conf FILE ::


First thing we’re going to do is modify our existing /etc/ldap.conf file to look towards LDAP for hosts information.
As root, create a back-up of your existing /etc/ldap.conf file:
# cp /etc/ldap.conf /etc/ldap.conf.backup

Next, find, uncomment and update the following line to match your LDAP information:
# vim /etc/ldap.conf

nss_base_hosts          ou=servers,dc=test,dc=internal?sub?objectClass=device

Save and exit the /etc/ldap.conf file.

Check to see if the nscd daemon service is running…:

# service nscd status
[root@lux001 /]# service nscd status
nscd (pid 13587) is running...


…stop the nscd service and invalidate it’ host cache:

[root@lux001 skel]# service nscd stop
Stopping nscd:                                             [  OK  ]
[root@lux001 skel]# nscd -i hosts

So long as the nscd service is running and unless it is configure to not cache host information (which it is not by default) then you will not be able to properly test LDAP host resolution.

Next, update the /etc/nsswitch.conf file to tell it use LDAP as a source of hosts information.

As root, back-up the existing /etc/nsswitch.conf file:

# cp /etc/nsswitch.conf /etc/nsswitch.conf.backup

Next, update the following line:

# vim /etc/nsswitch.conf

hosts:      files ldap

Save and exit the /etc/nsswitch.conf file. 

NOTE:  You can remove the “dns” entry if you are 100% sure that the name resolution for these servers will work as normal just using local files name resolution with /etc/hosts and LDAP.  I keep the “dns” entry in place to act as a final fall-back and for servers and services that I consider critical and dynamic.  For testing, though, to ensure that LDAP host resolution is working, remove “dns” as shown above.  Once you know that it is working with no “dns” entry in /etc/nsswitch.conf and no nscd service running; you can put “dns” back in at the end as you see fit. 

NOTE:  If you previously had Microsoft Windows DNS entries for servers you no longer wish to be represented by DNS and only by LDAP hosts device entries, then make sure you remove them and their associated pointer (PTR) records as necessary.

:: TESTING LDAP HOST NAME RESOLUTION ::


Now that we have updated /etc/hosts, /etc/nsswitch.conf, stopped the nscd daemon service, invalidated the nscd daemon hosts cache, and ensured that no DNS entry for the servers lux001, lux001.test.internal, lux002, or lux002.test.internal exist; we can test LDAP host name resolution from the RHEL server:

[root@lux001 /]# getent hosts | grep ^10.0      
10.0.0.60       lux001
10.0.0.60       lux001.test.internal
10.0.0.61       lux002
10.0.0.61       lux002.test.internal

You will notice that, unlike a traditional /etc/hosts file entry, we aren’t getting back a FQDN and a hostname per IP address line.  I consider this a minor trade-off for not having to maintain this in a /etc/hosts file across hundreds of servers.

And now a ping test against both lux001 and lux001.test.internal:

[root@lux001 /]# ping lux001 -c4
PING lux001 (10.0.0.60) 56(84) bytes of data.
64 bytes from lux001 (10.0.0.60): icmp_seq=1 ttl=62 time=1.12 ms
64 bytes from lux001 (10.0.0.60): icmp_seq=2 ttl=62 time=1.47 ms
64 bytes from lux001 (10.0.0.60): icmp_seq=3 ttl=62 time=1.38 ms
64 bytes from lux001 (10.0.0.60): icmp_seq=4 ttl=62 time=1.20 ms
--- lux001 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3000ms
rtt min/avg/max/mdev = 1.122/1.298/1.475/0.139 ms

[root@lux001 /]# ping lux001 -c 4
PING lux001.test.internal (10.0.0.60) 56(84) bytes of data.
64 bytes from lux001.test.internal (10.0.0.60): icmp_seq=1 ttl=62 time=2.01 ms
64 bytes from lux001.test.internal (10.0.0.60): icmp_seq=2 ttl=62 time=1.54 ms
64 bytes from lux001.test.internal (10.0.0.60): icmp_seq=3 ttl=62 time=1.53 ms
64 bytes from lux001.test.internal (10.0.0.60): icmp_seq=4 ttl=62 time=1.58 ms
--- lux001.test.internal ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 1.534/1.668/2.013/0.203 ms

:: FINAL STEPS ::


Now that we are certain that LDAP name resolution works you can turn the nscd service back on.
[root@lux001 /]# service nscd start
Starting nscd:                                             [  OK  ]

You can also add the “dns” option back to /etc/nsswitch.conf if you so desire:
# vim /etc/nsswitch.conf

hosts:      files ldap dns

This completes the process for managing the /etc/hosts files with LDAP (Microsoft Windows 2008 R2 Active Directory).

Thursday, September 13, 2012

RHEL 5 K5START-TICKET-RENEW.SH

The k5start-ticket-renew.sh Script

The original source for this script can found at:  https://build.opensuse.org/package/files?package=msktutil&project=home%3Adipe

The original author can be contacted at:  dipeit@gmail.com

I have modified this script for my purposes but you can find more information and functionality at the link provided above.

I've never spoken with the original author so I hope he doesn't mind my usage of his scripts.

This script should live in /etc/cron.hourly.

I've made a one change from the original; the full PATH to the Kerberos 5 binaries in RHEL was added as /usr/kerberos/bin.  I'm pretty sure that was the extent of it.

Pay attention to the authors note about adding the following to individual users' ~/.bash_profile:

export PROMPT_COMMAND="k5start -H 360"

Save this script as k5start-ticket-renew.sh (or whatever you'd like), chown it root.root, and chmod it it 755.

#! /bin/sh

# dipeit@gmail.com / 2010-09-01
# This script renews kerberos tickets for all logged on users
# that have not yet expired and removes tickets that have expired.
# It also allows a user to refresh her ticket in time by not
# auto renewing tickets that have between 8 and 1 hour to live
# durning the last 4 days of the renew_lifetime. Thus, the user
# is not prompted for a password for 3 days after logon if the
# ticket renew lifetime is 7 days (MS AD default policy)
# The user should set this env variable (6 hours):
# export PROMPT_COMMAND="k5start -H 360"
#
# Finally the scripts logs out users for who renew_lifetime is
# less than 1 hour. (FORCELOGOUT is set to "no" by default) and
# sends a warning email to all users for who renew_lifetime is less than
# 2 hours (SENDWARNING is set to "no" by default)
#
# Test cases, there are more test cases in the code below.
# kinit -l 10m -r 3d
# (ticket_lifetime = 10 minutes,  renew_lifetime = 3 days)
#
# Please put this script in /etc/cron.hourly and edit /etc/krb5.conf :
##[libdefaults]
##    ticket_lifetime = 10h
##    renew_lifetime = 7d

# Set path to Kerberos binaries for RHEL
PATH=$PATH:/usr/kerberos/bin

if [ -f /etc/krb5-ticket-renew.conf ]; then
  . /etc/krb5-ticket-renew.conf
else
  SENDWARNING="no"
  FORCELOGOUT="no"
  MAILHOST="mx"
  HOURSTOEXPIRE=48
fi
DOMAIN=`hostname -d`
CURRUSERS=`users | sed 's/ /\n/g' | sort -u`
for TCACHE in $( ls -1 /tmp/krb5cc* 2> /dev/null ); do
    OWNER=$( ls -l $TCACHE | awk '{print $3}' )
    GROUP=$( ls -l $TCACHE | awk '{print $4}' )
    NOW=$( date +%s )
    EXPIRE_TIME=$( date -d "$( klist -c $TCACHE | grep -m1 krbtgt | awk '{print $3, $4}' )" +%s )
    RENEW_TIME=$( date -d "$( klist -c $TCACHE | grep -m1 "renew until" | awk '{print $3, $4}' )" +%s )

    #logger -i -t krb5-renew owner:$OWNER tcache:$TCACHE expire:$EXPIRE_TIME renew:$RENEW_TIME current:$NOW

    # If the ticket has already expired, might as well delete it
    # testcase: kinit -l 10s
    if [ $NOW -ge $EXPIRE_TIME ]; then
        kdestroy -c $TCACHE &> /dev/null:
        logger -i -t krb5-renew "Removed expired ticket cache for $OWNER: $TCACHE"

    # log user out if we are within one hour or less of max renew_lifetime, prevent lockup
    # testcase: kinit -l 1h -r 1h
    elif [ $( expr $RENEW_TIME - $NOW ) -le 3600 ]; then
        logger -i -t krb5-renew "time to log user $OWNER out!"
        if [[ $FORCELOGOUT == "yes" ]]; then
            kill -15 $(ps -U $OWNER -o "pid=")
            logger -i -t krb5-renew "send notice to user $OWNER !"
            emailbody=`mktemp`
            mail -s "You have been logged out from '`hostname`' and all your jobs have been ended." -r root@`hostname -f` \
                     -S "smtp=$MAILHOST.$DOMAIN" $OWNER@$DOMAIN < $emailbody
            rm $emailbody
        fi

    # notify user if we are between 3 and 4 hours of max renew_lifetime to prevent forced logout
    # testcase: kinit -l 1h -r 4h
    elif [ $( expr $RENEW_TIME - $NOW ) -le 14400 ]; then
        if [ $( expr $RENEW_TIME - $NOW ) -gt 10800 ]; then
            logger -i -t krb5-renew "send warning to user $OWNER that they are pending automated logout!"
            if [[ $SENDWARNING == "yes" ]]; then
                emailbody=`mktemp`
                echo "$OWNER, please make sure to login to '`hostname`' to update your credentials."  >> $emailbody
                echo "If you can't login within 3 hours you will be logged out and your running jobs will be ended." >> $emailbody
                mail -s "Please login to '`hostname`' within the next 3 hours." -r root@`hostname -f` \
                         -S "smtp=$MAILHOST.$DOMAIN" $OWNER@$DOMAIN < $emailbody
                rm $emailbody
            fi
        fi

    else

        # standard refresh loop, tickets are not in immediate danger to expire
        for user in $CURRUSERS; do
            if [[ $user == $OWNER ]]; then
                logger -i -t krb5-renew "user $OWNER is logged on, check renewal!"
                # renew ticket if it will expire in one hour or less
                # testcase: kinit -l 1h -r 1d
                if [ $( expr $EXPIRE_TIME - $NOW ) -le 3600 ]; then
                    kinit -R -c $TCACHE
                    chown $OWNER:$GROUP $TCACHE
                    logger -i -t krb5-renew "auto renewed - 1h left - $OWNER - $TCACHE"

                # renew ticket if it will expire in 8 hours or less
                # testcase: kinit -l 8h -r 97h
                elif [ $( expr $EXPIRE_TIME - $NOW ) -le 28800 ]; then
                    # ....and if there is at least 96 hours left for renewal
                    let "SECTOEXPIRE = $HOURSTOEXPIRE * 3600"
                    if [ $( expr $RENEW_TIME - $NOW ) -ge $SECTOEXPIRE ]; then
                        kinit -R -c $TCACHE
                        chown $OWNER:$GROUP $TCACHE
                        logger -i -t krb5-renew "auto renewed < $HOURSTOEXPIRE h left: $OWNER - $TCACHE"
                    else
                        #testcase: kinit -l 8h -r 96h
                        logger -i -t krb5-renew "time for ticket refresh for $OWNER via k5start or systray app"
                    fi
                fi
            fi
        done

    fi

done


RHEL 5 MSKTUTIL_NFSV4.SH

The msktutil_nfsv4.sh Script

The original source for this script can found at:  https://build.opensuse.org/package/files?package=msktutil&project=home%3Adipe

The original author can be contacted at:  dipeit@gmail.com

I have modified this script for my purposes but you can find more information and functionality at the link provided above.

I've never spoken with the original author so I hope he doesn't mind my usage of his scripts.

Save this script as msktutil_nfsv4.sh (or whatever you'd like), chown it root.root, and chmod it it 755.

#! /bin/sh

# Creates Active Directory computer objects for kerberized NFSv4
# Modified 09.12.2012 By Aaron Wyllie
# Original source can be found at https://build.opensuse.org/package/files?package=msktutil&project=home%3Adipe
# Original author contact: dipeit@gmail.com

OU='ou=services,ou=servers'

if [ $# -ne 1 ]; then
  hostfqdn=`hostname -f`
else
  hostfqdn=$1
fi
computername=${hostfqdn%%.*}
if [ $hostfqdn == $computername ]; then
  hostfqdn=$computername.`hostname -d`
fi

if [ -e /etc/krb5.keytab ]; then
  rm /etc/krb5.keytab
fi 

# add --verbose for debugging

# CREATE ROOT servicePrincipleName (SPN) AND userPrincipleName (UPN) COMPUTER OBJECT - NOT REQUIRED FOR THIS IMPLEMENTATION - SEE ORIGINAL SOURCES ABOVE IF YOU'RE INTERESTED IN HOW IT COULD BE USED
#msktutil --dont-expire-password --no-pac --computer-name $computername-root --enctypes 0x1F -b "$OU" -k /etc/krb5.keytab -h $hostfqdn -s root/$hostfqdn --upn root/$hostfqdn  --verbose --description "TEST.INTERNAL ROOT SERVICE PRINCIPLE OBJECT - DO NOT DELETE, DISABLE, MODIFY, OR MOVE"

# CREATE NFSv4 servicePrincipleName (SPN) AND userPrincipleName (UPN) COMPUTER OBJECT
msktutil --delegation --dont-expire-password --no-pac --computer-name $computername-nfs --enctypes 0x1F -b "$OU" -k /etc/krb5.keytab -h $hostfqdn -s nfs/$hostfqdn --upn nfs/$hostfqdn  --verbose --description "TEST.INTERNAL NFSv4 SERVICE PRINCIPLE OBJECT - DO NOT DELETE, DISABLE, MODIFY, OR MOVE"

# I'm not using this
#echo -e "\nKerberized NFSv4 is activated\nDo you also want to create a ServicePricipleName HOST (aka "join the windows domain") to enable SSO, etc? Please select 'No' if you are already using another tool (like likewise or winbind) to bind this computer to Active Directory!"
#select yn in "Yes" "No"; do
#    case $yn in
#        Yes ) msktjoin; break;;
#        No ) klist -k -t -e; break;;
#    esac
#done

#echo -e "\nIf you experience problems, please delete the computer accounts in Active Directory that belong to $computername and run this tool again!\n"

echo -e "\nKerberized NFSv4 has been enabled.\n"

klist -ket

RHEL 5 MSKTUTIL_JOIN.SH

The msktutil_join.sh Script

The original source for this script can found at:  https://build.opensuse.org/package/files?package=msktutil&project=home%3Adipe

The original author can be contacted at:  dipeit@gmail.com

I have modified this script for my purposes but you can find more information and functionality at the link provided above.

I've never spoken with the original author so I hope he doesn't mind my usage of his scripts.

Save this script as msktutil_join.sh (or whatever you'd like), chown it root.root, and chmod it it 755.

#! /bin/sh

# Creates Active Directory computer object with host service principle, aka "joins AD Domain".
# Modified 09.12.2012 By Aaron Wyllie
# Original source can be found at https://build.opensuse.org/package/files?package=msktutil&project=home%3Adipe
# Original author contact: dipeit@gmail.com

OU='ou=servers'

if [ $# -ne 1 ]; then
  hostfqdn=`hostname -f`
else
  hostfqdn=$1
fi
computername=${hostfqdn%%.*}
if [ $hostfqdn == $computername ]; then
  hostfqdn=$computername.`hostname -d`
fi

# add --verbose for debugging
# host principal is needed for sso via sshd but can also be provided via samba/winbind

# CREATE HOST servicePrincipleName (SPN) AND userPrincipleName (UPN)
msktutil --delegation --dont-expire-password --no-pac --computer-name $computername --enctypes 0x1F -b "$OU" -k /etc/krb5.keytab -h $hostfqdn -s host/$hostfqdn -s host/$computername --upn host/$hostfqdn --verbose --description "TEST.INTERNAL KERBEROS RHEL 5 SERVER OBJECT - DO NOT DELETE, DISABLE, MODIFY, OR MOVE"

klist -ket

RHEL 5 KRB5-TICKET-RENEW.CONF

The krb5-ticket-renew.conf File

The original source for this script can found at:  https://build.opensuse.org/package/files?package=msktutil&project=home%3Adipe

The original author can be contacted at:  dipeit@gmail.com

This script has not been modified from it's original source.

I've never spoken with the original author so I hope he doesn't mind my usage of his scripts.

Save this script in /etc, chown it root.root, and chmod it 600.

# Config for /etc/cron.hourly/krb5-ticket-renew
# The script logs out users for who renew_lifetime is
# less than 1 hour. (FORCELOGOUT is set to "no" by default) and
# sends a warning email to all users for who renew_lifetime is less than
# 2 hours (SENDWARNING is set to "no" by default)
#
SENDWARNING="no"
FORCELOGOUT="no"
MAILHOST="mx"
HOURSTOEXPIRE=48

Wednesday, September 12, 2012

RHEL 5 K5START_LDAP

The k5start_ldap Initialization Script


For starters, the original source for this script can be found at the yp2ldap project page:  http://yp2ldap.sourceforge.net/

Beyond that, thanks go to Mark R. Bannister and his blog, Technical Prose located at:  http://technicalprose.blogspot.com/

This init script should live in /etc/rc.d/init/k5start_ldap.

The only change I've made was to set the K5START_OPTIONS to properly grab the server' proper principle from /etc/krb5.keytab.  I ran into a problem after trying to setup NFSv4 where the NFS principle was at the top of the keytab and that is what was being grabbed by this script.  Workable but it could cause problems down the road if I want to break the NFSv4 Kerberos ticket cache out and maybe add an HTTP ticket cache as well, etc., etc..  It works fine now.

#!/bin/bash
##############################################################################
# k5start_ldap:    Keeps Kerberos 5 /etc/.ldapcache ticket active
# Author:    Mark R. Bannister <cambridge@users.sourceforge.net>
#
# chkconfig: 345 20 75
# description:  Keeps Kerberos 5 /etc/.ldapcache ticket active
#
# processname: /usr/bin/k5start_ldap
# config: /etc/krb5.conf
# pidfile: /var/run/k5start_ldap.pid
##############################################################################
# k5start_ldap init script
# Copyright (c) 2011 Mark R. Bannister <cambridge@users.sourceforge.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
##############################################################################

# Sanity checks.
[ -f /etc/krb5.conf ] || exit 0
[ -x /usr/bin/k5start ] || exit 0

# Source function library.
. /etc/init.d/functions

K5START_KEYTAB=/etc/krb5.keytab
K5START_MINUTES=30
K5START_OPTIONS="-u `echo ${HOSTNAME%%.*}`\$"

# Source an auxiliary options file if we have one
# This can override K5START_KEYTAB, K5START_MINUTES and K5START_OPTIONS
# It can also set DAEMON_COREFILE_LIMIT and NICELEVEL
[ -r /etc/sysconfig/k5start_ldap ] && . /etc/sysconfig/k5start_ldap

RETVAL=0

start() {
    echo -n $"Starting k5start_ldap: "

    #
    # Use KINIT_PROG and the -t option to keep /etc/.ldapcache file always
    # readable by everyone (otherwise nss_ldap will hang if it is configured
    # to use this Kerberos ticket cache)
    #
    # Also running 'getent passwd' will serve two purposes:
    #    1. Pre-populate ticket cache with a ticket
    #        (user processes can't write to this file, so without this
    #        there will be a Kerberos ticket request every time nss_ldap
    #        needs some information from the directory)
    #    2. As a useful side-effect, nscd will be pre-populated
    #
    export KINIT_PROG="chmod 644 /etc/.ldapcache && getent passwd > /dev/null"
    daemon --pidfile /var/run/k5start_ldap.pid \
        /usr/bin/k5start -f $K5START_KEYTAB -bLtK$K5START_MINUTES \
            -p /var/run/k5start_ldap.pid -k /etc/.ldapcache \
            $K5START_OPTIONS
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/k5start_ldap
    return $RETVAL
}

stop() {
    echo -n $"Stopping k5start_ldap: "
    killproc -p /var/run/k5start_ldap.pid k5start
    RETVAL=$?
    [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/k5start_ldap
    echo
    return $RETVAL
}

restart() {
    stop
    start
}

# See how we were called.
case "$1" in
    start)
    start
    RETVAL=$?
    ;;
    stop)
    stop
    RETVAL=$?
    ;;
    status)
    status -p /var/run/k5start_ldap.pid k5start
    RETVAL=$?
    ;;
    restart)
    restart
    RETVAL=$?
    ;;
    try-restart | condrestart)
    [ -e /var/lock/subsys/k5start_ldap ] && restart
    RETVAL=$?
    ;;
    force-reload | reload)
        echo -n $"Refreshing k5start_ldap ticket cache: "
    killproc -p /var/run/k5start_ldap.pid k5start -ALRM
    RETVAL=$?
    echo
    ;;
    *)
    echo $"Usage: $0 {start|stop|status|restart|reload|condrestart}"
    RETVAL=1
    ;;
esac
exit $RETVAL

RHEL 5, ACTIVE DIRECTORY, AND KERBEROS

Configuring Red Hat Enterprise Linux (RHEL) 5 To Authenticate Against LDAP (Microsoft Windows Active Directory 2008 R2) Using Kerberos 5

 

:: ASSUMPTIONS ::

This post assumes the following: 

  • The server being joined to the domain does not have direct connectivity to the Internet.  This is why I have included steps to manually add the Fedora EPEL repository key and a couple of EPEL RPMs as opposed to using wget or some other easier solution.  If you have a direct connection to the Internet then, by all means, take advantage of it.
  • That the LDAP solution available to you is Windows Server Active Directory 2008 R2.  This solution should work with a little tweaking for Windows Server Active Directory 2003 RC2 but I have not tested it against it.  I have no idea if this will work against a Windows Server 2000 Active Directory deployment.
  • That you have no need of Samba winbind.  Part of my requirement for developing this process was to replace an existing and poorly functioning Samba winbind solution.  I plan on investigating why this Samba winbind solution was having so many problems at a later date.  Suffice it to say that "it needed to go".  This is not a commentary on any failing (perceived or otherwise) with Samba or the Samba team (who are awesome).
  • That the Linux server being joined is RHEL 5.* or a RHEL 5.* clone such as CentOS or Scientific Linux.  I understand that <insert your favorite Linux distro here> is much better because of <reasons...> but I have so far only tested this against what I have to work with.  Eat your own dog food, as the saying goes.  I'd like to work this against Debian in the near future, though.  For that matter, I'd like to work it against OpenLDAP as well.
  • Please see my "Thanks to..." section for the numerous sources from which I drew direction and examples from in completing this.
  • That your domain is using your Windows Active Directory Domain Controllers as an NTP time source.  If this is not the case, simple adjust as necessary to point toward your NTP time source.
  • Finally, I do not claim to be an authority on much of anything.  Please let me know how I can make this process better or if you see glaring deficiencies and\or errors.  I will do my best to make changes and always give credit where credit is due.

:: PURPOSE ::

 

This is a work in progress and subject to change.  Please confirm that the version you have is the latest version available.

The purpose of this process is to facilitate the secure authentication of employees and services from UNIX and Linux systems to Active Directory using native OS-level components.

This process should work with Windows Active Directory 2003R2 as well since that is the first iteration of Active Directory to natively support the majority of and, more importantly, the required RFC 2307 LDAP schema attributes.

However, this process has only been tested against Windows Active Directory 2008R2 and, therefore, results may vary.

This process has NOT been tested with any version of Solaris or against Windows Active Directory 2000.

This process uses Kerberos and LDAP only.  It does NOT use samba\winbind.  It does NOT use 3rd Party solutions such as Quest Authentication Services (VAS\QAS) or Centrify.

This method utilizes RFC 2307 LDAP Schema Attributes to communicate the following schema attributes from LDAP to the local server:
  • gecos - For our purposes, the gecos field is to be defined as “DOMAIN USER NAME EMPLOYEEID”.  As an example, “TEST.INTERNAL JOE USER E123456”, sans quotes, of course.
  • gidNumber - For our purposes, this is the gidNumber of the UNIX group you’d like the user account to be associated with.
NOTE:  This group will be considered the primary group for UNIX and is different than the primaryGroupID schema attribute.  Anything owned by the user account will display this group in the Discretionary Access Control (DAC) properties of the file or directory.

NOTE:  The gidNumber is comprised of a 2-digit domain identifier (TEST.INTERNAL=77) plus three (3) additional digits.  For example, the first group in the TEST.INTERNAL domain will have a gidNumber of 77001.
  • loginShell - For our purposes, the default shell for employees is /bin/bash whereas the default shell for LDAP accounts not requiring an interactive shell is /sbin/nologin.
  • uid - For test purposes, we will use a seven character employee ID value that starts with "e" and is followed by six numerals, e.g., eXXXXXX.
  • uidNumber - For test purposes, a 2-digit domain identifier will be used (TEST.INTERNAL = 77) plus the numeric portion of the employee ID (eXXXXXX); 77XXXXXX.
NOTE:  Non-physical user accounts, i.e., “service accounts”, will be issued uidNumbers that start with the 2-digit domain identifier (INTERNAL.TEST = 77) plus three (3) additional digits.  For example, the first service account in the INTERNAL.TEST domain will have a uidNumber of 77001.
  • unixHomeDirectory    For our purposes, /home/<sAMAccountName>.  For example, “/home/e123456”, sans quotes, of course.
NOTE:  Please ensure that the leading characters, the “e” in this case, is always lower-case.

This method utilizes Kerberos to securely communicate the following with LDAP and the local server:  
  •  Computer Domain Membership
    • Add RHEL 5 Server to Active Directory From The Command Line
    • Grant Computer SPN Kerberos Ticket
    • Change Computer Password Every 30 Days (Not Applicable If NFSv4 Is Supported)
  • Authentication to LDAP
    • Console Login
    • SSH\SFTP Login
  • Authorized Password Changes
    • Initial Login\First Time Login
    • Password Expired
    • Password Change From Command-Line (UNIX\Linux)
  • Password Policies from LDAP
    • Failed Login Attempts
    • Password Complexity Requirements
    • Account Lock-Out Per LDAP Policy (Lock-Out On LDAP Server)
  • Privilege Escalation
    • /etc/sudoers
NOTE:  This process does not currently provide dynamic DNS updates.  DNS objects must be manually created in Windows DNS and provided with static IP addresses.

NOTE:  This process does not allow the administration of Active Directory user objects from the UNIX\Linux server in the manner that Quest Authentication Services (VAS\QAS) does.  Users are able to change their own passwords from the UNIX\Linux server. 

:: SECTION ONE:  PRELIMINARY STEPS TO CONFIGURE RHEL 5.* FOR KERBEROS \ LDAP AUTHENTICATION ::


STEP ONE:  Determine what version of Red Hat Enterprise Linux (RHEL) the server is currently running at…:

# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 5.8 (Tikanga)

…if the returned major version does not match the above example then STOP.  This process should work with any of the RHEL 5.* releases but has not been tested against any other than release 5.8.

STEP TWO:  Check to see if the Kerberos 5 client package (krb5-workstation) is installed:

# yum info krb5-workstation | grep Repo
Repo       : clone-devcenter-rhel-x86_64-server-5

If the “Repo” line does not read “installed” then the software is not currently installed.

STEP THREE:  If the Kerberos 5 client (krb5-workstation) is already installed, back-up any existing configuration:

# cp /etc/krb5.conf /etc/krb5.conf.backup
# cp /etc/krb5.keytab /etc/krb5.keytab.backup

STEP FOUR:  Otherwise, install the Kerberos 5 client (krb5-workstation) as required:

# yum install krb5-workstation -y

Verify that the Kerberos 5 client (krb5-workstation) has been installed:

# yum info krb5-workstation | grep Repo
Repo       : installed

STEP FIVE:  Check to see if the nss_ldap package is installed:

# yum info nss_ldap | grep Repo
Repo       : clone-devcenter-rhel-x86_64-server-5

If the “Repo” line does not read “installed” then the software is not currently installed.

STEP SIX:  If the nss_ldap package is installed; then back-up affected and\or existing configuration:

# cp /etc/ldap.conf /etc/ldap.conf.backup
# cp /etc/nscd.conf /etc/nscd.conf.backup

STEP SEVEN:  Otherwise, install the nss_ldap package as required:

# yum install nss_ldap -y

NOTE:  This action installs nscd (Name Server Caching Daemon) as a dependency.

Verify that the nss_ldap package has been installed:

#yum info nss_ldap | grep Repo
Repo       : installed

STEP EIGHT:  Check to see if the OpenLDAP package (openldap) have been installed:

# yum info openldap | grep Repo
Repo       : clone-devcenter-rhel-x86_64-server-5

STEP NINE:  If the OpenLDAP package (openldap) is installed; then back-up any existing configuration files:

# cp /etc/openldap/ldap.conf /etc/openldap/ldap.conf.backup

STEP TEN:  Otherwise, install the OpenLDAP package (openldap) as required:

# yum install openldap -y

NOTE:  Installing the openldap package will include approximately 100 dependencies.

Verify that OpenLDAP package (openldap) has been installed:

# yum info openldap | grep Repo
Repo       : installed

STEP ELEVEN:  Check to see if the OpenLDAP clients package (openldap-clients) has been installed:

# yum info openldap-clients | grep Repo
Repo       : clone-devcenter-rhel-x86_64-server-5

STEP TWELVE:  Install the OpenLDAP clients package (openldap-clients) if not:

# yum install openldap-clients -y

Verify that the OpenLDAP clients package (openldap-clients) has been installed:

# yum info openldap-clients | grep Repo
 Repo       : installed

STEP THIRTEEN:  Check to see if any Samba packages are installed:

# yum info samba3x* | grep Repo
Repo       : installed
Repo       : installed
Repo       : installed
Repo       : clone-devcenter-rhel-x86_64-server-5
Repo       : clone-devcenter-rhel-x86_64-server-5
Repo       : clone-devcenter-rhel-x86_64-server-5
Repo       : clone-devcenter-rhel-x86_64-server-5
Repo       : clone-devcenter-rhel-x86_64-server-5
Repo       : clone-devcenter-rhel-x86_64-server-5
Repo       : clone-devcenter-rhel-x86_64-server-5

STEP FOURTEEN:  If any Samba winbind components are installed, back-up the existing configurations:

# cp /etc/pam_smb.conf /etc/pam_smb.conf.backup
# cp /etc/samba/smb.conf /etc/samba/smb.conf.backup

STEP FIFTEEN:  Stop any Samba winbind services that may be running:

# service winbind status
winbind is stopped

STEP SIXTEEN:  Make sure Samba winbind is turned off:

# chkconfig winbind off
# chkconfig winbind --list
winbind         0:off   1:off   2:off   3:off   4:off   5:off   6:off

STEP SEVENTEEN:  Remove the existing Samba winbind packages:

# yum remove samba3x* -y

NOTE:   This command will most likely return samba3x-common, samba3x-winbind for i386 architecture, and samba3x-winbind for x86_64 architecture.

STEP EIGHTEEN:  Make a copy of the /etc/hosts file:

# cp /etc/hosts /etc/hosts.backup

STEP NINETEEN:  Update the /etc/hosts file to include Active Directory domain controllers (DCs):

# vim /etc/hosts

Add the following entries for the DCSR.SITE Active Directory domain:

10.0.0.50   dc01.test.internal     dc01      # WIN2K8R2 DOMAIN CONTROLLER
10.0.0.51   dc02.test.internal     dc02      # WIN2K8R2 DOMAIN CONTROLLER

STEP TWENTY:  Make a copy of the /etc/resolv.conf file:

# cp /etc/resolv.conf /etc/resolv.conf.backup

STEP TWENTY-ONE:  Update the /etc/resolv.conf file to include the name resolution sources for your domain:

# vim /etc/resolv.conf

Remove any existing data and add the following:

nameserver 10.0.0.50
nameserver 10.0.0.51
search test.internal

STEP TWENTY-TWO:  Make a copy of the /etc/ntp.conf file:

# cp /etc/ntp.conf /etc/ntp.conf.backup

STEP TWENTY-THREE:  Verify that the ntpd service is running:

# service ntpd status
ntpd (pid  3125) is running...

STEP TWENTY-FOUR:  Edit /etc/ntp.conf to reference the Active Directory domain controllers (DCs) for time sync purposes:

# vim /etc/ntp.conf

Remove any existing entries and add the following:

restrict 127.0.0.1
restrict -6 ::1
server 10.0.0.50
server 10.0.0.51
driftfile /etc/ntp/ntp.drift
server 127.127.1.0        # LOCAL CLOCK
fudge    127.127.1.0 stratum 10

STEP TWENTY-FIVE:  Stop the ntpd service:

# service ntpd stop
Shutting down ntpd:                                        [  OK  ]

STEP TWENTY-SIX:  Check the availability of the new NTP time sync sources:

# ntpdate 10.0.0.50
15 Jun 09:41:30 ntpdate[19383]: adjust time server 10.0.0.50 offset -0.012710 sec

# ntpdate 10.0.0.51
 15 Jun 09:41:37 ntpdate[19384]: adjust time server 10.0.0.51 offset -0.007804 sec

STEP TWENTY-SEVEN:  Start the ntpd service:

# service ntpd start
Starting ntpd:                                             [  OK  ]

STEP TWENTY-EIGHT:  Verify that your /etc/ntp.conf server entries were not overwritten when restarting the service:

# grep ^server /etc/ntp.conf
server 10.0.0.50
server 10.0.0.51
server 127.127.1.0

STEP TWENTY-NINE:  Verify that you can resolve the host name for the NTP time sync sources:

# host 10.0.0.50
10.0.0.52.in-addr.arpa domain name pointer dc01.test.internal.

# host 10.0.0.51
10.0.0.52.in-addr.arpa domain name pointer dc02.test.internal.

STEP THIRTY:  Query the NTP time sources:

# ntpq -p
    remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
   dc01.test.      10.0.0.50     2 u   31   64    1    0.559   10.085   0.001
   dc02.test.      10.0.0.51     3 u   30   64    1    0.525    6.316   0.001
LOCAL(0)        .LOCL.          10 l   46   64    1    0.000    0.000   0.001


STEP THIRTY-ONE:  To resolve the follow NTP error in /var/log/messages:

Jun 15 10:09:11 lux ntpd[19398]: can't open /etc/ntp/ntp.drift.TEMP: Permission denied

# touch /etc/ntp/ntp.drift.TEMP
# chown ntp.ntp /etc/ntp/ntp.drift.TEMP
# service ntpd stop
Shutting down ntpd:                                        [  OK  ]
# service ntpd start
Starting ntpd:                                             [  OK  ]

STEP THIRTY-TWO:  Determine if the server hostname is properly set and correct if it is not (TEST.INTERNAL specific):

# hostname
lux

…or:

# cat /etc/sysconfig/network
NETWORKING=yes
NETWORKING_IPV6=no
HOSTNAME=lux
NOZEROCONFIG=true

Set the FQDN if it is not set:

# vim /etc/sysconfig/network

Update the HOSTNAME section to reflect the FQDN of the server:

HOSTNAME=lux.test.internal

STEP THIRTY-THREE:  This may not be required but if you have user home directories existing locally under a different directory then home, like /export/home/%username% for example, then create a symbolic link from /export to /home...:

# mkdir /export
# ln -s /home /export
# ll /export
lrwxrwxrwx 1 root root 7 Jun 15 10:23 home -> ../home

...otherwise you will need to update the userHomeDirectory schema attribute in Active Directory for every affected user as required.

STEP THIRTY-FOUR:  Install the Fedora EPEL Repository GPG key.  Please see the “Installing Fedora Project EPEL Repository Packages and Fedora Project GPG Keys” post for more information.

Get the Fedora EPEL Repository key for RHEL 5, RPM-GPG-KEY-EPEL , from https://fedoraproject.org/keys.  Right-click on the “Download: Fedora Project” link and choose “Save target as…”, accept the default of “217521F6.txt”, and save it locally to your workstation.

Upload the GPG key to the /tmp directory of the RHEL server.

Rename the key:

# mv /tmp/217521F6.txt /tmp/RPM-GPG-KEY-EPEL.txt

Move the key:

# mv /tmp/RPM-GPG-KEY-EPEL.txt /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL

Install the key:

# rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL

Test the key:

# gpg --quiet --with-fingerprint /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL
gpg: new configuration file `/root/.gnupg/gpg.conf' created
gpg: WARNING: options in `/root/.gnupg/gpg.conf' are not yet active during this run
pub  1024D/217521F6 2007-03-02 Fedora EPEL <epel@fedoraproject.org>
      Key fingerprint = B940 BE07 7D71 0A28 7D7F  2DD1 119C C036 2175 21F6
sub  2048g/B6610DAF 2007-03-02 [expires: 2017-02-27]

You can verify the output by referring back to page where you acquired the GPG key and comparing the key fingerprints.

NOTE:  While it is possible to install external packages without a corresponding GPG key file it is irresponsible to do so when the means to verify the authenticity and security of the external package is easily attainable.

STEP THIRTY-FIVE:  Upload the k5start_ldap init script to the /tmp directory of the RHEL server and copy to the /etc/rc.d/init.d directory:

# cp /tmp/k5start_ldap /etc/rc.d/init.d/k5start_ldap

Set appropriate DAC permissions and ensure ownership:

# chmod 755 /etc/rc.d/init.d/k5start_ldap
# chown root.root /etc/rc.d/init.d/k5start_ldap 

For more information, see my post for k5start. 

STEP THIRTY-SIX:  Upload the krb5-ticket-renew.sh script to the /tmp directory of the RHEL server and copy it to the /etc/cron.hourly/ directory:

# cp /tmp/krb5-ticket-renew.sh /etc/cron.hourly/krb5-ticket-renew.sh

Set appropriate DAC permissions and ensure ownership:

# chmod 755 /etc/cron.hourly/krb5-ticket-renew.sh
# chown root.root /etc/cron.hourly/krb5-ticket-renew.sh

For more information, see my post on krb5-ticket-renew.sh.

STEP THIRTY-SEVEN:  Upload the krb5-ticket-renew.conf file to the /tmp directory of the RHEL server and copy it to the /etc directory:

# cp /tmp/krb5-ticket-renew.conf /etc/krb5-ticket-renew.conf

Set appropriate DAC permissions and ensure ownership:

# chmod 600 /etc/krb5-ticket-renew.conf
# chown root.root /etc/krb5-ticket.renew.conf

For more information, see my post on krb5-ticket-renew.conf. 

STEP THIRTY-EIGHT:  Upload the msktutil_join.sh and msktutil_nfsv4.sh scripts to the /tmp directory of the RHEL server.  Set appropriate DAC permissions and ensure ownership:

# chmod 755 /tmp/msktutil_join.sh && chown root.root /tmp/msktutil_join.sh
# chmod 755 /tmp/msktutil_nfsv4.sh && chown root.root /tmp/msktutil_nfsv4.sh

For more information, see my post in msktutil_join.sh.

For more information, see my post on msktutil_nfsv4.sh. 

NOTE:  You should move these scripts to another more secure directory after use so as to have them available if required in the future.

STEP THIRTY-NINE:  Install or make sure that following packages are installed as msktutil, primarily, depends on them:
  • make 
  • gcc++ 
  • cyrus-sasl-gssapi 
  • cyrus-sasl-devel 
  • cyrus-sasl-md5 
  • openldap-devel 
  • krb5-devel
# yum install make gcc-c++ cyrus-sasl-gssapi cyrus-sasl-md5 cyrus-sasl-devel openldap-devel krb5-devel -y

STEP-FORTY:  Upload and install the kstart RPM to the /tmp directory of the RHEL server.

You can download the i386 RPM from the Fedora EPEL repository at:   http://dl.fedoraproject.org/pub/epel/5/i386/repoview/kstart.html 

You can download the x86_64 RPM from the Fedora EPEL repository at:   http://dl.fedoraproject.org/pub/epel/5/x86_64/repoview/kstart.html 

# yum install /tmp/kstart-3.16-1.el5.1.x86_64.rpm -y

STEP FORTY-ONE:  Upload and install the msktutil RPM to the /tmp directory of the RHEL server:

You can download the i386 RPM from the Fedora EPEL repository at:  http://dl.fedoraproject.org/pub/epel/5/i386/repoview/msktutil.html

You can download the x86_64 RPM from the Fedora EPEL repository at:  http://dl.fedoraproject.org/pub/epel/5/x86_64/repoview/msktutil.html 

# yum install /tmp/msktutil-0.4.1-1.el5.x86_64.rpm -y

:: SECTION TWO:  ACTIVE DIRECTORY CONFIGURATION STEPS ::


Red Hat Enterprise Linux (RHEL) 5 requires no additions or changes to your existing Active Directory schema, OUs, or objects from Active Directory.  All changes will be initiated from the RHEL 5 Linux server insofar as Computer objects, servicePrincipleName (SPN) schema attributes, userPrincipleName (UPN) schema attributes, and Kerberos tickets are concerned.

NOTE:  You will need to provide the individual user and group schema attributes in Active Directory as described in the "Purpose" section.  If you have not already established a UID\GID management strategy for your LDAP environment, please revisit the "purpose" section above.

NOTE:  You will need to provide the username and password of an Active Directory account with permissions to join a Computer object to the domain.

:: SECTION THREE:  RHEL 5.* LDAP AND KERBEROS CONFIGURATION STEPS ::


STEP ONE:  Use the authconfig command to perform the preliminary Kerberos and LDAP configuration:

# authconfig --enablekrb5 --krb5realm=TEST.INTERNAL --enablekrb5kdcdns --disableldapauth --disablewinbindauth \
--disablewinbind --enableldap --ldapserver dc01.test.internal --ldapbasedn dc=test,dc=internal --enablelocauthorize \
--disablesmbauth --update

NOTE:  This process will make changes to the following files listed below… 
  • /etc/krb5.conf
  • /etc/pam.d/system-auth 
  • /etc/nsswitch.conf 
  • /etc/ldap.conf
STEP TWO:  Make a copy of the /etc/krb5.conf file:

# cp /etc/krb5.conf /etc/krb5.conf.backup

STEP THREE:  Make a copy of /etc/krb5.keytab (if present):

# cp /etc/krb5.keytab /etc/krb5.keytab.backup

STEP FOUR:  Configure the /etc/krb5.conf file:

# vim /etc/krb5.conf

Remove anything currently in the file:

:d 100 <ENTER>

Add the following:

[logging]
 default = FILE:/var/log/krb5libs.log
 kdc = FILE:/var/log/krb5kdc.log
 admin_server = FILE:/var/log/kadmind.log

[libdefaults]
 default_realm = TEST.INTERNAL
 dns_lookup_realm = true
 dns_lookup_kdc = true
 ticket_lifetime = 10h
 renew_lifetime = 7d
 forwardable = yes
 validate = true

[realms]
 DCSR.SITE = {
  kdc = dc01.test.internal:88
  kdc = dc02.test.internal:88
  admin_server = dc01.test.internal:749
  admin_server = dc02.test.internal:749
  default_domain = test.internal
 }

[domain_realm]
 .dcsr.site = TEST.INTERNAL
 dcsr.site =TEST.INTERNAL

[appdefaults]
 pam = {
   debug = false
   ticket_lifetime = 10h
   renew_lifetime = 7d
   forwardable = true
   krb4_convert = false
   validate = true
 }

Save and exit.

STEP FIVE:  Make a copy of the /etc/pam.d/system-auth file:

# cp /etc/pam.d/system-auth /etc/pam.d/system-auth.backup

STEP SIX:  Configure the /etc/pam.d/system-auth file:

# vim /etc/pam.d/system-auth

Remove anything currently in the file:

:d 100 <ENTER>

Add the following:

#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
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_krb5.so use_first_pass ignore_root minimum_uid=1000
auth        required      pam_deny.so

account     required      pam_access.so
account     required      pam_unix.so broken_shadow
account     sufficient    pam_localuser.so
account     sufficient    pam_succeed_if.so uid < 500 quiet
account     [default=bad success=ok user_unknown=ignore] pam_krb5.so
account     required      pam_permit.so

password    requisite     pam_cracklib.so try_first_pass retry=3 type=
password    sufficient    pam_unix.so md5 shadow nullok try_first_pass use_authtok
password    sufficient    pam_krb5.so use_authtok
password    required      pam_deny.so

session     optional      pam_keyinit.so revoke
session     required      pam_limits.so
session     optional      pam_mkhomedir.so skel=/etc/skel/ umask=0022
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session     required      pam_unix.so
session     optional      pam_krb5.so

Save and exit.

STEP SEVEN:  Make a copy of the /etc/ldap.conf file:

# cp /etc/ldap.conf /etc/ldap.conf.backup

STEP EIGHT:  Configure the /etc/ldap.conf file:

# vim /etc/ldap.conf

Remove anything currently in the file:

:d 200 <ENTER>

Add the following:

# /etc/ldap.conf

base dc=test,dc=internal
port 389
timelimit 120
bind_timelimit 120
bind_policy soft
idle_timelimit 3600
nss_base_passwd         ou=users,dc=test,dc=internal?sub?objectClass=user
nss_base_shadow         ou=users,dc=test,dc=internal?sub?objectClass=user
nss_base_group          ou=groups,dc=test,dc=internal?sub?objectClass=group
nss_initgroups_ignoreusers root,ldap,named,avahi,haldaemon,dbus,radvd,tomcat,radiusd,news,mailman,nscd,gdm
nss_map_objectclass posixAccount user
nss_map_objectclass shadowAccount user
nss_map_objectclass posixGroup group
nss_map_attribute uid sAMAccountName
nss_map_attribute uidNumber uidNumber
nss_map_attribute gidNumber gidNumber
nss_map_attribute loginShell loginShell
nss_map_attribute gecos gecos
nss_map_attribute homeDirectory unixHomeDirectory
nss_map_attribute shadowLastChange pwdLastSet
nss_map_objectclass posixGroup group
nss_map_attribute uniqueMember member
pam_login_attribute sAMAccountName
pam_member_attribute member
pam_filter objectclass=User
pam_password ad
uri ldap://dc01.test.internal/ ldap://dc02.test.internal/
ssl no
tls_cacertdir /etc/openldap/cacerts

sasl_secprops maxssf=0
use_sasl on
rootuse_sasl yes
krb5_ccname FILE:/etc/.ldapcache

Save and exit.

STEP NINE:  Make a copy of the /etc/openldap/ldap.conf file:

# cp /etc/openldap/ldap.conf /etc/openldap/ldap.conf.backup

STEP TEN:  Configure the /etc/openldap/ldap.conf file:

# vim /etc/openldap/ldap.conf

Remove anything currently in the file:

:d 100 <ENTER>

Add the following:

#
# LDAP Defaults
#

# See ldap.conf(5) for details
# This file should be world readable but not world writable.

#BASE   dc=example, dc=com
#URI    ldap://ldap.example.com ldap://ldap-master.example.com:666

#SIZELIMIT      12
#TIMELIMIT      15
#DEREF          never
URI ldap://dc01.test.internal/
BASE dc=test,dc=internal
TLS_CACERTDIR /etc/openldap/cacerts

Save and exit.

STEP ELEVEN:  Make a copy of the /etc/nsswitch.conf file:

# cp /etc/nsswitch.conf /etc/nsswitch.conf.backup

STEP TWELVE:  Configure the /etc/nsswitch.conf file:

# vim /etc/nsswitch.conf

Remove anything currently in the file:

:d 100 <ENTER>

Add the following:

#
# /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 ldap
shadow:     files ldap
group:      files ldap

#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:     files
netmasks:   files
networks:   files
protocols:  files
rpc:        files
services:   files

netgroup:   files

publickey:  nisplus

automount:  files
aliases:    files nisplus

sudoers: files

STEP THIRTEEN:  Joining the RHEL 5 server to the Active Directory domain using the msktutil utility.

Please read this step completely before executing any script changes as it explains how the msktutil utility works.

First, as root, request a Kerberos ticket for an Active Directory user that has the ability to add computers to the domain, "AD_Administrator" in this case:

# /usr/kerberos/bin/kinit AD_Administrator
Password for AD_Administrator@TEST.INTERNAL:

Next, issue an msktutil command to join the server to the Active Directory domain.  In this process, you are required to provide the FQDN of the server you are join in the command.  This is because, in addition to creating the computer object and joining the domain, you are also creating servicePrincipleName (SPN) entries for both “host” and “nfs” services but also a userPrincipleName (UPN); of which, there can be only one per computer object in Active Directory.  The userPrincipleName will be set to “host\%FQDN%@KERBEROS_REALM” automatically by the msktutil command.  For example, the “--upn host/lux.test.internal” flag in the msktutil command will result in a UPN of “host/lux.internal.test@TEST.INTERNAL” on the actual computer object in Active Directory.

NOTE:  There are a number of sources online that suggest that only certain encryption type, like DES, can be used or that Windows Server 2008 R2 only supports UPNs in a “host\%FQDN%” manner.  To allow kerberized NFSv4, for example, to function properly where the rpcgssd service can properly find machine credentials, the UPN must be set the correct value and encryption types must be changed from the default value found in the msDS-SupportedEncryptionTypes Active Directory schema attribute of 0x1C or 28 (both of which represent all possible encryption values except DES) to 0x1F or 31 (both of which represent all possible encryption values including DES).  Do not be tempted to make changes or to add extraneous lines for encryption types to the /etc/krb5.conf file.  They are not required and could cause additional future, kerberized services to fail.

Here is an example of how to manually run the msktutil command using these parameters:

# msktutil --delegation --dont-expire-password --no-pac --computer-name lux --enctypes 0x1F -b "ou=servers" \
-k /etc/krb5.keytab -h lux.test.internal -s host/lux.test.internal -s host/lux --upn host/lux.test.internal --verbose \
--description "TEST.INTERNAL KERBEROS RHEL 5 SERVER OBJECT - DO NOT DELETE, DISABLE, MODIFY, OR MOVE"
…<OUTPUT OMITTED FOR BREVITY>…
No computer account for lux found, creating a new one.
dn: cn=lux,ou=servers,dc=TEST,dc=INTERNAL

NOTE:  The “\” at the end of the above “# msktutil -c …” command signifies a line-wrap and should not be included in the actual command.  If you were to cut and paste, that section should look like “… --upn host/lux.test.internal --verbose” and not like “… --upn host/lux.test.internal \ --verbose”.  Also, the “--verbose” flag is completely optional but is included because it will help you understand what the msktutil command is actually doing.  It can safely be omitted.

NOTE:  The msktutil command derives the domain name from the server hostname so the “-b” flag only needs the base DN up to the part where “dc=test,dc=internal” would start.  So, instead of “-b ou=servers,dc=test,dc=internal” all you need is “-b ou=servers”.

NOTE:  We will manage updating the server Kerberos ticket with the k5start_ldap init script in Section 1, Step 35.

To join the RHEL 5 server to the Active Directory domain, we will use two scripts that we uploaded to the /tmp directory on the RHEL server in Section 1, Step 38.  Please review the scripts to ensure that you understand what they are actually doing.

NOTE:  If you are NOT using or planning to use NFSv4 in the future, only execute the msktutil_join.sh script.

You will need to create the SPN and UPN attributes for NFSv4 before you join the server to the domain.  Run the following script to complete this step:

# ./msktutil_nfsv4.sh

When this script completes, you will see a new server object in Active Directory.

The msktutil_nfsv4.sh script creates an Active Directory computer object, lux-nfs, a userPrincipleName (UPN) object of nfs/lux.test.internal@TEST.INTERNAL and a serverPrincipleName (SPN) of nfs/lux.test.internal.  It also creates the object using all possible encryption types and sets the computer password to never expire.

NOTE:  A variation of this script could be created to support HTTP UPN and SPN creation but I have not tested this.

Next, we will run the msktutil_join.sh script that actually joins the server to the Active Directory domain.  Run the following command to complete this step:

# ./msktutil_join.sh

When this script completes, you will see a new server object in Active Directory. 

NOTE:  These scripts create a non-expiring Computer object in Active Directory.  This is contrary to normal Windows Computer objects in Active Directory which change their passwords every 30 days.  Other 3rd party solution like Quest Authentication Services (QAS\VAS) create Computer objects with non-expiring passwords as well.  If the answer to each of the following questions is yes, then you must use non-expiring Computer objects:

  • Is Active Directory every expected to support NFSv4 through the use of nisObject and nisMap objects (used to represent AutoFS automount objects not present in Windows 2008 R2 Active Directory)? 
  • Is NFSv4 currently in use or expected to be used in the domain?

Otherwise, you can skip the msktutil_nfsv4.sh script and just use the msktutil_join.sh script and remove the --dont-expire-password flag.  The server will then use the crontab entry setup in the following steps to refresh the server Kerberos keytab found in /etc/krb5.keytab.

STEP FOURTEEN:  As root, create a crontab entry to allow msktutil change the computer object password in Active Directory every 30 days:

# crontab -e

Add the following entry and save:

15 3 * * * /usr/sbin/msktutil -b ou=servers --auto-update

NOTE:  The “-b ou=servers” overrides the msktutil default behavior to look in ou=computers.

NOTE:  Despite the appearance that the job will run every day at 3:15AM, the msktutil --auto-update flag actually first checks to see if the computer object password is at least 30 days old and, then, it verifies that the computer object does not have password expiry disabled.  Unless both of those criteria are met, nothing actually happens.

STEP FIFTEEN:  Verify that Active Directory granted Kerberos tickets properly after joining the server to the domain:

# /usr/kerberos/bin/klist -ket

Keytab name: FILE:/etc/krb5.keytab

KVNO Timestamp         Principal

---- ----------------- --------------------------------------------------------
   2 08/23/12 10:09:59 lux-nfs$@TEST.INTERNAL (DES cbc mode with CRC-32)
   2 08/23/12 10:09:59 lux-nfs$@TEST.INTERNAL (DES cbc mode with RSA-MD5)
   2 08/23/12 10:09:59 lux-nfs$@TEST.INTERNAL (ArcFour with HMAC/md5)
   2 08/23/12 10:09:59 lux-nfs$@TEST.INTERNAL (AES-128 CTS mode with 96-bit SHA-1 HMAC)
   2 08/23/12 10:09:59 lux-nfs$@TEST.INTERNAL (AES-256 CTS mode with 96-bit SHA-1 HMAC)
   2 08/23/12 10:09:59 nfs/lux.test.internal@TEST.INTERNAL (DES cbc mode with CRC-32)
   2 08/23/12 10:09:59 nfs/lux.
test.internal@TEST.INTERNAL (DES cbc mode with RSA-MD5)
   2 08/23/12 10:09:59 nfs/lux.
test.internal@TEST.INTERNAL (ArcFour with HMAC/md5)
   2 08/23/12 10:09:59 nfs/lux.
test.internal@TEST.INTERNAL (AES-128 CTS mode with 96-bit SHA-1 HMAC)
   2 08/23/12 10:09:59 nfs/lux.
test.internal@TEST.INTERNAL (AES-256 CTS mode with 96-bit SHA-1 HMAC)
   2 08/23/12 10:10:07 lux$@TEST.INTERNAL (DES cbc mode with CRC-32)
   2 08/23/12 10:10:07 lux$@TEST.INTERNAL (DES cbc mode with RSA-MD5)
   2 08/23/12 10:10:07 lux$@TEST.INTERNAL (ArcFour with HMAC/md5)
   2 08/23/12 10:10:07 lux$@TEST.INTERNAL (AES-128 CTS mode with 96-bit SHA-1 HMAC)
   2 08/23/12 10:10:07 lux$@TEST.INTERNAL (AES-256 CTS mode with 96-bit SHA-1 HMAC)
   2 08/23/12 10:10:07 host/lux.
test.internal@TEST.INTERNAL (DES cbc mode with CRC-32)
   2 08/23/12 10:10:07 host/lux.
test.internal@TEST.INTERNAL (DES cbc mode with RSA-MD5)
   2 08/23/12 10:10:07 host/lux.
test.internal@TEST.INTERNAL (ArcFour with HMAC/md5)
   2 08/23/12 10:10:07 host/lux.
test.internal@TEST.INTERNAL (AES-128 CTS mode with 96-bit SHA-1 HMAC)
   2 08/23/12 10:10:07 host/lux.
test.internal@TEST.INTERNAL (AES-256 CTS mode with 96-bit SHA-1 HMAC)
   2 08/23/12 10:10:07 host/lux@TEST.INTERNAL (DES cbc mode with CRC-32)
   2 08/23/12 10:10:07 host/lux@TEST.INTERNAL (DES cbc mode with RSA-MD5)
   2 08/23/12 10:10:07 host/lux@TEST.INTERNAL (ArcFour with HMAC/md5)
   2 08/23/12 10:10:07 host/lux@TEST.INTERNAL (AES-128 CTS mode with 96-bit SHA-1 HMAC)
   2 08/23/12 10:10:07 host/lux@TEST.INTERNAL (AES-256 CTS mode with 96-bit SHA-1 HMAC)


STEP SIXTEEN:  Start the k5start_ldap service:

# service k5start_ldap start
Starting k5start_ldap:                                     [  OK  ]

Verify that the k5start_ldap service is running:

# service k5start_ldap status
k5start (pid  2954) is running...

And verify how the k5start_ldap service is running:

# ps -ef | grep k5start
root     28573     1  0 09:36 ?        00:00:00 /usr/bin/k5start -f /etc/krb5.keytab -bLtK30 \
-p /var/run/k5start_ldap.pid -k /etc/.ldapcache -u lux$

STEP SEVENTEEN:  Configure the k5start_ldap service to run at boot and verify.

# chkconfig k5start_ldap on
# chkconfig k5start_ldap --list
k5start_ldap    0:off   1:off   2:on    3:on    4:on    5:on    6:off

STEP EIGHTEEN:  List the Kerberos keys for the server in /etc/.ldapcache:

# /usr/kerberos/bin/klist -e /etc/.ldapcache
Ticket cache: FILE:/etc/.ldapcache
Default principal: lux$@TEST.INTERNAL

Valid starting     Expires            Service principal
06/26/12 09:36:56  06/26/12 19:36:56  krbtgt/TEST.INTERNAL@TEST.INTERNAL
        renew until 07/03/12 09:36:56, Etype (skey, tkt): ArcFour with HMAC/md5, ArcFour with HMAC/md5
06/26/12 09:36:56  06/26/12 19:36:56  ldap/dc01.test.internal@TEST.INTERNAL
        renew until 07/03/12 09:36:56, Etype (skey, tkt): AES-256 CTS mode with 96-bit SHA-1 HMAC, AES-256 CTS mode with 96-bit SHA-1 HMAC

STEP NINETEEN:  Login as a Active Directory user who has been properly configured with RFC2703 Schema Attributes (gecos, loginShell, unixHomeDirectory, uid, uidNumber, and gidNumber) and list the Kerberos key:

$ klist
Ticket cache: FILE:/tmp/krb5cc_77123456_WQP8p4
Default principal: e123456@TEST.INTERNAL

Valid starting     Expires            Service principal
06/26/12 10:06:53  06/26/12 20:06:53  krbtgt/TEST.INTERNAL@TEST.INTERNAL
        renew until 07/03/12 10:06:53

Kerberos 4 ticket cache: /tmp/tkt77123456
klist: You have no tickets cached

STEP TWENTY:  Verify that you can view your LDAP information:

$ getent passwd e123456
e123456:*:77123456:77001:TEST.INTERNAL JOE USER E123456:/home/e123456:/bin/bash

STEP TWENTY-ONE:  Verify that you can search LDAP from the RHEL server

$ ldapsearch -b cn="Joe User",ou=users,dc=test,dc=internal
SASL/GSSAPI authentication started
SASL username: e123456@TEST.INTERNAL
SASL SSF: 56
SASL installing layers
# extended LDIF
#
# LDAPv3
# base <cn=Joe User,ou=users,dc=test,dc=internal> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# Joe User, USERS, test.internal
dn: CN=Joe User,OU=USERS,DC=test,DC=internal
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: Joe User
sn: User
description: E123456 (TEST USER)
givenName: Joe
distinguishedName: CN=Joe User,OU=USERS,DC=test,DC=internal
instanceType: 4
whenCreated: <REDACTED>
whenChanged: <REDACTED>
displayName: Joe User
uSNCreated: <REDACTED>
memberOf: CN=UNIXGRP,OU=GROUPS,DC=test,DC=internal
memberOf: CN=Domain Users,CN=Users,DC=test,DC=internal

uSNChanged: <REDACTED>
name: Joe User
objectGUID:: <REDACTED>
userAccountControl: 512
badPwdCount: 0
codePage: 0
countryCode: 0
employeeID: E123456
badPasswordTime: <REDACTED>
lastLogoff: 0
lastLogon: <REDACTED>
pwdLastSet: <REDACTED>
primaryGroupID: 1170
objectSid:: <REDACTED>
adminCount: 0
accountExpires: <REDACTED>
logonCount: 348
sAMAccountName: e123456
sAMAccountType: 805306368
userPrincipalName: e123456@test.internal
lockoutTime: 0
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=test,DC=internal
dSCorePropagationData: 20120307133803.0Z
dSCorePropagationData: 20120307133645.0Z
dSCorePropagationData: 20120302193220.0Z
dSCorePropagationData: 20120224192124.0Z
dSCorePropagationData: 16010101000000.0Z
lastLogonTimestamp: <REDACTED>
uid: e123456
mail: joe.user@test.internal
uidNumber: 77123456
gidNumber: 77001
gecos: TEST.INTERNAL JOE USER E123456
unixHomeDirectory: /home/e123456
loginShell: /bin/bash

# search result
search: 5
result: 0 Success

# numResponses: 2
# numEntries: 1

STEP TWENTY-TWO:  As root, update the /etc/ssh/ssh_config file to ensure that forwarded SSH sessions delegate Kerberos authentication based on your existing Kerberos tickets.  Please include and\or uncomment this entry:  

Host *
    GSSAPIAuthentication yes
    GSSAPIDelegateCredentials yes
    Port 22
    Protocol 2

STEP TWENTY-THREE:  As root, update the /etc/ssh/sshd_config file to match to following:

Port 22
#Protocol 2,1
Protocol 2
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::

# HostKey for protocol version 1
#HostKey /etc/ssh/ssh_host_key
# HostKeys for protocol version 2
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_dsa_key

# Lifetime and size of ephemeral version 1 server key
#KeyRegenerationInterval 1h
#ServerKeyBits 768

# Logging
# obsoletes QuietMode and FascistLogging
#SyslogFacility AUTH
SyslogFacility AUTHPRIV
#LogLevel INFO

# Authentication:

#LoginGraceTime 2m
#PermitRootLogin yes
PermitRootLogin no
#StrictModes yes
#MaxAuthTries 6

#RSAAuthentication yes
#PubkeyAuthentication yes
#AuthorizedKeysFile    .ssh/authorized_keys

# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
RhostsRSAAuthentication no
# similar for protocol version 2
HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# RhostsRSAAuthentication and HostbasedAuthentication
IgnoreUserKnownHosts yes
# Don't read the user's ~/.rhosts and ~/.shosts files
IgnoreRhosts yes

# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
PasswordAuthentication yes

# Change to no to disable s/key passwords
#ChallengeResponseAuthentication yes
ChallengeResponseAuthentication no

# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no

# GSSAPI options
#GSSAPIAuthentication no
GSSAPIAuthentication yes
#GSSAPICleanupCredentials yes
GSSAPICleanupCredentials yes

# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication mechanism.
# Depending on your PAM configuration, this may bypass the setting of
# PasswordAuthentication, PermitEmptyPasswords, and
# "PermitRootLogin without-password". If you just want the PAM account and
# session checks to run without PAM authentication, then enable this but set
# ChallengeResponseAuthentication=no
#UsePAM no
UsePAM yes

# Accept locale-related environment variables
AcceptEnv LANG LANGUAGE LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL
#AllowTcpForwarding yes
#GatewayPorts no
#X11Forwarding no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
PrintMotd no
PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
#UsePrivilegeSeparation yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#ShowPatchLevel no
#UseDNS yes
PidFile /var/run/sshd.pid
#MaxStartups 10
#PermitTunnel no
#ChrootDirectory none

# no default banner path
#Banner /some/path
Banner /etc/ssh/LOGIN_BANNER

# override default of no subsystems
Subsystem    sftp    /usr/libexec/openssh/sftp-server

STEP TWENTY-FOUR:  Restart the sshd service:

NOTE:  Ensure that you have opened another ssh session as root or as an account that has the ability to “su -“ or “sudo su -“ to root before restarting the service.  SSH root logins will not be possible once the service has been restarted due to the “PermitRootLogin no” directive in the /etc/ssh/sshd_config file.

# service sshd restart
Stopping sshd:                                             [  OK  ]
Starting sshd:                                             [  OK  ]

STEP TWENTY-FIVE:  Create an SSH Login Banner if one does not exist:

# touch /etc/ssh/LOGIN_BANNER

Edit the /etc/ssh/LOGIN_BANNER to include an appropriate representation of your security disclosure notification.  Please confirm with your internal legal group if in doubt.

NOTE:  If an SSH Banner is not desired but a legal notification must be displayed, the following steps can be used to augment steps 20 and 21 to use the /etc/motd file:

STEP TWENTY-SIX:  Make a back-up of the existing /etc/motd file:

# cp /etc/motd /etc/motd.original

STEP TWENTY-SEVEN:  Edit the /etc/ssh/sshd_config file to use the /etc/motd file instead of the file referenced by the Banner setting.

Change “PrintMotd no” to “PrintMotd yes

Change “Banner/etc/ssh/LOGIN_BANNER” to “#Banner /etc/ssh/LOGIN_BANNER

Save and exit.

STEP TWENTY-EIGHT:  Copy the contents of the /etc/ssh/LOGIN_BANNER to /etc/motd.

STEP TWENTY-NINE:  Restart the sshd service.

# service sshd restart
Stopping sshd:                                             [  OK  ]
Starting sshd:                                             [  OK  ]

NOTE:  If a user wishes to not be presented with the login banner as login, instruct the user to run this command:

$ touch ~/.hushlogin

STEP THIRTY:  The krb5-ticket-renew.sh script is configured to run hourly and check against any existing users’ Kerberos ticket currently in /tmp.  It can be configured to log-out users with expired Kerberos tickets if required.  This can be enabled in the either /etc/krb5-ticket-renew.conf file (preferred) or from the /etc/cron.hourly/krb5-ticket-renew.sh script directly.

By default, the script checks the user Kerberos tickets and renews them automatically for five (5) days.

By default, past five (5) days, the user will be prompted to re-enter their password so long as this line is added to the user’ ~/.bash_profile:

# Ask k5start to check for a happy (-H) Kerberos ticket
export PROMPT_COMMAND="k5start -H 360"

This line uses k5start to check for a “happy” Kerberos ticket that is not within six (6) hours of expiring.

If that line is not added, users will only receive a Kerberos error but no prompt to provide their password.  Users will, therefore, need to know to run a kinit command on their own to be prompted.

By default, the script will remove any expired Kerberos ticket from /tmp.

This completes the RHEL 5 Kerberos and LDAP configuration process.

:: SECTION FOUR:  TROUBLESHOOTING... :::

 

...RESTORING KERBERIZED LDAP SERVICE AFTER AN IP ADDRESS CHANGE


To restore service after an IP address has changed, two things must occur.

STEP ONE:  The IP address of the server must be updated in Active Directory DNS.  Verify that the “Update associated pointer (PTR) record” checkbox is set.

STEP TWO:  On the Linux server, confirm that the host command returns the proper DNS information:

# host lux
lux.test.internal has address 10.0.0.60

# host 10.0.0.60
60.0.0.10.in-addr.arpa domain name pointer lux.test.internal.

STEP THREE:  On the Linux server, run the following command to reload the k5start_ldap service:

# service k5start_ldap reload
Refreshing k5start_ldap ticket cache:                      [  OK  ]

4.    Verify that the getent passwd command returns proper LDAP user information:

# getent passwd e123456
e123456:*:77123456:77001:TEST.INTERNAL JOE USER E123456:/home/e123456:/bin/bash 

THANKS TO...


...the following for their skill, documentation, and willingness to share their knowledge:

Mark. R. Bannister and his Technical Prose blog and for his yp2ldap project.

dipeit@gmail.com and the scripts, packages, and documentation he added to dipe's Home Project for openSUSE.