2FA en SSH con Google Authenticator: guía completa 2026
Si tu servidor SSH está expuesto a internet (y aunque no lo esté, cualquier máquina con port-forwarding o Dynamic DNS lo está), password solo no alcanza. Una clave ed25519 protege del robo de password pero no del robo del portátil. El segundo factor (TOTP) cierra esa puerta.
TL;DR — Lo que vas a tener al final
- Tiempo de setup: 1-2 horas para un server nuevo.
- Requisitos: Acceso root, 2 sesiones SSH abiertas durante cambios.
- Resultado: Login por clave ed25519, fail2ban activo, 99% de ataques bloqueados.
- Troubleshooting: Consola del proveedor, journalctl -u sshd, fail2ban-client status.
Índice
- Qué resuelve (y qué NO) 2FA en SSH
- Instalar y configurar Google Authenticator
- Configurar PAM para que pida el código TOTP
- Configurar SSH para aceptar TOTP
- Códigos de respaldo y recuperación
- Troubleshooting común
1. Qué resuelve (y qué NO) 2FA en SSH
El ataque clásico contra un servidor SSH expuesto es credential stuffing: prueba una lista de pares usuario/password leaked de breaches públicos. Si tu usuario es root o admin y tu password es Welcome2024!, te lo revienta en segundos. Cambiar a clave SSH ed25519 cierra ese vector casi por completo, pero abre otro: si te roban la máquina donde está ~/.ssh/id_ed25519, el atacante entra sin fricción. No necesita tu password porque tiene la clave privada.
El segundo factor (TOTP) cierra ese vector: el atacante necesita, además de la clave privada, un código que rota cada 30 segundos desde tu app autenticadora (Google Authenticator, Authy, FreeOTP, Bitwarden, 1Password, etc.). Aunque te roben el portátil, no puede entrar sin el dispositivo con la app.
Lo que 2FA NO resuelve:
- Ataques zero-day en OpenSSH: si aparece una vulnerabilidad en el servidor que permite bypass del auth, 2FA no te salva. Mantené OpenSSH actualizado.
- Robo del dispositivo con sesión activa: si te rojan el portátil con la sesión SSH abierta, el atacante entra. Para eso existen los screen lockers y los timers de inactividad (
ClientAliveInterval). - Tokens leaks en logs: si tipeás mal el código y queda en
~/.bash_historyo en logs del servidor, queda expuesto. Los códigos vencen a los 30s pero el secret no.
¿Por qué Google Authenticator específicamente? Porque es el módulo PAM más battle-tested. Hay alternativas (Duo, Yubico PAM, Authy), pero Google Authenticator tiene la ventaja de funcionar offline (TOTP puro, sin llamadas a la nube de Google) y tener apps compatibles en cualquier teléfono. Es el estándar de facto.
Antes de empezar, verifica la versión de SSH del servidor. El módulo PAM que vamos a configurar necesita SSH >= 6.2 (2013) para soportar la directiva AuthenticationMethods con sub-methods (:pam). La directiva ChallengeResponseAuthentication existe desde OpenSSH 2.x (2000), no es nueva:
# Verificar versión de OpenSSH (más portable que sshd -V, que solo anda en 9.x+)
dpkg -l openssh-server 2>/dev/null | tail -1
rpm -q openssh-server 2>/dev/null
# o, si tienes el binario:
/usr/sbin/sshd -V 2>&1 | head -1 # falla en OpenSSH < 9, mejor evitar
Si sshd -V no funciona: en Debian/Ubuntu el binario está en /usr/sbin/sshd. En RHEL/Fedora también. La versión del cliente (ssh -V) suele coincidir con la del server. Si tu server es viejo (pre-2013), la única opción es upgradear OpenSSH o usar ForceCommand con un script wrapper (no lo vamos a cubrir acá).
2. Instalar y configurar Google Authenticator
El paquete del módulo PAM se llama libpam-google-authenticator en Debian/Ubuntu y google-authenticator en RHEL/Fedora. La instalación es directa, pero NO corras el comando google-authenticator todavía sin tener dos cosas: una copia de los códigos de respaldo y la sesión abierta en una segunda ventana SSH. Vamos paso por paso.
# Debian/Ubuntu
sudo apt update
sudo apt install -y libpam-google-authenticator qrencode
# RHEL/Fedora
sudo dnf install -y google-authenticator qrencode
# Arch
sudo pacman -S libpam-google-authenticator
Si qrencode no está disponible: no es crítico, lo único que hace es generar un QR para escanear desde la app. Si no lo instalas, puedes tipear el secret a mano. Pero qrencode está en los repos de todas las distros grandes; si no aparece, tu apt o dnf está mal configurado.
Una vez instalado, corré el configurador como tu usuario (no como root; cada usuario tiene su propio secret). El primer prompt pregunta si quieres tokens basados en tiempo (TOTP) — decí que sí:
google-authenticator
# Do you want authentication tokens to be time-based (y/n) y
# Do you want me to update your "~/.google_authenticator" file (y/n) y
# Do you want to disallow multiple uses of the same token (y/n) y
# Do you want to increase the window from default 3 to 17 (y/n) n
# Do you want to enable rate-limiting (y/n) y
Esto te imprime:
- Un QR code en la terminal
- Un secret key (la línea de texto que también puedes tipear en la app)
- 5 códigos de respaldo de un solo uso (anotalos en papel o en un password manager AHORA)
- El path al archivo
~/.google_authenticator
Escaneá el QR con Google Authenticator / Authy / Bitwarden / lo que uses. prueba que funcione: la app te muestra un código de 6 dígitos que rota cada 30 segundos.
CRÍTICO — anota los 5 códigos de respaldo ahora. Son tu única forma de entrar si perdés el teléfono. Si los perdés y perdés el teléfono, te quedás afuera del server. La única recuperación es entrar por consola (IPMI, KVM, console física) o desde una sesión SSH ya abierta.
3. Configurar PAM para que pida el código TOTP
El módulo PAM de Google Authenticator se enchufa en el stack de auth de SSH. Hay dos archivos a tocar: /etc/pam.d/sshd (lado PAM) y /etc/ssh/sshd_config (lado SSH). Acá te muestro la configuración: 2FA obligatorio cuando el usuario tiene ~/.google_authenticator (el flag nullok lo hace opcional — si el archivo no existe, devuelve PAM_SUCCESS sin pedir TOTP). Para hacerlo obligatorio de verdad: sacá el nullok, y dale el archivo a todos los usuarios con google-authenticator en su login. Si quieres solo 2FA sin fallback, ajustá la línea auth required.
sudo cp /etc/pam.d/sshd /etc/pam.d/sshd.bak
sudo nano /etc/pam.d/sshd
Editá /etc/pam.d/sshd para que arriba diga:
# Google Authenticator
auth required pam_google_authenticator.so nullok
# NO usar secret=/home/${USER}/.google_authenticator — PAM no expande $USER, y el módulo ya resuelve ~/.google_authenticator del uid del proceso
Y comentá (con # al principio) las líneas que dicen @include common-auth y las auth substack. El módulo PAM de SSH debería leer solo la parte del challenge-response, pero el stack default mete el password antes y eso rompe el flujo.
Si te equivocas acá, te quedás afuera del server. Por eso: antes de tocar nada, abrí una segunda sesión SSH en otra ventana y dejala abierta. Si algo rompe, puedes revertir desde ahí. Si no tienes segunda sesión, abrí un cron job que en 5 minutos revierta /etc/pam.d/sshd desde el .bak. Sí, en serio. configura ese cron antes de tocar el PAM.
4. Configurar SSH para aceptar TOTP
Después de tocar PAM, hay que decirle a sshd que use challenge-response (que es lo que permite el prompt para el código TOTP). El cambio es en /etc/ssh/sshd_config. Buscá estas directivas y dejalas así:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo nano /etc/ssh/sshd_config
# Estas son las que importan (buscá en el archivo y modificá)
ChallengeResponseAuthentication yes
UsePAM yes
AuthenticationMethods publickey,keyboard-interactive:pam
# IMPORTANTE: NO pongas PasswordAuthentication yes junto con 2FA.
# Si lo dejás en yes, los usuarios pueden entrar con password y saltarse el TOTP.
PasswordAuthentication no
Reiniciá sshd (ojo, no SSH — el servicio sshd):
# Test de config antes de reiniciar (CRÍTICO)
sudo sshd -t
# Si no tira error, reiniciá
sudo systemctl restart sshd
# verifica que esté corriendo
sudo systemctl status sshd
Si sudo sshd -t tira error de sintaxis: NO reinicies. Volvé /etc/ssh/sshd_config al .bak con sudo cp /etc/ssh/sshd_config.bak /etc/ssh/sshd_config && sudo systemctl restart sshd y revisa qué línea está mal. El error típico es una directiva repetida o mal escrita.
Si después del restart no puedes entrar: espera 5 minutos y el cron job que configuraste revierte PAM. Si no configuraste el cron, usa la segunda sesión SSH abierta. Si tampoco tienes segunda sesión, necesitas acceso por consola (IPMI, KVM cloud, dropbear en el boot loader, lo que tengas).
5. Códigos de respaldo y recuperación
Los 5 códigos que google-authenticator imprimió son tu red de seguridad. Funcionan una vez cada uno y no rotan. Si perdés el teléfono, los usas en el prompt del TOTP (te deja tipear uno en lugar del código de la app).
Guardalos en lugares distintos:
- Password manager (Bitwarden, 1Password, KeePass)
- Papel en una caja fuerte o lugar seguro
- (Opcional) Una copia encriptada en otro server de confianza
NO los guardes en texto plano en el mismo server. Si te rompen el server, el atacante tiene los códigos.
Para agregar más códigos después: simplemente corré google-authenticator de nuevo. Te va a generar un nuevo secret, un nuevo QR y nuevos 5 códigos. Los anteriores quedan invalidados (el archivo ~/.google_authenticator se sobreescribe). Si quieres mantener los anteriores y agregar nuevos, NO corras google-authenticator; editá el archivo a mano (los códigos de respaldo están al final, una línea por código).
Si tu usuario tiene múltiples dispositivos (ej: teléfono personal + tablet + teléfono del trabajo), escaneá el mismo QR en los tres. Los tres generan el mismo código en el mismo momento. Útil para no depender de un único dispositivo.
6. Troubleshooting común
“Invalid verification code” al primer intento después de configurar: el reloj de tu server o de tu teléfono está desincronizado. TOTP usa tiempo UTC, y la ventana default del módulo es ±90 segundos (±3 steps de 30s). Si hay más de esa diferencia entre server y teléfono, falla. Solución:
# Ver hora del server
date -u
# Forzar sync NTP (si tienes systemd-timesyncd)
sudo timedatectl set-ntp true
# O con ntpdate directo
sudo ntpdate pool.ntp.org
# Ver hora del teléfono: Settings → Date & Time → Automatic
No me aparece el prompt del TOTP, entra directo con la clave: el orden de AuthenticationMethods no incluye keyboard-interactive:pam, o ChallengeResponseAuthentication quedó en no. Volvé al paso 4 y revisa.
“Permission denied (keyboard-interactive)”: el archivo ~/.google_authenticator no existe, o el usuario que intenta entrar no corrió google-authenticator. Cada usuario necesita su propio. Como root, puedes generárselo:
sudo -u usuario google-authenticator
Me quedé afuera del server por borrar accidentalmente ~/.google_authenticator: la única salida es consola física/IPMI/KVM. Si el server está en la nube, usa la consola de la cloud (AWS Lightsail tiene console serial, Hetzner tiene KVM rescue, DigitalOcean tiene recovery ISO). Desde ahí entrás como root, regenerás el archivo, y vuelves.
Quiero 2FA solo para algunos usuarios: PAM permite reglas por usuario. Creá /etc/pam.d/sshd-2fa con la config completa de TOTP, y /etc/pam.d/sshd-default sin 2FA. Después en /etc/ssh/sshd_config usas Match Group:
Match Group ssh-2fa
AuthenticationMethods publickey,keyboard-interactive:pam
Match Group *
AuthenticationMethods publickey
Y agregás los usuarios al grupo ssh-2fa. Útil si tienes scripts automatizados (CI/CD, backups) que no pueden tipear un código TOTP.
Conclusión
2FA en SSH con TOTP cierra el vector de “te robaron el portátil”, y la implementación con libpam-google-authenticator es suficientemente battle-tested para producción. La parte crítica es la disciplina: no perder los 5 códigos de respaldo, no quedarse afuera del propio server al configurar PAM, y verificar antes de reiniciar sshd.
Si quieres algo más fuerte todavía, el siguiente paso es moverte a claves FIDO2/WebAuthn (YubiKey, Solokey, etc.). Eso sí requiere hardware y un setup más complejo. Para el 95% de los casos, TOTP + ed25519 es la combinación correcta.
Preguntas frecuentes
¿Por qué 2FA en SSH con Google Authenticator: guía completa 2026 es relevante para sysadmins Linux?
Forma parte del flujo diario de administración. Los conceptos explicados se aplican directamente a servidores en producción y resuelven problemas reales que enfrentan sysadmins hispanohablantes.
¿Qué necesito para empezar con 2FA en SSH con Google?
Distribución Linux actualizada (Debian, Ubuntu, RHEL, Fedora o Arch), acceso root, y conexión a internet. Para producción: entorno de staging separado antes de aplicar cambios.
¿Cuáles son los errores más comunes con 2FA en SSH con Google?
Los tres más frecuentes: (1) saltar la lectura de logs, (2) aplicar cambios directos en producción sin probar, (3) olvidar permisos y ownership. La documentación y un plan de rollback siempre.
¿Cuándo usar 2FA en SSH con Google y cuándo una alternativa?
Esta solución es ideal para el caso descrito. Alternativas como Docker, Ansible o configuración manual pueden ser mejores según contexto: portabilidad, escala y reproducibilidad son los factores clave.
¿Cómo migro desde una configuración previa a 2FA en SSH con Google?
Documentar el estado actual, probar la nueva configuración en staging, validar funcionalmente, y aplicar en producción con rollback plan listo. Los posts de SoyLinux incluyen troubleshooting para los problemas más comunes.
Lee también
- Guía Fedora 44: Novedades, Instalación y Upgrade para Sysadmins Linux
- Configura VLANs en Linux con nmcli: Guía paso a paso para sysadmins
- Protege tu SSH: Guía esencial para configurar Fail2ban en Linux
- Guía Definitiva: Configura Kubernetes con kubeadm en Ubuntu para Sysadmins Linux
- Configura Prometheus y Grafana: Guía DevOps para SysAdmins Linux

Pingback: Seguridad en la nube: desafíos de autenticación para sysadmins Linux - Soy Linux