Configurar slaves OpenLDAP para aplicar lock de usuarios por logins fallidos (ppolicy)
Quienes utilicen LDAP para autenticación de servidores/workstations, seguramente se han topado o se toparan con el overlay ppolicy, el cual permite configurar policies de password como largo mínimo, complegidad, history, lock por cantidad de intentos, etc. Cómo habilitar y configurar ppolicy está bastante bien explicado en diversos sites como este, por lo que no lo incluiré acá. El problema es que ninguno explica bien qué hacer si tenes servidores slave que se utilizan para autenticación.

Cuando tenés una configuración master -> slaves, los slaves son read-only, por lo que no guardarán ningún atributo por si mismos, sino que replican lo que tiene el master. Esto es, si por ejemplo están utilizando un slave como ldap server, varios intentos fallidos de login nunca bloquearán la cuenta, porque el tipo no guardará el atributo pwdAccountLockedTime en ningún lado. Esto es lo mismo que sucede cuando intentan hacer un change password y están usando un slave, el pass no se puede cambiar.

Para solucionar este problema, OpenLDAP provee la alternativa de que los slave redirijan los updates al master. Esto es, si alguien quiere actualizar un valor en el slave, el slave redirigirá el update al ldap master, y lo obtendrá por replicación. La solución comprende utilizar updateref, enconjunto con el overlay chain y la opción ppolicy_forward_updates, donde:
  • updateref "<master ldap server>" indica a qué servidor LDAP enviar los updates (se utiliza sólo en slaves). Esta opción por sí sola retorna al cliente la URL del master ldap, y es el cliente quien se debe encargar de tomar esa URL y hacer el update allí.
  • El overlay chain facilita lo anterior, haciendo que el update lo haga el mismo slave, en lugar de retornar la URL del master al cliente. Con chain podemos configurar que si alguna acción dispara un update, el slave se conecte al master y lo aplique. Para ello, hay que configurar un usuario de binding que en el master tenga permisos de escritura para los atributos que deberá actualizar. Este overlay también se usa para resolver DNs que no están replicados en el slave, ya que sin él, OpenLDAP retornará un redirect que el cliente final deberá seguir.
  • ppolicy_forward_updates es la opción del overlay ppolicy que le indica que debe forwardear los password failures, ya que sino asume que es un master y no dispara el hook de redirect.

Veamos todo junto en un ejemplo, donde el ldap master se llama masterserver.dvpem.org. Esta config es para el slave y va en slapd.conf. Incluí sólo las líneas relevantes de la configuración, no es una configuración slapd.conf completa.

IMPORTANTE:
  • La configuración del overlay chain debe ir lo más arriba posible, antes de la configuración de cualquier base de datos y de la configuración de replicación.
  • updateref debe ir luego de la configuración de replicación (syncrelp).
  • El usuario que utilicen para el overlay chain debe tener permiso manage sobre los atributos de password. Por ejemplo, este es el permiso necesario para un user SlaveUpdater:
    {0}to dn.subtree="ou=people,dc=dvpem,dc=org" attrs=pwdChangedTime,pwdAccountLockedTime,pwdFailureTime,pwdHistory,pwdGraceUseTime,pwdReset by dn.base="cn=SlaveUpdater,dc=dvpem,dc=org" manage by * +0 break
...
#importamos el módulo que contiene el overlay chain
moduleload back_ldap.la

#cargamos el overlay
overlay chain
#definimos cuál es la URL del master y con qué usuario bindear. Recuerden que el user debe tener permiso manage.
chain-uri "ldap://masterserver.dvpem.org"
chain-idassert-bind     bindmethod="simple"
                        binddn="cn=SlaveUpdater,dc=dvpem,dc=org"
                        credentials="elpassdeSlaveUpdater"
                        mode="self"
                        #starttls=yes        #necesario si usamos ldaps como protocolo
                        #tls_reqcert=allow   #necesario si usamos ldaps como protocolo
chain-return-error TRUE

...
...

#cargamos el overlay ppolicy
moduleload ppolicy.la
overlay ppolicy

#indicamos dónde está la pólicy default de password (largo, cantidad de intentos, etc). Misma config que en el master.
ppolicy_default "cn=default,ou=Policies,dc=dvpem,dc=org"

#indicamos que se deben forwardear los updates al master
ppolicy_forward_updates

...
...

#configuración estándar syncrelp
syncrelp rid=001
    provider=ldap://masterserver.dvpem.org
    type=refreshAndPersist
    interval=00:00:02:00
    retry="30 10 120 +"
    searchbase="dc=dvpem,dc=org"
    attrs="*,+"
    bindmethod=simple
    binddn="cn=replicator,dc=dvpem,dc=org"
    credentials=elpassdelreplicator
    tls_reqcert=allow

#especificamos a dónde redirigir los updates
updateref "ldap://masterserver.dvpem.org"

Si tienen configurado el slave para utilizar la base cn=config, deberán ejecutar el diguiente ldif (aquí lo llamo enable-ppolicy-forward.ldif):
dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: back_ldap

dn: olcOverlay={0}chain,olcDatabase={-1}frontend,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcChainConfig
olcOverlay: {0}chain
olcChainCacheURI: FALSE
olcChainMaxReferralDepth: 1
olcChainReturnError: TRUE

dn: olcDatabase=ldap,olcOverlay={0}chain,olcDatabase={-1}frontend,cn=config
changetype: add
objectClass: olcLDAPConfig
objectClass: olcChainDatabase
olcDatabase: ldap
olcDbURI: "ldaps://masterserver.dvpem.org"
olcDbStartTLS: none  starttls=no
olcDbIDAssertBind: mode=self
  flags=prescriptive,proxy-authz-non-critical 
  bindmethod=simple
  timeout=0
  network-timeout=0
  binddn="cn=SlaveUpdater,dc=dvpem,dc=org"
  credentials="elpassdeSlaveUpdater"
  keepalive=0:0:0
  starttls=yes
  tls_cert="/etc/ldap/ssl/certificado.pem"
  tls_key="/etc/ldap/ssl/certificado.pem"
  tls_cacert="/etc/ldap/ssl/certificado.pem"
  tls_reqcert=allow
  tls_cipher_suite=NORMAL
olcDbRebindAsUser: FALSE
olcDbChaseReferrals: TRUE
olcDbTFSupport: no
olcDbProxyWhoAmI: FALSE
olcDbProtocolVersion: 3
olcDbSingleConn: FALSE
olcDbCancel: abandon
olcDbUseTemporaryConn: FALSE
olcDbConnectionPoolMax: 16
olcDbSessionTrackingRequest: FALSE
olcDbNoRefs: FALSE
olcDbNoUndefFilter: FALSE

dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcUpdateRef
olcUpdateRef: ldaps://masterserver.dvpem.org

dn: olcOverlay={0}ppolicy,olcDatabase={1}hdb,cn=config
changetype: modify
replace: olcPPolicyForwardUpdates
olcPPolicyForwardUpdates: TRUE

Ejecutamos el ldif con ldapmodify (cambien el usuario admin por el que corresponda a ustedes):
ldapmodify -D "cn=admin,cn=config" -W -f enable-ppolicy-forward.ldif

Como siempre, espero que les haya resultado útil. Yo perdí un buen rato hasta entender cómo funciona esta lógica.