Autenticar con kerberos y almacenar información de usuarios con LDAP en GNU/Linux
En los artículos anteriores se explicaron las bases del funcionamiento y utilización de kerberos, LDAP y PAM. Además se explicó cómo autenticar usuarios de GNU/Linux utilizando kerberos. Con esta información en mente, ahora somos capaces de armar un servicio de autenticación centralizada para hosts GNU/Linux, que utilice estos ampliamente aceptados y utilizados servicios.

Para lograr que toda la información de usuarios y grupos se almacene y administre en servidores LDAP, debemos encontrar la forma de que las workstations GNU/Linux se comuniquen con LDAP para obtener los datos que comúnmente se encuentran en los archivos /etc/passwd, /etc/shadow y /etc/group.

En /etc/passwd tenemos los datos concernientes a los usuarios del sistema. Cada entrada representa un usuario y los campos almacenados son los siguientes:
  • credenciales (sólo el nombre de usuario se almacena en /etc/passwd, cuestiones de contraseña se encuentran en /etc/shadow)
  • ID, identificador de usuario
  • grupos a los cuales pertenece
  • nombre real
  • directorio home (ej: /home/demasiadovivo)
  • shell a utilizar (opcional)
Como ya adelanté en el punto anterior, /etc/shadow contiene información de contraseñas. Las contraseñas se almacenan hasheadas (o encriptadas en soluciones antiguas) utilizando un salt. Los campos que se almacenan para cada usuario son:
  • nombre de login
  • hash del password o el password encriptado.
  • fecha del último cambio de password.
  • edad mínima de un password, es decir, el número de días que el usuario debe esperar entre cambios de passwords.
  • edad máxima de un password. Duración del password, es decir, cuanto tiempo podemos usar un password como máximo.
  • período de advertencia. Cuántos días antes de que el password expire, el sistema debe avisar al usuario que esto sucederá.
  • período de inactividad de un password. La cantidad de días que un password debe ser aceptado para generar uno nuevo, luego de que el password expiró. Una vez que este período expira, el usuario no podrá loguearse más y deberá contactar al administrador.
  • fecha de expiración del usuario, en formato timestamp Unix.
Por su parte /etc/group contiene los datos de los grupos, donde para cada grupo se almacena lo siguiente:
  • nombre de grupo
  • contraseña de grupo encriptada (opcional)
  • GID, o identificador de grupo
  • lista de los usuarios que pertenecen al grupo
Cambiar el mecanismo de autenticación de usuarios en GNU/Linux es simple gracias a PAM (ver artículo anterior).
El problema con PAM, es que no permite acceder el resto de la información del usuario almacenada en un LDAP, es decir, información comúnmente almacenada en passwd, shadow y group. Para ello debemos valernos de otra herramienta, llamada NSS (Name Service Switch).
NSS permite utilizar distintas fuentes para obtener diferentes tipos de datos comunes, como los datos de usuario citados anteriormente. Es decir, agrega transparencia al resto de los programas a la hora de acceder dinstinta información. NSS es la capa que permite a un administrador configurar los sistemas para que obtengan de fuentes remotas datos que normalmente se buscarían en archivos locales en /etc (como passwd, group, hosts, etc).
Gracias a NSS, ahora podremos almacenar los datos que nos interesen, como los de usuarios y grupos, en LDAP, simplemente configurando el archivo /etc/nsswitch.conf


Creación de usuarios en kerberos

Para autenticar usuarios con kerberos, primero debemos agregar los principals correspondientes en la base de datos. Agregar un principal para un usuario es tan fácil como ejecutar addprinc utilizando kadmin:
# kadmin.local
Authenticating as principal root/admin@DEMASIADOVIVO.ORG with password.
kadmin.local: addprinc demasiadovivo
WARNING: no policy specified for demasiadovivo@DEMASIADOVIVO.ORG; defaulting to no policy
Enter password for principal "demasiadovivo@DEMASIADOVIVO.ORG":
Re-enter password for principal "demasiadovivo@DEMASIADOVIVO.ORG":
Principal "demasiadovivo@DEMASIADOVIVO.ORG" created.
Podemos checkear que el usuario se creó correctamente ejecutando kinit y klist:
# kinit demasiadovivo
Password for demasiadovivo@DEMASIADOVIVO.ORG:
# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: demasiadovivo@DEMASIADOVIVO.ORG
Valid starting Expires Service principal
06/22/11 14:07:18 06/23/11 00:07:18 krbtgt/DEMASIADOVIVO.ORG@DEMASIADOVIVO.ORG
renew until 06/23/11 14:07:14
Lo que hicimos fue obtener un ticket para el usuario demasiadovivo (con kinit), y luego listar los tickets cacheados en la máquina (klist). Como pudieron ver, /tmp/krb5cc_0 es nuestro ticket. Con klist se pueden ver varias propiedades de los tickets, como algoritmos de encripción (-e), direcciones en las credenciales (-a), etc. kinit también acepta varios parámetros, como tiempo de vida (-l), hora de inicio (-s), renovar un ticket (-R), etc.


