Autenticación en GNU/Linux con PAM

Antiguamente, la autenticación en sistemas UNIX estaba ligada al que hoy conocemos como «sistema tradicional UNIX», el cual verifica usuario y contraseña contra los valores almacenados en el archivo /etc/passwd (en versiones modernas el password se movió al archivo /etc/shadow por cuestiones de seguridad).
Dado que con los años se fueron desarrollando distintos métodos de autenticación más seguros, seguir clavados utilizando el método tradicional era poco flexible y sin sentido.
A partir de la necesidad de poder cambiar fácilmente entre métodos de autenticación y utilizar distintos métodos, Sun diseñó PAM (Pluggable Authentication Modules). PAM es un conjunto de librerías que permiten una gran variedad de mecanismos de autenticación, entre los cuales contamos con Kerberos, LDAP, y RADIUS (además del tradicional /etc/passwd). Gracias a esto, actualmente es posible autenticar usuarios GNU/Linux contra bases centralizadas de usuarios como el citado kerberos.
PAM no sólo permite utilizar distintos métodos de autenticación, sino que permite utilizar varios al mismo tiempo. Además agrega la posibilidad de utilizar otros medios de autenticación (más allá del clásico usuario/password), como ser smartcards, tockens, etc.

En este artículo les explicaré cómo se configura la autenticación utiliando PAM, y sobre el final podremos entender la configuración de un debian default.

Configuración

PAM divide la tarea de autenticación en cuatro grupos de administración separados:

account provee verificación de tipos de servicio para la cuenta: el password expiro? tiene permitido acceder el servicio requerido? root puede loguearse por consola?
authentication autentica el usuario, y luego otorga los privilegios correspondientes (como membresía de grupo). Este módulo permite setear distintos requerimientos para autenticar al usuario, como passwords, smartcards, tockens, etc.
password es responsable de actualizar los mecanismos de autenticación. Estos servicios están fuertemente acoplados con los del grupo authentication.
session cubre las acciones que se deben hacer antes de que se otorgue un servicio y luego de que el servicio haya sido retirado. En el caso de login, las acciones pueden ser logging y montado de directorios.

La configuración de PAM se realiza a través de reglas y el archivo principal es /etc/pam.conf, aunque en general se prefiere dividir las reglas en diferentes archivos del directorio /etc/pam.d/.
Cada regla tiene cinco campos, separados por espacios:

servicio tipo control path-modulo argumentos-modulo

donde:

servicio es el nombre familiar que corresponde a la aplicación (ej: login, su, sshd). Este campo no se incluye en los archivos de /etc/pam.d, dado que el servicio está indicado por el nombre del archivo en minúscula. El servicio correspondiente a login utiliza a los archivos common-account, common-auth, common-password y common-session para configurar cada uno de los grupos.

tipo: es el grupo de administración al que se aplica la regla (account, auth, password o session).

control indica el comportamiento que PAM debe seguir en caso de que el módulo asociado tenga éxito o falle. Este campo permite dos notaciones. En la notación simple, se utiliza una palabra clave, y en la compleja se encierran pares valor=acción entre corchetes [valor1=acción1, valor2=acción2, ….]
Una característica importante de PAM es que las reglas se pueden «apilar» para combinar los servicios de varios PAMs para una dada autenticación. Los valores de retorno de cada módulo se guardan en una pila. Gracias a esto, es posible, por ejemplo, intentar autenticar primero con kerberos, y si esto falla, intentar autenticar localmente con autenticación unix.

Las palabras claves más comúnmente utilizadas en la notación simple, son:

required: indica que la ejecución del módulo debe ser exitosa para que la operación sea exitosa. Sin embargo, si el módulo falla, la operación fallará recién luego de que se invoque al resto de los módulos que vienen después.
requisite: igual que required, pero si el módulo falla, se retorna el control directamente a la aplicación. Es decir, no se continua invocando módulos como sucede con required.
sufficient: el éxito del módulo es requerimiento suficiente para la operación, esto es, no se continúa procesando los siguientes módulos. Si falla, el proceso continúa en la siguiente regla.
optional: el resultado de este módulo es importante sólo si es el único en el stack.

En la notación compleja, los valores son códigos de retorno. Los más vistos comúnmente son:

