Permisos y Grupos en Openldap

Documnetación de openldap: http://www.openldap.org/doc/admin24/

En el encuentro 2014 se habló de una raíz dc=interior,dc=udelar,dc=edu,dc=uy, pero finalmente conviene poner la raíz en dc=udelar,dc=edu,dc=uy
La estructura del árbol es la que se manejó desde el inicio:

dc=udelar,dc=edu,dc=uy
--- Recursos
--
--- Gente
--
--- Grupos
------ admins (Superadministradores)
--
------ cup (un grupo para cada regional)
----------admins (un grupo para los administradores de cada regional)
--
------ redmine (un grupo para cada servicio)
-------- login (una cuenta para que el servicio se conecte al ldap)
--

Exploración inicial de ACL's

En las nuevas versiones de OpenLDAP el control de acceso ya no se maneja desde el fichero slapd.conf sinó desde la on-line configuration (OLC) que permite agregar nuevas reglas sin parar el servicio.

Para agregar estas reglas primero se deben especificar creando un fichero ldif:

# nano olcAccess.ldif

dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: to dn.subtree="ou=cure,dc=interior,dc=udelar,dc=edu,dc=uy" 
  by group.exact="cn=admins,ou=grupos,ou=cure,dc=interior,dc=udelar,dc=edu,dc=uy" write
  by self write
  by * read

Para este caso los miembros del grupo "admins" del CURE pueden escribir en el subdirectorio, un usuario puede modificar sus propias entradas y el resto leerlas.

Para aplicar la nueva regla hay que ejecutar la linea

sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f ./olcAccess.ldif

NOTA: Es importante repetar el formato definido anteriormente, incluyendo los espacios de separación, de lo contrario no se puede crear la regla mostrándose un error del tipo:

ldap_modify: Other (e.g., implementation specific) error (80)
    additional info: <olcAccess> handler exited with 1

Para listar las reglas activas hay que ejecutar:
ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config '(olcAccess=*)' olcAccess olcSuffix

Mostrándose
olcAccess: {3}to dn.subtree="ou=cure,dc=interior,dc=udelar,dc=edu,dc=uy" by gr
 oup.exact="cn=admins,ou=grupos,ou=cure,dc=interior,dc=udelar,dc=edu,dc=uy" wr
 ite by self write by * read

En este caso es la 3ra regla que se creó, el orden se puede especificar a la hora de crearla incluyendo "olcAccess: {3}..." en la definición.

Para eliminar una regla, se crea un .ldif donde se puede especificar la regla a eliminar o el indice de esta:

dn: olcDatabase={1}hdb,cn=config
changetype: modify
delete: olcAccess
olcAccess: {3}

...o...
dn: olcDatabase={1}hdb,cn=config
changetype: modify
delete: olcAccess
olcAccess: to dn.subtree="ou=cure,dc=interior,dc=udelar,dc=edu,dc=uy" 
  by group.exact="cn=admins,ou=grupos,ou=cure,dc=interior,dc=udelar,dc=edu,dc=uy" write
  by self write
  by * read

Funciones del LDAP:

1) Crear/eliminar usuarios.
2) Crear/eliminar grupos (grupos y servicios).
3) Agregar/quitar usuarios a grupos.
4) Definir superadministradores, y administradores de cada CENUR.
5) Definir ACL's (agregar/quitar permisos de usuario/grupos a ramas/grupos/usuarios).

Por ahora toda función administrativa se puede realizar con ApacheDS con un usuario superadministrador, o desde el servidor utilizando archivos ldif (con las herramientas ldap-utils).

Crear/eliminar usuarios.

Para crear un usuario se utiliza PWM, todos los usuarios van a ser hijos del grupo gente.

objectClass=inetOrgPerson.
cn=username
sn=Apellido
givenName=Nombre
mail=correo
userPassword=SSHA hashed password

Para eliminar un usuario, un superadministrador o un administrador (si corresponde) borra la entrada del usuario.

Crear/eliminar grupos (servicios).

Para crear grupos:

objectClass=groupOfNames 
cn=nombreGrupo
member=entrada de usuario miembro
member=entrada de usuario miembro
member=entrada de usuario miembro
......

Servicios:

Si el grupo es un servicio, crear una cuenta autenticador, para que el servicio se conecte con ese usuario (y no con el admin del ldap).

Para eliminar grupos se borra la entrada del grupo.

Agregar/quitar usuarios a grupos.

Para agregar un usuario a un grupo se crea un atributo member=cn=usuario,..., en el grupo.

Para quitar un usuario de un grupo se borra el atributo member=cn=usuario,..., del grupo.