Creación de usuarios en LDAP

Si bien podríamos utilizar la autenticación LDAP para autenticar los usuarios, lo mejor es utilizar el confiable kerberos, y dejar LDAP para almacenar los datos de usuarios, grupos y demás.
Como vimos anteriormente, debemos almacenar ciertos atributos del usuario que normalmente estarían en /etc/passwd. Dado que la autenticación la realizamos con kerberos, no es necesario almacenar el password del usuario, aunque esto podría hacerse si se quisiera autenticar con LDAP.

Existe un RFCs (RFC 2307), que describe un mecanismo para mapear entidades UNIX al estándar X.500, para que los atributos se puedan resolver utilizando LDAP. Si bien este documento es experimental, se utiliza ampliamente en el mundo UNIX.
La librería NSS-LDAP utiliza este mapeo para resolver los atributos del usuario, por lo tanto es el formato que debemos adoptar para crear las entradas en el LDAP. OpenLDAP trae esquemas predefinidos para este mapeo, los cuales pueden encontrar en /etc/ldap/schema/nis.schema. Los objectClass que utilizaremos comúnmente son posixAccount, shadowAccount y posixGroup.

Veamos cómo se mapea cada campo del /etc/passwd en atributos LDAP:
  • login name = uid
  • user ID = uidNumber
  • group ID = gidNumber
  • nombre de usuario = cn para el nombre y sn para el apellido.
  • directorio home = homeDirectory
  • shell = loginShell (opcional)
Los usuarios que deseemos autenticar con Kerberos y LDAP deberán tener definida una entrada con estos datos, en la unidad organizativa (OU) People, y con posixAccount como objectClass. El Distinguished Name (DN) de cada usuario tendrá el formato uid=,ou=People,dc=demasiadovivo,dc=org.

Por su parte, el equivalente de atributos para cada grupo es el siguiente:

  • nombre del grupo = cn
  • contraseña = userPassword (opcional)
  • group ID = gidNumber
  • lista de usuarios = memberUid
Los grupos deben situarse en la OU Group y con posixGroup como objectClass. El DN se arma utilizando cn=,ou=Group,dc=demasiadovivo,dc=org.

Ahora que contamos con los datos suficientes para crear un usuario, creemos el archivo user1.ldif donde pondremos la definición de nuestro primer usuario y grupo.

dn: cn=Administrador_Seguridad,ou=Group,dc=demasiadovivo,dc=org cn: Administrador_Seguridad gidNumber: 2000 objectClass: top objectClass: posixGroup
dn: uid:demasiadovivo,ou=People,dc=demasiadovivo,dc=org uid: demasiadovivo uidNumber: 2000 gidNumber: 2000 cn: Victor objectClass: top objectClass: person objectClass: posixAccount objectClass: shadowAccount loginShell: /bin/bash homeDirectory: /home/demasiadovivo
En la definición encontramos varios objectClass. Para el caso de grupos, utilizamos la ya mencionada posixGroup, mientras que para usuarios usamos person, posixAccount, y shadowAccount. La clase person nos permite agregar información atributos como número de teléfono y descripción. Por su parte, shadowAccount permite agregar atributos concernientes al tratamiento de passwords, como el password en si, fecha de último cambio, y resto de información que se encuentra en /etc/shadow. Si bien no almacenaremos passwords en LDAP, sí resulta útil guardar el resto de la información referente al mismo.

Para agregar el usuario, ejecutamos ldapadd de la siguiente manera:
ldapadd -c -x -D cn=admin,dc=demasiadovivo,dc=org -W -f user1.ldif
Podemos verificar los datos recien ingresados con:

