Escribes el nombre de usuario correcto. La contraseña correcta. Incluso la pegas desde el gestor de contraseñas, lo que significa que está definitivamente correcta. Y OpenVPN responde con el mensaje más frío de las redes: AUTH_FAILED.
Este es el tipo de fallo que hace perder horas porque está etiquetado como un problema humano (“contraseña incorrecta”) mientras que a menudo es un problema de sistemas (política, plugin, reloj, cifrado, revocación, entorno). Trátalo como un incidente, no como una obra moralizante.
Qué significa realmente AUTH_FAILED (y qué no significa)
AUTH_FAILED significa: el servidor decidió rechazar al cliente durante la fase de “autenticación de usuario” y se lo comunicó al cliente. Eso es todo. No significa que “tu contraseña es incorrecta.” Ni siquiera significa que el servidor comprobó tu contraseña.
La autenticación en OpenVPN puede involucrar múltiples capas, y diferentes capas producen resultados en el cliente que se parecen peligrosamente:
- Identidad TLS: certificados, CA, revocación, EKU, validez por reloj, opciones TLS.
- Autenticación de usuario: archivo estático, PAM, LDAP, RADIUS, envoltorios tipo OAuth, gateways MFA personalizados.
- Política: restricciones por usuario, pertenencia a grupos, “sin sesiones concurrentes”, reglas por IP de origen, permisos de rutas.
- Plomería de sesión: auth-token, renegociación, caché de autenticación, overrides de client-config-dir.
La parte operativa y molesta: dependiendo de la configuración, el cliente puede ver AUTH_FAILED incluso si el problema real fue un detalle TLS, un fallo de plugin, un timeout del backend o una diferencia en la normalización del nombre de usuario.
Una única cadena de error, muchos modos de fallo
OpenVPN es intencionalmente extensible. Por eso sobrevive en empresas que aún tienen un mainframe y tres proveedores de identidad. Pero la extensibilidad significa que la “decisión” puede ocurrir en un script o plugin que esté fuera del núcleo de OpenVPN. Y cuando el script dice “no”, el cliente oye “AUTH_FAILED”, incluso si el script dijo “no porque LDAP está caído” o “no porque el nombre de usuario contiene una @ y lo eliminamos”.
Una idea parafraseada de Werner Vogels (CTO de Amazon) que la gente de operaciones repite por una razón: todo falla, todo el tiempo; diseña y opera asumiendo que fallará
(idea parafraseada). AUTH_FAILED es un ejemplo perfecto: tu trabajo es encontrar qué dependencia falló.
Broma corta #1: Las contraseñas son como la leche: todo el mundo jura que la suya está fresca hasta que empieza a fallar en producción.
Guía rápida de diagnóstico (comprobar primero/segundo/tercero)
Este es el flujo para “detener la hemorragia”. Está sesgado a reducir el tiempo medio hasta tener claridad, no a explicar teoría. Puedes hacer la arqueología más profunda después.
Primero: confirma dónde estás fallando (TLS vs autenticación de usuario)
- Aumenta la verbosidad del cliente a 4–6. Busca: “TLS: Initial packet,” “VERIFY OK,” “Peer Connection Initiated,” luego “AUTH_FAILED.”
- Si TLS nunca termina, no persigas contraseñas. Persigue certificados, tiempo, cifrados, cadena CA, y escucha/puerto/firewall del servidor.
- Si TLS se completa y luego AUTH_FAILED, investiga la canalización de autenticación de usuario: plugin, script, PAM/LDAP/RADIUS/MFA y comprobaciones de política del servidor.
Segundo: revisa los logs del servidor en la marca de tiempo exacta
- Encuentra la línea de conexión para ese cliente (campos comunes: common-name, username, real address).
- Busca `AUTH_FAILED`, `PLUGIN_CALL`, `AUTH-PAM`, `radiusplugin`, `auth-user-pass-verify`, `client-denied`.
- Si ves un error de backend (bind LDAP fallido, timeout RADIUS), trátalo como una caída de identidad, no como un error de tecleo del usuario.
Tercero: valida tus suposiciones sobre usuario, dominio y método de auth
- ¿Espera el servidor `samaccountname`, `user@domain` o `DOMAIN\user`?
- ¿Estás usando `–auth-user-pass` con un archivo de contraseña, y contiene espacios en blanco finales?
- ¿Se requiere MFA? Algunas configuraciones rechazan “solo contraseña” con AUTH_FAILED y un mensaje inútil en los logs.
Cuarto: revisa política y estado
- Reglas de sesiones concurrentes (duplicate-cn, management interface, límites de sesión).
- Certificado revocado o usuario deshabilitado pero aun con “credenciales correctas”.
- Overrides en client-config-dir (push por usuario, iroute, o `disable`).
Quinto: reproducir en forma controlada
- Prueba las mismas credenciales desde una configuración de cliente conocida buena.
- Prueba un usuario conocido bueno desde la configuración de cliente que falla.
- Esto aísla “identidad” de “configuración del cliente” en minutos.
Hechos y contexto: por qué la autenticación de OpenVPN es extrañamente compleja
Algunos hechos pequeños y concretos ayudan a explicar por qué AUTH_FAILED es un cajón de sastre en el mundo real:
- OpenVPN nació en 2001, y sus puntos de extensión (scripts/plugins) fueron diseñados para autenticación empresarial heterogénea mucho antes de que “SSO” fuera la expectativa por defecto.
- La autenticación usuario/contraseña no es intrínseca a las VPN TLS; OpenVPN la añadió para satisfacer organizaciones que querían un segundo factor además de certificados.
- La integración con PAM hizo que OpenVPN se sintiera “nativo” en Unix—y también heredó la complejidad de PAM: políticas de cuenta, contraseñas expiradas, cuentas bloqueadas y orden de módulos.
- El soporte RADIUS se convirtió en un patrón empresarial común porque centraliza decisiones de autenticación y MFA, pero también introduce timeouts que parecen contraseñas incorrectas.
- client-config-dir de OpenVPN es poderoso: puedes sobrescribir silenciosamente configuraciones por usuario. Ese poder incluye romper silenciosamente el acceso de un usuario.
- Las listas de revocación (CRLs) son operativamente difíciles: son archivos, caducan, se olvidan. Un certificado revocado puede coexistir con credenciales “correctas” y aun así bloquearte.
- La corrección del reloj es crítica para la seguridad: los certificados y algunos tokens tienen ventanas temporales. Una deriva de tiempo provoca fallos de autenticación que se disfrazan de problemas de credenciales.
- La caché de autenticación evolucionó (auth-token, renegotiation) para reducir prompts repetidos, pero una mala configuración puede causar bucles o fallos por “token obsoleto”.
- La negociación de cifrados moderna cambió los valores por defecto en OpenVPN 2.5+ (data-ciphers). Desajustes pueden producir desconexiones tempranas que los usuarios interpretan como “problemas de auth”.
Triage en el cliente: demostrar lo que enviaste
Cuando alguien dice “las credenciales son correctas”, lo que a menudo quiere decir es “las credenciales funcionan en otro sitio”. Eso no es la misma afirmación. El cliente de OpenVPN podría estar enviando un nombre de usuario diferente al que el usuario cree. O podría enviar el nombre de usuario correcto con otra codificación. O el archivo de contraseña podría contener una nueva línea, retorno de carro o BOM.
Busca evidencia en el log del cliente (no en sentimientos)
En el cliente, aumenta la verbosidad y busca la secuencia:
- Handshake TLS establecido.
- El servidor envía opciones.
- El cliente solicita usuario/contraseña o las lee desde archivo.
- El servidor responde con AUTH_FAILED o envía un auth-token.
Si no ves un TLS handshake completado, no persigas la autenticación de usuario. Si lo ves, el servidor es accesible y la conversación de “contraseña” ocurrió (o se intentó).
Presta atención al formato del nombre de usuario
Las implementaciones empresariales de OpenVPN frecuentemente normalizan nombres de usuario. Algunas eliminan dominios; otras los requieren. Algunas aceptan `DOMAIN\user` y rechazan `user@domain`. Algunas convierten todo a minúsculas. Algunas tratan “john.smith” y “John.Smith” como usuarios distintos si están pegadas a un directorio legado.
Cuando depures, decide una representación canónica y pruébala. Si no, serás “correcto” de tres maneras diferentes y aun así estarás equivocado en producción.
Los archivos de credenciales son trampas
`–auth-user-pass /path/to/file` espera un archivo con dos líneas: usuario y contraseña. Ese archivo puede traicionarte con:
- Finales de línea CRLF de Windows (
\r\n), creando un\roculto en la contraseña. - Un espacio final copiado desde un ticket.
- Un BOM UTF-8 al inicio de la línea del usuario.
Broma corta #2: Lo único más persistente que una contraseña VPN expirada es un retorno de carro de Windows escondido al final de la misma.
Triage en el servidor: demostrar lo que decidió el servidor
Los registros del servidor son la fuente de la verdad, pero solo si registras lo suficiente y miras en el lugar correcto. OpenVPN puede registrar vía syslog, un archivo, journal de systemd o la interfaz de management. Plugins y scripts de auth pueden registrar en otro sitio. A veces la única pista es que el plugin devolvió non-zero.
Conoce tu mecanismo de autenticación
En el servidor, la autenticación de usuario suele venir de uno de estos:
- PAM (`openvpn-plugin-auth-pam.so`): usa la pila PAM del sistema, puede imponer expiración de contraseñas/bloqueos de cuentas.
- Script externo (`auth-user-pass-verify`): tu script decide. Si se bloquea, obtienes AUTH_FAILED.
- Plugin RADIUS: delega en un servidor RADIUS; timeouts y problemas con el shared secret parecen contraseñas incorrectas.
- Plugin/script LDAP: hace bind a LDAP; base DN, filtro o TLS incorrectos causan rechazos.
- Gateway MFA: flujos tipo Duo frecuentemente modifican el campo de contraseña (append de código push) o usan challenge/response RADIUS.
Diferencia entre “auth rechazado” y “auth roto”
Una canalización de autenticación puede rechazar porque el usuario es incorrecto. También puede rechazar porque la canalización está rota. Operacionalmente son severidades distintas:
- Usuario equivocado: un usuario, consistente, backend saludable.
- Canalización rota: muchos usuarios, timeouts, errores de plugin, ráfagas en logs, picos de CPU, fallos de resolutor.
Sé implacable con esta distinción. Si cinco personas fallan a la vez justo después de un deploy, no son cinco personas que de repente olvidaron cómo teclear.
Tareas prácticas: comandos, salidas, decisiones
A continuación hay comprobaciones prácticas que puedes ejecutar. Cada una incluye un fragmento de salida realista y la decisión que tomas a partir de ella. Úsalas como un runbook, no como un buffet.
Task 1: Confirmar que el cliente realmente alcanza el servidor y completa TLS
cr0x@server:~$ sudo openvpn --config client.ovpn --verb 5
...
TCP/UDP: Preserving recently used remote address: [AF_INET]203.0.113.10:1194
TLS: Initial packet from [AF_INET]203.0.113.10:1194, sid=2c0e1f9d 1a2b3c4d
VERIFY OK: depth=1, CN=corp-vpn-ca
VERIFY OK: depth=0, CN=vpn-gateway-1
Control Channel: TLSv1.3, cipher TLS_AES_256_GCM_SHA384, peer certificate: 256 bit RSA
[corp-vpn] Peer Connection Initiated with [AF_INET]203.0.113.10:1194
AUTH: Received control message: AUTH_FAILED
SIGTERM[soft,auth-failure] received, process exiting
Significado: TLS funcionó; el fallo está en auth de usuario/política. Decisión: Dejar de depurar certificados y pasar a logs/plugins de auth del servidor.
Task 2: Revisar el journal del servidor por líneas relacionadas con auth en el momento del fallo
cr0x@server:~$ sudo journalctl -u openvpn-server@corp -S "2025-12-27 09:10:00" -U "2025-12-27 09:15:00"
Dec 27 09:12:31 vpn1 openvpn[1842]: 198.51.100.44:51233 TLS: Username/Password authentication deferred for username 'j.smith'
Dec 27 09:12:31 vpn1 openvpn[1842]: 198.51.100.44:51233 PLUGIN_CALL: POST /usr/lib/openvpn/openvpn-plugin-auth-pam.so/PLUGIN_AUTH_USER_PASS_VERIFY status=1
Dec 27 09:12:31 vpn1 openvpn[1842]: 198.51.100.44:51233 AUTH_FAILED: user 'j.smith'
Significado: El plugin PAM rechazó. Decisión: Validar la configuración PAM, el estado de la cuenta y si PAM está devolviendo “expirada/bloqueada” vs “contraseña incorrecta”.
Task 3: Verificar qué mecanismo de autenticación usa el servidor
cr0x@server:~$ sudo grep -E '^(plugin|auth-user-pass-verify|client-cert-not-required|verify-client-cert|management)' /etc/openvpn/server/corp.conf
plugin /usr/lib/openvpn/openvpn-plugin-auth-pam.so login
verify-client-cert require
management 127.0.0.1 7505
Significado: El plugin PAM está en uso; el certificado de cliente también es requerido. Decisión: Depurar PAM y también comprobar validez/revocación de certificados si los síntomas no encajan con auth de usuario.
Task 4: Probar la auth PAM directamente en el servidor (aislando OpenVPN)
cr0x@server:~$ sudo pamtester login j.smith authenticate
Password:
pamtester: Authentication failure
Significado: PAM rechaza por sí mismo; OpenVPN solo es el mensajero. Decisión: Revisar conectividad del directorio, orden de módulos PAM, expiración de contraseña, bloqueo de cuenta y salud de NSS/SSSD.
Task 5: Inspeccionar la pila PAM usada por el plugin
cr0x@server:~$ sudo sed -n '1,200p' /etc/pam.d/login
auth required pam_securetty.so
auth requisite pam_nologin.so
auth include common-auth
account include common-account
session include common-session
Significado: El plugin usa el servicio “login”, que puede ser más estricto de lo esperado (nologin, securetty). Decisión: Considerar un archivo de servicio PAM dedicado (p. ej., /etc/pam.d/openvpn) para evitar restricciones no relacionadas.
Task 6: Comprobar la salud de SSSD / directorio (culpable silencioso común)
cr0x@server:~$ sudo systemctl status sssd --no-pager
● sssd.service - System Security Services Daemon
Loaded: loaded (/lib/systemd/system/sssd.service; enabled)
Active: active (running) since Fri 2025-12-27 08:40:18 UTC; 32min ago
...
Significado: SSSD está activo, pero eso no garantiza que pueda alcanzar LDAP. Decisión: Consultar un usuario y revisar logs por timeouts.
Task 7: Verificar búsqueda de usuario y pertenencia a grupos (la política puede bloquear)
cr0x@server:~$ id j.smith
uid=110245(j.smith) gid=10000(domain users) groups=10000(domain users),12010(vpn-users)
Significado: El usuario existe y está en vpn-users. Decisión: Si la auth sigue fallando, no es “usuario inexistente”; es estado de contraseña/cuenta o un flujo upstream de política/MFA.
Task 8: Revisar estado de la cuenta (bloqueada/expirada) cuando usas auth local o respaldada por LDAP
cr0x@server:~$ sudo passwd -S j.smith
j.smith L 2025-11-02 0 99999 7 -1
Significado: “L” indica cuenta bloqueada (para cuentas locales; la interpretación varía con setups de directorio). Decisión: Desbloquear/resetear mediante el sistema de identidad apropiado; dejar de decir al usuario “intente de nuevo”.
Task 9: Validar archivo de credenciales del cliente por caracteres ocultos
cr0x@server:~$ sed -n '1,2p' -n auth.txt | cat -A
j.smith$
MyS3cretP@ssw0rd^M$
Significado: La línea de contraseña termina con ^M (CR). Esa es otra contraseña. Decisión: Convertir el archivo a finales de línea Unix y reintentar.
Task 10: Arreglar CRLF en el archivo de credenciales y volver a probar
cr0x@server:~$ sed -i 's/\r$//' auth.txt
cr0x@server:~$ sed -n '1,2p' auth.txt | cat -A
j.smith$
MyS3cretP@ssw0rd$
Significado: CR eliminado. Decisión: Ejecutar el cliente de nuevo; si ahora funciona, te ahorraste una hora de culpar innecesariamente a LDAP.
Task 11: Comprobar revocación de certificados / problemas con CRL
cr0x@server:~$ sudo grep -E '^(crl-verify|ca|cert|key)' /etc/openvpn/server/corp.conf
ca /etc/openvpn/pki/ca.crt
cert /etc/openvpn/pki/issued/vpn-gateway-1.crt
key /etc/openvpn/pki/private/vpn-gateway-1.key
crl-verify /etc/openvpn/pki/crl.pem
Significado: Se aplica CRL. Un certificado cliente revocado puede bloquear el acceso incluso si la contraseña es correcta. Decisión: Comprobar si el certificado que se conecta está revocado y si el archivo CRL está actualizado/legible.
Task 12: Inspeccionar vigencia y permisos del archivo CRL
cr0x@server:~$ sudo ls -l /etc/openvpn/pki/crl.pem
-rw-r----- 1 root openvpn 2451 Nov 1 2024 /etc/openvpn/pki/crl.pem
Significado: Marca de tiempo antigua. Si tu PKI rota, podrías estar aplicando una CRL obsoleta (o perdiendo revocaciones recientes). Decisión: Regenerar/actualizar la CRL como parte de las operaciones PKI y asegurarse de que OpenVPN pueda leerla.
Task 13: Confirmar que OpenVPN está leyendo la configuración que crees
cr0x@server:~$ sudo systemctl cat openvpn-server@corp
# /lib/systemd/system/openvpn-server@.service
ExecStart=/usr/sbin/openvpn --status %t/openvpn-server/status-%i.log --status-version 2 --suppress-timestamps --config /etc/openvpn/server/%i.conf
Significado: La instancia usa /etc/openvpn/server/corp.conf. Decisión: Dejar de editar el archivo equivocado bajo /etc/openvpn/ y esperar milagros.
Task 14: Revisar la interfaz de management para pistas de auth en tiempo real (si está habilitada)
cr0x@server:~$ printf "status 3\nquit\n" | nc 127.0.0.1 7505
OpenVPN STATISTICS
Updated,2025-12-27 09:13:02
CLIENT_LIST,UNDEF,198.51.100.44:51233,10.8.0.0,0,0,2025-12-27 09:12:31
END
Significado: El cliente nunca llegó a establecerse completamente (UNDEF common name es una pista). Decisión: Enfocarse en la etapa de auth, no en routing/opciones push.
Task 15: Verificar la hora del servidor (tokens/MFA y validez de certificados dependen de ello)
cr0x@server:~$ timedatectl
Local time: Fri 2025-12-27 09:13:55 UTC
Universal time: Fri 2025-12-27 09:13:55 UTC
RTC time: Fri 2025-12-27 09:13:55
Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
Significado: La hora está sincronizada. Decisión: Si esto estuviera desincronizado, arregla NTP antes de depurar fallos “aleatorios” de auth, especialmente con tokens de corta vida.
Task 16: Comprobar resolución DNS en el servidor VPN (LDAP/RADIUS a menudo usa nombres)
cr0x@server:~$ getent hosts ldap01.corp.local
10.20.30.40 ldap01.corp.local
Significado: El nombre resuelve. Decisión: Si falla o resuelve a una IP antigua, arregla DNS/hosts/SSSD resolver; los backends de auth no serán alcanzables de forma fiable.
Task 17: Si usas RADIUS, confirmar conectividad (timeout vs rechazo)
cr0x@server:~$ nc -vz radius01 1812
Connection to radius01 1812 port [tcp/*] succeeded!
Significado: Conectividad TCP existe (nota: RADIUS es típicamente UDP; esto solo prueba nombre/ruta/firewall básicos). Decisión: Si la red está bloqueada, el plugin RADIUS puede representarlo como AUTH_FAILED.
Task 18: Revisar alineación de versiones de OpenVPN (el comportamiento cambia entre versiones)
cr0x@server:~$ openvpn --version
OpenVPN 2.6.8 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD]
library versions: OpenSSL 3.0.13 30 Jan 2024, LZO 2.10
Significado: El servidor es 2.6.x con OpenSSL 3. Decisión: Si los clientes son antiguos, revisa data-ciphers y TLS min version. Un desajuste puede parecer “rareza de auth” para los usuarios.
Errores comunes (síntoma → causa raíz → solución)
1) Síntoma: “AUTH_FAILED” inmediatamente después de “Peer Connection Initiated”
Causa raíz: Plugin o script de auth está rechazando; las credenciales pueden estar bien pero el backend está caído o la política niega al usuario.
Solución: Inspecciona logs del servidor alrededor de `PLUGIN_CALL` / `AUTH-PAM` / salida del script. Si es una caída de backend, trátalo como un incidente y restaura la salud de la dependencia.
2) Síntoma: Las credenciales funcionan por SSH/PAM, pero OpenVPN dice AUTH_FAILED
Causa raíz: El plugin PAM de OpenVPN apunta a un servicio PAM distinto (p. ej., `login`) con restricciones adicionales (nologin, securetty, reglas por hora).
Solución: Usar un archivo de servicio PAM dedicado (p. ej., /etc/pam.d/openvpn) y ajustar la línea `plugin … openvpn` en consecuencia.
3) Síntoma: Solo fallan clientes Windows; Linux/macOS funcionan
Causa raíz: Archivo de credenciales guardado con CRLF, añadiendo `\r` a la contraseña; o el cliente GUI enviando el nombre de usuario en formato distinto.
Solución: Normalizar finales de línea; evitar archivos de contraseña cuando sea posible; probar con entrada manual; estandarizar el formato del nombre de usuario.
4) Síntoma: Solo un usuario falla, repetidamente, en todos los dispositivos
Causa raíz: Cuenta bloqueada, contraseña expirada, usuario eliminado del grupo requerido, o certificado revocado mientras la contraseña sigue válida.
Solución: Revisar el estado en el proveedor de identidad de ese usuario; verificar pertenencia a grupos; comprobar CRL y estado de certificado.
5) Síntoma: Todos fallan justo después de una actualización de OpenVPN
Causa raíz: Cambios en valores por defecto de cifrado/TLS; plugin binario incompatible; o verificación más estricta que revela problemas de certificados existentes.
Solución: Validar `data-ciphers` y mínimos TLS; confirmar ruta del plugin y compatibilidad ABI; hacer rollback si es necesario y luego reintroducir cambios deliberadamente.
6) Síntoma: Usuarios aleatorios fallan y luego tienen éxito al reintentar
Causa raíz: Timeouts del backend (RADIUS/LDAP), flaps de DNS, servidor de autenticación sobrecargado, o políticas de rate limit/bloqueo.
Solución: Instrumentar y monitorizar latencia del backend; reducir timeouts con cuidado; añadir redundancia; arreglar DNS. Reintentos no son una estrategia.
7) Síntoma: El usuario introduce contraseña + MFA, aun así AUTH_FAILED
Causa raíz: La integración MFA espera un formato distinto (concatenar OTP, usar challenge/response) o requiere un atributo RADIUS específico.
Solución: Confirmar el flujo MFA con el equipo de identidad; actualizar instrucciones al cliente; asegurar que el plugin soporta el modo MFA desplegado.
8) Síntoma: AUTH_FAILED en reconexión/renegociación, no en la primera conexión
Causa raíz: Caché de auth/token y comportamiento de renegociación inconsistente; `auth-nocache` y políticas de token en conflicto; estado de sesión perdido tras reinicio del servidor.
Solución: Decidir si se quieren tokens; alinear configuración servidor/cliente; probar ventanas de renegociación; evitar configuraciones “a medias” de tokens.
Tres micro-historias corporativas desde el frente
Micro-historia 1: El incidente causado por una suposición equivocada
La empresa tenía una pasarela VPN que “usaba LDAP”. Esa frase había sido repetida en tickets por años, como un encantamiento para evitar preguntas. Un nuevo SRE recibió un pager por una tormenta de AUTH_FAILED tras un cambio en el directorio. Los usuarios insistían en que sus credenciales eran correctas. El helpdesk insistía en que la VPN estaba bien. El dashboard no decía nada, porque no existía.
El SRE siguió los logs de OpenVPN y vio `PLUGIN_CALL` seguido de `status=1`. Sin más detalle. Excelente. Así que asumieron fallos de bind LDAP y empezaron a investigar: conectividad, DNS, firewall. Todo parecía normal. Pasaron una hora revisando el calendario de cambios del equipo de directorio, preparando el cortés mensaje “¿rompieron LDAP?”.
Antes de enviarlo, comprobaron la configuración del servidor OpenVPN y notaron que el plugin era PAM, no LDAP. LDAP era solo una dependencia upstream vía SSSD, y la caché de SSSD estaba obsoleta porque el servidor no podía alcanzar la fuente de tiempo tras un cambio de routing. La capa Kerberos/LDAP no falló por completo; se volvió lenta e inconsistente. PAM devolvió fallos. OpenVPN informó AUTH_FAILED.
La suposición equivocada fue sutil: “AUTH_FAILED después de cambio en directorio implica fallo de bind LDAP.” El problema real fue “resolución de identidad se está timeout-eando porque la sincronización de tiempo se rompió”, que es el tipo de cosa que te hace respetar NTP como si fuera una base de datos de producción.
Arreglaron el routing hacia NTP, reiniciaron SSSD para limpiar la caché más grave, y los fallos desaparecieron. El equipo de directorio nunca supo que había un correo de culpas en borradores.
Micro-historia 2: La optimización que salió mal
Un equipo preocupado por seguridad quería menos prompts de contraseña. Habilitaron reauth basada en tokens para que los usuarios no tuvieran que teclear credenciales al reconectar. Sonaba bien: menos prompts, menos bloqueos, menos tickets. Lo desplegaron durante una semana “tranquila”, que en tiempo corporativo significa “justo antes de un feriado”.
Al principio, éxito. Luego los portátiles empezaron a dormir y despertar, moviéndose entre redes, intentando reconectar. Algunas reconexiones funcionaban. Otras fallaban con AUTH_FAILED. El helpdesk lo escaló como “problemas de contraseña”. Los usuarios empezaron a resetear contraseñas, lo que por supuesto no arreglaba fallos por tokens. Ahora había fallos VPN y churn por resets de contraseña.
La causa raíz fue un desajuste entre los tiempos de vida de los tokens y el comportamiento de renegociación. Algunos clientes presentaban un token obsoleto después de un largo sueño; el servidor lo trató como inválido y rechazó. Los logs eran insuficientes, así que todo parecía como si el usuario hubiera tecleado una contraseña mala, a pesar de que no se había tecleado ninguna.
La solución fue aburrida: alinear las políticas de token con el comportamiento real de los dispositivos, aumentar el logging alrededor de validación de tokens y añadir una caída a entrada de credenciales cuando falla auth por token. También: no hagas cambios de comportamiento de autenticación justo antes de feriados a menos que disfrutes aprender palabrotas nuevas durante tus vacaciones.
Micro-historia 3: La práctica aburrida pero correcta que salvó el día
Un equipo de plataforma interna ejecutaba dos gateways OpenVPN detrás de un balanceador de carga. Nada sofisticado. Lo sofisticado fue su disciplina: cada cambio tenía un canario, y cada canario tenía un usuario de prueba conocido bueno y uno conocido malo. También mantenían una pequeña suite de “chequeos de dependencias de identidad” que corría cada minuto: ¿podemos resolver hostnames LDAP?, ¿podemos hacer bind?, ¿alcanzamos RADIUS?, ¿está el tiempo sincronizado?.
Una mañana, los usuarios comenzaron a reportar AUTH_FAILED—solo en un gateway. Los chequeos canarios lo detectaron en menos de dos minutos: latencia de bind LDAP se disparó en vpn2, pero no en vpn1. El balanceador seguía enviando tráfico a vpn2 porque las comprobaciones de salud eran solo “puerto abierto”.
Como tenían logs por nodo y chequeos estructurados, no debatieron si los usuarios olvidaron contraseñas. Drenaron vpn2 del pool, restaurando el servicio, y luego depuraron con calma: vpn2 tenía un drift en la configuración del resolutor que apuntaba a un DNS antiguo. La resolución de nombres LDAP fallaba intermitentemente, provocando timeouts de auth y rechazos.
Arreglaron la configuración del resolutor, añadieron una comprobación de salud en el balanceador que ejercitara realmente las dependencias de autenticación, y redactaron un postmortem con exactamente una frase de culpa: “Confiamos en una comprobación de puerto para representar una canalización de identidad”. Fue aburrido, y evitó que el mismo incidente reapareciera con nuevo disfraz.
Listas de comprobación / plan paso a paso
Paso a paso: cuando un usuario reporta AUTH_FAILED
- Captura una marca de tiempo (incluyendo zona horaria) y la IP pública del cliente.
- Pide el formato exacto del nombre de usuario que ingresó (incluyendo dominio/realm).
- Confirma si usó un archivo de credenciales o un prompt interactivo.
- Revisa logs del servidor en esa marca de tiempo. Encuentra la línea de conexión y la línea de decisión de auth.
- Identifica el backend de auth: PAM vs script vs RADIUS vs plugin LDAP.
- Prueba el backend directamente: test PAM, bind LDAP, conectividad RADIUS, pertenencia a grupos.
- Revisa capas de política: pertenencia a grupos, límites de sesión concurrente, overrides CCD por usuario.
- Si hay certificados: verificar que el certificado cliente no esté expirado/revocado; validar frescura de la CRL.
- Decidir: remediación del usuario (desbloquear/resetear) vs incidente de infraestructura (backend caído).
Paso a paso: cuando muchos usuarios reportan AUTH_FAILED
- Asume caída de dependencia hasta que se demuestre lo contrario.
- Revisa un usuario conocido bueno desde una configuración de cliente conocida buena. Si falla, no es educación al usuario.
- Revisa backends de identidad: disponibilidad del directorio, salud del servidor RADIUS, estado del proveedor MFA, DNS, sincronización de tiempo.
- Revisa cambios recientes: actualización de OpenVPN, actualizaciones de plugin, ediciones en PAM, rotación de certificados, cambios en firewall.
- Aísla por nodo si tienes múltiples gateways: drena uno a la vez para ver si los fallos están localizados.
- Aumenta logging temporalmente (con cuidado por datos sensibles) para capturar paths de salida de plugins/scripts.
- Estabiliza primero: haz rollback o bypass de funciones de auth no críticas si la política lo permite (p. ej., deshabilitar chequeos de grupo estrictos temporalmente).
- Escribe la línea de tiempo. Lo olvidarás en 24 horas, y tu yo futuro lo agradecerá.
Qué evitar (opinado)
- No pidas a los usuarios que reseteen contraseñas como primer paso. Crea ruido y oculta fallos sistémicos.
- No depures solo desde el cliente. AUTH_FAILED es una decisión del servidor.
- No cambies tres variables a la vez (“actualizamos OpenVPN, rotamos certificados y modificamos PAM”). Eso no es ingeniería; es apuesta.
- Sí crea un cliente conocido bueno y mantenlo impecable. Es tu grupo de control.
Preguntas frecuentes
¿Por qué OpenVPN dice AUTH_FAILED cuando la contraseña es correcta?
Porque el servidor rechazó el intento de autenticación por razones que incluyen, pero no se limitan a: contraseña incorrecta; cuenta bloqueada; contraseña expirada; falta de pertenencia a grupo; timeout del backend; fallo de plugin; o política MFA.
¿Cómo sé si son problemas TLS/certificados o de usuario/contraseña?
Busca un handshake TLS completado en el log del cliente. Si ves “Peer Connection Initiated” y luego AUTH_FAILED, TLS probablemente tuvo éxito y falló la auth/política de usuario.
¿Puede un certificado revocado causar AUTH_FAILED aunque las credenciales sean correctas?
Sí. Si el servidor exige certificados de cliente y aplica una CRL, un certificado revocado te bloqueará independientemente de la corrección del usuario/contraseña.
¿Cuál es el log de servidor más rápido para revisar en Linux con systemd?
journalctl -u openvpn-server@<instance> alrededor del tiempo del fallo. Busca llamadas a plugins, invocación de scripts y líneas explícitas AUTH_FAILED con nombres de usuario.
¿Por qué solo fallan usuarios Windows?
Causas comunes: CRLF en un archivo de credenciales, formato de nombre de usuario distinto en el cliente GUI, o usuarios copiando una contraseña con espacio final. Valida el archivo de credenciales con cat -A y estandariza la entrada.
Usamos PAM. ¿Por qué SSH funciona pero OpenVPN falla?
PAM es modular. SSH puede usar el servicio PAM sshd mientras que OpenVPN usa login (u otro). Esas pilas pueden diferir en reglas de cuenta, TTYs permitidos, o comportamiento nologin.
¿Problemas de DNS pueden presentarse como AUTH_FAILED?
Sí. Si tu backend de auth usa nombres (LDAP, RADIUS, gateways MFA), fallos de resolución o DNS obsoleto pueden causar timeouts que terminan en un rechazo genérico de auth.
¿Importa la sincronización de tiempo para la autenticación VPN?
Absolutamente. Los certificados tienen ventanas de validez; sistemas MFA y tokens dependen del tiempo; la autenticación basada en Kerberos es muy sensible a skew de reloj. Arregla la hora primero si está mal.
¿Debemos habilitar logging más verboso permanentemente?
Mantén logs base que distingan fallos TLS de fallos del backend de auth. Aumenta la verbosidad temporalmente durante incidentes. Ten cuidado de no registrar material sensible desde scripts/plugins.
¿Es seguro confiar en health checks “puerto abierto” para gateways VPN?
No. Un listener puede estar OK mientras la canalización de auth está rota. Añade health checks que validen reachability de dependencias (DNS, bind del directorio, respuesta RADIUS) y drena nodos cuando fallen.
Conclusión: siguientes pasos que realmente reducen ruido de pager
Si solo haces unas pocas acciones a partir de esto:
- Separa fallos TLS de fallos de auth de usuario usando evidencia del log del cliente. Deja de tratar AUTH_FAILED como automáticamente “contraseña mala”.
- Haz que el servidor se explique: asegura que los logs incluyan resultados de plugins/scripts y sean fáciles de consultar por timestamp.
- Prueba los backends de auth directamente (PAM/SSSD/LDAP/RADIUS) para que puedas decir “caída de identidad” con confianza.
- Estandariza formatos de nombres de usuario y documenta los flujos MFA en un lugar que no se pudra.
- Crea un usuario de prueba conocido bueno y una configuración de cliente conocida buena, y úsalos como tu grupo de control durante incidentes.
AUTH_FAILED no es un veredicto. Es una pista de que el servidor tomó una decisión. Tu trabajo es encontrar qué componente le susurró al oído.