Ben Stienstra

Linux, Unix, network, radio and more...

User Tools

Site Tools


openldap_centos7_tls

CentOS 7 - OpenLDAP 2.4 provider (master)

This page describes the installation of an OpenLDAP server with TLS.

Points of departure:

  • TLS only, RSA SHA256 / 4096 bit subject alternative name (SAN) certificate.
  • Self signed CA / certificates.
  • LDAP v3 only.
  • Require forward secrecy.
  • Minimum SSF 256 (recommended by manual).
  • No anonymous binds.
  • Users can only change own password, nothing else (cannot alter UID/GID etc).
  • Users cannot see password hashes.
  • Use the default repo packages (note: uses MozNSS instead of OpenSSL).
  • SELinux enabled.
  • iptables enabled.

Italic text is quoted from the OpenLDAP Admin guide.

Generate self signed CA and server certificates

  • If your LDAP server is multhomed, has multiple FQDNs, you need to generate TLS SAN (subject alt name) certificates. Use the certuil -8 option.
  • Create the certificate database directory, if it does not already exisist:
    # mkdir /etc/openldap/certs
  • Generate a secure password:
    # pwgen -sy 32 1 > /etc/openldap/certs/password
  • Create a new empty database, if it does not already exists:
    # certutil -d /etc/openldap/certs -N -f /etc/openldap/certs/password
  • Create a temporary random seed:
    # head -c 1024 /dev/urandom > /tmp/noise.txt
  • Create a self signed CA, valid for 10 years:
    # certutil -S -n LDAP-CA -t "C,C,C" -x \
    -f /etc/openldap/certs/password \
    -d /etc/openldap/certs \
    -z /tmp/noise.txt \
    -s "CN=LDAP-CA,OU=IT,O=Company,L=City,ST=State,C=NL" \
    -v 120 \
    -Z SHA256 \
    -g 4096
  • Create a certificate and sign with CA, valid for 3 years:
    # certutil -S -n 'OpenLDAP Server' -t ",," \
    -c LDAP-CA \
    -f /etc/openldap/certs/password \
    -d /etc/openldap/certs \
    -z /tmp/noise.txt \
    -s "CN=OpenLDAP Server,OU=IT,O=Company,L=City,ST=State,C=NL" \
    -8 "ldap.domain.tld,ldap.mgmt.domain.tld-example!" \
    -v 36 \
    -Z SHA256 \
    -g 4096
  • Trust the CA certificate:
    # certutil -M -n "LDAP-CA" -t TCu,Cu,Cu -d /etc/openldap/certs
  • Modify rights so that LDAP can read the NSS database:
    # chmod 440 /etc/openldap/certs/password
    # chown ldap. /etc/openldap/certs/*

Verify

  • List all certificates:
    # certutil -L -d /etc/openldap/certs/
  • List all private keys in the database:
    # certutil -K -d /etc/openldap/certs/ -f /etc/openldap/certs/password
  • View certificate:
    # certutil -L -d /etc/openldap/certs/ -n LDAP-CA
  • Verify certificate:
    # certutil -V -d /etc/openldap/certs -n "OpenLDAP Server" -u C
    certutil: certificate is valid

Open firewall port

  • Open port 636:
    # firewall-cmd --permanent --zone public --add-service=ldaps
    success
    # firewall-cmd --reload
    success