ldapsearch "(uid=demasiadovivo)" -x
y
ldapsearch "(cn=Administrador_Seguridad)" -x


Configurar PAM para utilizar kerberos

Este paso ya se explicó en el artículo del mismo nombre que pueden encontrar aquí


Configurar NSS para utilizar LDAP

Como ya adelante en las secciones anteriores NSS (Name Service Switch) es una funcionalidad provista por la librería GNU C para independizar a las aplicaciones de la ubicación de los servicios.
Antíguamente los datos se buscaban en archivos locales como /etc/passwd, /etc/group, /etc/hosts, etc, pero con el crecimiento de tecnologías de base de datos centralizadas como DNS, NIS, LDAP, etc, se hizo evidente la necesidad de contar con un servicio que abstraiga al programa de la ubicación de los datos. Por ello se creó NSS, basándose en un método utilizado por Sun en Solaris 2.
NSS permite al administrador configurar dónde se encontrarán los datos de diferentes bases de datos a través del archivo nsswitch.conf. Incluso se puede establecer un orden sobre qué base de datos consultar primero. El programa sólo utiliza una llamada al sistema y se olvida de donde se encuentran los datos. Gracias a esto, cambiar de base de datos es muy simple. Este caso es muy similar al de PAM.
Entre las bases de datos que podemos configurar tenemos:
  • password: información de usuarios. Default /etc/passwd
  • group: información de grupos de usuarios. Default: /etc/group
  • shadow: contraseñas de usuario. Default: /etc/shadow
  • hosts: nombres de computadoras. Default: /etc/hosts
  • network: nombres de redes. Default: /etc/networks
 Algunas posibles fuentes de datos son:
  • files: archivos, por ejemplo /etc/passwd
  • compat: se puede usar para traer información de usuarios y grupos en archivos con nueva sitaxis como /etc/passwd, /etc/shadow, /etc/group
  • dns: obtener la información de hosts de servidores DNS
  • ldap: traer los datos del directorio LDAP
 Para utilizar LDAP como base de datos de usuarios, deberemos instalar la librería NSS correspondiente. Antes de hacer este paso, es recomendable hacer un backup de los archivos /etc/pam.d/{common-auth,common-account,common-password,common-session}:
cp /etc/pam.d/{common-auth,common-account,common-password,common-session} /root/backup
Luego entenderán porque es necesario este backup.
Ahora si, instalamos la librería libnss-ldapd que provee servicios LDAP para NSS, y el demonio nslcd que es el encargado de realizar las búsquedas LDAP para los procesos que quieran información de usuarios, grupos, etc:
# apt-get install libnss-ldapd nslcd
NOTA: Algo a tener en cuenta aquí es utilizar libnss-ldapd y no libnss-ldap. Con la segunda no pude realizar autenticación de usuarios utilizando GSSAPI, a pesar de mucho intentarlo. libnss-ldapd es más nueva y mejora varias cuestiones de libnss-ldap.

En la instalación, debconf requerirá algunos datos de configuración.
Para el paquete libnss-ldapd:

  • Servicios a configurar para que utilicen LDAP. Los valores por defecto sirven para la mayoría de los casos: passwd, shadow, y group.
 Por su parte, el paquete nslcd solicita:
  • URI del servidor LDAP: ldap://ldap.demasiadovivo.org/
  • DN base para las búsquedas ldap: dc=demasiadovivo,dc=org
El siguiente paso es configurar NSS para que utilice LDAP para buscar información de usuarios. Para esto, hay que editar el archivo /etc/nsswitch.conf para que quede de la siguiente manera:
passwd: files ldap group: files ldap shadow: files ldap
hosts: files dns networks: files
protocols: db files services: db files ethers: db files rpc: db files
netgroup: nis
Se puede observar que el sistema intentará resolver los datos de usuario localmente, y si no puede, consultará al servidor ldap.
Como el demonio nscd cachea los valores, es necesario reiniciarlo:

# /etc/init.d/nscd restart
Para testear la configuración, se puede utilizar el comando getent. Este comando permite obtener entradas de la base de datos administrativa, esto incluye passwd, group, hosts, services, protocols y networks.
La mejor forma de ver que todo está funcionando es obtener los datos de un usuario que esté declarado en el servidor LDAP, pero que no esté localmente. Si por ejemplo el usuario demasiadovivo no se encuentra declarado en el /etc/passwd local y si en el LDAP, pueden probar el siguiente comando:

