OpenLDAP

De castillowiki
Saltar a: navegación, buscar

OpenLDAP es una de las implementaciones del servicio de LDAP más populares en el mundo Linux.

Se trata de software libre y multiplataforma.

OpenLDAP tiene tres componentes principales:

  • slapd - Es el demonio que espera peticiones.
  • Bibliotecas para implementar el protocolo
  • Programas clientes: ldapsearch, ldapadd, ldapdelete...



Opciones de configuración

La opción más simple es la de un servicio local, ya sea en una LAN o en un ordenador individual. Un servidor proporciona el servicio a uno o más clientes.

Config local.png

La siguiente opción, es la que se usa para añadir nuestro servidor a un servicio de directorio más amplio. Puede que administrado por otros.

Config ref.png

Como se puede ver, si el servidor local no es capaz de resolver la petición, le indica al cliente que la pida a un servidor superior.

La tercera opción es la de crear duplicados del servicio de directorio.

Config repl.png

En esta opción, el servidor maestro crea duplicados en otros servidores.


Referencia: http://www.openldap.org/doc/admin24/config.html

Backend

El servidor OpenLDAP tiene un sección frontal para controlar conexiones y el protocolo LDAP y una base de datos en segundo plano o backend que se dedica a guardar los datos.

Puesto que tiene una arquitectura modular, se pueden usar múltiples backends para ofrecer el servicio.

OpenLDAP permite por defecto 16 backends distintos. Estos se pueden clasificar en tres categorías:

  • De almacenamiento de datos
  • Proxy backends, que actuan como puertas de enlace con otros sistemas de almacenamiento.
  • Dinámicos, los que generan los datos en el momento.

Un servidor LDAP puede dar, simultáneamente, acceso a múltiples bases de datos. En las nuevas versiones de LDAP hay como mínimo dos:

  • config para la configuración
  • /var/lib/ldap que es el backend de la base de datos. Suele estar en hdb

Configuración

A partir de OpenLDAP 2.3, la configuración se vuelve dinámica. Esto quiere decir que permite modificaciones con el servidor en marcha. Además, la propia configuración se almacena como un directorio LDAP y se puede administrar con las órdenes comunes del servidor.

Puesto que la configuración también es como un directorio LDAP, tiene su DIT. Es el siguiente:

Config dit.png

El primer nodo es cn=config y tiene los ajustes de configuración global. En las otras entradas están los demás ajustes:

  • cn=module Carga dinámica de módulos.
  • cn=schema Contiene el schema del sistema.
  • Los objetos hijos de cn=schema contienen los schemas del usuario añadidos más tarde.
  • La configuración del Backend y de la base de datos, otras configuraciones de la base de datos se pueden colocar como hijos de esta. olcDatabase es el parámetro que se usa para configurar la base de datos.

Veamos el LDIF de una configuración estándar.

       # global configuration settings
       dn: cn=config
       objectClass: olcGlobal
       cn: config
       <global config settings>
       # schema definitions
       dn: cn=schema,cn=config
       objectClass: olcSchemaConfig
       cn: schema
       <system schema>
       dn: cn={X}core,cn=schema,cn=config
       objectClass: olcSchemaConfig
       cn: {X}core
       <core schema>
       # additional user-specified schema
       ...
       # backend definitions
       dn: olcBackend=<typeA>,cn=config
       objectClass: olcBackendConfig
       olcBackend: <typeA>
       <backend-specific settings>
       # database definitions
       dn: olcDatabase={X}<typeA>,cn=config
       objectClass: olcDatabaseConfig
       olcDatabase: {X}<typeA>
       <database-specific settings>
       # subsequent definitions and settings
       ...

la X indica un número. LDAP no mantiene un orden en sus entradas. Si es necesario este orden se puede forzar con esos números.

Las directivas de configuración en detalle se pueden ver en: http://www.openldap.org/doc/admin24/slapdconf2.html#Configuration%20Directives

Ejemplo de configuración

(Al final de cada fragmento de LDIF hay una línea en blanco para indicar el final de una entrada)

dn: cn=config
objectClass: olcGlobal
cn: config
olcReferral: ldap://root.openldap.org

Este es el LDIF del nodo raíz. Las tres primeras líneas indican que es el nodo raíz. El atributo olcReferral indica dónde debe preguntar el cliente en caso de que el servidor no pueda responder su petición.

# internal schema
dn: cn=schema,cn=config
objectClass: olcSchemaConfig
cn: schema

Aquí está el schema interno del sistema. No es necesario indicar nada más porque los schemas principales están en el própio código de slapd

