Estuve peleando un rato con certificados autofirmados (self-signed certificates) para lograr que los clientes se comuniquen con Openldap usando TLS.

Recientemente hice una migración de un Primary Domain Controller, el cual tenía OpenLDAP y algunos clientes configurados sin TLS con ldap://server.domain y otros con SSL con ldaps://server.domain. Habían unos certificados «self-signed» que se presentaban para autenticar a los clientes con SSL todo esto en una versión antigua de openldap.

Sin embargo, OpenLDAP deprecó el uso de ldaps:// (puerto 636) y a partir de su versión 2.0 en el mismo puerto ‘389’ se manejan conexiones con y sin encriptación como lo indica la documentacion oficial, ahora para encriptar la comunicación se usa la configuración StartTLS.

Adicional a estos cambios, la configuración de Openldap ya no se centraliza en el archivo ldap.conf (servidor), sino en preferiblemente en la estructura cn=config que se manipula de una forma particular (un tanto incómoda).

Para utilizar certificados autofirmados y que estos sean accesibles para los clientes debemos:

  1. Generar los certificados autofirmados (self-signed) como indica el HowTo de OpenLDAP TLS o también este buen tutorial en Digital Ocean
  2. Agregar los certificados, key  y el CA en la configuración de cn=config
  3. Configurar los clientes (de ser necesario).
  4. Verificar los permisos de los certificados
  5. Reiniciar Openldap

Agregar los certificados vía cn=config

Genere un archivo add-certs.ldif con el siguiente contenido:

dn: cn=config
changetype: modify
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ssl/certs/ca_server.pem
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ssl/certs/ldap_server.pem
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ssl/private/ldap_server.key

Y ejecute:

ldapmodify -H ldapi:// -Y EXTERNAL -f addcerts.ldif

Verifique que los paths en el archivo generado concuerdan con la ubicación de sus certificados y que además que el usuario openldap pueda acceder a los mismos (verifique los permisos además de las rutas)

Durante el proceso, obtuve los siguientes errores:

Es muy importante reiniciar o invalidar el caché de nscd tras cada cambio descrito en este documento para evitar problemas. Pueden utilizar:

  • service nscd restart
  • nscd -i groups
  • nscd -i passwd

Si no realizan esto, podrían experimentar el error : Could not connect to any LDAP server as (null) – Can’t contact LDAP server

Una vez se haya invalidado la caché de nscd, espere unos minutos y pruebe nuevamente.

additional info: TLS already started

Error

root@servidor: ~ # ldapsearch -ZZ -x -H ldaps://servidor.dominio.example
ldap_start_tls: Operations error (1)
additional info: TLS already started

Solución

O bien usamos la opción -ZZ y ldap://  o utilizamos ldaps:// sin la opción -ZZ pero no ambas juntas:

root@servidor: ~ # ldapsearch -ZZ -x -H ldap://servidor.dominio.example
ldapsearch -x -H ldaps://servidor.dominio.example

Otros errores

  • TLS: peer cert untrusted or revoked (0x42)
  • ldap_sasl_bind(SIMPLE): Can’t contact LDAP server (-1)
  • TLS: can’t connect: (unknown error code)
  • connection_read(13): unable to get TLS client DN, error=49 id=5

Estos errores estaban asociados a lo mismo, pueden obtenerse iniciando en modo debug el servidor de openldap:

#Iniciar Openldap en modo debug
slapd -h "ldapi:/// ldap:// ldaps://" -u openldap -g openldap -d 65 -F /etc/ldap/slapd.d/ -d 65

#Realizar debug desde clientes con -d1 hasta -d8
ldapsearch -v -H ldaps://servidor.dominio.example/ -D cn=admin,dc=dominio,dc=example -W -x -b dc=dominio,dc=example -d1

Error (utilizando el modo debug d -1)

ldapsearch -ZZ -x -H ldap://servidor.dominio.example -D "cn=admin,dc=dominio,dc=example" -W -d 1
....
ldap_msgfree
TLS: peer cert untrusted or revoked (0x42)
...

Solución

El certificado no está bien configurado en el servidor / cliente. Verificar:

  • Que el certificado, key y CA están correctamente configurados en cn=config
  • Que el certificado está bien configurado en ldap.conf (cliente y servidor)
  • Que el certificado es válido-> openssl verify -CApath  /etc/ldap/ssl/ servidor.pem
  • Que los permisos al path y certificado sean correctos (cliente y servidor)

Mi implementación luce así:

cn=config

ldapsearch -LLLQY EXTERNAL -H ldapi:/// -b cn=config |less

dn: cn=config
objectClass: olcGlobal
cn: config
olcArgsFile: /var/run/slapd/slapd.args
olcLogLevel: none
olcPidFile: /var/run/slapd/slapd.pid
olcTLSCACertificateFile: /etc/ldap/ssl/servidorCA.pem
olcTLSCertificateFile: "/etc/ldap/ssl/servidor.pem"
olcTLSCertificateKeyFile: /etc/ldap/ssl/servidor.key

ldap.conf (servidor)

uri ldap://servidor.dominio.example ldap://servidor1.dominio.example
base dc=dominio,dc=example

ldap_version 3
sizelimit    0
timeout      10
bind_timeout 10
bind_policy  soft
deref        never

loglevel        0
logfile	/var/log/ldap.log

nss_base_passwd ou=users,dc=dominio,dc=example?sub
nss_base_shadow ou=users,dc=dominio,dc=example?sub
nss_base_group  ou=groups,dc=dominio,dc=example?one

pam_login_attribute  uid
pam_password         md5
pam_member_attribute memberuid
pam_filter           objectClass=posixAccount

ssl off
tls_reqcert    allow
tls_cacertfile /etc/ldap/ssl on
TLSCACertificateFile    /etc/ldap/ssl/servidor.pem
#TLSCipherSuite NORMAL
TLSCipherSuite +RSA:+AES-256-CBC:+SHA1

ldap.conf (cliente)

uri ldaps://servidor.dominio.example
base dc=dominio,dc=example

ldap_version 3
timeout      10
bind_timeout 10
bind_policy  soft
deref        never

nss_base_passwd dc=dominio,dc=example?sub
nss_base_shadow dc=dominio,dc=example?sub
nss_base_group  dc=dominio,dc=example?one

pam_login_attribute  uid
pam_password         md5
pam_member_attribute memberuid
pam_filter           objectClass=posixAccount

ssl            on
TLS_CACERT /etc/ldap/ssl/servidor.pem
#TLS_CACERTDIR /etc/ldap/ssl/
# valida el certificado
TLS_REQCERT demand