Nitrokey (o cualquier otra llave de hardware) para bloquear o desbloquear la computadora
Hace un tiempo comenté que tengo una llave USB Nitrokey, y la estaba usando para guardar claves SSH. La verdad que viene re bien para eso. También la estoy usando para un par de TOTP que quiero tener más seguros que en Keepass, o en el teléfono (y además es más cómodo si ya lo voy a tener enchufado siempre para usar git).
Lo que había visto hace un tiempo era una sugerencia en el sitio de Nitrokey de bloquear la computadora cuando desenchufás la llave. Y bueno, combinando eso con la posibilidad de desbloquear, me sirve.
Bloquear cuando sacás la llave
Esta es la más fácil. El sitio de Nitrokey tiene una explicación. Pero lo que no dice, y que capaz que te sirve, es que podés usar el mismo método para bloquear la computadora (o potencialmente hacer otras cosas) cuando desenchufás cualquier cosa, no sólo una llave Nitrokey. Podés hacer que suene un grito de dolor desgarrador cuando desenchufás el teclado si querés. No sé por qué lo harías, pero si querés, podés.
El truco está en udev. Lo que tenés que hacer es agregar una regla en udev para que cuando desenchufes el dispositivo se bloquee la pantalla. El ejemplo en la web es específico de Gnome, pero se puede modificar un poco. Yo lo cambié para usar loginctl. El tema es que loginctl lock-sessions requiere contraseña, y obviamente eso no me sirve. Pero, por alguna razón, loginctl lock-session <id> sí funciona sin contraseña. Así que hice esto:
| |
La primera línea se encarga de listar todas las sesiones abiertas por mí, y la segunda línea las bloquea a todas.
Por partes:
loginctl -j list-sessionslista todas las sesiones abiertas, y devuelve en formato json (-j).jq '.[] | select(.class == "user" and .user == "nacho") | .session | tonumber'procesa el json, pasándolo por varios selectores..[]toma cada elemento del array raíz y lo procesa aparteselect(...)descarta los elementos que no coincidan con la condición (en este caso, quiero sólo mis sesiones, y que sean de la clase user)..sessionselecciona el atributosession, que tiene el id de sesióntonumberpor último convierte el string a un número, para que la salida dejqno me lo muestre entre comillas.
loginctl lock-session $sessionidssimplemente pasa los ids de sesiones seleccionados antes (típicamente sólo uno) aloginctl lock-session, y bloquea la sesión.
Lo siguiente es decirle a udev que corra ese script cuando desenchufo el dispositivo. Para eso, hay que crear un archivo en /etc/udev/rules.d/. El nombre no importa, siempre que termine en .rules (yo usé lo que sugiere Nitrokey, 85-nitrokey.rules).
El contenido:
ACTION=="remove", ENV{PRODUCT}=="20a0/42b2/108" RUN+="/home/nacho/bin/lock-sessions.sh"
Eso le dice que cuando se desconecte (ACTION=="remove") el dispositivo con el id de producto especificado, corra el script de arriba.
El dato que falta es el número mágico del id de producto. La página de Nitrokey lista algunos, pero obviamente para otros casos no es lo que querés. Para saber cuál es el id de producto que tenés que poner, podés monitorear eventos con este comando:
udevadm monitor --property --udev
Desenchufá, y fijate lo que sale. Te va a tirar un montón de basura, pero entre todo eso, está lo que buscás.
Y con eso ya está: la computadora se bloquea automáticamente cuando sacás la llave.
Desbloquear con la llave
Esto es un poco más complicado. Obviamente no podemos hacer lo mismo pero con loginctl unlock-session, porque entonces se desbloquearía con cualquier llave Nitrokey, y eso es algo que definitivamente no queremos.
Así que hay que remangarse y laburar un poco con PAM
Quién es PAM y qué hace
PAM es Pluggable Authentication Modules, y se encarga de un montón de cosas alrededor de logins en Linux. Como su nombre lo indica, PAM se basa en una serie de módulos que configurás para que corran en secuencia. Algunos módulos validan autenticación (que es lo que nos interesa ahora), y otros hacen otras cosas, como preparar la sesión después de que te autenticaste.
PAM se configura con archivos en /etc/pam.d, donde cada servicio que use PAM va a tener su propia configuración (o, si no existe, usar una por defecto).
Configuración de PAM
Para poder usar la llave de hardware para desbloquear tenemos que, primero, tener el módulo correcto. En Arch, el paquete es pam-u2f, en otras distribuciones posiblemente sea igual o similar.
Después de instalarlo, tenés que generar una clave en el dispositivo. El directorio por defecto tiene el nombre Yubico por razones históricas. Se puede cambiar, pero es más sencillo mantenerlo.
Tenés que correr lo siguiente:
| |
Eso te va a pedir el PIN del dispositivo y que confirmes tocándolo, y te crea la clave.
Con eso ya tenés lo necesario para que el módulo de PAM te autentique.
Autenticación para desbloquear
Tenés que editar (o crear) el archivo /etc/pam.d/kde. O, bueno, lo que corresponda en tu caso. Yo uso KDE, y ese archivo guarda la configuración para el bloqueador de sesión de KDE. Tené en cuenta que esto es sólo para desbloquear: el login está en una configuración aparte.
Si mirás en distintos lugares en internet vas a tener distintas configuraciones. En el caso de login, hay includes importantes que tenés que mantener. En el caso de desbloquear la sesión, puede ser algo bien mínimo:
auth sufficient pam_unix.so try_first_pass nullok
auth sufficient pam_u2f.so cue nouserok origin=pam://hostname appid=pam://hostname
auth [default=die] pam_faillock.so authfail
Los distintos módulos configurados en PAM se ejecutan en secuencia, por lo que el orden es importante.
Lo que dice esta configuración es: primero, probá con usuario/password de unix; si no funciona, probá con u2f (la llave), y si no funciona, no dejes entrar al usuario.
auth dice que es una configuración para autenticación. sufficient dice “si este método funciona, con esto alcanza”. Si querés que sean requeridos, cambialo por required. Luego de eso, viene el módulo, y luego las opciones.
pam_unix.so es el módulo de autenticación “estándar”. Básicamente, usuario y contraseña. La opción nullok le dice que no explote si no hay contraseña, y try_first_pass usa la contraseña que pusiste, pero no la “consume”, la puede usar el siguiente módulo (lo vamos a usar en la siguiente sección).
pam_u2f.so es el módulo que autentica la llave de hardware. Las opciones origin y appid dicen cómo identificar la clave, ahí poné tu hostname. cue dice que te muestre el texto que te dice que toques la llave. nouserok hace que no falle si no tenés la llave enchufada.
La última línea dice que si no llegó nada autorizado a ese punto, que termine el proceso.
Pero esto se ve un poco inseguro
El problema es que puede venir cualquiera, sacarte la llave mientras dormís, y desbloquear tu computadora. Sí, es un riesgo, con esta configuración todo lo que necesitan es acceso físico a la llave y la computadora a la vez.
Para mejorar, podés decirle que te pida el PIN. Para eso, agregá a las opciones del módulo la opción pinverification=1. Y acá es donde entra en juego aquel try_first_pass. Si tenés la llave enchufada, podés en lugar de tu contraseña poner el PIN de la llave. El módulo pam_unix.so va a probarlo como contraseña y va a fallar (a menos que tu PIN y tu contraseña sean idénticos, en cuyo caso andá y cambiá la contraseña ahora). Pero después cuando pam_u2f.so vaya a autenticar, va a agarrar ese PIN y usarlo para validar con la llave, y listo, entraste. Y siempre, en cualquier caso, podés usar tu contraseña normal.
El resultado final
El proceso para desbloquear va a depender un poco de cómo configuraste, si con pinverification=1 o no.
En cualquier caso, para desbloquear te va a mostrar el cuadro de contraseña. Si ponés tu contraseña, genial, entraste, hasta ahí como siempre. Si ponés una contraseña incorrecta, o vacía, va a pasar al siguiente paso.
Si no tenés la llave enchufada, falla, obviamente. Si la tenés enchufada, y pinverification=1 no está (o es pinverification=0), te va a pedir que toques la llave y listo, entrás. Pero si tenés el pinverification habilitado, va a usar lo que pusiste en el campo de contraseña como PIN, y si funciona, te va a pedir que toques la llave, y listo.
Para login
Podés hacer lo mismo para login, pero ahí hay que tener cuidado con los includes que hacés. Para desbloquear no se necesita mucho, pero al crear una sesión nueva (o sea, hacer login), muchas veces hay otros procesos que necesitan correrse en este punto, y están configurados en /etc/pam.d.
Pero tal vez más importante: si usás KDE, seguramente tenés kwallet corriendo. Kwallet se desbloquea al inicio de sesión usando tu contraseña. Si hacés login sin contraseña (por ejemplo, sólo con tu llave física), kwallet no se va a desbloquear, porque no tiene con qué. Entonces el resultado es que entrás a KDE, e inmediatamente te salta un cuadro de kwallet pidiendo tu contraseña. No es ideal, sobre todo si tu idea era justamente no tener que teclear la contraseña.
Podés configurar kwallet para que guarde todo sin encriptar, y no necesite tu contraseña, pero obviamente no es lo ideal. No ahondé mucho en otras posibilidades porque no tengo problema con poner la contraseña para login.
Y listo, con eso ya te queda todo andando. Desenchufás la llave, y se bloquea la computadora. La enchufás, le das enter un par de veces (o ponés el PIN y le das enter), tocás la llave, y se desbloquea. Todo lindo y seguro.