Throughout this HOWTO we use an example.com organization. This must be substituted for an appropriate value.
First of all we must edit the file /etc/openldap/slapd.conf, so we make the initial configuration of our LDAP server and create our database.
The modifications we have made to the default configuration include the following: inclusion of several schemes to be used by the server, some basic security restrictions, location of certificates to enable SSL encrypted connections, and definition of our database:
# $OpenLDAP: pkg/ldap/servers/slapd/slapd.conf,v 1.23.2.8 2003/05/24 23:19:14 kurt Exp $
#
# See slapd.conf(5) for details on configuration options.
# This file should NOT be world readable.
#
include /etc/openldap/schema/core.schema
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/inetorgperson.schema
include /etc/openldap/schema/java.schema
include /etc/openldap/schema/krb5-kdc.schema
include /etc/openldap/schema/nis.schema
# Define global ACLs to disable default read access.
# Do not enable referrals until AFTER you have a working directory
# service AND an understanding of referrals.
#referral ldap://root.openldap.org
pidfile /var/run/openldap/slapd.pid
argsfile /var/run/openldap/slapd.args
# Load dynamic backend modules:
# modulepath /usr/lib/openldap/openldap
# moduleload back_bdb.la
# moduleload back_ldap.la
# moduleload back_ldbm.la
# moduleload back_passwd.la
# moduleload back_shell.la
# Sample security restrictions
# Require integrity protection (prevent hijacking)
# Require 112-bit (3DES or better) encryption for updates
# Require 63-bit encryption for simple bind
# security ssf=1 update_ssf=112 simple_bind=64
security simple_bind=64
# Sample access control policy:
# Root DSE: allow anyone to read it
# Subschema (sub)entry DSE: allow anyone to read it
# Other DSEs:
# Allow self write access
# Allow authenticated users read access
# Allow anonymous users to authenticate
# Directives needed to implement policy:
# access to dn.base="" by * read
# access to dn.base="cn=Subschema" by * read
# access to *
# by self write
# by users read
# by anonymous auth
#
# if no access controls are present, the default policy is:
# Allow read by all
#
# rootdn can always write!
access to dn.base="" by * read
access to dn.base="cn=Subschema" by * read
access to *
by self write
by users read
by anonymous auth
by * none
# SSL/TLS configuration
TLSCACertificatePath /etc/ssl/certs
TLSCertificateFile /etc/openldap/ssl/ldap.example.com.pem
TLSCertificateKeyFile /etc/openldap/ssl/ldap.example.com.key
# Misc options
# Maximum number of entries to return from a search operation. Useful
# to prevent trolling of directory by spammers, etc.
sizelimit 20
# Maximum size of the primary thread pool.
threads 8
# Allows acceptance of LDAPv2 bind requests (required for mozilla)
allow bind_v2
#######################################################################
# ldbm database definitions
#######################################################################
include /etc/openldap/example.confSuitable certificates must have been created and placed in the given directory.
Next we edit the file /etc/openldap/example.conf, containing the definition of our database:
#
# Example Corporation database configuration
#
database bdb
suffix "dc=example,dc=com"
rootdn "cn=manager,dc=example,dc=com"
# Cleartext passwords, especially for the rootdn, should
# be avoid. See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
rootpw {MD5}gRUck5diiA7A3fCFN0+mDg==
# The database directory MUST exist prior to running slapd AND
# should only be accessible by the slapd/tools. Mode 700 recommended.
directory /var/lib/openldap-example
# Indexes to maintain
index default eq,pres
index objectClass eq
index cn,sn,givenname,mail eq,pres,sub
index uid,uidNumber,gidNumber
#index memberUid,uniqueMember -- This version of OpenLDAP does not support indexing of uniqueMember
index memberUid
index krb5PrincipalName,krb5PrincipalRealm
# SASL configuration
sasl_host ldap.example.local
sasl_realm EXAMPLE.COM
# Clear text password, as we will be using {SASL}principal@REALM
password-hash {CLEARTEXT}
# ACLs
#include /etc/openldap/example.access.confMake sure you use the canonical name of the machine in sasl-host. Otherwise OpenLDAP won't be able to offer GSSAPI authentication.
You may obtain a password as the one shown in rootpw using the command slappasswd -h {MD5}. Output from that command must be copied and pasted without modification in the configuration file. We will use this administration user and password only until we have done the initial data loading so we can authenticate using Kerberos.
It is very important to define correct indexes so we get a decent performance in the database lookups. You may notice you have lacking indexes whenever you get a line like the following in your logs:
Aug 17 11:10:00 server slapd[7346]: <= bdb_equality_candidates: (memberUid) index_param failed (18)
In this case we had a lacking equality index for the memberUid attribute.
At the end of the configuration file we include an additional file containing the access configuration for our database. Right now we will use the default configuration. Proper ACLs will be shown after.
The directory containing our database must exist and must be accessible only to the LDAP user and group:
server root # mkdir /var/lib/openldap-example server root # chown ldap:ldap /var/lib/openldap-example server root # chmod 700 /var/lib/openldap-example
No extra steps are needed: once we start the slapd server the database will be automatically created.
Configuration of services to be started is made editing the file /etc/conf.d/slapd. Here we will activate the following services: ldap, ldaps, and ldap using unix socket:
# conf.d file for the openldap-2.1 series # # To enable both the standard unciphered server and the ssl encrypted # one uncomment this line or set any other server starting options # you may desire. # OPTS="-h 'ldap:// ldaps:// ldapi://'"
The default configuration provided by Gentoo places the LDAP unix socket in /var/run/openldap/slapd.sock. However, Heimdal expects to find this socket in its default location (/var/lib/ldapi) and this location is hard wired. That's why we must change this to the default location, deleting the location provided in the default configuration file.
In order to create our database we must start the LDAP server. We also add it to the services run on boot up:
server root # /etc/init.d/slapd start server root # rc-update add slapd default
All the mentioned configuration files must be accessible to the LDAP user. Otherwise we'll have problems starting the service.
Before accessing the LDAP directory we must check the configuration included in /etc/openldap/ldap.conf so they point to the server we are installing. This way we won't be forced to include this information in every invocation of the LDAP tools. It should contain something like this:
BASE dc=example,dc=com URI ldap://ldap.example.com TLS_CACERTDIR /etc/ssl/certs
We first create our basic structure. We will have a root for our directory, and then several branches containing groups, system accounts and people. In order to create this basic structure we first edit a file structure.ldif containing the following:
# Organization dn: dc=example,dc=com objectClass: dcObject objectClass: organization dc: example description: The example corporation o: Example Corporation Inc. # Kerberos only principals (admin accounts, hosts,...) dn: ou=kerberos,dc=example,dc=com objectClass: organizationalUnit objectClass: top ou: kerberos description: Kerberos only principals # Groups dn: ou=group,dc=example,dc=com objectClass: organizationalUnit objectClass: top ou: group description: Groups in example # System related accounts dn: ou=system,dc=example,dc=com objectClass: organizationalUnit objectClass: top ou: system description: System accounts # People dn: ou=people,dc=example,dc=com objectClass: organizationalUnit objectClass: top ou: people description: People in example
Now we import this into LDAP:
server root # ldapadd -x -D "cn=manager,dc=example,dc=com" -W -f structure.ldifNext we will be creating (importing) the groups we have in our /etc/group file. We must create a file containing the following entries, one per group, named group.ldif:
dn: cn=root,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: root gidNumber: 0 dn: cn=bin,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: bin gidNumber: 1 memberUid: daemon memberUid: root dn: cn=daemon,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: daemon gidNumber: 2 memberUid: bin memberUid: root dn: cn=sys,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: sys gidNumber: 3 memberUid: adm memberUid: bin memberUid: root dn: cn=adm,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: adm gidNumber: 4 memberUid: daemon memberUid: root dn: cn=tty,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: tty gidNumber: 5 dn: cn=disk,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: disk gidNumber: 6 memberUid: adm memberUid: root dn: cn=lp,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: lp gidNumber: 7 dn: cn=mem,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: mem gidNumber: 8 dn: cn=kmem,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: kmem gidNumber: 9 dn: cn=wheel,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: wheel gidNumber: 10 memberUid: root dn: cn=floppy,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: floppy gidNumber: 11 memberUid: root dn: cn=mail,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: mail gidNumber: 12 dn: cn=news,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: news gidNumber: 13 dn: cn=uucp,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: uucp gidNumber: 14 dn: cn=man,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: man gidNumber: 15 dn: cn=cron,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: cron gidNumber: 16 dn: cn=console,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: console gidNumber: 17 dn: cn=audio,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: audio gidNumber: 18 dn: cn=cdrom,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: cdrom gidNumber: 19 dn: cn=dialout,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: dialout gidNumber: 20 memberUid: root dn: cn=ftp,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: ftp gidNumber: 21 dn: cn=sshd,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: sshd gidNumber: 22 dn: cn=at,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: at gidNumber: 25 dn: cn=tape,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: tape gidNumber: 26 memberUid: root dn: cn=video,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: video gidNumber: 27 memberUid: root dn: cn=squid,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: squid gidNumber: 31 dn: cn=gdm,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: gdm gidNumber: 32 dn: cn=xfs,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: xfs gidNumber: 33 dn: cn=games,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: games gidNumber: 35 dn: cn=named,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: named gidNumber: 40 dn: cn=mysql,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: mysql gidNumber: 60 dn: cn=postgres,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: postgres gidNumber: 70 dn: cn=cdrw,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: cdrw gidNumber: 80 dn: cn=apache,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: apache gidNumber: 81 dn: cn=nut,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: nut gidNumber: 84 dn: cn=usb,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: usb gidNumber: 85 dn: cn=vpopmail,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: vpopmail gidNumber: 89 dn: cn=users,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: users gidNumber: 100 memberUid: games dn: cn=nofiles,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: nofiles gidNumber: 200 dn: cn=qmail,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: qmail gidNumber: 201 dn: cn=postfix,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: postfix gidNumber: 207 dn: cn=postdrop,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: postdrop gidNumber: 208 dn: cn=smmsp,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: smmsp gidNumber: 209 dn: cn=slocate,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: slocate gidNumber: 245 dn: cn=portage,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: portage gidNumber: 250 dn: cn=utmp,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: utmp gidNumber: 406 dn: cn=nogroup,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: nogroup gidNumber: 65533 dn: cn=nobody,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: nobody gidNumber: 65534 dn: cn=ldap,ou=group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: ldap gidNumber: 439
The file provided contains the groups found in a clean stage3 Gentoo installation with no additional software installed, adding the ldap group. Should your group file differ from the groups included here you must modify this file to reflect your installation.
Whenever you install any application using portage that creates a new group, you will have to manually add this group to the LDAP directory, as portage uses groupadd to add such a group, and this only adds the group to the /etc/group file.
Now we import this data into the LDAP directory:
server root # ldapadd -x -D "cn=manager,dc=example,dc=com" -W -f group.ldifI like to have system and people accounts in different places in the LDAP directory, so they don't mess around. This is completely optional, so you may have all the accounts under the people branch.
First of all, we create a file with our system accounts, name system.ldif:
dn: uid=bin,ou=system,dc=example,dc=com uid: bin cn: bin objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 1 gidNumber: 1 homeDirectory: /bin dn: uid=daemon,ou=system,dc=example,dc=com uid: daemon cn: daemon objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 2 gidNumber: 2 homeDirectory: /sbin dn: uid=adm,ou=system,dc=example,dc=com uid: adm cn: adm objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 3 gidNumber: 4 homeDirectory: /var/adm dn: uid=lp,ou=system,dc=example,dc=com uid: lp cn: lp objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 4 gidNumber: 7 homeDirectory: /var/spool/lpd dn: uid=sync,ou=system,dc=example,dc=com uid: sync cn: sync objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/sync uidNumber: 5 gidNumber: 0 homeDirectory: /sbin dn: uid=shutdown,ou=system,dc=example,dc=com uid: shutdown cn: shutdown objectClass: top objectClass: account objectClass: posixAccount loginShell: /sbin/shutdown uidNumber: 6 gidNumber: 0 homeDirectory: /sbin dn: uid=halt,ou=system,dc=example,dc=com uid: halt cn: halt objectClass: top objectClass: account objectClass: posixAccount loginShell: /sbin/halt uidNumber: 7 gidNumber: 0 homeDirectory: /sbin dn: uid=mail,ou=system,dc=example,dc=com uid: mail cn: mail objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 8 gidNumber: 12 homeDirectory: /var/spool/mail dn: uid=news,ou=system,dc=example,dc=com uid: news cn: news objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 9 gidNumber: 13 homeDirectory: /usr/lib/news dn: uid=uucp,ou=system,dc=example,dc=com uid: uucp cn: uucp objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 10 gidNumber: 14 homeDirectory: /var/spool/uucppublic dn: uid=operator,ou=system,dc=example,dc=com uid: operator cn: operator objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/bash uidNumber: 11 gidNumber: 0 homeDirectory: /root dn: uid=man,ou=system,dc=example,dc=com uid: man cn: man objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 13 gidNumber: 15 homeDirectory: /usr/man dn: uid=postmaster,ou=system,dc=example,dc=com uid: postmaster cn: postmaster objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 14 gidNumber: 12 homeDirectory: /var/spool/mail dn: uid=cron,ou=system,dc=example,dc=com uid: cron cn: cron objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 16 gidNumber: 16 homeDirectory: /var/spool/cron dn: uid=ftp,ou=system,dc=example,dc=com uid: ftp cn: ftp objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 21 gidNumber: 21 homeDirectory: /home/ftp dn: uid=sshd,ou=system,dc=example,dc=com uid: sshd cn: sshd objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 22 gidNumber: 22 homeDirectory: /dev/null dn: uid=at,ou=system,dc=example,dc=com uid: at cn: at objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 25 gidNumber: 25 homeDirectory: /var/spool/cron/atjobs dn: uid=squid,ou=system,dc=example,dc=com uid: squid cn: Squid objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 31 gidNumber: 31 homeDirectory: /var/cache/squid dn: uid=gdm,ou=system,dc=example,dc=com uid: gdm cn: GDM objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 32 gidNumber: 32 homeDirectory: /var/lib/gdm dn: uid=xfs,ou=system,dc=example,dc=com uid: xfs cn: X Font Server objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 33 gidNumber: 33 homeDirectory: /etc/X11/fs dn: uid=games,ou=system,dc=example,dc=com uid: games cn: games objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 35 gidNumber: 35 homeDirectory: /usr/games dn: uid=named,ou=system,dc=example,dc=com uid: named cn: bind objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 40 gidNumber: 40 homeDirectory: /var/bind dn: uid=mysql,ou=system,dc=example,dc=com uid: mysql cn: mysql objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 60 gidNumber: 60 homeDirectory: /var/lib/mysql dn: uid=postgres,ou=system,dc=example,dc=com uid: postgres cn: postgres objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/bash uidNumber: 70 gidNumber: 70 homeDirectory: /var/lib/postgresql dn: uid=apache,ou=system,dc=example,dc=com uid: apache cn: apache objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 81 gidNumber: 81 homeDirectory: /home/httpd dn: uid=nut,ou=system,dc=example,dc=com uid: nut cn: nut objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 84 gidNumber: 84 homeDirectory: /var/state/nut dn: uid=cyrus,ou=system,dc=example,dc=com uid: cyrus cn: cyrus objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 85 gidNumber: 12 homeDirectory: /usr/cyrus dn: uid=vpopmail,ou=system,dc=example,dc=com uid: vpopmail cn: vpopmail objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 89 gidNumber: 89 homeDirectory: /var/vpopmail dn: uid=alias,ou=system,dc=example,dc=com uid: alias cn: alias objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 200 gidNumber: 200 homeDirectory: /var/qmail/alias dn: uid=qmaild,ou=system,dc=example,dc=com uid: qmaild cn: qmaild objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 201 gidNumber: 200 homeDirectory: /var/qmail dn: uid=qmaill,ou=system,dc=example,dc=com uid: qmaill cn: qmaill objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 202 gidNumber: 200 homeDirectory: /var/qmail dn: uid=qmailp,ou=system,dc=example,dc=com uid: qmailp cn: qmailp objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 203 gidNumber: 200 homeDirectory: /var/qmail dn: uid=qmailq,ou=system,dc=example,dc=com uid: qmailq cn: qmailq objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 204 gidNumber: 201 homeDirectory: /var/qmail dn: uid=qmailr,ou=system,dc=example,dc=com uid: qmailr cn: qmailr objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 205 gidNumber: 201 homeDirectory: /var/qmail dn: uid=qmails,ou=system,dc=example,dc=com uid: qmails cn: qmails objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 206 gidNumber: 201 homeDirectory: /var/qmail dn: uid=postfix,ou=system,dc=example,dc=com uid: postfix cn: postfix objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 207 gidNumber: 207 homeDirectory: /var/spool/postfix dn: uid=smmsp,ou=system,dc=example,dc=com uid: smmsp cn: smmsp objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 209 gidNumber: 209 homeDirectory: /var/spool/mqueue dn: uid=portage,ou=system,dc=example,dc=com uid: portage cn: portage objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 250 gidNumber: 250 homeDirectory: /var/tmp/portage dn: uid=guest,ou=system,dc=example,dc=com uid: guest cn: guest objectClass: top objectClass: account objectClass: posixAccount loginShell: /dev/null uidNumber: 405 gidNumber: 100 homeDirectory: /dev/null dn: uid=nobody,ou=system,dc=example,dc=com uid: nobody cn: nobody objectClass: top objectClass: account objectClass: posixAccount loginShell: /bin/false uidNumber: 65534 gidNumber: 65534 homeDirectory: / dn: uid=ldap,ou=system,dc=example,dc=com uid: ldap cn: ldap objectClass: top objectClass: account objectClass: posixAccount loginShell: /dev/null uidNumber: 439 gidNumber: 439 homeDirectory: /usr/lib/openldap
Do not add the root user to this file. Keep in mind that we are building a central authentication server, so adding root here would mean that somebody knowing the root password would have root access to every machine in the whole network.
The file provided contains the accounts found in a clean stage3 Gentoo installation with no additional software installed, adding the ldap user. Should your passwd file differ from the accounts included here you must modify this file to reflect your installation.
Whenever you install any application using portage that creates a new account, you will have to manually add this account to the LDAP directory, as portage uses useradd to add such an account, and this only adds the account to the /etc/passwd file.
Now we import this data into the LDAP directory:
server root # ldapadd -x -D "cn=manager,dc=example,dc=com" -W -f system.ldifNext we will create the entries for our users, editing the file people.ldif:
dn: cn=Jose Gonzalez Gomez,ou=people,dc=example,dc=com objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: person objectClass: posixAccount objectClass: top objectClass: krb5Principal objectClass: krb5KDCEntry krb5PrincipalName: jgonzalez@EXAMPLE.COM krb5KeyVersionNumber: 1 krb5MaxLife: 86400 krb5MaxRenew: 604800 krb5KDCFlags: 126 cn: Jose Gonzalez Gomez givenName: Jose mail: jgonzalez@example.com sn: Gonzalez Gomez uid: jgonzalez uidNumber: 500 gidNumber: 100 homeDirectory: /home/jgonzalez loginShell: /bin/bash dn: cn=Antonio Perez Lopez,ou=people,dc=example,dc=com objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: person objectClass: posixAccount objectClass: top objectClass: krb5Principal objectClass: krb5KDCEntry krb5PrincipalName: aperez@EXAMPLE.COM krb5KeyVersionNumber: 1 krb5MaxLife: 86400 krb5MaxRenew: 604800 krb5KDCFlags: 126 cn: Antonio Perez Lopez givenName: Antonio mail: aperez@example.com sn: Perez Lopez uid: aperez uidNumber: 501 gidNumber: 100 homeDirectory: /home/aperez loginShell: /bin/bash
Now we import this data into the LDAP directory:
server root # ldapadd -x -D "cn=manager,dc=example,dc=com" -W -f example.ldifWe are creating our first Kerberos principals, but they still lack their password (krb5Key). This password will be set once we configure Kerberos so it's able to access the whole directory to find Kerberos principals. See Setting Kerberos to read the whole directory.
First we create the configuration file /etc/krb5.conf, with the information relative to the Kerberos domain we will be creating:
[libdefaults]
ticket_lifetime = 600
default_realm = EXAMPLE.COM
default_etypes = des3-hmac-sha1 des-cbc-crc des-cbc-md5
default_etypes_des = des3-hmac-sha1 des-cbc-crc des-cbc-md5
[realms]
EXAMPLE.COM = {
kdc = kerberos.example.local:88
admin_server = kerberos.example.local:749
}
[domain_realm]
.example.local = EXAMPLE.COM
example.local = EXAMPLE.COM
[kdc]
database = {
realm = EXAMPLE.COM
dbname = ldap:ou=kerberos,dc=example,dc=com
mkey_file = /var/heimdal/m-key
}
[logging]
kdc = SYSLOG
admin_server = SYSLOG
default = SYSLOGWe may have all the keys of our principals encrypted with a master key. In order to create this master key we invoke the kstash command:
server root # kstash
Master key:<type master key>
Verifying - Master key:<type master key>
kstash: writing key to `/var/heimdal/m-key'Once created the master key we can initialize our domain, issuing the following command:
server root # kadmin -l kadmin> init EXAMPLE.COM Realm max ticket life [unlimited]: Realm max renewable ticket life [unlimited]: kadmin>
This should have created several entries in our LDAP directory under the system branch.
Heimdal provides a pluggable mechanism for controlling password quality. This mechanism may be configured using the following section in /etc/krb5.conf:
[password_quality]
check_library = library
check_function = functionHowever, Heimdal doesn't seem to provide any library for password quality enforcement out of the box.
Let's change the kadmin/admin password so we may use this principal for administration:
server root # kadmin -l kadmin> cpw kadmin/admin kadmin/admin@EXAMPLE.COM's Password:<enter password> Verifying - kadmin/admin@EXAMPLE.COM's Password:<enter password> kadmin>
Let's create a user for LDAP administration:
server root # kadmin -l kadmin> add ldapmaster Max ticket life [1 day]: Max renewable life [1 week]: Principal expiration time [never]: Password expiration time [never]: Attributes []: ldapmaster@EXAMPLE.COM's Password:<enter password> Verifying - ldapmaster@EXAMPLE.COM's Password:<enter password> kadmin>
File /var/heimdal/kadmind.acl:
kadmin/admin@EXAMPLE.COM all otheruser@EXAMPLE.COM all
For every network service accepting Kerberos authenticated connections we need to create a principal for the service and then we must extract a service ticket and put it in a keytab. We need to do this in order to provide PAM or SSH authentication:
server root # kadmin -l kadmin> add --random-key host/kerberos.example.local Max ticket life [1 day]: Max renewable life [1 week]: Principal expiration time [never]: Password expiration time [never]: Attributes []: kadmin> ext_keytab host/kerberos.example.local kadmin>
It is extremely important to use the canonical name of the machine where the server is located, since Kerberos uses this name to get the service ticket, although we access the service using an alias. If we don't use the canonical name we may face an error like this "GSSAPI Error: Miscellaneous failure (Server not found in Kerberos database)" when we try to access the service.
Once we have reached this point we may init the Kerberos services and add them to the services started on boot up:
server root # /etc/init.d/heimdal-kdc start server root # /etc/init.d/heimdal-kadmind start server root # /etc/init.d/heimdal-kpasswdd start server root # rc-update add heimdal-kdc default server root # rc-update add heimdal-kadmind default server root # rc-update add heimdal-kpasswdd default
We may check the service is working properly trying to initialize our credentials cache with one of the previously created users:
server root # kinit kadmin/admin kadmin/admin@EXAMPLE.COM's Password:<enter password> kinit: NOTICE: ticket renewable lifetime is 1 hour server root # klist Credentials cache: FILE:/tmp/krb5cc_0 Principal: kadmin/admin@EXAMPLE.COM Issued Expires Principal Aug 17 12:07:56 Aug 17 12:17:56 krbtgt/EXAMPLE.COM@EXAMPLE.COM
Until now we have been working in the ou=kerberos,dc=example,dc=com branch in order to create needed entries for Kerberos to work properly, and to create Kerberos principals that doesn't correspond to real people, as the ldapmaster principal for LDAP administration. Now we must make Kerberos able to access the whole directory so it can find real people under the ou=people,dc=example,dc=com branch. To achieve this, we edit the file /etc/krb5.conf and change dbname in the kdc section to look like this:
[kdc]
database = {
realm = EXAMPLE.COM
dbname = ldap:dc=example,dc=com
mkey_file = /var/heimdal/m-key
}Now we have access to all the principals defined in all the directory branches:
server root # kadmin -l kadmin> list * aperez@EXAMPLE.COM changepw/kerberos@EXAMPLE.COM default@EXAMPLE.COM kadmin/admin@EXAMPLE.COM kadmin/changepw@EXAMPLE.COM kadmin/hprop@EXAMPLE.COM krbtgt/EXAMPLE.COM@EXAMPLE.COM ldapmaster@EXAMPLE.COM host/kerberos.example.local@EXAMPLE.COM ldap/commserver.example.local@EXAMPLE.COM jgonzalez@EXAMPLE.COM
Now we can set the password of the users we created in the ou=people branch:
kadmin> cpw jgonzalez
jgonzalez@EXAMPLE.COM's Password:<enter password>
Verifying - jgonzalez@EXAMPLE.COM's Password:<enter password>
Now we are going to configure a few things in order to provide Kerberos authenticated access to OpenLDAP.
First we must create a principal for the LDAP service and then export its service ticket to a keytab accessible by OpenLDAP:
server root # kadmin -l kadmin> add --random-key ldap/ldap.example.local Max ticket life [1 day]: Max renewable life [1 week]: Principal expiration time [never]: Password expiration time [never]: Attributes []: kadmin> q server root # kinit kadmin/admin kadmin/admin@EXAMPLE.COM's Password:<enter password> kinit: NOTICE: ticket renewable lifetime is 1 hour server root # ktutil -k /etc/openldap/ldap.keytab get ldap/commserver.example.local server root # chown root:ldap /etc/openldap/ldap.keytab server root # chmod 640 /etc/openldap/ldap.keytab
In order to authenticate against OpenLDAP using SASL/GSSAPI we have to create this service ticket. It is extremely important to use the canonical name of the machine where the LDAP server is located, since Kerberos uses this name to get the service ticket, although we access the service using an alias. If we don't use the canonical name we may face an error like this "GSSAPI Error: Miscellaneous failure (Server not found in Kerberos database)" when we try to access the service.
Next we must tell OpenLDAP/SASL where to find the keytab containing its service ticket. To do so, we edit the file /etc/conf.d/slapd, adding the KRB5_KTNAME environment variable. This file would look like this:
# conf.d file for the openldap-2.1 series # # To enable both the standard unciphered server and the ssl encrypted # one uncomment this line or set any other server starting options # you may desire. # OPTS="-h 'ldap:// ldaps:// ldapi://'" # Kerberos keytab file export KRB5_KTNAME=/etc/openldap/ldap.keytab
Next we may restart OpenLDAP for changes to take effect:
server root # /etc/init.d/slapd restartNow we will check the SASL authentication services offered by OpenLDAP, both with encrypted and unencrypted communications. We should get something like this:
server root # ldapsearch -H ldap://ldap.example.local/ -x -b "" -s base -LLL supportedSASLMechanisms dn: supportedSASLMechanisms: NTLM supportedSASLMechanisms: GSSAPI supportedSASLMechanisms: DIGEST-MD5 supportedSASLMechanisms: CRAM-MD5 server root # ldapsearch -H ldap://ldap.example.local/ -x -b "" -s base -LLL -ZZ supportedSASLMechanisms dn: supportedSASLMechanisms: NTLM supportedSASLMechanisms: LOGIN supportedSASLMechanisms: PLAIN supportedSASLMechanisms: GSSAPI supportedSASLMechanisms: DIGEST-MD5 supportedSASLMechanisms: CRAM-MD5 server root # ldapsearch -H ldaps://ldap.example.local/ -x -b "" -s base -LLL supportedSASLMechanisms dn: supportedSASLMechanisms: NTLM supportedSASLMechanisms: LOGIN supportedSASLMechanisms: PLAIN supportedSASLMechanisms: GSSAPI supportedSASLMechanisms: DIGEST-MD5 supportedSASLMechanisms: CRAM-MD5
OpenLDAP tools, when compiled with Kerberos support, will use GSSAPI as the default authentication mechanism. So in order to check if this functionality is working we have just to issue an ldapsearch, as long as we have our credentials cache correctly initialized:
server root # kinit ldapmaster ldapmaster@EXAMPLE.COM's Password:<enter password> kinit: NOTICE: ticket renewable lifetime is 1 week server root # ldapsearch SASL/GSSAPI authentication started SASL username: ldapmaster@EXAMPLE.COM SASL SSF: 56 SASL installing layers # extended LDIF # # LDAPv3 # base <> with scope sub # filter: (objectclass=*) # requesting: ALL # ........
The first four lines tell us that GSSAPI authentication has been successful. This example shows the single sign on capability offered by Kerberos.
If we authenticate ourselves against the directory server using GSSAPI, we will have what is known as an authentication identity. This identity is in the name space of the SASL authentication mechanism, not in the name space of the LDAP server:
server root # ldapwhoami SASL/GSSAPI authentication started SASL username: ldapmaster@EXAMPLE.COM SASL SSF: 56 SASL installing layers dn:uid=ldapmaster,cn=gssapi,cn=auth server root # ldapwhoami -Y EXTERNAL -H ldapi:// SASL/EXTERNAL authentication started SASL username: uidNumber=0+gidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 dn:uidnumber=0+gidnumber=0,cn=peercred,cn=external,cn=auth
The dn uses to be of the form
uid=<username>,cn=<realm>,cn=<mechanism>,cn=auth
or
uid=<username>,cn=<mechanism>,cn=auth
if the mechanism doesn't understand the concept of realms, or the authentication took place using the default realm.
It's convenient to map these authentication identities to LDAP entries, so we may later assign permissions in our ACLs based on those entries. To do so, we include the following in /etc/openldap/example.conf:
# Mapping of SASL authentication identities to LDAP entries
sasl-regexp
uid=(.+),cn=(.+),cn=.+,cn=auth
ldap:///dc=$2,dc=com??sub?(|(uid=$1)(cn=$1@$2))
sasl-regexp
uid=(.+),cn=.+,cn=auth
ldap:///dc=example,dc=com??sub?(|(uid=$1)(krb5PrincipalName=$1@EXAMPLE.COM))
sasl-regexp
uidnumber=0\\\+gidnumber=0,cn=peercred,cn=external,cn=auth
cn=ldapmaster@circuitcat.com,ou=kerberos,dc=circuitcat,dc=comThis basically maps any authentication identity to the LDAP entry containing an uid or krb5PrincipalName equal to the identity provided. The last expression maps connections made to ldapi:// by root to the ldap administrator account.
For a rather deep discussion about mapping identities to entries, see the OpenLDAP 2.2 Administrator Guide.
After doing this, and restarting the server, we obtain the following:
server root # ldapwhoami SASL/GSSAPI authentication started SASL username: ldapmaster@EXAMPLE.COM SASL SSF: 56 SASL installing layers dn:cn=ldapmaster@example.com,ou=kerberos,dc=example,dc=com server root # ldapwhoami -Y EXTERNAL -H ldapi:// SASL/EXTERNAL authentication started SASL username: uidNumber=0+gidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 dn:cn=ldapmaster@example.com,ou=kerberos,dc=example,dc=com
We are now going to create a LDAP entry that will act as a proxy for the NSS, so attributes related to Unix/Linux authorization may be accessed only using this proxy. First we create the entry for our proxy, editing the file nssproxy.ldif:
dn: cn=nssproxy@example.com,ou=kerberos,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: krb5Principal
objectClass: krb5KDCEntry
krb5PrincipalName: nssproxy@EXAMPLE.COM
krb5KeyVersionNumber: 1
krb5MaxLife: 86400
krb5MaxRenew: 604800
krb5KDCFlags: 126
cn: nssproxy@example.com
sn: nssproxy@example.com
userPassword: {SASL}nssproxy@EXAMPLE.COMnss_ldap is able to do Kerberos authentication, but this should mean getting and renewing a ticket without user interaction. It's far easier to setup nss_ldap using simple bind, and this way we'll also show how to setup simple bind authentication when accessing the directory.
Now we import this data into the LDAP directory:
server root # ldapadd -x -D "cn=manager,dc=example,dc=com" -W -f nssproxy.ldifNow we must assign a password to the principal we have just created:
server root # kadmin -l kadmin> cpw nssproxy nssproxy@EXAMPLE.COM's Password:<enter password> Verifying - nssproxy@EXAMPLE.COM's Password:<enter password>
The whole purpose of this HOWTO is setting up a central authentication server using Kerberos as the key component of the installation. We use Kerberos because is meant to provide secure authentication in untrusted environments.
We are now going to configure SASL and LDAP to allow simple bind authentication against the LDAP server. What does this mean? This means we will be sending the clear text password over the wire!!! Why are we doing this? Because unfortunately not all clients support SASL/GSSAPI authentication, so we must provide other means of authentication for those clients.
I think there's no need to stress the importance of making such an authentication under the context of a secured connection, for instance, using SSL/TLS, and giving this access only when strictly needed. If we don't, we are blowing up the whole security infrastructure we are setting up.
Simple bind authentication is a mechanism offered by OpenLDAP so users can authenticate to the directory server providing a bind DN and a password. OpenLDAP then compares the password provided with the password stored in the userPassword attribute of the provided DN. If they match, the user gets authenticated, and proper permissions are given based on provided ACLs.
Passwords in OpenLDAP may be stored using some hash, but passwords provided in a simple bind operation are always transmitted as clear text. Be sure you have a security option with at least the following included in /etc/openldap/slapd.conf in order to disallow simple binds in unprotected connections:
security simple_bind=64
We will be using the SASL authentication daemon (saslauthd) to authenticate users trying to bind to our directory. We want to keep just one password database, so we'll configure saslauthd so it contacts Kerberos to do user/password verification.
This setup may lead to performance problems. Keep in mind that every simple bind authentication will lead to a Kerberos authentication. This may get worse if you use this setup to authenticate not only OpenLDAP users but users of other services, as your SMTP or POP/IMAP server. The solution to these problems is to use another authentication mechanism instead of Kerberos. In that case you will need a separate password database for users authenticating through saslauthd.
Which solution is better? That depends on you: you may prefer a greater performance making saslauthd authenticate against its native database, or you may prefer ease of maintenance having only one password database. In our case we have chosen the second option.
First we must edit the file /etc/sasl2/slapd.conf, so simple bind authentication is redirected to saslauthd:
pwcheck_method:saslauthd
Then we must configure saslauthd so it checks users and passwords against Kerberos. This is done in /etc/conf.d/saslauthd:
SASLAUTHD_OPTS="${SASLAUTH_MECH} -a kerberos5"Now we must start the saslauthd daemon. We also add it to the services run on boot up:
server root # /etc/init.d/saslauthd start server root # rc-update add saslauthd default
Finally, we must locate every user we want to let authenticate using simple bind, and change their userPassword attribute to {SASL}principal@REALM (substituting principal and REALM for proper values, of course). We have done so with the NSS proxy user we created before, so we may use it to test this functionality:
server root # ldapwhoami -ZZ -x -D "cn=nssproxy@example.com,ou=kerberos,dc=example,dc=com" -W
Enter LDAP Password:<enter password>
dn:cn=nssproxy@example.com,ou=kerberos,dc=example,dc=comOnce we have mapped authentication identities to LDAP entries we may set suitable ACLs to control who is able to access information stored in our directory service. Firs we must uncomment the line that includes our access configuration in /etc/openldap/example.conf:
# ACLs include /etc/openldap/example.access.conf
Then we must create the /etc/openldap/example.access.conf file, with the following content:
# Remember that rootdn has always write access
# posixAccount/posixGroup attributes may only be accessible to root/ldapmaster (write) and pamproxy (read)
access to attrs=uid,uidNumber,gidNumber,gecos,homeDirectory,loginShell,memberUid
by dn="cn=pamproxy@circuitcat.com,ou=kerberos,dc=circuitcat,dc=com" read
# This is needed so sasl-regexp/GSSAPI works correctly
access to attrs=krb5PrincipalName
by anonymous auth
# Kerberos attributes may only be accessible to root/ldapmaster
access to attrs=krb5KeyVersionNumber,krb5PrincipalRealm,krb5EncryptionType,krb5KDCFlags,krb5Key,krb5MaxLife,krb5MaxRenew,krb5PasswordEnd,krb5ValidEnd,krb5ValidStart,krb5RealmNam
by * none
# We will be using userPassword to provide simple BIND access, so we don't want this to be user editable
access to attrs=userPassword
by anonymous auth
# Write access to common attributes for users
access to dn.subtree="ou=people,dc=circuitcat,dc=com" attrs=telephoneNumber,facsimileTelephoneNumber,jpegPhoto,homePhone,homePostalAddress
by self write
by users read
# Anything else we may have forgotten is writable by admin, and viewable by authenticated users
access to dn.subtree="dc=circuitcat,dc=com"
by users readThis is a rather simple access configuration file that should be customized for your needs, but that offers a basic security protection.
For a rather deep discussion about OpenLDAP ACLs, see the OpenLDAP 2.2 Administrator Guide.
Now we change the rootdn in /etc/openldap.example.conf and take away the rootpw option:
rootdn "cn=ldapmaster@example.com,ou=kerberos,dc=example,dc=com" # Be sure to take away or comment out the rootpw option!!!
If we want to be able to access a machine using SSH, we must activate the following options in the file /etc/ssh/sshd_config:
# Kerberos options KerberosAuthentication yes KerberosOrLocalPasswd yes KerberosTicketCleanup yes #KerberosGetAFSToken no # GSSAPI options GSSAPIAuthentication yes GSSAPICleanupCredentials yes # Disable PAM authentication (make sure PasswordAuthentication is not set to no) UsePAM no
If we don't disable PAM, we will be able to access the remote machine using the Kerberos user and password, but the credentials cache won't get correctly initialized. This has a secondary effect: as long as we don't use PAM, we won't be able to automatically create the home directory for an user in her first login. On the other hand, in order to allow login to users that aren't included in Kerberos, we must activate the PasswordAuthentication option.
In order to get differentiated logs for every service, we may add the following to the syslog-ng configuration file, located at /etc/syslog-ng/syslog-ng.conf:
# SASL/Kerberos/SSH/... authentication
destination auth { file("/var/log/auth.log"); };
filter auth { facility(auth); };
log { source(src); filter(auth); destination(auth); };
# Kerberos kdc
destination krb5kdc { file("/var/log/krb5kdc.log"); };
filter krb5kdc { facility(auth) and program("krb5kdc"); };
log { source(src); filter(krb5kdc); destination(krb5kdc); };
# Kerberos admin
destination kadmin { file("/var/log/kadmin.log"); };
filter kadmin { facility(auth) and (program("kadmin.*") or program("kdb5.*")); };
log { source(src); filter(kadmin); destination(kadmin); };
# LDAP
destination slapd { file("/var/log/slapd.log"); };
filter slapd { program("slapd"); };
log { source(src); filter(slapd); destination(slapd); };Feel free to customize for your current logger.