Install and configure OpenLDAP

  • Install required packages:
    # yum install openldap-clients openldap-servers openldap pam_ldap nss-pam-ldapd pam_krb5 sssd migrationtools openldap-devel
  • Activate LDAPS (TLS), change ldap to ldaps, only start LDAPS and LDAPI (IPC socket). And run slapd with user and group ldap:
    # vi /etc/sysconfig/slapd
    SLAPD_URLS="ldapi:/// ldaps:///"
    
    # Any custom options
    SLAPD_OPTIONS="-g ldap"
  • Modify /etc/openldap/ldap.conf:
    # vi /etc/openldap/ldap.conf
    
    BASE    dc=<domain>,dc=<tld>
    URI     ldaps://<FQDN>
    TLS_CACERTDIR  /etc/openldap/certs
    TLS_REQCERT demand
  • Use the DB config example. You can configure the DB_LOG_AUTOREMOVE directive in DB_CONFIG, but If the log files are removed automatically, recovery after a catastrophic failure is likely to be impossible.:
    # install -m 644 -o ldap -g ldap /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
  • Start OpenLDAP:
    slaptest -u
    systemctl start slapd
    systemctl enable slapd
  • Add required schema's:
    core.schema		OpenLDAP core (required)
    cosine.schema		Cosine and Internet X.500 (useful)
    inetorgperson.schema	InetOrgPerson (useful)
    nis.schema		Network Information Services (FYI)
    
    
    ## already exists:
    # ldapadd -Q -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/core.ldif
    
    # ldapadd -Q -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
    # ldapadd -Q -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif
    # ldapadd -Q -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
  • Generate an LDAP root password, you need this hash in the next steps:
    # slappasswd
    New password: <password>
    Re-enter new password: <password>
    {SSHA}<hash>
  • Export variables used in next steps:
    # export MYHASH="{SSHA}your-hash"
    # export MYDOMAIN=your-domain
    # export MYTLD=your-tld
  • olcDatabase={0}config: Add a root password, and modify the olcAccess in order to (at least) require a password using simple authentication
    # ldapmodify -Q -Y EXTERNAL -H ldapi:/// <<EOF
    dn: olcDatabase={0}config,cn=config
    changetype: modify
    add: olcRootPW
    olcRootPW: ${MYHASH}
    -
    replace: olcAccess
    olcAccess: {0}to * 
           by dn.base="cn=Manager,dc=${MYDOMAIN},dc=${MYTLD}" manage
           by * none
    EOF
  • olcDatabase={1}monitor: Change the monitor ACL:
    # ldapmodify -H ldapi:/// -x -D "cn=config" -W <<EOF
    dn: olcDatabase={1}monitor,cn=config
    changetype: modify
    replace: olcAccess
    olcAccess: {0}to *
           by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read
           by dn.base="cn=Manager,dc=${MYDOMAIN},dc=${MYTLD}" read
           by * none
    EOF
  • olcDatabase={2}hdb: Change the standard DN suffix and root password
    # ldapmodify -H ldapi:/// -x -D "cn=config" -W <<EOF
    dn: olcDatabase={2}hdb,cn=config
    changetype: modify
    replace: olcSuffix
    olcSuffix: dc=${MYDOMAIN},dc=${MYTLD}
    -
    replace: olcRootDN
    olcRootDN: cn=Manager,dc=${MYDOMAIN},dc=${MYTLD}
    -
    add: olcRootPW
    olcRootPW: ${MYHASH}
    EOF
  • olcDatabase={2}hdb: configure indexing:
    # ldapmodify -H ldapi:/// -x -D "cn=config" -W <<EOF
    dn: olcDatabase={2}hdb,cn=config
    changetype: modify
    replace: olcDbIndex
    olcDbIndex: objectClass eq,pres
    olcDbIndex: ou,cn,mail,surname,givenname eq,pres,sub
    olcDbIndex: uid,memberUid,gidNumber eq
    -
    EOF
  • Modify the configration so that users can change their own passwords, but cannot view others':
    # ldapmodify -H ldapi:/// -x -D "cn=config" -W <<EOF
    dn: olcDatabase={2}hdb,cn=config
    changetype: modify
    replace: olcAccess
    olcAccess: {0}to attrs=userPassword,shadowLastChange
           by dn.exact="cn=Manager,dc=${MYDOMAIN},dc=${MYTLD}" write
           by self =xw
           by anonymous auth
           by * none
    olcAccess: {1}to *
           by dn.exact="cn=Manager,dc=${MYDOMAIN},dc=${MYTLD}" write
           by self read
           by users read
           by * none
    EOF
  • Modify the TLS configuration:
    # ldapmodify -H ldapi:/// -x -D "cn=config" -W <<EOF
    dn: cn=config
    changetype: modify
    replace: olcTLSCipherSuite
    olcTLSCipherSuite: HIGH
    -
    replace: olcTLSProtocolMin
    olcTLSProtocolMin: 3.1
    -
    replace: olcDisallows
    olcDisallows: bind_anon
    -
    replace: olcIdleTimeout
    olcIdleTimeout: 120
    EOF
  • olcDatabase={-1}frontend: Due to a bug i was not able to perform this step… I had to manually edit the olcDatabase={-1}frontend.ldif file and set olcDatabase to “olcDatabase: {-1}frontend”.
  • Set global options: Some backend types, such as frontend and monitor use a hard-coded suffix which may not be overridden in the configuration. Access controls defined in the frontend are appended to all other databases' controls. Configure password and require LDAPv3:
    # ldapmodify -H ldapi:/// -x -D "cn=config" -W <<EOF
    dn: olcDatabase={-1}frontend,cn=config
    changetype: modify
    add: olcPasswordHash
    olcPasswordHash: ${MYHASH}
    -
    add: olcRequires
    olcRequires: LDAPv3 authc
    EOF
  • Accept only TLS:
    # ldapmodify -H ldaps://<FQDN> -x -D "cn=config" -W <<EOF
    dn: cn=config
    changetype: modify
    add: olcSecurity
    olcSecurity: tls=1
    EOF