$ getent passwd demasiadovivo demasiadovivo:x:2000:2000:Victor:/home/demasiadovivo:/bin/bash
Pueden corroborar que el usuario no existe localmente mirando /etc/passwd.
Si ejecutan "getent passwd" sin un nombre de usuario, pueden ver la base de datos completa de usuarios, que incluye a los locales y a los de LDAP.


Prueba de login

Bien, ya tenemos todo lo necesario para ver si nuestro sistema centralizado de usuarios está funcionando correctamente. Veamos los pasos que seguimos hasta aquí:

  • instalamos kerberos
  • instalamos LDAP
  • dimos de alta al usuario demasiadovivo en kerberos y configuramos un password
  • dimos de alta al usuario demasiadovivo en LDAP, donde pusimos toda la información necesaria del /etc/passwd
  • configuramos PAM en la máquina cliente para que autentique utilizando kerberos. Incluso agregamos una regla en common-session para que se cree un directorio home para los usuarios que no existan localmente.
  • configuramos NSS en la máquina cliente para busque los datos del usuario en LDAP
Ufff, fue mucho trabajo, pero si todo fue bien, estamos al borde de la gloria (?!). La prueba? loguearnos con el usuario demasiadovivo en la máquina cliente y ver si anda =D
machine login: demasiadovivo Password: Linux machine 2.6.32-5-amd64 #1 SMP Mon Mar 7 21:35:22 UTC 2011 x86_64
The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Creating directory '/home/demasiadovivo' machine@demasiadovivo:~$ id uid=2000(demasiadovivo) gid=2000(Administrador_Seguridad) grupos=2000(Administrador_Seguridad)
yeah! como se puede observar, el sistema automáticamente creó el directorio home y asignó los IDs correspondientes al usuario, como se declaró en la correspondiente entrada LDAP.

CUIDADO!
Algo que hay que tener muy en cuenta es que kerberos utiliza verificación de host resolviendo el nombre de la máquina desde donde nos conectamos. Por ello es necesario tener definido el nombre de la máquina y el mapeo IP-nombre (registro PTR) en el servidor DNS. Caso contrario, pueden encontrarse con el siguiente error en /var/log/auth.log:

pam_krb5(login:auth): (user demasiadovivo) credential verification failed: Hostname cannot be canonicalized

Referencias

- Authentication against LDAP servers
- PADL Software Pty Ltd - nss_ldap
- OpenLDAP installation on Debian
- MIT Kerberos installation on Debian
- OpenLDAP provider with MIT Kerberos V on Debian squeeze
- OpenLDAPServer
- SingleSignOn
- The POSIX API
- Linux NSS (libnss) and nss_ldap problems and possible solutions
- LDAPClientAuthentication
- LDAP Implementation HOWTO - 2. LDAP authentication using pam_ldap and nss_ldap
- opensolaris - About the Name Service Switch
- NSS Wiki
- Linux Authentication Using OpenLDAP, Part One
- ZYNTRAX - Chapter 5. OpenLDAP Samples - 5.2 Securing the Directory
- SEAM Error Messages and Troubleshooting
- Kerberos and LDAP
- Replacing NIS with Kerberos and LDAP HOWTO
LDAP System Administration - A.2 Name Service Switch (NSS)

3 comentarios:

Anónimo dijo...

Felicidades por el tutorial
Me encuentro en el punto que al hacer login desde un cliente con un usuario creado con todos los pasos me muestra un mensaje ..

Me dice que no ha podido crear el home del usuario... alguna idea???

d3m4s1@d0v1v0 dijo...

Agregaste la siguiente línea:
session required pam_mkhomedir.so skel=/etc/skel/
en el archivo /etc/pam.d/common-session?
Lo que hace es crearte el home del usuario con el que te estas logueando. Sino tenes que crear el home a mano antes de que el usuario se loguee. Podes encontrar más información en el artículo de pam y kerberos:
http://itfreekzone.blogspot.com/2011/09/configurar-pam-para-utilizar-kerberos.html

Unknown dijo...

Excelente explicación, estoy creando una guía(NO OFICIAL) en función de varias fuentes para los laboratorios de la Universidad Simon Bolivar en Venezuela. En referencia a la información recopilada, pondré tu pagina web como una de las fuentes.

Publicar un comentario