Replicación y Accesos en OpenLDAP (Parte I)
Esta entrada ha surgido de la implementación de un servicio de DHCP con pools en failover sobre un backend de configuración contenido en LDAP. Junto con esta también se ha publicado Cómo configurar un servidor DHCP con backend sobre OpenLDAP, actualizaciones DDNS para PowerDNS y las ventajas que ofrece.
1.LDAP
En este POST se van a tratar cómo controlar los accesos en un servicio LDAP, concretamente en OpenLDAP y las distintas formas de replicación.
1.1.Modos de replicación
Estos son los modos que vienen en el manual oficial de OpenLDAP:
syncrepl
delta-syncrepl
N-way Multi-Master
Mirror mode
1.1.1.syncrepl
Este es el típico modo maestro-esclavo, llamado en LDAP provider-consumer.
Este tipo de replicación copia un fragmento del DIT en el consumer haciendo lecturas en el provider, por tanto la configuración de cómo se va a replicar se hace en el consumer y no en el provider.
Funciona con cualquier backend de bases de datos de LDAP.
Solo se permiten escrituras en el provider.
1.1.2.delta-syncrepl
Este tipo de replicación es igual que syncrepl pero no transfiere los objetos completos o los valores de los atributos de los objetos que ha cambiado, sino solo las diferencias que se hayan producido. Este modo sí necesita configuración en ambos servidores.
Si ha pasado mucho tiempo entre el último checkpoint, será necesario un syncrepl para igualar los cambios.
Al igual que el anterior tampoco permite escrituras en el consumer.
1.1.3.Multi-Master
Mantiene sincronizados ambos servidores LDAP y permite escritura en ambos, aunque se pueden romper las garantías de la consistencia de datos del modelo de directorio ligero.
1.1.4.Mirror mode
Igual que el modo multi-máster pero sí garantiza la consistencia de los datos debido a que no se permite la escritura en ambos. Hay que poner un proxy frontal que mande las escrituras a uno de los dos. En caso de que uno falle, el frontal debe ser consciente de ello para enviar las escrituras al que ha quedado en pie. En el momento que el servidor caído vuelva a estar operativo, este se actualizará con los nuevos cambios.
2.Usuarios y Control de acceso
Guardando relación con el POST de ISC-DCHP-Server con backend de LDAP, y como ejemplo, necesito un par de usuarios con ciertos privilegios sobre el árbol del servidor LDAP de DNS1. Uno que pueda leer la configuración del servidor DHCP, este usuario solo tendrá privilegios de lectura sobre su rama, y otro que se usará con la finalidad de replicar el servicio.
Toda la documentación respecto a este apartado se encuentra aquí control de acceso.
Creando un par de usuarios y otorgándole privilegios creo que es más que suficiente para que tú sigas a partir de la documentación oficial.
2.1.Creación de los usuarios
2.1.1.Para el demonio DHCP
El usuario con privilegios de lectura sobre la configuración del DCHP será “cn=dhcp, ou=Users, ou=IPv4 DHCP Servers, dc=lab, dc=linuxarena, dc=net”, esa configuración se encuentra sobre la unidad organizativa “ou=IPv4 DHCP Servers,dc=lab,dc=linuxarena,dc=net”.
Primero necesito la unidad organizativa para alojar ese usuario:
root@dns1:~# ldapadd -xwlinuxarena -D 'cn=admin,dc=lab,dc=linuxarena,dc=net' dn: ou=Users,ou=IPv4 DHCP Servers,dc=lab,dc=linuxarena,dc=net ou: Users objectClass: top objectClass: organizationalUnit adding new entry "ou=Users,ou=IPv4 DHCP Servers,dc=lab,dc=linuxarena,dc=net" root@dns1:~#
Para generar la contraseña que necesitará el usuario uso ‘slappasswd’:
root@dns1:~# slappasswd -h {SSHA} -s linuxarena {SSHA}Gptufd3vHWVXaYsyGOq5ME1g9Pf2JaoF
Por último, inserto el usuario:
root@dns1:~# ldapadd -xwlinuxarena -D 'cn=admin,dc=lab,dc=linuxarena,dc=net' dn: cn=dhcp,ou=Users,ou=IPv4 DHCP Servers,dc=lab,dc=linuxarena,dc=net ou: Users objectClass: top objectClass: organizationalRole objectClass: simpleSecurityObject userPassword: {SSHA}Gptufd3vHWVXaYsyGOq5ME1g9Pf2JaoF adding new entry "cn=dhcp,ou=Users,ou=IPv4 DHCP Servers,dc=lab,dc=linuxarena,dc=net" root@dns1:~#
2.1.2.Para la replicación del LDAP
root@dns1:~# ldapadd -xwlinuxarena -D 'cn=admin,dc=lab,dc=linuxarena,dc=net' dn: cn=replicator,dc=lab,dc=linuxarena,dc=net objectClass: top objectClass: organizationalRole objectClass: simpleSecurityObject cn: replicator userPassword: {SSHA}kbzV4htS/pkz0OECG0jvFqcg+Z8HrKBk adding new entry "cn=replicator,dc=lab,dc=linuxarena,dc=net" root@dns1:~#
2.2.Control de acceso
Un breve resume a modo de introducción para comprender muy por encima como se controlan los accesos a las distintas zonas del DIT.
2.2.1.Políticas por defecto
En el servidor OpenLDAP la política de acceso por defecto es permitir leer todo a todos y el ‘rootDN’ tiene privilegios completos sobre todo.
2.2.2.Cómo se evalúa la lista de acceso
La lista de acceso es una línea de la forma: “<what> <who> <access> [control := (stop | continue | break)]”.
El control de acceso del demonio ‘slapd’ compara la entrada sobre la que se está accediendo con el “<what>” hasta que encuentra una coincidencia. Cuando es encontrada, recorre su lista de acceso hasta que el primer “who” coincide con el usuario que está accediendo. Entonces aplica el acceso que contiene.
Si no se define ninguna lista de acceso para una base de datos, entonces la lista de acceso implícita para esa base de datos es: access to * by * read;
Por el contrario si se define al menos una oclAccess para esa base de datos, entonces la última lista de acceso implícita para esa base de datos es: access to* by * none;
Es una buena estrategia para la creación de las primeras reglas, poner las más genéricas y permisivas al final de la lista de control y las más específicas y restrictivas al principio, aunque esta regla no es aplicable al 100% de los casos.
Por último, el parámetro de control establece qué hacer una vez leída la lista de acceso.
‘stop’, por defecto, hace que cuando se lea la lista, ya no se lean más listas.
‘continue’ sigue leyendo los ‘who’ de la línea a pesar de haber encontrado coincidencia.
‘break’ sigue leyendo las demás listas de acceso.
2.3.Creación de listas de acceso
2.3.1.Acceso a la configuración del DCHP
Para el ejemplo de la entrada, como la unidad organizativa del servidor DHCP tiene datos como MACs de dispositivos, sería deseable que no pueda leerse por usuario anónimos del servidor LDAP para evitar que nos hagan spoofing en la red.
Si echamos un vistazo a la configuración que trae por defecto OpenLDAP en Debian (Stretch) veremos que al final se permite leer todo, por tanto, como no hay una ACL sobre la OU del servidor DHCP deberemos crearla justo encima de esta última regla {2}.
Este es el contenido de la configuración del LDAP que tengo en la máquina:
root@dns1:~# ldapsearch -Y EXTERNAL -H ldapi:/// -b "olcDatabase={1}mdb,cn=config" SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 # extended LDIF # # LDAPv3 # base <olcDatabase={1}mdb,cn=config> with scope subtree # filter: (objectclass=*) # requesting: ALL # # {1}mdb, config dn: olcDatabase={1}mdb,cn=config objectClass: olcDatabaseConfig objectClass: olcMdbConfig olcDatabase: {1}mdb olcDbDirectory: /var/lib/ldap olcSuffix: dc=lab,dc=linuxarena,dc=net olcAccess: {0}to attrs=userPassword by self write by anonymous auth by * none olcAccess: {1}to attrs=shadowLastChange by self write by * read olcAccess: {2}to * by * read olcLastMod: TRUE olcRootDN: cn=admin,dc=lab,dc=linuxarena,dc=net olcRootPW: {SSHA}Fz1z+Qj/939aKUeOFLfnG6bfBz0P7Da6 olcDbCheckpoint: 512 30 olcDbIndex: objectClass eq olcDbIndex: cn,uid eq olcDbIndex: uidNumber,gidNumber eq olcDbIndex: member,memberUid eq olcDbIndex: dhcpHWAddress eq olcDbIndex: dhcpClassData eq olcDbMaxSize: 1073741824
Se puede ver que la lista de acceso tiene un índice en cada atributo ‘{i}’.
Este índice es auto-generado por slapd, pero cuando tengamos que borrar o modificar una de esas entradas podemos hacer referencia a ese privilegio de acceso únicamente por su índice.
Para insertar también lo usaremos, de modo que si inserto un atributo de esta forma:
dn: olcDatabase={1}mdb,cn=config changetype: modify add: olcAccess olcAccess: {2}to dn.subtree="ou=IPv4 DHCP Servers,dc=lab,dc=linuxarena,dc=net" by users read by * none
Este atributo se pondrá en la posición {2}, desplazando a “to * by * read a la {3}”
Con este último cambio cualquier usuario que se haya autenticado contra el servicio de LDAP (who=users) podría leer (access=read) la rama completa (what=dn.subtree…), no así el resto.
Para borrarlo el ldif sería este:
dn: olcDatabase={1}mdb,cn=config changetype: modify delete: olcAccess olcAccess: {2}
Eso volvería a dejar, en este caso particular, las entradas como justo en el estado previo a la inserción anterior.
La rama del servidor DHCP responde a esta estructura:
Los usuarios con acceso al DHCP van a estar en “ou=Users, ou=IPv4 DHCP Servers, dc=lab, dc=linuxarena, dc=net”.
Finalmente, como voy a permitir el acceso únicamente a los usuarios que cuelguen por debajo de esa OU, este sería el LDIF a insertar ‘add_dhcp_acl.ldif’:
dn: olcDatabase={1}mdb,cn=config changetype: modify add: olcAccess olcAccess: {2}to dn.subtree="ou=IPv4 DHCP Servers,dc=lab,dc=linuxarena,dc=net" by dn.children="ou=Users,ou=IPv4 DHCP Servers,dc=lab,dc=linuxarena,dc=net" read by * none
Para insertarlo bastaría este comando:
root@dns1:~/ldifs# ldapadd -Y EXTERNAL -H ldapi:/// -f add_dhcp_acl.ldif
¿Qué pasaría si lo inserto en el índice {0}?…
2.3.2.Acceso para el replicador DNS2
El ‘what’ del acceso del replicador sobre el LDAP que queremos replicar debe ser muy parecido al del rootDN puesto que le vamos a dar acceso de lectura a todo el árbol del servidor.
Se lo doy a todo el árbol porque el modo de replicación ‘syncRepl’ hace que no se permitan escrituras en el ‘consumer’ y necesito pasar a él todos los datos del ‘provider’, no solo la configuración del DHCP.
La secuencia de comandos de modificación para añadir la lista de acceso a añadir sería esta:
dn: olcDatabase={1}mdb,cn=config changetype: modify add: olcAccess olcAccess: {0}to * by dn.base="cn=replicator,dc=lab,dc=linuxarena,dc=net" read by * break
Obsérvese que se ha hecho uso de la directiva de control ‘break’, si no fuera así el ‘to *’ haría que no se evaluara ninguna lista de acceso inferior puesto ‘*’ abarca todas las entradas de la base de datos y la directiva de control por defecto es ‘stop’.
Inicialmente yo lo ponía en la posición {2} de mi lista de acceso, pero entonces no tendría acceso para leer las contraseñas porque en el {0}, por defecto en Debian, cierra el acceso a ese atributo a todo el mundo, salvo a las propias contraseñas cuando son leídas por uno mismo.
Como la lista de acceso que yo inserto al principio termina con el parámetro de control ‘break’ no afecta al resto de listas de acceso y garantiza que el usuario replicator puede leerlo todo.
Comentarios recientes