Definir superadministradores, y administradores de cada CENUR.

Crear un grupo admins (de superadministradores) y agregar usuarios al grupo.

Crear un grupo para cada Cenur, y dentro un grupo administradores para cada Cenur.

Definir ACL's (agregar/quitar permisos de usuario/grupos a ramas/recursos).

**Esto habría que ver, que permisos se da a cada usuario o grupo.

Miembros de un grupo

Como todos los usuarios estan dentro del grupo Gente, hay que dar permisos a miembros de un grupo y no a subárboles o ramas.
Para dar permiso sobre los usuarios miembros de un grupo es necesario habilitar y configurar el modulo memberof, con 2 archivos:

memberof_add.ldif

dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: /usr/lib/ldap
olcModuleLoad: memberof

memberof_config.ldif

dn: olcOverlay=memberof,olcDatabase={1}hdb,cn=config
objectClass: olcMemberOf
objectClass: olcOverlayConfig
objectClass: olcConfig
objectClass: top
olcOverlay: memberof
olcMemberOfDangling: ignore
olcMemberOfRefInt: TRUE
olcMemberOfGroupOC: groupOfNames
olcMemberOfMemberAD: member
olcMemberOfMemberOfAD: memberOf

Los agregamos al openldap

sudo ldapadd -Y EXTERNAL -H ldapi:/// -f memberof_add.ldif
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f memberof_config.ldif

Este módulo hace que cuando se agrega un usuario al grupo, se cree un atributo memberOf en el usuario con el valor del grupo, de forma automática.

Link: http://www.cbjck.de/2012/05/08/enabling-the-memberof-overlay-for-openldap/

Cree otro archivo para que cuando se agregue un atributo memberOf en el usuario con el grupo, en el grupo se cree un atributo member con el usuario, de forma automática.

memberof_a_member.ldif

dn: olcOverlay=memberof,olcDatabase={1}hdb,cn=config
objectClass: olcMemberOf
objectClass: olcOverlayConfig
objectClass: olcConfig
objectClass: top
olcOverlay: memberof
olcMemberOfDangling: ignore
olcMemberOfRefInt: TRUE
olcMemberOfGroupOC: inetOrgPerson
olcMemberOfMemberAD: memberOf
olcMemberOfMemberOfAD: member

Los agregamos al openldap

sudo ldapadd -Y EXTERNAL -H ldapi:/// -f memberof_a_member.ldif

Agregar una ACL

sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f olcAccess.ldif

Ver la lista de ACL's para decidir que poner en ocAccess.ldif

Ver la lista de los ACL configurados:

ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config '(olcAccess=*)' olcAccess olcSuffix

ACL para que el usuario admin y los administadores puedan administrar las ACL's

dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcAccess
olcAccess: {1}to * by dn="cn=admin,dc=interior,dc=udelar,dc=edu,dc=uy" write by group.exact="cn=admins,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" write by * break

Implementación final de ACL's

Para ver como fueron implementadas las ACL's en el servidor, consultar el link ACL's Curie

Los siguientes son ejemplos de las ACL que implemento Tupac en su servidor de prueba:

olcAccess: {0}to attrs=userPassword,shadowLastChange filter=(&(objectclass=per
 son)(memberof=cn=cup,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy)) by self w
 rite by dn="cn=admin,dc=interior,dc=udelar,dc=edu,dc=uy" write by group.exact
 ="cn=admins,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" write by group.exac
 t="cn=admins,cn=cup,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" write by * 
 auth
olcAccess: {1}to attrs=userPassword,shadowLastChange by self write by dn="cn=a
 dmin,dc=interior,dc=udelar,dc=edu,dc=uy" write by group.exact="cn=admins,ou=g
 rupos,dc=interior,dc=udelar,dc=edu,dc=uy" write by * auth
olcAccess: {2}to filter=(&(objectclass=person)(memberof=cn=cup,ou=grupos,dc=in
 terior,dc=udelar,dc=edu,dc=uy)) by group.exact="cn=admins,cn=cup,ou=grupos,dc
 =interior,dc=udelar,dc=edu,dc=uy" write by dn="cn=admin,dc=interior,dc=udelar
 ,dc=edu,dc=uy" write by group.exact="cn=admins,ou=grupos,dc=interior,dc=udela
 r,dc=edu,dc=uy" write by * break
olcAccess: {3}to dn.base="cn=cup,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" 
  attrs="member" by self write by dn="cn=admin,dc=interior,dc=udelar,dc=edu,dc
 =uy" write by group.exact="cn=admins,ou=grupos,dc=interior,dc=udelar,dc=edu,d
 c=uy" write by group.exact="cn=admins,cn=cup,ou=grupos,dc=interior,dc=udelar,
 dc=edu,dc=uy" write by * auth