# include the core schema
include: file:///usr/local/etc/openldap/schema/core.ldif

Este include hace referencia al esquema core.

# global database parameters
dn: olcDatabase=frontend,cn=config
objectClass: olcDatabaseConfig
olcDatabase: frontend
olcAccess: to * by * read

Aquí llega la configuración de la base de datos. La última línea es control de acceso global que permite a todos leer.

# set a rootpw for the config database so we can bind.
# deny access to everyone else.
dn: olcDatabase=config,cn=config
objectClass: olcDatabaseConfig
olcDatabase: config
olcRootPW: {SSHA}XKYnrjvGT3wZFQrDD5040US592LxsdLy
olcAccess: to * by * none

Se define con olcRootPW la contraseña del superusuario de la base de datos. La siguiente línea niega el acceso a todos menos al superusuario.

# BDB definition for example.com
dn: olcDatabase=bdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcBdbConfig
olcDatabase: bdb
olcSuffix: "dc=example,dc=com"
olcDbDirectory: /usr/local/var/openldap-data
olcRootDN: "cn=Manager,dc=example,dc=com"
olcRootPW: secret
olcDbIndex: uid pres,eq
olcDbIndex: cn,sn,uid pres,eq,approx,sub
olcDbIndex: objectClass eq
olcAccess: to attrs=userPassword
by self write
by anonymous auth
by dn.base="cn=Admin,dc=example,dc=com" write
by * none
olcAccess: to *
by self write
by dn.base="cn=Admin,dc=example,dc=com" write
by * read

En esta parte se define un backend para example.com. Primero se especifica el sufijo para consultas y el directorio donde se guardará. A continuación se indica quien es el superusuario de esa base de datos. las siguientes líneas indican el control de acceso para esta base de datos. Para todas las entradas, el atributo userPassword puede ser escrito por la propia entrada o el administrador. Se puede usar para autentificar, pero de otra forma no es legible. Todos los demás atributos pueden ser leidos por todos y modificados por la entrada o el adminstrador.

Anteriormente he mencionado que la configuración ya se hace de forma dinámica. Pero en algunas distribuciones y algunos manuales [1] indican que se puede usar el fichero antiguo slapd.conf para hacer la configuración. (Más información en esta parte del manual oficial [2])

Para hacer esto, primero hay que fijarse en que el este fichero esté la contraseña de root.

database config
rootpw VerySecret

Luego se hace:

slaptest -f /usr/local/etc/openldap/slapd.conf -F /usr/local/etc/openldap/slapd.d

Y para comprobar:

ldapsearch -x -D cn=config -w VerySecret -b cn=config

Instalación

Instalación en Ubuntu: https://help.ubuntu.com/12.04/serverguide/openldap-server.html

slapd

Se trata del demonio, multiplataforma, encargado de hacer de servidor LDAP. Como características tiene:

  • Implementa el protocolo LDAPv3, que puede funcionar sobre IPv4 o IPv6
  • Permite autenticación simple y una capa de seguridad. Para conseguirlo usa SASL.
  • Soporta TLS para un transporte seguro de los datos. Puede trabajar con OpenSSL.
  • Tiene control de acceso a través de ACL o por parámetros de la red.
  • Soporta Unicode
  • Permite elegir entre múltiples backends.
  • Puede servir múltiples bases de datos en una sola instalación.
  • Permite el uso de módulos para dotarlo de más características.
  • Usa threads, lo cual le permite un mayor rendimiento.
  • Puede usarse para ser replicado, replicar o actuar como proxy caché.
  • Se puede configurar dinámicamente.

Control de Acceso

La política por defecto es dejar leer a todos y reservar al root todos los derechos.

