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.