Test server config, restart and test connectivity

  • Restart slapd:
    # slaptest -u
    # systemctl restart slapd
  • Test connection and verify certificate. Export ca certificate for testing with openssl:
    # certutil -L -d /etc/openldap/certs -n "LDAP-CA" -a > /tmp/ca.crt
     # openssl s_client -connect localhost:636 -showcerts -CAfile /tmp/ca.crt
    ...
        Verify return code: 0 (ok)
    
    # ldapwhoami -H ldaps://<FQDN> -x -D "cn=Manager,dc=<domain>,dc=<tld>" -W
    
    # ldapsearch -H ldaps://<FQDN> -x -D "cn=Manager,dc=<domain>,dc=<tld>" -W
    
    # ldapsearch -H ldap://<FQDN> -x -D "cn=Manager,dc=<domain>,dc=<tld>" -W
    ldap_bind: Confidentiality required (13)
    	additional info: TLS confidentiality required
    
    
    or:
    ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)
    
    
    # openssl s_client -connect localhost:636 2>&1 | openssl x509 -text | grep DNS
    

Create basic structure

  • Load the basic structure:
    # ldapadd -H ldaps://<FQDN> -x -W -D "cn=Manager,dc=<domain>,dc=<tld>" -f base.ldif
    
    dn: ,dc=<domain>,dc=<tld>
    dc: <domain>
    objectClass: top
    objectClass: domain
    
    dn: ou=people,dc=<domain>,dc=<tld>
    ou: people
    objectClass: top
    objectClass: organizationalUnit
    
    dn: ou=groups,dc=<domain>,dc=<tld>
    ou: groups
    objectClass: top
    objectClass: organizationalUnit
    
    dn: ou=hosts,dc=<domain>,dc=<tld>
    ou: hosts
    objectClass: top
    objectClass: organizationalUnit

User management

Verify cipher suites / analyse network traffic

  • nmap test cipher suites:
    # nmap --script ssl-enum-ciphers -p 636 ldap.server.tld
    
    Starting Nmap 6.40 ( http://nmap.org ) at 2015-09-07 20:54 CEST
    Nmap scan report for ldap.server.tld ()
    Host is up (0.00025s latency).
    PORT    STATE SERVICE
    636/tcp open  ldapssl
    | ssl-enum-ciphers:
    |   TLSv1.2:
    |     ciphers:
    |       TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - strong
    |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - strong
    |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - strong
    |       TLS_RSA_WITH_3DES_EDE_CBC_SHA - strong
    |       TLS_RSA_WITH_AES_128_CBC_SHA - strong
    |       TLS_RSA_WITH_AES_256_CBC_SHA - strong
    |       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA - strong
    |       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA - strong
    |     compressors:
    |       NULL
    |_  least strength: strong
    MAC Address:  (QEMU Virtual NIC)
    
    Nmap done: 1 IP address (1 host up) scanned in 0.17 seconds
  • tshark:
    tshark -f "tcp port 636" -i any
openldap_centos7_tls.txt · Last modified: 2015/09/15 07:16 by admin