El acceso a las entradas de LDAP se controla mediante el atributo olcAccess. La forma general de configurar olcAccess es:

   olcAccess: <access directive>
   <access directive> ::= to <what>
       [by <who> [<access>] [<control>] ]+
   <what> ::= * |
       [dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
       [filter=<ldapfilter>] [attrs=<attrlist>]
   <basic-style> ::= regex | exact
   <scope-style> ::= base | one | subtree | children
   <attrlist> ::= <attr> [val[.<basic-style>]=<regex>] | <attr> , <attrlist>
   <attr> ::= <attrname> | entry | children
   <who> ::= * | [anonymous | users | self
           | dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
       [dnattr=<attrname>]
       [group[/<objectclass>[/<attrname>][.<basic-style>]]=<regex>]
       [peername[.<basic-style>]=<regex>]
       [sockname[.<basic-style>]=<regex>]
       [domain[.<basic-style>]=<regex>]
       [sockurl[.<basic-style>]=<regex>]
       [set=<setspec>]
       [aci=<attrname>]
   <access> ::= [self]{<level>|<priv>}
   <level> ::= none | disclose | auth | compare | search | read | write | manage
   <priv> ::= {=|+|-}{m|w|r|s|c|x|d|0}+
   <control> ::= [stop | continue | break]

El <what> indica qué entradas se verán afectadas por esta regla de acceso. <who> indica a quién se le aplica esta regla. <access> define los permisos aplicados. Esto se verá con más detalle y mediante ejemplos a continuación.

Qué

El <what> puede representarse como una expresión regular o un DN, por ejemplo:

to * 

Este indica a todos los objetos del árbol. Otra opción es poner dn.base, one, subtree, o children. Esto selecciona la rama del aŕbol al cual queremos aplicar la regla. Así, base indica que se aplica sólo al DN indicado. one indica las entradas cuyo padre sea el sufijo indicado. subtree hace referencia a todas las entradas a partir del sufijo y children es igual que subtree pero sin contar el propio sufijo.

Ejemplo:

   0: o=suffix
   1: cn=Manager,o=suffix
   2: ou=people,o=suffix
   3: uid=kdz,ou=people,o=suffix
   4: cn=addresses,uid=kdz,ou=people,o=suffix
   5: uid=hyc,ou=people,o=suffix

entonces:

     dn.base="ou=people,o=suffix" coincide con 2
     dn.one="ou=people,o=suffix" coincide con 3 y 5
     dn.subtree="ou=people,o=suffix" coincide con 2, 3, 4, y 5
     dn.children="ou=people,o=suffix" coincide con 3, 4, y 5.

También se puede expresar como un filtro. Por ejemplo:

to filter=(objectClass=person)

a Quien

selector Entidades
* Todos, incluidos los anónimos o autenticados
anonymous Usuarios no autenticados
users Usuarios autenticados
self El usuario de la entrada donde está la regla.
dn[.<basic-style>]=<regex> Expresión regular
dn.<scope-style>=<DN> Un dn específico.

Qué pueden hacer

El acceso a otorgar puede ser alguno de los siguientes:

Level Privileges Description
none =0 no access
disclose =d needed for information disclosure on error
auth =dx needed to authenticate (bind)
compare =cdx needed to compare
search =scdx needed to apply search filters
read =rscdx needed to read search results
write =wrscdx needed to modify/rename
manage =mwrscdx needed to manage

Cualquiera de los privilegios implica los privilegios anteriores.

Evaluación de los privilegios

Para evaluar si un solicitante debe tener el acceso demandado, slapd, evalúa una por una las descripciones del "qué". Se aplica primero las ACL que hay en la base de datos que tiene la entrada. Después las directivas de acceso global (en el frontend).

Cuando evalúa la ACL contenida en la propia entrada, examina "quién" y en el orden en que aparece. A continuación evalúa el "qué puede hacer". Puesto que va en orden, es necesario que las ACL más específicas estén delante.

Hay que recordar que las ACL no son un "fichero de configuración", sino una especie de script. Esto quiere decir que se evaluan de forma secuencial y, en el momento que una ACL satisface la consulta, se termina y las ACL posteriores no se evaluan.

Por ejemplo:

Si tenemos la siguiente:

olcAccess: to *
  by * read
  by self write
  by anonymous auth

Si intenta acceder un usuario anónimo para autentificar, primero verá que el primer * le dice que esa ACL corresponde a lo que está buscando (Porque es para todos los elementos del DIT). A continuación el segundo * le dice que él está dentro de ese * (Porque son todos) y le da permiso de lectura. El resto de reglas no se aplican y no puede autentificarse. De hecho, nadie puede leer las otras reglas porque el * és tan genérico que todos entran en él: Todos tienen acceso de lectura.

Ejemplos de control de acceso

olcAccess: to * by * read

Otorga el privilegio de lectura de todo a cualquiera.

olcAccess: to *
 by self write
 by anonymous auth
 by * read

Este otorga el privilegio de modificar su propia entrada a los usuarios, a los anónimos a autentificar y a todos a leer. Pero como especifica antes que anonymous auth, estos no pueden leer.

   olcAccess: to dn.children="dc=example,dc=com"
        by * search
   olcAccess: to dn.children="dc=com"
        by * read

El acceso a lectura se otorga en todo el dominio dc=com, excepto en el dc=example, dc=com se especifica que se puede buscar. Obsérvese que el orden es importante. Si fuera al revés, todo el mundo podría leer, incluso en dc=example, dc=com.

   olcAccess: to dn.subtree="dc=example,dc=com" attrs=homePhone
       by self write
       by dn.children=dc=example,dc=com" search
       by peername.regex=IP:10\..+ read
   olcAccess: to dn.subtree="dc=example,dc=com"
       by self write
       by dn.children="dc=example,dc=com" search
       by anonymous auth

En este ejemplo, para todos los atributos de todas las entradas de dc=example,dc=com excepto homePhone, le aplica los siguientes permisos: Escritura para el propietario, búsqueda para las entradas de ese subárbol y cualquier otro no tiene acceso excepto para autenticación para los no autenticados (by * none implícito). Al atributo homePhone pueden leerlo los de un determinado rango de IPs, pero todos los demás no tienen permiso para nada (to * by * none implícito)

Generalmente, se puede comenzar con una ACL básica como:

   access to attr=userPassword
       by self =xw
       by anonymous auth
       by * none
     access to *
       by self write
       by users read
       by * none

Se puede ver como se especifica que el propietario sólo puede autentificar o escribir su userPassword, pero no leerlo. Los no autentificados se pueden autentificar con el y se deniega cualquier cosa a todos los demás. En la segunda ACL se permite escribir a los propietarios, leer a los autenticados y nada a los demás. Cabe recordar que la segunda ACL no se aplica en el caso del userPassword, ya que la primera regla es más específica.

Para garantizar la lectura sólo a los autenticados:

   access to *
     by anonymous none
     by * read

Y también se puede hacer de esta manera:

   access to *
     by users read
     by * none

slapd-config

Recordemos que en LDAP tanto la configuración como el frontend (los datos) son accesibles y modificables con LDAP.

Si hacemos:

$ sudo slapcat

Lo que nos muestra es el contenido del frontend.

Sin embargo, es posible consultar el contenido del backend o de la configuración del servicio mediante:

$ sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config

Y si queremos sólo ver los objetos del DIT de configuración podemos poner:

$ sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config dn

Para que sólo nos muestre los DN.

ldapsearch

Utilidad para buscar dentro de LDAP.

Sinopsis:

      ldapsearch   [-V[V]]   [-d debuglevel]  [-n]  [-v]  [-c]  [-u]  [-t[t]]
      [-T path] [-F prefix] [-A]  [-L[L[L]]]  [-S attribute]  [-b searchbase]
      [-s {base|one|sub|children}]  [-a {never|always|search|find}] [-l time-
      limit]  [-z sizelimit]  [-f file]   [-M[M]]   [-x]   [-D binddn]   [-W]
      [-w passwd]  [-y passwdfile]  [-H ldapuri]  [-h ldaphost] [-p ldapport]
      [-P {2|3}] [-e [!]ext[=extparam]] [-E [!]ext[=extparam]]  [-o opt[=opt-
      param]] [-O security-properties] [-I] [-Q] [-N] [-U authcid] [-R realm]
      [-X authzid] [-Y mech] [-Z[Z]] filter [attrs...]

ldapsearch abre una conexión a un servidor LDAP, enlaza y ejecuta una búsqueda usando los parámetros especificados. El filtro debe ajustarse a la representación de cadena de filtros de búsqueda de RFC 4515.

Si encuentra alguna coincidencia, muestra los atributos pedidos, si no se especifican atributos, los muestra todos.

Los resultados los muestra en formato LDIF.

ldapsearch tiene multitud de parámetros. Los que más nos interesan son:

  • -x Simple autentificación. En vez de con SASL.
  • -LLL La primera L restringe la salida a LDIF, la segunda quita los comentarios y la tercera desactiva la impresión de la versión de LDIF.
  • -H Especifica la URI del servidor LDAP. Si es local se puede poner ldap:///
  • -D En caso de que sea necesario autentificarse para buscar dentro del directorio, con -D se puede poner el DN del usuario con el que nos autentificamos.
  • -w Para poner la contraseña para autentificarse.
  • -W Para no ponerla y que nos la pida por la terminal.
  • -b Para especificar la base a partir de la que se busca.

Ejemplo:

$ ldapsearch -x -LLL -b dc=example,dc=com 'uid=john' cn gidNumber

Muestra, a partir de dc=example,dc=com el cn y el gidNumber de aquellas entradas que tengan uid=john.

ldapadd / ldapmodify

Estas son herramientas para introducir o modificar entradas en la base de datos.

Entre sus opciones principales destaca la -f para indicarle un fichero LDIF con las entradas a introducir o modificar.

Las opciones se pueden buscar en man ldapadd y son iguales que ldapsearch.