============================ Centos openldap installation ============================ :Title: Centos ldap installation/configuration :Author: Douglas O'Leary :Description: Notes/links for installation of ldap on centos :Disclaimer: Standard: Use the information that follows at your own risk. If you screw up a system, don't blame it on me... .. contents:: Overview: ========= There are a number of good tutorials out there on getting openldap installed, running, and authenticating. This isn't a tutorial; but, a checklist of steps that I've been able to repeat a number of times. Three important lessons learned from this exercise: * Most of the tutorials on the net start with *Edit the slapd.conf.bak file*. Problem is, rhel6/centos6 don't supply that file - at least not where all the tutorials say it should be. It's supplied as /usr/share/openldap-servers/slapd.conf.obsolete. In case, for whatever reason, redhat stops supplying that file at all, it's included at the tail end of this doc. * All of the tutorials say *Thou shalt not edit the ldif files under /etc/openldap/slap.d*. Well, turns out you can. (1) slapd has to be off and (2) you have to be **very** careful, though, as a mistake will prevent your ldap server from starting. I was going that route to get the server going in the first place when I finally found the slapd.conf.obsolete file. * And the big one: By default, there are two main and mutually exclusive methods of grouping people in ldap. The classes are posixgroup and groupofnames. Rfc2307bis bridges that mutual exclusivity but, for reasons with which I'm unfamiliar, it's been deleted by the IETF. I have a much more detailed discussion of the issue at http://www.olearycomputers.com/ll/ldap/openldap_groups.html There seemingly is no way to enable rfc2307bis schema after the directory's built as it replaces the nis.schema and you can't delete a schema after it's enabled. Since rfc2307bis provides additional options and flexibility, from my perspective, there's no reason **not** to use rfc2307bis, so I'm suggesting that it be enabled from the start. This guide will demonstrate how to do that, including how to configure authentication to take advantage of it. Alot of the process was taken from this site_ which **is** an excellent tutorial; walking the reader through stages installation and configuration. Excellent job; it was very helpful. .. _site: http://spectlog.com/content/Minimal_LDAP_configuration_on_RHEL6_in_stages_and_details This checklist covers installation and configuration of an ldap server for my company. Replace domains and IPs as needed. It also covers configuring ldap authentication on clients both legacy and sssd. For reasons that I haven't explored yet, one client insists on legacy authentication even for rhel6 systems so my goal was to figure out how to support that. So, short version: following these steps will get you a functioning openldap server with the following: * Rfc2307bis schema to enable groupofnames and posixaccount compatibility. * Memberof module and overlay to enable memberof syntax and searches. * Basic ACLs to cover the shadow passwords. * Ppolicy module and overlay to enable password aging and expiration. * The ability to configure other linux systems to authenticate against the server. Good luck; let me know if there's anything that's unclear or mistaken. Creating ldap directory server: =============================== * Install required packages: * openldap-servers * openldap-clients * migrationtools * perl-LDAP # req for the `ldap wrapper script `_. * Edit */etc/sysconfig/ldap*; ensure ldap, ldapi, and ldaps are enabled. We'll disable ldap (unsecure) later. * ldapi will be used for directory configuration updates * ldaps will be used for normal operations * ldap will be used for verification of initial set up. * Update firewall rules to allow port 636 (ldaps). If using */etc/sysconfig/iptables* * Add two lines to file: :: -A INPUT -m state --state NEW -m udp -p udp --dport 636 -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 636 -j ACCEPT * ``service iptables restart`` * If going w/rfc2307bis: * Download the rfc2307bis schema: :: cd /etc/openldap/schema wget http://www.grotan.com/ldap/rfc2307bis.schema * Comment out uidnumber and gidnumber OIDs in /etc/openldap/schema/rfc2307bis.scema to avoid duplication errors. These are the first two entries, so easy to find. Comment the entire stanza, not just the attributetype line. * Copy, edit initial splad.conf file: * /usr/share/openldap-servers/slapd.conf.obsolete -> /etc/openldap/slapd.oci.conf * If going with rfc2307bis * Remove nis.schema and add rfc2307bis schema using the same syntax. * In the indices section of the database definition, remove memberUID from the indecies as it doesnt' exist anymore. * Change: * Manager -> admin * my-domain -> oci * Add rootpw in the bdb section below the rootdn. Use ``slappasswd`` to get a hash of the password and use that. Unencrypted passwords are bad, m'kay? * Edit ldap.conf, * update BASE and URI * Leave ldap (port 389) enabled for the time being - it's blocked by the firewall so it's local only. * Create startup ldif files: :: # Root entry dn: dc=oci,dc=com objectclass: dcObject objectclass: organization o: OLeary Computers dc: oci # Admin DN dn: cn=admin,dc=oci,dc=com objectclass: organizationalRole cn: admin # Base DN for users dn: ou=users,dc=oci,dc=com changetype: add objectclass: top objectclass: organizationalUnit ou: users # Base DN for groups dn: ou=groups,dc=oci,dc=com changetype: add objectclass: top objectclass: organizationalUnit ou: groups * Initialize slapd.d config: * ``rm -fr /etc/openldap/slapd.d/* /var/lib/ldap/*`` * ``cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG`` * `` echo "" | slapadd -f /etc/openldap/slapd.oci.conf`` * ``slaptest -f /etc/openldap/slapd.oci.conf -F /etc/openldap/slapd.d`` * Initialize directory entries: * ``slapadd -l /root/working/ldap/oci.com.ldif`` * ``slapadd -l /root/working/ldap/admin.oci.com.ldif`` * ``chown -R ldap:ldap /var/lib/ldap /etc/openldap/slapd.d`` * Start up slapd and verify: * ``service slapd start`` * Verify with ``ldapsearch -x -b 'dc=oci,dc=com'`` * Add users and groups then verify: * ``ldapadd -x -D "cn=admin,dc=oci,dc=com" -w ${pwd} -f /root/working/ldap/users.oci.com.ldif`` * ``ldapadd -x -D "cn=admin,dc=oci,dc=com" -w ${pwd} -f /root/working/ldap/groups.oci.com.ldif`` * ``ldapsearch -x -b 'dc=oci,dc=com'`` NOTE: db:config is set up to allow uid:gid 0:0 (root:root) only, based on *access to* lines in the original slapd.oci.conf. cn=admin,dc=oci,dc=com is root for db:bdb. Theoretically, I could set up (os) root to have access to db:bdb too. * Update defaults in migrate_common.ph, create test user and ldif files: * ``vi /usr/share/migrationtools/migrate_common.ph`` * People -> users * Group -> groups * Update DEFAULT_MAIL_DOMAIN * Update DEFAULT_BASE * ``groupadd -g 100000 qwer`` * ``useradd -u 100000 -g qwer qwer`` * ``passwd qwer`` * ``grep qwer /etc/passwd | /usr/share/migrationtools/migrate_passwd.pl - qwer.passwd.ldif`` * ``grep qwer /etc/group | /usr/share/migrationtools/migrate_group.pl - qwer.group.ldif`` If using rfc2307bis, update qwer.group.ldif to include * objectclass: groupofnames * member: cn=admin,dc=oci,dc=com # cat qwer.group.ldif dn: cn=qwer,ou=groups,dc=oci,dc=com objectClass: posixGroup objectclass: groupofnames objectClass: top cn: qwer userPassword: {crypt}x gidNumber: 100000 member: cn=admin,dc=oci,dc=com * Add test user to directory, verify, then delete him from the system. * ``ldapadd -x -D "cn=admin,dc=oci,dc=com" -w "${pwd}" -f ./qwer.group.ldif`` * ``ldapadd -x -D "cn=admin,dc=oci,dc=com" -w "${pwd}" -f ./qwer.passwd.ldif`` * ``ldapsearch -LLL -x -b 'dc=oci,dc=com'`` * ``userdel -r qwer`` * Certificates: * Update certificate definitions in directory: :: # ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b cn=config \* | \ grep -i ^olctlscert SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 olcTLSCertificateFile: "OpenLDAP Server" olcTLSCertificateKeyFile: /etc/openldap/certs/password # cat /root/working/ldap/add.certificate.conf.ldif dn: cn=config changetype: modify replace: olcTLSCertificateFile olcTLSCertificateFile: /etc/pki/tls/certs/slapdcert.pem - replace: olcTLSCertificateKeyFile olcTLSCertificateKeyFile: /etc/pki/tls/certs/slapdkey.pem - # ldapmodify -Y EXTERNAL -H ldapi:/// \ -f /root/working/ldap/add.certificate.conf.ldif [[snip]] # ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b cn=config \* | \ grep -i ^olctlscert SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 olcTLSCertificateFile: /etc/pki/tls/certs/slapdcert.pem olcTLSCertificateKeyFile: /etc/pki/tls/certs/slapdkey.pem * Generate server key and cert request: :: openssl req -new -nodes -keyout \ /etc/pki/tls/private/ldapsvr.oci.com.key \ -out /etc/pki/tls/ldapsvr.oci.com.csr * Get the cert signed. The author of the tutorial also has steps for generating your own Certificate Authority so you can sign your certs w/o having to go through verisign. The locally signed certs obviously aren't as *trustworthy* as ones from the major vendors; but, they work for this purpose. His checkist is available at: http://spectlog.com/content/Create_Certificate_Authority_(CA)_instead_of_using_self-signed_Certificates I have one, too, but I think his is more recent. Mine was taken right from the openssl book and doesn't reflect the directory structure that comes w/rhel6. My page, if you're interested, is at http://www.olearycomputers.com/ll/misc_openssl_ca.html * Obtain the signed cert: :: scp caauth:/etc/pki/CA/certs/ldapsvr.olearycomputers.com.crt /tmp * Retrieve and update CA cert: :: # pwd /etc/pki/tls # scp caauth:/etc/pki/CA/cacert.pem certs # hash=$(openssl x509 -noout -hash -in certs/cacert.pem ) # echo ${hash} aa65d400 # ln -s /etc/pki/tls/certs/cacert.pem /etc/pki/tls/certs/${hash}.0 # ll certs/${hash}.0 lrwxrwxrwx. 1 root root 29 Jan 5 08:39 certs/aa65d400.0 -> /etc/pki/tls/certs/cacert.pem # openssl verify /tmp/ldapsvr.olearycomputers.com.crt /tmp/ldapsvr.olearycomputers.com.crt: OK * Copy newly created keys into the place: :: # cp /etc/pki/tls/private/ldapsvr.oci.com.key \ /etc/pki/tls/certs/slapdkey.pem # cp /tmp/ldapsvr.olearycomputers.com.crt \ /etc/pki/tls/certs/slapdcert.pem # openssl verify /etc/pki/tls/certs/slapdcert.pem /etc/pki/tls/certs/slapdcert.pem: OK # chown root:ldap /etc/pki/tls/certs/slapdcert.pem \ /etc/pki/tls/certs/slapdkey.pem # chmod 750 /etc/pki/tls/certs/slapdkey.pem * Disable ldap (port 389): * Set *SLAPD_LDAP=no* in */etc/sysconfig/ldap*; restart slapd * Update firewall rules, if needed. * Set *TLS_REQCERT allow* in */etc/openldap/ldap.conf.* Temporary measure while I figure out what's up with the certificates. *allow* enables the sesssion to continue if there's no cert or a bad one is provided. I have verified, via wireshark, that the data is, in fact, encrypted. If someone knows why this isn't working, a tip would be appreciated. * In */etc/openldap/ldap.conf*, remove or replace ldap uri with ldaps. ldaps should be the only one left. * Verify output from ``ldapsearch -x -b dc=oci,dc=com`` Since ldap is disabled and cli switches don't allow for ldapi, this is going through port 636. Use wireshark on the ldap server to verify port and encryption. * Cert lessons learned: * The host used in the URI must match the cn used in the signed cert. If it doesn't, you'll get bind errors unless tls_reqcert is set to allow (basically, use certs that can't be authenticated). * tls_cacert (caps in ldap.conf, lower case in authentication files) can specify the name of the CA pem file directly. You can also use tls_cacertdir; but, the contents of that must be set in a specific way. Short version: if you're not sepcifying the cacert retrieval in the authconfig line, specify the file directly with *ldap_tls_cacert = /etc/openldap/cacerts/cacert.pem* (for instance) * ACLs: protect shadow password: * Create access.ldif: :: # cat access1.ldif ## BDB access control list dn: olcDatabase={2}bdb,cn=config changetype: modify replace: olcAccess olcAccess: {0}to attrs=userpassword by self write by anonymous auth by * none olcAccess: {1}to attrs=shadowlastchange by self write by * none olcAccess: {2}to * by self write by * read * Apply it: :: # ldapmodify -Y EXTERNAL -H ldapi:/// -f /root/working/ldap/access.ldif SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 modifying entry "olcDatabase={2}bdb,cn=config" * To delete, use: :: ## BDB access control list dn: olcDatabase={2}bdb,cn=config changetype: modify delete: olcAccess olcAccess: {0} * The syntax is **incredibly** touchy. It took way longer than it should to get those two simple processes down. * If using rfc2307bis, Enable memberof module/overlay: * This seems to have zero functionality if not using the rfc2307bis schema. * Create memberof ldif to add module and overlay: :: dn: cn=module,cn=config cn: module objectClass: olcModuleList objectclass: top olcModuleLoad: memberof.la olcModulePath: /usr/lib64/openldap dn: olcOverlay=memberof,olcDatabase={2}bdb,cn=config objectclass: olcconfig objectclass: olcMemberOf objectclass: olcoverlayconfig objectclass: top olcoverlay: memberof * Add it to the cn=config: ``ldapadd -Y EXTERNAL -H ldapi:/// -f ./memberof.ldif`` * I wasn't able to retrieve memberof searches until I added yet another group and then they all started working. To me, this implies that the memberof functionality is indexed somehow and wasn't re-indexed until I added another group. I would think there'd be some way of forcing that outside of adding a group; but, no information on that yet. * Enable password policy module and overlay: * Enable module and install overlay: :: # cat ppolicy_module_overlay.ldif dn: cn=module,cn=config objectClass: olcModuleList cn: module olcModuleLoad: ppolicy olcModulePath: /usr/lib64/openldap dn: olcOverlay=ppolicy,olcDatabase={2}bdb,cn=config objectClass: olcPPolicyConfig olcOverlay: ppolicy olcPPolicyDefault: cn=default,ou=policies,dc=example,dc=com # olcPPolicyUseLockout: TRUE # olcPPolicyHashCleartext: TRUE # ldapadd -Y EXTERNAL -H ldapi:/// -f ./ppolicy_module_overlay.ldif SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 adding new entry "cn=module,cn=config" adding new entry "olcOverlay=ppolicy,olcDatabase={2}bdb,cn=config" * Define a password policy. A fairly generic one that defines the following is listed below: * password attribute is userPassword * Password history is 8 * Minimum password length is 8 * 3 bad passwords in 15 minutes before account is locked * Passwords must change after adminsitrative update. * Password max age 90 days * Password expiration warning set to 7 days. :: # cat policies.oci.com.ldif dn: ou=policies,dc=oci,dc=com objectClass: organizationalUnit objectClass: top ou: policies dn: cn=default,ou=policies,dc=oci,dc=com cn: default objectClass: top objectClass: device objectClass: pwdPolicyChecker objectClass: pwdPolicy pwdAttribute: userPassword pwdInHistory: 8 pwdMinLength: 8 pwdMaxFailure: 3 pwdFailureCountInterval: 900 pwdCheckQuality: 1 pwdMustChange: TRUE pwdGraceAuthNLimit: 0 pwdMaxAge: 7776000 pwdExpireWarning: 604800 pwdLockoutDuration: 300 pwdLockout: TRUE * Add the policy: :: # ldapadd -xD ${rootdn} -w "${rootpw}" -f ./policies.oci.com.ldif adding new entry "ou=policies,dc=oci,dc=com" adding new entry "cn=default,ou=policies,dc=oci,dc=com" Legacy authentication: ====================== NOTE1: I haven't tried this on a rhel5 (or earlier) box yet; works on rhel6. NOTE2: I also haven't had a chance to test the legacy authentication against the rfc2307bis schema yet. For sssd, I had to ensure it was aware that I was using rfc2307bis and tell it the attribute which defines group membership. NOTE3: I just reinstalled everything and am having issues with the sssd again, go figure. I'll post notes regarding what I find when I get a solution; but, for the moment, take the info that follows with a grain of salt. * Install required packages: ``yum -y install openldap-clients nss-pam-ldapd`` * Set *FORCELEGACY=yes* in */etc/sysconfig/authconfig* * Run ``authconfig``: :: authconfig --enableldap --enableldapauth \ --ldapserver=ldaps://ldapsvr.olearycomputers.com \ --ldapbasedn="dc=oci,dc=com" --enablemkhomedir \ --ldaploadcacert=ftp://192.168.122.1/pub/CA/cacert.pem --update * enableldap, enableldapauth, ldapbasedn are self explanatory * ldapserver must match the cn used in the signed cert. If it doesn't, you'll get bind errors. * enablemkhomedir adds the appropriate entry to /etc/pam.d/system-auth to automatically create home directories upon access. Verify proper settings. * ldaploadcacert defines the url from which to get the Certificate Authority's (not the ldap server's) public key. It will use the proper commands so that tls_cacertdir entries are honored. * Verify output from ``ldapsearch -x -b dc=oci,dc=com`` * Verify: * authentication works: ``getent passwd qwer`` * ssh/mkhomedir work by accessing account. ``ssh -l qwer client1`` sssd authentication: ==================== NOTE: pretty much the same thing minus the forcelegacy entry in /etc/sysconfig/authconfig and you don't need nss-pam-ldapd... * Install required packages: ``yum -y install openldap-clients`` * Run ``authconfig``: :: authconfig --enableldap --enableldapauth \ --ldapserver=ldaps://ldapsvr.olearycomputers.com \ --ldapbasedn="dc=oci,dc=com" --enablemkhomedir \ --ldaploadcacert=ftp://192.168.122.1/pub/CA/cacert.pem --update * enableldap, enableldapauth, ldapbasedn are self explanatory * ldapserver must match the cn used in the signed cert. If it doesn't, you'll get bind errors. * enablemkhomedir adds the appropriate entry to /etc/pam.d/system-auth to automatically create home directories upon access. Verify proper settings. * ldaploadcacert defines the url from which to get the Certificate Authority's (not the ldap server's) public key. It will use the proper commands so that tls_cacertdir entries are honored. * Organize /etc/sssd/sssd.conf. Not really required, but it'll make long term support much easier. I put the sssd stanza at the top, aligned the equals in the domain/default, and groups the entries. A listing is below. * Add rfc2307bis related entries to domain/default: * ``ldap_schema = rfc2307bis`` * ``ldap_group_member = member`` * If required, add ``ldap_tls_reqcert = allow`` until I figure out those doubly damned certs... * Verify output from ``ldapsearch -x -b dc=oci,dc=com`` * Verify: * authentication works: ``getent passwd qwer`` * ssh/mkhomedir work by accessing account. ``ssh -l qwer client1`` * sssd.conf file: :: # cat sssd.conf [sssd] services = nss, pam config_file_version = 2 domains = default [domain/default] id_provider = ldap auth_provider = ldap chpass_provider = ldap cache_credentials = True ldap_search_base = dc=oci,dc=com ldap_schema = rfc2307bis ldap_group_member = member ldap_uri = ldaps://ldapsvr.olearycomputers.com ldap_tls_cacertdir = /etc/openldap/cacerts ldap_tls_reqcert = allow krb5_realm = EXAMPLE.COM krb5_server = kerberos.example.com [[empty sections snipped]] Summary: ======== That should do it. Next step would be to add users, configure which users can access which systems and add anything else you may be looking for from your ldap server. Original slapd.conf.{bak,obsolete}: =================================== :: # # See slapd.conf(5) for details on configuration options. # This file should NOT be world readable. # include /etc/openldap/schema/corba.schema include /etc/openldap/schema/core.schema include /etc/openldap/schema/cosine.schema include /etc/openldap/schema/duaconf.schema include /etc/openldap/schema/dyngroup.schema include /etc/openldap/schema/inetorgperson.schema include /etc/openldap/schema/java.schema include /etc/openldap/schema/misc.schema include /etc/openldap/schema/nis.schema include /etc/openldap/schema/openldap.schema include /etc/openldap/schema/ppolicy.schema include /etc/openldap/schema/collective.schema # Allow LDAPv2 client connections. This is NOT the default. allow bind_v2 # 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 is architecture dependent value (32/64-bit system) # - back_sql.la overlay requires openldap-server-sql package # - dyngroup.la and dynlist.la cannot be used at the same time # modulepath /usr/lib/openldap # modulepath /usr/lib64/openldap # moduleload accesslog.la # moduleload auditlog.la # moduleload back_sql.la # moduleload chain.la # moduleload collect.la # moduleload constraint.la # moduleload dds.la # moduleload deref.la # moduleload dyngroup.la # moduleload dynlist.la # moduleload memberof.la # moduleload pbind.la # moduleload pcache.la # moduleload ppolicy.la # moduleload refint.la # moduleload retcode.la # moduleload rwm.la # moduleload seqmod.la # moduleload smbk5pwd.la # moduleload sssvlv.la # moduleload syncprov.la # moduleload translucent.la # moduleload unique.la # moduleload valsort.la # The next three lines allow use of TLS for encrypting connections using a # dummy test certificate which you can generate by running # /usr/libexec/openldap/generate-server-cert.sh. Your client software may balk # at self-signed certificates, however. TLSCACertificatePath /etc/openldap/certs TLSCertificateFile "\"OpenLDAP Server\"" TLSCertificateKeyFile /etc/openldap/certs/password # 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 # 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 # allows anyone and everyone to read anything but restricts # updates to rootdn. (e.g., "access to * by * read") # # rootdn can always read and write EVERYTHING! # enable on-the-fly configuration (cn=config) database config access to * by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage by * none # enable server status monitoring (cn=monitor) database monitor access to * by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read by dn.exact="cn=Manager,dc=my-domain,dc=com" read by * none ####################################################################### # database definitions ####################################################################### database bdb suffix "dc=my-domain,dc=com" checkpoint 1024 15 rootdn "cn=Manager,dc=my-domain,dc=com" # Cleartext passwords, especially for the rootdn, should # be avoided. See slappasswd(8) and slapd.conf(5) for details. # Use of strong authentication encouraged. # rootpw secret # rootpw {crypt}ijFYNcSNctBYg # The database directory MUST exist prior to running slapd AND # should only be accessible by the slapd and slap tools. # Mode 700 recommended. directory /var/lib/ldap # Indices to maintain for this database index objectClass eq,pres index ou,cn,mail,surname,givenname eq,pres,sub index uidNumber,gidNumber,loginShell eq,pres index uid,memberUid eq,pres,sub index nisMapName,nisMapEntry eq,pres,sub # Replicas of this database #replogfile /var/lib/ldap/openldap-master-replog #replica host=ldap-1.example.com:389 starttls=critical # bindmethod=sasl saslmech=GSSAPI # authcId=host/ldap-master.example.com@EXAMPLE.COM