Linux System Administration |
Home | Tech | Linux | Links | Consulting |
|
OpenLDAP provider with MIT Kerberos V on Debian lenny
This page describes how to set up an OpenLDAP provider server with MIT Kerberos V support for authentication and encryption. It depends on a previously installed MIT Kerberos V master server, kdc1.example.com. Another Kerberos server, kdc2.example.com, a slave KDC, is also mentioned in the configuration, but does not have to be available for this procedure. It is assumed that the reader is familiar with the concepts involved in the installation and configuration of an OpenLDAP provider. However, as opposed to that configuration, this OpenLDAP server will only store Unix user account information for authorization; the task of authentication will be performed by Kerberos, with all username and password combinations being stored in the Kerberos database. In this example, OpenLDAP is installed on a host running Debian 5.0 (lenny). If followed properly, the step-by-step process should produce a provider server with a new DIT. But, before the interesting parts can begin, it will first be necessary to install the operating system on a new host called ldapks1.example.com. A DNS server must also be available on the network with a zone file to which forward and reverse mappings can be added for this host, as well as an alias for it called ldapks.example.com. After the initial installation of the operating system, make sure these packages are installed on the system as well: ~# apt-get install ntp ntpdate nmap Afterwards, edit /etc/ntp.conf so that the machine synchronizes to a common NTP server (preferably a local one) and edit /etc/default/ntpdate to use the same host also. Now the installation of the new server can begin. 1. Kerberos client First, run the following command to test if the MIT Kerberos V server installed previously is available on the network: ~# nmap kdc1.example.com This should be among the results: PORT STATE SERVICE 749/tcp open kerberos-adm 754/tcp open krb_prop If there is a problem, fix it first. If not, continue by installing these three packages: ~# apt-get install krb5-{config,user} libpam-krb5 A total of four packages are installed as a result, including one dependency: krb5-config 1.22 Configuration files for Kerberos Version 5 krb5-user 1.6.dfsg.4~beta1-5lenny2 Basic programs to authenticate using MIT Kerberos libkadm55 1.6.dfsg.4~beta1-5lenny2 MIT Kerberos administration runtime libraries libpam-krb5 3.11-4 PAM module for MIT Kerberos During the installation, the krb5-config package will automatically have the default realm set to EXAMPLE.COM, but a few questions have to be answered for it as well: Kerberos servers for your realm: kdc1.example.com kdc2.example.com Administrative server for your Kerberos realm: krb.example.com These settings, along with the default realm, are saved in /etc/krb5.conf. 2. Realm config file Edit the Kerberos realm configuration file, /etc/krb5.conf. This file is initially created by the Debian installer and contains information about the realms of a number of famous institutions, but none of that is necessary in this case. Instead, replace its contents with this: [libdefaults] default_realm = EXAMPLE.COM forwardable = true proxiable = true [realms] EXAMPLE.COM = { kdc = kdc1.example.com kdc = kdc2.example.com admin_server = krb.example.com } [domain_realm] .example.com = EXAMPLE.COM example.com = EXAMPLE.COM See this section for a more detailed explanation of this file. Regarding the list of KDCs that are specified here, it is often recommended to use a predetermined set of DNS hostname aliases (CNAME records) to refer to the Kerberos servers on a network. However, it is also possible to omit the mention of any KDCs here and instead rely on the relatively new SRV DNS resource record type. See the article DNS discovery for MIT Kerberos V for information on how to do that. 3. Service princ & keytab Use kadmin to create a Kerberos principal for the LDAP service and a matching keytab file by issuing a few commands: ~# kadmin -p admin Authenticating as principal admin with password. Password for admin@EXAMPLE.COM: Lampropeltis kadmin: addprinc -randkey ldap/ldapks1.example.com WARNING: no policy specified for ldap/ldapks1.example.com@EXAMPLE.COM; defaulting to no policy Principal "ldap/ldapks1.example.com@EXAMPLE.COM" created. kadmin: ktadd ldap/ldapks1.example.com Entry for principal ldap/ldapks1.example.com with kvno 3, encryption type AES-256 CTS mode with 96-bit SHA-1 HMAC added to keytab WRFILE:/etc/krb5.keytab. Entry for principal ldap/ldapks1.example.com with kvno 3, encryption type ArcFour with HMAC/md5 added to keytab WRFILE:/etc/krb5.keytab. Entry for principal ldap/ldapks1.example.com with kvno 3, encryption type Triple DES cbc mode with HMAC/sha1 added to keytab WRFILE:/etc/krb5.keytab. Entry for principal ldap/ldapks1.example.com with kvno 3, encryption type DES cbc mode with CRC-32 added to keytab WRFILE:/etc/krb5.keytab. kadmin: q ~# _ The -randkey switch is used because a machine cannot enter a password. To list the keys in /etc/krb5.keytab, use the klist -ke command. A host (or service) principal and a keytab file should be created for and saved on all of the various client machines that are part of a Kerberos realm. 4. OpenLDAP install On the new host, ldaps1.example.com, start by installing these two packages: ~# apt-get install slapd ldap-utils A total of ten packages are installed as a result, including eight dependencies: ldap-utils 2.4.11-1+lenny1 OpenLDAP utilities libdb4.2 4.2.52+dfsg-5 Berkeley v4.2 Database Libraries [runtime] libltdl3 1.5.26-4+lenny1 A system independent dlopen wrapper for GNU libtool libperl5.10 5.10.0-19lenny2 Shared Perl library libsasl2-modules 2.1.22.dfsg1-23+lenny1 Cyrus SASL - pluggable authentication modules libslp1 1.2.1-7.5 OpenSLP libraries odbcinst1debian1 2.2.11-16 Support library and helper program for accessing odbc ini file psmisc 22.6-1 Utilities that use the proc filesystem slapd 2.4.11-1+lenny1 OpenLDAP server (slapd) unixodbc 2.2.11-16 ODBC tools libraries During the install process, an administrator password will be requested for slapd. Use piscivorus: Administrator password: piscivorus Confirm password: piscivorus Run the following command to test if the OpenLDAP server is actually running: ~# nmap ldapks1.example.com This should be among the results: PORT STATE SERVICE 389/tcp open ldap Perform a quick test by generating an LDIF dump of the contents of a the database: ~# slapcat dn: dc=example,dc=com objectClass: top objectClass: dcObject objectClass: organization o: example.com dc: example structuralObjectClass: organization entryUUID: 6d22e2e8-6e30-102e-9761-05effbdceeba creatorsName: createTimestamp: 20091125170507Z entryCSN: 20091125170507.217451Z#000000#000#000000 modifiersName: modifyTimestamp: 20091125170507Z dn: cn=admin,dc=example,dc=com objectClass: simpleSecurityObject objectClass: organizationalRole cn: admin description: LDAP administrator userPassword:: e2NyeXB0fU1TVXFoNlFiZlp0MXM= structuralObjectClass: organizationalRole entryUUID: 6d237c58-6e30-102e-9762-05effbdceeba creatorsName: createTimestamp: 20091125170507Z entryCSN: 20091125170507.221751Z#000000#000#000000 modifiersName: modifyTimestamp: 20091125170507Z ~# _ 5. admin → rootdn During the initial setup, an account was created that will soon be be more of a security risk. Since the object here is to create a more secure sevice by storing all credentials in the Kerberos database exclusively, it would be considered a security weakness if it were left in the LDAP database. Therefore, in this step it will be deleted after hard-coding a new name and password for administrative access. To do this it will be necessary to edit /etc/ldap/slapd.conf, but the opportunity will also be taken to make a few other changes to this file. Starting at the top, comment out the logging option, which will return it to its default value (256): #loglevel "none" Next, the important part, insert these rootdn and rootpw directives: # rootdn "cn=admin,dc=example,dc=com" rootdn cn=admin,dc=example,dc=com rootpw piscivorus Then modify the ACLs to look like this: access to attrs=userPassword,shadowLastChange by * none access to attrs=loginShell by self write by users read by * none access to dn.base="" by * read access to * by users read by * none Respectively, this is 1.) to prevent any access to password information, 2.) to allow everyone to change their own shell settings, which are included in the LDAP schema for posixAccount, and 3.) to ensure read access to the base of the tree for things like supportedSASLMechanisms, 4.) otherwise to only allow authenticated users to have read access to everything else in the LDAP database. Having committed the above changes, restart the LDAP service: ~# /etc/init.d/slapd restart Stopping OpenLDAP: slapd. Starting OpenLDAP: slapd. ~# _ At this point it is safe to delete the admin account from the directory: ~# ldapdelete -x -h localhost -D cn=admin,dc=example,dc=com \ -w piscivorus cn=admin,dc=example,dc=com ~# _ Perform a quick test by generating an LDIF dump of the contents of a the database: ~# slapcat dn: dc=example,dc=com objectClass: top objectClass: dcObject objectClass: organization o: example.com dc: example structuralObjectClass: organization entryUUID: 2244f4f4-83f3-102e-9a45-0554836ee547 creatorsName: createTimestamp: 20091223094147Z entryCSN: 20091223094147.892297Z#000000#000#000000 modifiersName: modifyTimestamp: 20091223094147Z ~# _ The results should look like the above, showing that only the entry for the organization object, dc=example,dc=com, is left. 6. ldap.conf Edit /etc/ldap/ldap.conf and use these two lines: BASE dc=example,dc=com URI ldap://ldapks1.example.com/ This configuration file is used to set system-wide defaults for LDAP clients. 7. Basic tree Create a basic tree structure. First create a file, ~/tree.ldif, with the following content: dn: ou=people,dc=example,dc=com objectClass: organizationalUnit ou: people dn: ou=groups,dc=example,dc=com objectClass: organizationalUnit ou: groups Add this information to the LDAP database using the ldapadd command: ~# ldapadd -xWD cn=admin,dc=example,dc=com -f ~/tree.ldif Enter LDAP Password: piscivorus adding new entry "ou=people,dc=example,dc=com" adding new entry "ou=groups,dc=example,dc=com" ~# _ A quick ldapsearch should show the new objects: ~# ldapsearch -xLLL dn: dc=example,dc=com objectClass: top objectClass: dcObject objectClass: organization o: example.com dc: example dn: ou=people,dc=example,dc=com objectClass: organizationalUnit ou: people dn: ou=groups,dc=example,dc=com objectClass: organizationalUnit ou: groups ~# 8. Slapd kerberization To kerberize slapd, start by installing this package: ~# apt-get install libsasl2-modules-gssapi-mit Only one package is installed as a result: libsasl2-modules-gssapi-mit 2.1.22.dfsg1-23+lenny1 Cyrus SASL - pluggable authentication modules (GSSAPI) GSSAPI stands for Generic Security Service API. Defined in RFC-2743, it provides a common interface for accessing different security services, one of the most popular of which is Kerberos V. The way that GSSAPI services can be used for SASL authentication and the establishment of a security layer is described in RFC-2222 (Simple Authentication and Security Layer). Change the permissions and ownership of the Kerberos keytab file to make sure that slapd can access it: ~# chmod 640 /etc/krb5.keytab ~# chown root.openldap /etc/krb5.keytab ~# _ Edit /etc/default/slapd and uncomment a line near the end of the file that will export the location of the Kerberos system keytab file as a variable: export KRB5_KTNAME=/etc/krb5.keytab Edit /etc/ldap/ldap.conf and add the following line to the end of the file to specify the authentication mechanism: SASL_MECH GSSAPI Now to configure the link that maps GSSAPI-format user names to LDAP names. Once users have been authenticated by Kerberos and have valid Kerberos tickets, the SASL layer redirects them to the GSSAPI mechanism. This results in distinguished names that consist of four parts:
For instance, the Kerberos admin account becomes uid=admin,cn=example.com,cn=gssapi,cn=auth. The key is to match these GSSAPI-format names to ones that can be used together with the LDAP DIT. This is done by adding the authz-regexp directive to /etc/ldap/slapd.conf, which includes a regular expression. Modify this file by adding the following stanza to the end of the Global section: tool-threads 1 authz-regexp uid=([^,]+),cn=example.com,cn=gssapi,cn=auth uid=$1,ou=people,dc=example,dc=com The authz-regexp directive shown here is followed by two options: a search pattern that matches all of the GSSAPI-format user names from Kerberos, and a replacement pattern that changes them to names found in the ou=people,dc=example,dc=com organizational unit. This is an example of a direct mapping and is the generally recommended approach, since it not only avoids the expense of searching for user DNs, but also allows mapping to DNs that refer to entries not found on the same server (or even in the entire DIT, such as with the admin user, which is only significant because of the rootdn directive on the provider server). The drawback of direct mapping is that it only maps users to a single organizational unit. If it becomes necessary or desirable to organize users into more than one organizational unit, then solutions are possible using multiple authz-regexp statements with direct mappings and/or search-based mappings with LDAP URLs. As an example of the latter, consider the following authz-regexp statement: authz-regexp uid=([^,]+),cn=example.com,cn=gssapi,cn=auth ldap:///dc=example,dc=com??sub?php (& (| (entryDN:dnSubtreeMatch:=ou=people,dc=example,dc=com) (entryDN:dnSubtreeMatch:=ou=robots,dc=example,dc=com) ) (& (uid=$1) (objectclass=person) ) ) LDAP search URLs must always be written on a single line and without any of the extra spacing, unlike the format shown here for the sake of clarity. In this example, the search pattern matches all GSSAPI-format names as before, but the replacement pattern searches two organizational units, people and robots, for matching LDAP user names. The disadvantages of this solution are that it is slower than direct mapping, and that GSSAPI names are not mapped if no matching LDAP counterparts are found for them. The admin entry, for instance, would not be found. A solution to the latter problem would be to either move the admin entry to ou=people, or to add an extra authz-regexp statement to specifically match the current DN of the admin entry: authz-regexp uid=admin,cn=example.com,cn=gssapi,cn=auth uid=admin,dc=example,dc=com Anyway, still editing /etc/ldap/slapd.conf, add this directive, which specifies the Kerberos realm, to the end of the Global section, just below the new authz-regexp statement: authz-regexp uid=([^,]+),cn=example.com,cn=gssapi,cn=auth uid=$1,ou=people,dc=example,dc=com sasl-realm EXAMPLE.COM This is important, because without it the authz-regexp mechanism will not work. The last change to /etc/ldap/slapd.conf is due to the implementation of the authz-regexp statement. It is now necessary to modify the rootdn and desirable to comment out the rootpw: rootdn uid=admin,ou=people,dc=example,dc=com #rootpw piscivorus Note that this moves the admin user to ou=people! If this is neglected, the previously described problem will occur and the LDAP admin account will no longer be resolved. Regarding the rootpw, from this point on the LDAP administrator's password will be the one used for the Kerberos admin account: Lampropeltis. Having saved the above changes, restart the LDAP service: ~# /etc/init.d/slapd restart Stopping OpenLDAP: slapd. Starting OpenLDAP: slapd. ~# _ 9. Testing Run some tests. First try a simple unauthenticated (-x) LDAP query: ~# ldapsearch -xLLL No such object (32) ~# _ Since the last ACL applied in step 5 grants "access to * by * none," this should result in no objects being found. However, the authenticated version of this query, which is its default operational mode, will give an error: ~# ldapsearch -LLL SASL/GSSAPI authentication started ldap_sasl_interactive_bind_s: Local error (-2) ~# _ The solution is to first acquire a Kerberos ticket for the admin user (password Lampropeltis): ~# kinit admin Password for admin@EXAMPLE.COM: Lampropeltis ~# _ A verification of the ticket should show a success: ~# klist -5 Ticket cache: FILE:/tmp/krb5cc_0 Default principal: admin@EXAMPLE.COM Valid starting Expires Service principal 12/23/09 19:38:48 12/24/09 19:38:45 krbtgt/EXAMPLE.COM@EXAMPLE.COM ~# _ Now the previously attempted authenticated query should work: ~# ldapsearch -LLL SASL/GSSAPI authentication started SASL username: admin@EXAMPLE.COM SASL SSF: 56 SASL data security layer installed. dn: dc=example,dc=com objectClass: top objectClass: dcObject objectClass: organization o: example.com dc: example dn: ou=people,dc=example,dc=com objectClass: organizationalUnit ou: people dn: ou=groups,dc=example,dc=com objectClass: organizationalUnit ou: groups ~# _ Also, under these circumstances the ldapwhoami command behaves more like whoami: ~# whoami root ~# ldapwhoami SASL/GSSAPI authentication started SASL username: admin@EXAMPLE.COM SASL SSF: 56 SASL data security layer installed. dn:uid=admin,ou=people,dc=example,dc=com ~# _ Make no mistake: except when anonymous access is requested (and granted), authentication is necessary for every individual LDAP command. However, in this case Kerberos takes care of authentication in the background, significantly increasing ease of use. Single sign-on in action! 10. See also
11. Further reading
12. Sources
Last modified: 2017-08-02, 17:50
©2003-2020 RJ Systems. Permission is granted to copy, distribute and/or modify the content of this page under the terms of the OpenContent License, version 1.0. |