olcAccess: {4}to filter=(&(objectclass=person)(!(memberof=cn=redmine,ou=grupos
 ,dc=interior,dc=udelar,dc=edu,dc=uy))) by dn="cn=login,cn=redmine,ou=grupos,d
 c=interior,dc=udelar,dc=edu,dc=uy" none by dn="cn=admin,dc=interior,dc=udelar
 ,dc=edu,dc=uy" write by group.exact="cn=admins,ou=grupos,dc=interior,dc=udela
 r,dc=edu,dc=uy" write by * read
olcAccess: {5}to dn.base="" by * read
olcAccess: {6}to * by dn="cn=admin,dc=interior,dc=udelar,dc=edu,dc=uy" write b
 y group.exact="cn=admins,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" write 
 by anonymous none by * read

{0} La contraseña de los usuarios miembros del grupo cup, cada uno puede cambiar su contraseña, la pueden cambiar los miembros del grupo cn=admins,cn=cup,ou=grupos...., el usuario admin y los miembros del grupo admins, los demas nada

password_admin_cup.ldif

dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: to attrs=userPassword,shadowLastChange filter=(&(objectclass=person)(memberof=cn=cup,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy)) by self write by dn="cn=admin,dc=interior,dc=udelar,dc=edu,dc=uy" write by group.exact="cn=admins,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" write by group.exact="cn=admins,cn=cup,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" write by * auth

{1} La contraseña de todos los usuarios, cada uno puede cambiar su contraseña, la pueden cambiar el usuario admin y los miembros del grupo admins, los demas nada

password.ldif

dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=admin,dc=interior,dc=udelar,dc=edu,dc=uy" write by group.exact="cn=admins,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" write by * auth

{2} Los usarios del grupo cup, pueden ser modificados por los miembros del grupo cn=admins,cn=cup,ou=grupos...., el usuario admin y los miembros del grupo admins, los demas nada

admin_cup.ldif

dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: {1}to filter=(&(objectclass=person)(memberof=cn=cup,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy)) by group.exact="cn=admins,cn=cup,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" write by dn="cn=admin,dc=interior,dc=udelar,dc=edu,dc=uy" write by group.exact="cn=admins,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" write by * break

{3} Los administradores del cup, pueden agregar miembros al grupo cup

member_cup.ldif

dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: {3}to dn.base="cn=cup,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" attrs="member" by self write by dn="cn=admin,dc=interior,dc=udelar,dc=edu,dc=uy" write by group.exact="cn=admins,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" write by group.exact="cn=admins,cn=cup,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" write by * auth

{3} Los administradores del cup, solo pueden ver los miembros de grupo cup, esta no iría pero queda como ejemplo por si se quiere hacer algo parecido

olcAccess: {3}to filter=(&(objectclass=person)(!(memberof=cn=cup,ou=grupos,dc=
 interior,dc=udelar,dc=edu,dc=uy))) by group.exact="cn=admins,cn=cup,ou=grupos
 ,dc=interior,dc=udelar,dc=edu,dc=uy" none by dn="cn=admin,dc=interior,dc=udel
 ar,dc=edu,dc=uy" write by group.exact="cn=admins,ou=grupos,dc=interior,dc=ude
 lar,dc=edu,dc=uy" write by * break

admin_cup_solo.ldif

dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: to filter=(&(objectclass=person)(!(memberof=cn=cup,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy))) by group.exact="cn=admins,cn=cup,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" none by dn="cn=admin,dc=interior,dc=udelar,dc=edu,dc=uy" write by group.exact="cn=admins,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" write by * break

{4} El autenticador del servicio redmine solo puede ver a los miembros del grupo redmine

redmine.ldif

dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: to filter=(&(objectclass=person)(!(memberof=cn=redmine,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy))) by dn="cn=login,cn=redmine,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" none by dn="cn=admin,dc=interior,dc=udelar,dc=edu,dc=uy" write by group.exact="cn=admins,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" write by * read

{5} Todos pueden leer la base del ldap

rdn_base.ldif

dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: to dn.base="" by * read

{6} El usuario admin, y los miembros del grupo admins pueden escribir todo el arbol los demás lo pueden leer

total.ldif

dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: to * by dn="cn=admin,dc=interior,dc=udelar,dc=edu,dc=uy" write by group.exact="cn=admins,ou=grupos,dc=interior,dc=udelar,dc=edu,dc=uy" write by * read

Seguir con Listas de control de acceso (ACLs) definitivas