success: la función retornó ok
– ignore: ignorar el módulo en cuestión, sin importar si el flag de control es required, optional o sufficient.
new_authtok_reqd: se requiere un nuevo token de autenticación. Utilizado generalmente cuando el password debe ser cambiado.
default: implica todos los valores que no se mencionan explícitamente.
Las posibles acciones en esta notación pueden ser un entero n sin signo, que indica la cantidad de módulos a saltar en el stack, o tomar alguna de las siguientes formas:
ignore: el estado de retorno del módulo no influenciará el resultado final, a menos que no haya otro módulo en el stack.
bad: el estado de retorno debe indicar el fallo del módulo. Si esta es la primer falla, este estatus se usará para todo el stack.
die: idem a bad, excepto que el stack termina y se retorna el control a la aplicación inmediatamente.
ok: el código de retorno sobreescribirá un valor previo de éxito, pero no un estado previo de falla.
done: idem a ok, excepto que el stack termina y el control se retorna inmediatamente a la aplicación.
reset: se limpia el stack y se comienza de nuevo con el próximo modulo.

Como se puede observar, en la notación compleja se permite mucha más granularidad que utilizando palabras claves. Por ello, es posible representar los mismos valores que las palabras claves con notación compleja:

required = [success=ok new_authtok_reqd=ok ignore=ignore default=bad]
requisite = [success=ok new_authtok_reqd=ok ignore=ignore default=die]
sufficient = [success=done new_authtok_reqd=done default=ignore]
optional = [success=ok new_authtok_reqd=ok default=ignore]

path-modulo es el path al módulo, o la dirección relativa al directorio donde se ubican los módulos por default, el cual es /lib/security en debian.

argumentos-modulo son los argumentos, separados por espacios, que se envían al módulo.

Ejemplo práctico

Para entender mejor cómo funciona PAM, veamos el contenido de los archivos en la configuración de un sistema debian default.
/etc/pam.d/common-account (verificación de tipos de servicio)

account [success=1 new_authtok_reqd=done default=ignore] pam_unix.so
account requisite pam_deny.so
account required pam_permit.so

De la explicación anterior, podemos entender que el sistema utilizará el módulo pam_unix. Si esta autenticación tiene éxito (success=1), se saltea la siguiente regla y se ejecuta el módulo pam_permit, permitiendo el acceso.
En caso de fallar, se ejecuta el módulo pam_deny, el cual siempre retorna un valor de fallo; y como el parámetro de control es «requisite», la operación termina inmediatamente.

/etc/pam.d/common-auth (autenticación de usuario y seteo de credenciales)

auth [success=1 default=ignore] pam_unix.so nullok_secure
auth requisite pam_deny.so
auth required pam_permit.so

Este caso es casi igual al anterior, sólo que se utiliza el parámetro nullok_secure al llamar al módulo. En la acción default del módulo no se permite el acceso a un servicio si su password oficial es nulo. Lo que hace este parámetro es sobreescribir este comportamiento y permitir usuarios con password en blanco.

/etc/pam.d/common-password (actualización de passwords)

password [success=1 default=ignore] pam_unix.so obscure sha512
password requisite pam_deny.so
password required pam_permit.so
password optional pam_gnome_keyring.so

En este archivo el cambio es que se agregan los parámetros obscure y sha512 al módulo pam_unix. obscure fuerza el checkeo de la fortaleza del password y sha512 hace que los passwords se almacenen hasheados con sha512.
El módulo pam_gnome_keyring permite el desbloqueo del archivo donde Gnome almacena credenciales del usuario (viene con Gnome). Como ven, el resultado de la ejecución de este módulo no afecta el resultado final de la operación.

/etc/pam.d/common-session (acciones a realizar antes de login y luego de logout)

session [default=1] pam_permit.so
session requisite pam_deny.so
session required pam_permit.so
session required pam_unix.so

En este último archivo no encontramos nada especial, sólo que se ejecuta el módulo pam_unix. El formato de este archivo no tiene mucho sentido, porque dado que pam_permit siempre termina bien, lo siguiente a ejecutar es nuevamente pam_permit, con lo cual se continúa hasta la ejecución de pam_unix. La razón de que esto esté así es por compatibilidad con los archivos anteriores, ya que si observan bien, la estructura es similar.

Referencias

PAM configuration guide for Debian
The Linux-PAM System Administrators’ Guide – 4. The Linux-PAM configuration file
Understanding PAM

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *