Problema

En entornos mixtos Windows / Linux es frecuente que una aplicación Linux necesite consultar usuarios y grupos en un dominio Active Directory (AD). La comunicación LDAP sin cifrado funciona sin problemas, pero cuando se intenta forzar LDAPS (LDAP sobre TLS/SSL, puerto 636) aparecen errores de verificación de certificado como:

CONNECTED(00000003)
depth=0 CN = my.server.dc verify error:num=20:unable to get local issuer certificate
depth=0 CN = my.server.dc verify error:num=21:unable to verify the first certificate

Este mensaje indica que el cliente Linux no confía en la cadena de certificación que presenta el controlador de dominio. El patrón se repite en muchos setups: el certificado del DC se ha exportado, se ha copiado al host Linux y se ha ejecutado update-ca-certificates, pero openssl s_client sigue sin validar la cadena. El problema no es exclusivo de un dominio concreto; cualquier organización que use certificados internos emitidos por su propia AD Certificate Services puede tropezar con la misma situación.

Causa

  1. Certificado raíz no disponible en el almacén de confianza
    Los controladores de dominio suelen usar un certificado emitido por la CA interna de AD. Si el host Linux solo tiene el certificado del DC (el “leaf”) y no el certificado raíz o intermedio que lo firmó, la cadena está incompleta y la verificación falla.

  2. Formato o ubicación incorrecta del certificado
    update-ca-certificates solo procesa archivos con extensión .crt o .pem dentro de /usr/local/share/ca-certificates/ (o la ruta configurada). Renombrar el archivo sin cambiar el contenido es suficiente, pero si se coloca en otro directorio o se deja la extensión .cer, el script lo ignora.

  3. Uso de un algoritmo o longitud de clave no soportado
    Algunas versiones de OpenSSL rechazan certificados con SHA‑1 o claves menores a 2048 bits cuando la política de seguridad del sistema está endurecida. El error se manifiesta como “unable to get local issuer certificate”.

  4. Nombre del CN/SAN que no coincide con el FQDN usado en la conexión
    Si el certificado del DC tiene un SAN que no incluye my.server.dc y la conexión se hace a ese nombre, la verificación de host falla después de la cadena de confianza, aunque el mensaje de error sea el mismo.

  5. Configuración de OpenSSL que omite la búsqueda de certificados del sistema
    Variables de entorno como SSL_CERT_FILE o SSL_CERT_DIR pueden redirigir la búsqueda a rutas vacías, provocando que el cliente ignore los certificados instalados.

Solución

La estrategia general consiste en garantizar que el cliente Linux tenga acceso a toda la cadena de confianza (raíz + intermedios) y que la configuración de OpenSSL apunte a ella. Los pasos siguientes funcionan en la mayoría de distribuciones basadas en Debian/Ubuntu y en Red Hat/CentOS con ligeras variaciones de ruta.

1. Exportar la cadena completa desde AD

  1. En el servidor Windows abre la consola de Certification Authority.
  2. Exporta el certificado raíz (CA) y, si existe, cualquier certificado intermedio en formato DER o Base‑64.
  3. Exporta también el certificado del controlador de dominio (puede obtenerse con certutil -store My o simplemente copiando el archivo .cer que ya tienes).

2. Convertir a PEM y colocar en el directorio correcto

# Convertir DER a PEM (si fuera necesario)
openssl x509 -inform DER -in ca_root.der -out ca_root.pem
openssl x509 -inform DER -in ca_intermediate.der -out ca_intermediate.pem
openssl x509 -inform DER -in dc_cert.der -out dc_cert.pem

# Copiar al directorio de CA del sistema
sudo cp ca_root.pem ca_intermediate.pem /usr/local/share/ca-certificates/
sudo chmod 644 /usr/local/share/ca-certificates/*.pem

En Red Hat la ruta es /etc/pki/ca-trust/source/anchors/ y el comando es update-ca-trust.

3. Actualizar el almacén de confianza

sudo update-ca-certificates   # Debian/Ubuntu
# o
sudo update-ca-trust extract   # Red Hat/CentOS

El comando mostrará cuántos certificados nuevos se añadieron. Verifica que los archivos aparecen en /etc/ssl/certs/.

4. Forzar la verificación de la cadena completa

Ejecuta de nuevo openssl s_client pero especifica la ruta del almacén para asegurarte de que se usa el nuevo CA:

openssl s_client -connect my.server.dc:636 -CApath /etc/ssl/certs -showcerts

Si la cadena está completa, la salida mostrará Verify return code: 0 (ok).

5. Ajustar la configuración de la aplicación LDAP

Muchas aplicaciones leen /etc/ldap/ldap.conf o /etc/openldap/ldap.conf. Añade o verifica los siguientes parámetros:

TLS_CACERT   /etc/ssl/certs/ca-certificates.crt
TLS_REQCERT  demand   # o hard para forzar la validación

En caso de que la aplicación use ldapsearch:

ldapsearch -H ldaps://my.server.dc -b "dc=example,dc=com" -D "[email protected]" -W -ZZ

El flag -ZZ inicia StartTLS (para LDAP sobre puerto 389) y -H ldaps:// fuerza LDAPS.

6. Solucionar problemas de nombre

Si el certificado del DC no contiene el FQDN usado, crea un alias en /etc/hosts que coincida con un SAN válido, o solicita a la CA que incluya el nombre correcto en el certificado.

7. Revisar políticas de OpenSSL

En sistemas con openssl.cnf endurecido, busca la sección system_default_sect y verifica que MinProtocol y CipherString permitan TLS 1.2 o superior y que no excluyan SHA‑1 si tu CA lo usa. Ajusta solo si es estrictamente necesario.

Cuándo aplicar esta solución

  • Síntomas: openssl s_client devuelve unable to get local issuer certificate o unable to verify the first certificate al conectar a ldaps://<dc>:636.
  • Entorno: Linux cliente que necesita autenticarse contra AD mediante LDAPS, con certificados internos emitidos por la CA de la organización.
  • No aplica: Cuando el dominio usa certificados públicos de una CA reconocida (p. ej., DigiCert) o cuando la aplicación LDAP no permite especificar un CA externo. En esos casos basta con confiar en los almacenes predeterminados del sistema.

Código

# 1. Exportar y convertir certificados (ejemplo con DER)
openssl x509 -inform DER -in ca_root.der -out ca_root.pem
openssl x509 -inform DER -in ca_intermediate.der -out ca_intermediate.pem

# 2. Copiar al almacén de confianza
sudo cp ca_root.pem ca_intermediate.pem /usr/local/share/ca-certificates/
sudo chmod 644 /usr/local/share/ca-certificates/*.pem

# 3. Actualizar el almacén
sudo update-ca-certificates

# 4. Probar la conexión LDAPS
openssl s_client -connect my.server.dc:636 -CApath /etc/ssl/certs -showcerts

Verificación

  1. Almacén actualizado: grep -i "my.server.dc" -R /etc/ssl/certs debe devolver al menos un archivo que contenga el certificado del DC.
  2. Conexión exitosa: openssl s_client … muestra Verify return code: 0 (ok).
  3. Aplicación LDAP: Ejecuta una consulta real (ldapsearch u otra herramienta) y confirma que la autenticación se realiza sin advertencias de certificado.
  4. Logs del servidor AD: En el visor de eventos de AD verifica que la conexión TLS se haya registrado como exitosa.

Notas adicionales

  • Renovar certificados: Cuando la CA interna renueve su certificado raíz, repite el proceso. Los clientes que aún tengan el antiguo seguirán fallando.
  • Múltiples dominios: Si tu red tiene varios controladores con certificados diferentes, incluye todos los leafs en el mismo directorio antes de ejecutar update-ca-certificates.
  • Depuración: Usa openssl s_client -debug para obtener trazas de handshake más detalladas; a menudo revelan si falta un certificado intermedio.
  • Automatización: En entornos con gestión de configuración (Ansible, Puppet) coloca los archivos .pem en la ruta adecuada y ejecuta el comando de actualización como parte del playbook.
  • Política de seguridad: Si tu organización requiere TLS 1.3, asegúrate de que tanto el DC como la versión de OpenSSL del cliente lo soporten; de lo contrario, fuerza TLS 1.2 con -tls1_2.

Con la cadena completa en el almacén de confianza y la configuración adecuada, LDAPS funciona de forma segura y transparente, eliminando el temido error unable to verify the first certificate y permitiendo que cualquier aplicación Linux consuma datos de Active Directory sin exponer credenciales en texto plano.