En este artículo veremos cómo utilizar GSSAPI, y cómo definir los accesos al directorio en base a los usuarios autenticados con kerberos para obtener una estructura de usuarios centralizada con autenticación segura, similar a Active Directory.
Con esto cierro la serie de artículos Autenticación y administración centralizada de usuarios en GNU/Linux, la cual comencé a publicar en julio del año pasado y contempla todos los pasos necesarios para armar dicha estructura. En el artículo principal pueden encontrar los links a todos los artículos de la serie.
Autenticar con SASL-GSSAPI kerberos
Para poder utilizar SASL-GSSAPI en LDAP, es necesario instalar el API Cyrus SASL compilado para el kerberos de MIT, tanto en el servidor como en clientes:
# apt-get install libsasl2-modules-gssapi-mit
Como vimos en la descripción de kerberos, cada servicio que desee kerberizarse deberá tener un principal en la base de datos. Entonces, para poder utilizar GSSAPI con kerberos necesitamos crear el principal correspondiente. Esto se logra utilizando kadmin o kadmin.local de la siguiente manera:
# kadmin.localEl siguiente paso es guardar la clave del principal recién creado en un archivo (keytab), el cual luego se utilizará desde OpeLDAP para la autenticación:
Authenticating as principal root/admin@DEMASIADOVIVO.ORG with password.
kadmin.local: addprinc -randkey ldap/ldap01.demasiadovivo.org@DEMASIADOVIVO.ORG
WARNING: no policy specified for ldap/ldap01.demasiadovivo.org@DEMASIADOVIVO.ORG; defaulting to no policy
Principal "ldap/ldap01.demasiadovivo.org@DEMASIADOVIVO.ORG" created.
donde ldap01.demasiadovivo.org es la dirección del servidor ldap y -randkey permite generar un password random.
kadmin.local: ktadd -k /root/ldap.keytab ldap/ldap01.demasiadovivo.orgSi no especifican el nombre del archivo (-k), la clave se escribe en /etc/krb5.keytab. Esto no es aconsejable porque este archivo será utilizado por OpenLDAP, para lo cual debemos darle permiso de lectura/escritura, y al hacerlo, le damos acceso a todas las claves que se encuentren en el. Por ello, es mejor separar la clave de OpenLDAP en un archivo propio.
Entry for principal ldap/ldap01.demasiadovivo.org with kvno 5, encryption type AES-256 CTS mode with 96-bit SHA-1 HMAC added to keytab WRFILE:/root/ldap.keytab.
Entry for principal ldap/ldap01.demasiadovivo.org with kvno 5, encryption type ArcFour with HMAC/md5 added to keytab WRFILE:/root/ldap.keytab.
Entry for principal ldap/ldap01.demasiadovivo.org with kvno 5, encryption type Triple DES cbc mode with HMAC/sha1 added to keytab WRFILE:/root/ldap.keytab.
Entry for principal ldap/ldap01.demasiadovivo.org with kvno 5, encryption type DES cbc mode with CRC-32 added to keytab WRFILE:/root/ldap.keytab.
Una vez creado el principal y exportado a un archivo, hay que copiar el mismo al servidor donde se encuentre OpenLDAP y darle permiso de lectura/escritura al usuario openldap, que es el usuario con el que se ejecuta el servicio. Un buen lugar para ubicar el archivo es dentro del mismo directorio de ldap.
/etc/ldap# chown openldap:openldap ldap.keytabA continuación hay que editar el archivo /etc/default/slapd para indicar donde se encuentra el keytab para utilizar con SASL, ya que por default intentará usar /etc/krb5.keytab. Esto se hace editando o agregando la siguiente línea:
/etc/ldap# chmod 750 ldap.keytab
export KRB5_KTNAME=/etc/ldap/ldap.keytab
OpenLDAP mapea los principals de kerberos a DNs especiales, que tienen el siguiente formato:
uid=<nombre de="" usuario="">,cn=<realm>,cn=<mecanismo>,cn=autho
<nombre de="" usuario=""><realm><mecanismo>
<nombre de="" usuario=""><realm><mecanismo>
<nombre de="" usuario=""><realm><mecanismo> uid=<nombre de="" usuario="">,cn=<mecanismo>,cn=authPor ejemplo, si el principal es demasiadovivo@DEMASIADOVIVO.ORG, éste se mapeará con el DN:
<nombre de="" usuario=""><realm><mecanismo><nombre de="" usuario=""><mecanismo>
uid=demasiadovivo,cn=DEMASIADOVIVO.ORG,cn=gssapi,cn=auth
es decir, para poder utilizar autenticación kerberos en LDAP, debe existir una entrada en el directorio con el formato mostrado.
Si están utilizando LDAP como directorio de usuarios, el formato de los DN para estos usuarios (uid=demasiadovivo,ou=People,dc=demasiadovivo,dc=org) es muy diferente al recién mostrado (uid=demasiadovivo,cn=DEMASIADOVIVO.ORG,cn=gssapi,cn=auth). Esta diferencia se debe a que una entrada es para usuarios de LDAP y el otro es para usuarios almacenados en LDAP. Una entrada es para autenticar quién es el usuario y qué puede hacer en el directorio, y la otra es para almacenar datos de un usuario.
En el caso de utilizar autenticación kerberos y tomar los datos del usuario de LDAP con NSS, ambos usuarios son el mismo usuario, entonces se necesita una forma de mapearlos.
Para esto, OpenLDAP provee reemplazo de nombres de autenticación utilizando expresiones regulares. Esto es, en lugar de tener que definir dos entradas para el mismo usuario, es posible definir la entrada con los datos del usuario y mapear el DN de autenticación al DN real. La forma de hacerlo es ingresando una regla authz-regexp en el archivo slapd.conf (/usr/share/slapd/slapd.conf en debian). La directiva utiliza dos parámetros:
authz-regexp <patron buscado=""> <patron de="" reemplazo="">Entonces, ingresando la siguiente regla, se tiene el reemplazo buscado:
authz-regexp
uid=([^,]*),cn=DEMASIADOVIVO.ORG,cn=gssapi,cn=auth
uid=$1,cn=People,dc=demasiadovivo,dc=org
# /etc/init/slapd restart
$ kinit demasiadovivo
Password for demasiadovivo@DEMASIADOVIVO.ORG:
$ ldapwhoami
SASL/GSSAPI authentication started
SASL username: demasiadovivo@DEMASIADOVIVO.ORG:
SASL SSF: 56
SASL data security layer installed.
dn:uid=demasiadovivo,cn=gssapi,cn=auth
Cannot determine realm for numeric host address
$ ldapsearch -s base -b "" supportedSASLMechanisms
Configurar permisos para acceder LDAP
Hasta ahora la configuración cuenta con autenticación GSSAPI-kerberos que es mucho mejor a tener autenticación simple, o no tener autenticación, pero todavía no se definió ningún rol de usuario que determine qué usuario puede hacer qué.
Por default OpenLDAP cuenta con el usuario admin que posee control total sobre el directorio, y se autentica utilizando autenticación simple con password. Además cuenta con un perfil público a través del cual cualquier persona, utilizando autenticación simple, puede leer los datos del directorio. Como se mostró en el artículo de instalación y configuración de LDAP, estos permisos se pueden observar ejecutando:
# slapcat -b cn=config -a olcDatabase={1}hdb
Para lograr esta configuración, los pasos a realizar son los siguientes:
1. Eliminar al usuario admin y accesos default.
2. Crear un grupo administrador de dominio.
3. Otorgar control total al grupo del paso anterior (como suele ser el grupo Domain Admins en Active Directory).
4. Asignar acceso de lectura a usuarios autenticados.
1. Eliminar usuario admin y accesos default
Por defecto, OpenLDAP provee acceso de escritura para el usuario admin y de lectura sin autenticación. En la configuración de un servicio centralizado de usuarios con kerberos, estos accesos son poco flexibles e inseguros, por lo tanto hay que eliminarlos, y luego plantear nuevos accesos que utilicen usuarios autenticados con kerberos.
Al utilizar la estructura kerberos, los atributos userPassword y shadowLastChange no son necesarios, por lo que se puede eliminar dicho acceso.
Para lograr este objetivo, crear el siguiente LDIF llamado delete-default.ldif:
dn: olcDatabase={1}hdb,cn=config
changetype: modify
#
# Eliminar acceso al usuario admin
delete: olcAccess
olcAccess: {2}to *
by self write
by dn="cn=admin,dc=dvpem,dc=org" write
by * read
-
# Eliminar acceso de lectura sin autenticacion
delete: olcAccess
olcAccess: {1}to dn.base=""
by * read
-
# Eliminar accesos a los atributos password de los usuarios
delete: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange
by self write
by anonymous auth
by dn="cn=admin,dc=dvpem,dc=org" write
by * none
-
# Prohibir acceso al atributo password
add: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange
by * none
-
# Eliminar el usuario admin
delete: olcRootPW
-
$ ldapmodify -f delete-default.ldif -x -D cn=admin,cn=config -W
# slapcat -b cn=config -a olcDatabase={1}hdb
2. Crear grupo administrador del dominio
Como muchos sabrán, en Active Directory existe un grupo denominado Domain Admins, el cual tiene permiso de administración sobre todo el directorio y las máquinas unidas al dominio.
En el caso del dominio que se está configurando, es muy útil tener un grupo con las mismas características, que permita administrar el directorio. El siguiente LDIF denominado domain-root.ldif crea dicho grupo, cuyo único miembro (por ahora) es el usuario demasiadovivo:
dn: cn=domain_root,ou=Group,dc=demasiadovivo,dc=org
cn: domain_root
gidNumber: 1000
objectClass: top
objectClass: posixGroup
memberUid: demasiadovivo
$ ldapadd -x -D cn=admin,cn=config -W -f domain-root.ldif
Enter LDAP Password:
adding new entry "cn=domain_root,ou=Group,dc=demasiadovivo,dc=org"
3. Otorgar control total al grupo domain_root sobre el directorio
Este punto es uno de los más complejos. Como vimos, OpenLDAP es muy flexible en cuanto a otorgar permisos y posee una facilidad para otorgar permisos por grupo (by group). El problema es que este se aplica a la clase groupOfNames y no sirve para posixGroup.
Se me ocurrieron varias alternativas para solucionar este problema:
1- Utilizar groupOfNames y mapear los request NSS_LDAP con una expresión regular que sustituya los pedidos, como se mostró en la sección anterior.
2- Editar el esquema de posixGroup para agregar el atributo member.
3- Utilizar la definición de posixGroup del RFC 2307bis, la cual expiró y nunca se aprobó. Esta RFC incluye el campo member en la definición.
4- Otorgar permisos basados en sets.
5- Cambiar el formato de las consultas LDAP de la librería NSS_LDAP para que utilice groupOfNames.
Para el permiso definimos el siguiente LDIF denominado domain_root-access.ldif:
dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: {0}to dn.subtree="dc=demasiadovivo,dc=org"
by set="([uid=] + ([cn=domain_root,ou=Group,dc=demasiadovivo,dc=org])/memberUid + [,cn=gssapi,cn=auth])/entryDN & user" write
En la primer línea se indica que se está otorgando permiso a todo el dominio demasiadovivo.org. dn.subtree es el scope, e indica que se aplique a todo lo que contiene el dominio.
En la segunda línea se indica a quién se otorga el permiso y qué tipo de permiso (write). Esta es la parte más confusa.
Primero hay que entender qué es lo que se desea otorgar. Lo que debemos hacer es otorgar permiso de escritura a todos los miembros del grupo domain_root. Los miembros se obtienen del atributo memberUid, pero este atributo no es un DN, sino sólo el nombre del usuario. Como el permiso debe otorgarse a un DN, primero hay que armarlo.
El DN de un usuario consta de uid=
[uid=], para agregar el string uid= ([cn=domain_root,ou=Groups,dc=demasiadovivo,dc=org])/memberUid para agregar el nombre de usuario de los miembros del grupo. Se utilizan los parentesis porque los mismos indican precedencia, de esta forma se evalúa primero el grupo y luego se obtienen los miembros. [,cn=gssapi,cn=auth] para agregar la parte restante del DN
Para agregar este nuevo acceso, utilizar ldapmodify con el usuario administrador de la base de datos de configuración (cn=admin,cn=config):
$ ldapmodify -f domain_root-access.ldif -x -D cn=admin,cn=config -W
4. Asignar acceso de lectura a usuarios autenticados
Llegado este punto, ya tenemos el grupo de administración del dominio, pero no los accesos de lectura para que los usuarios lean las entradas. Esto se logra definiendo el siguiente LDIF denominado read-access.ldif:
dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: {1}to *
by users read
by * none
$ ldapmodify -f read-access.ldif -x -D cn=admin,cn=config -W
Configurar las máquinas cliente para usar GSSAPI
De la configuración anterior tenemos que ahora sólo se puede consultar al servidor LDAP si el cliente se autenticó previamente ante kerberos. Debido a esto, hay que configurar NSS-LDAP de forma especial, para que el servicio pueda consultar el directorio y obtener los datos del usuario que se está autenticando.
Hasta ahora, cuando un usuario se autentica ante el sistema, primero PAM valida las credenciales con kerberos, y luego NSS se conecta de forma anónima al servidor LDAP para traer los datos del usuario. Como ahora no es posible obtener datos de forma anónima, es necesario que NSS utilice GSSAPI con un ticket kerberos. El problema es qué ticket utilizar? dado que no podemos utilizar el ticket que se obtiene al validar al usuario.
Para solucionar este problema, es necesario realizar los siguientes pasos:
1. crear un principal por cada host,
2. exportar la clave de cada principal a keytabs,
3. mover cada keytab al host correspondiente,
4. configurar NSS de cada host para utilizar kerberos y realizar la autenticación con el keytab correspondiente.
Crear principal para host y exportar clave en keytab
Para crear el principal del host maquina01 y exportarlo en el keytab maquina01.keytab, nuevamente hacemos uso de la herramienta kadmin.local (o kadmin si se conectan remoto), y ejecutamos lo siguiente:
kadmin.local: addprinc -randkey host/maquina01.dvpem.org@DVPEM.ORG
WARNING: no policy specified for host/maquina01.dvpem.org@DVPEM.ORG; defaulting to no policy
Principal "host/maquina01.dvpem.org@DVPEM.ORG" created.
kadmin.local: ktadd -k /root/maquina01.keytab host/maquina01.dvpem.org
Entry for principal host/maquina01.dvpem.org with kvno 2, encryption type AES-256 CTS mode with 96-bit SHA-1 HMAC added to keytab WRFILE:/root/maquina01.keytab.
Entry for principal host/maquina01.dvpem.org with kvno 2, encryption type ArcFour with HMAC/md5 added to keytab WRFILE:/root/maquina01.keytab.
Entry for principal host/maquina01.dvpem.org with kvno 2, encryption type Triple DES cbc mode with HMAC/sha1 added to keytab WRFILE:/root/maquina01.keytab.
Entry for principal host/maquina01.dvpem.org with kvno 2, encryption type DES cbc mode with CRC-32 added to keytab WRFILE:/root/maquina01.keytab.
El paso anterior podría haberse realizado directamente desde el host maquina01, utilizando el comando kadmin y descargando la clave a un keytab local (/etc/krb5.keytab). En resultado es el mismo.
Configurar NSS-LDAP para utilizar kerberos en los clientes
Una vez generado el principal del host maquina01, hay que mover el keytab recién creado al host correspondiente. Un buen lugar para colocar el keytab es en /etc/krb5.keytab, que es el archivo default de kerberos. Por seguridad, el archivo debe poseer permisos 640:
# chmod 640 /etc/krb5.keytab
sasl_mech gssapi
krb5_ccname FILE:/tmp/krb5cc_0
donde:
- sasl_mech indica el mecanismo SASL a utilizar (GSSAPI)
- krb5_ccname informa donde se encuentra el ticket kerberos
K5START_START="yes"
K5START_PRINCIPAL="host/maquina01.dvpem.org"
Si todavía no tienen instalado kstart, pueden hacerlo con:
# apt-get install kstart
# /etc/init.d/nslcd restart
$ getent passwd
# /etc/init.d/nscd stop
- en el cliente:
/var/log/auth.log
- en el servidor:
/var/log/debug
# lsof -r 2 -i
-r 2 pone lsof en modo repetición. De esta forma lsof lista lo seleccionado por otros argumentos, espera 2 segundos y vuelve a listar.
-i lista los procesos que estan escuchando en sockets tcp o udp.
Referencias
- OpenLDAP - 15. Using SASL
- Red Hat Documentation - 10.2.6. Setting Up Kerberos Authentication
- OpenLDAP - 5. Configuring slapd
- LDAP Administration Guide
- OpenLDAP FAQ - Sets in Access Controls
- Integrated Kerberos-OpenLDAP client on Debian lenny
- Configuring LDAP Authentication
- RedHat mailing list - nss_ldap using sasl with gssapi. Kerberos credentials cache problem[Scanned]
0 comentarios:
Publicar un comentario