Endurecer PAM¶
PAM es el sistema que decide quién entra y quién no en un servidor Linux. SSH, sudo, su y el login local no verifican credenciales por su cuenta: delegan en esta pila de módulos. Endurecer PAM cierra una vía de ataque que el resto de la guía no cubre — el momento en el que alguien ya tiene credenciales.
Qué es PAM¶
Cada servicio con autenticación tiene un fichero en /etc/pam.d/: sshd, sudo, su, login, passwd... Dentro se define la pila de módulos que se ejecutan en orden:
- auth — comprobación de la identidad (contraseña, token, clave).
- account — autorización: ¿puede este usuario entrar ahora y desde aquí?
- password — reglas de cambio de contraseña.
- session — acciones al iniciar/cerrar sesión (montajes, límites, logs).
Cada línea usa un flag de control que decide cómo afecta el resultado del módulo al resto de la pila:
| Flag | Qué hace |
|---|---|
required | Si falla, la autenticación falla, pero el resto de módulos se ejecutan. |
requisite | Si falla, la autenticación falla y se detiene la pila. |
sufficient | Si tiene éxito, la autenticación pasa sin mirar el resto de módulos. |
optional | Su resultado no decide nada; solo aporta información extra. |
Quién gestiona estos ficheros
En Ubuntu los common-auth, common-password, common-account y common-session los regenera pam-auth-update. En Fedora/RHEL los ficheros password-auth y system-auth los gestiona authselect — no se editan a mano, se activan features. Las recetas de abajo respetan ambos.
Enfoque por niveles¶
Como en Proteger SSH, la guía sube de nivel añadiendo capas a la autenticación. Puedes parar donde quieras.
| Nivel | Qué añade | ¿Aplicarlo? |
|---|---|---|
| 1 | Política de contraseñas (pam_pwquality) | Recomendado |
| 2 | Bloqueo de intentos (pam_faillock) | Recomendado |
| 3 | Acceso por origen y horario (pam_access/pam_time) | Opcional, según uso |
| 4 | Segundo factor TOTP (pam_oath) | Opcional, avanzado |
Nivel 1 — Política de contraseñas¶
Recomendado. Fuerza una longitud mínima y composición obligatoria al definir o cambiar contraseña. No afecta a la de hosting actual, solo a las nuevas.
-
Configurar la política en
/etc/security/pwquality.conf(común a ambas):sudo vim /etc/security/pwquality.confContenido recomendado:
minlen = 14 retry = 3 lcredit = -1 ucredit = -1 dcredit = -1 ocredit = -1Con
minlen = 14y los cuatro*credit = -1, la contraseña debe tener al menos 14 caracteres e incluir letras, mayúsculas, dígitos y un símbolo. Un crédito (positivo) reduciría la longitud requerida; un valor negativo exige al menos uno de esa clase. -
Comprobar que el módulo
pam_pwqualityestá en la pila de contraseñas:sudo vim /etc/pam.d/common-passwordDebe existir (antes de la línea de
pam_unix):password requisite pam_pwquality.so retry=3Si no está, añadirla como primera línea de
password.grep pam_pwquality /etc/pam.d/system-authDebe salir una línea
password requisite pam_pwquality.so retry=3. Si no aparece, activarla:sudo authselect enable-feature with-pwquality
Nivel 2 — Bloqueo de intentos¶
Recomendado. pam_faillock bloquea la cuenta durante un tiempo tras varios intentos fallidos. Complementa a Fail2ban: este actúa en la red bloqueando IPs, y pam_faillock frena localmente aunque el atacante cambie de IP.
-
Activar el bloqueo:
Editar
/etc/pam.d/common-auth. Añadir esta línea al inicio:auth required pam_faillock.so preauth silent deny=5 unlock_time=900Y añadir estas dos entre la línea de
pam_unixy la depam_deny:auth [default=die] pam_faillock.so authfail silent deny=5 unlock_time=900 auth sufficient pam_faillock.so authsucc silent deny=5 unlock_time=900El orden importa: el contador solo se resetea si
authsuccse evalúa después de quepam_unixhaya validado la contraseña. Si pones todas las líneas juntas al principio,authsucc(que essufficient) aceptaría la sesión sin mirar la contraseña.Con estos ajustes, el bloque final debe leer así:
auth required pam_faillock.so preauth silent deny=5 unlock_time=900 auth [success=1 default=ignore] pam_unix.so nullok auth [default=die] pam_faillock.so authfail silent deny=5 unlock_time=900 auth sufficient pam_faillock.so authsucc silent deny=5 unlock_time=900 auth requisite pam_deny.so auth required pam_permit.sosudo authselect enable-feature with-faillockAjustar en
/etc/security/faillock.conf:deny = 5 unlock_time = 900 silent audit -
Validar que el fichero editado es válido cuando aplica:
sudo pam-auth-update --packagesudo authselect apply-changes
Con gestión desde la línea de comandos:
sudo faillock # estado de todas las cuentas
sudo faillock --user hosting # estado de un usuario
sudo faillock --reset --user hosting # desbloquear manualmente
Por defecto root queda fuera del conteo (even_deny_root apagado), lo que garantiza una vía de recuperación por consola si se bloquea una cuenta real.
Nivel 3 — Acceso por origen y horario¶
Opcional, según uso. Aplicar si quieres restringir desde dónde y cuándo se puede entrar por SSH — por ejemplo, solo desde tu IP/VPN y en horario laboral. Saltarlo si administras desde cualquier lugar o si prefieres no mantener una lista de IPs.
-
Activar
pam_accessen SSH (ambas distros; el ficherosshdno lo gestionaauthselectnipam-auth-update):sudo vim /etc/pam.d/sshdAñadir al bloque
account:account required pam_access.so -
Definir quién puede entrar desde dónde en
/etc/security/access.conf:sudo vim /etc/security/access.confEjemplo — solo el grupo
sshusersdesde tu IP, tu VPN y la consola local:+ : (sshusers) : 203.0.113.10 10.8.0.0/24 localhost - : ALL : ALLReglas en orden
La primera regla que coincide decide.
+permite,-deniega.(grupo)referencia un grupo, yLOCALhace match con terminales locales (no por red).Ten siempre una vía alternativa (consola física, o red de origen incluida) — si tu IP cambia y no la actualizas, te quedas fuera por SSH.
-
(Opcional) Restringir por horario con
pam_time. Añadir también en/etc/pam.d/sshd:account required pam_time.soY definir la ventana en
/etc/security/time.conf— el ejemplo deniega ahostingpor SSH fuera de las 8:00–18:00:sshd ; * ; hosting ; !Al0800-1800Formato
servicios ; terminales ; usuarios ; franjas; las franjas con!se deniegan, las demás se permiten (Al= los días indicados,MoTuWeThFr= de lunes a viernes). -
Validar la configuración sin cerrar sesión:
sudo pam-auth-update --packagesudo authselect apply-changesLas reglas de
access.confytime.confaplican en cuanto se guardan; no hay servicio que reiniciar. Prueba siempre en una sesión nueva antes de cerrar la actual.
Nivel 4 — Segundo factor TOTP¶
Opcional, avanzado. Añade un segundo factor a SSH: además de tu clave pública, necesitas un código que cambia cada 30 segundos (pam_oath). Su gracia se multiplica si ya aplicaste Proteger SSH: la pila queda clave + código, sin contraseña en juego.
Con pam_oath la tabla de secretos es central (/etc/users.oath) — limpio para un servidor con pocos administradores. Para varios usuarios con gestión individual, mira la alternativa pam_google_authenticator al final.
Riesgo de quedarte fuera
Este nivel es la capa que más puede dejarte fuera: si pierdes el teléfono o el secreto, no podrás autenticarte. Guarda una copia del secreto en tu gestor de contraseñas y mantén una vía de rescate por consola. Actívalo solo sobre un usuario cuyo acceso por clave ya funcione (Nivel 2 de proteger-ssh).
-
Instalar
pam_oath:sudo apt install libpam-oath oath-toolkitsudo dnf install oath-toolkit -
Crear la tabla de secretos:
sudo sh -c 'umask 077; echo "HOTP/T30/6 hosting $(openssl rand 20 | base32 | tr -d \"=\")" > /etc/users.oath'Guarda el secreto (tercer campo de la línea que acaba de escribir):
sudo grep hosting /etc/users.oathAñádelo a tu app de TOTP (Aegis, Authenticator, 1Password...) y verifica el código actual:
oathtool --totp --base32 "$(awk '$2=="hosting"{print $3}' /etc/users.oath)"Debe coincidir con el de tu app. Para un segundo operador, repite añadiendo otra línea con su nombre.
Formato de línea:
HOTP/T30/6 usuario SECRETO_BASE32. El fichero se crea conumask 077(solo root). Si quieres crearlo a mano:sudo vim /etc/users.oath+sudo chmod 600 /etc/users.oath. -
Enchufar el módulo en la pila de
sshd(ambas distros, antes de cualquier@includeosubstack):sudo vim /etc/pam.d/sshdAñadir al bloque
auth:auth required pam_oath.so usersfile=/etc/users.oath window=30 digits=6 -
Obligar a usar clave más código en SSH — amplía el fichero
00-hardening.confde Proteger SSH:sudo vim /etc/ssh/sshd_config.d/00-hardening.confAñadir:
AuthenticationMethods publickey,keyboard-interactive KbdInteractiveAuthentication yesPasswordAuthentication no(de proteger-ssh) se mantiene; el canal keyboard-interactive queda reservado para el reto TOTP, no para contraseñas. El servidor tiene que poder consultar la hora (NTP) — un reloj mal sincronizado invalida los códigos. -
Validar y recargar sin cerrar la sesión actual:
sudo sshd -t sudo service sshd reload -
En una terminal nueva, confirmar que entras con clave + código:
ssh hosting@<ip-servidor>
Alternativa: pam_google_authenticator
Si prefieres secretos por usuario en vez de una tabla central: instala libpam-google-authenticator (Ubuntu) o google-authenticator (Fedora), ejecuta google-authenticator como cada usuario (genera un QR para importar en la app) y añade en /etc/pam.d/sshd:
auth required pam_google_authenticator.so
La gestión es individual (~/.google_authenticator), cómoda para muchos usuarios y dependiente de que cada uno configure su secreto — donde la tabla central de pam_oath es más controlable para un servidor propio.
Referencia¶
Ficheros que quedan tocados por nivel:
| Nivel | Ficheros |
|---|---|
| 1 | /etc/security/pwquality.conf, common-password / system-auth |
| 2 | common-auth (Ubuntu) o authselect + /etc/security/faillock.conf (Fedora) |
| 3 | /etc/pam.d/sshd, /etc/security/access.conf, /etc/security/time.conf |
| 4 | /etc/pam.d/sshd, /etc/users.oath, sshd_config.d/00-hardening.conf |
Verificar¶
- Nivel 1 — como usuario
hosting, intenta poner una contraseña débil conpasswd; debe rechazarla indicando la política. - Nivel 2 — falla 5 veces el login de
hostingy comprueba quesudo faillocklo marca bloqueado; desbloquea consudo faillock --reset --user hosting. - Nivel 3 — desde una IP no incluida,
ssh hosting@<ip-servidor>debe denegar el acceso sin pedir clave; desde tu IP permitida, entra normal. Fuera de la ventana detime.conf, también se deniega. - Nivel 4 —
ssh hosting@<ip-servidor>pide la clave y después el código; un código erróneo corta la conexión.
Y ahora qué
La autenticación ya tiene política, bloqueo y opcionalmente segundo factor. El siguiente paso es mantener el servidor al día con las Actualizaciones automáticas.