Problema

En entornos de producción con Windows Server 2022 se habilita la característica OpenSSH Server para ofrecer SFTP o acceso remoto a scripts de backup. Con frecuencia los administradores observan que las transferencias funcionan durante varios ciclos y, de repente, aparecen fallos sin un mensaje de error claro. Los síntomas típicos son:

  • Conexiones SFTP que se cierran después de un tiempo sin razón aparente.
  • Mensajes de “Connection closed by remote host” en los logs del cliente.
  • Intermitencia que parece seguir un patrón de éxito‑fallo‑éxito.
  • Ningún cambio reciente en la configuración del daemon (sshd_config) ni en la red.

Este comportamiento es frustrante porque los backups pueden quedar incompletos y el equipo de operaciones pierde tiempo revisando credenciales, permisos de archivo y la configuración de cifrado, sin encontrar la causa raíz.

Causa

OpenSSH en Windows Server no es un port directo de la versión Linux; depende de componentes del subsistema de Windows y de la cuenta bajo la que corre el servicio. Las causas más habituales de los fallos intermitentes son:

  1. Cuenta de servicio con privilegios insuficientes
    El servicio sshd se ejecuta bajo la cuenta NT SERVICE\sshd. Cuando el proceso necesita crear una sesión de usuario para la autenticación, recurre a la cuenta que se especifica en el archivo de configuración (AuthorizedKeysFile, PasswordAuthentication, etc.). Si esa cuenta es un dominio o un usuario con membresías especiales, el proceso puede colgarse al intentar cargar perfiles o validar grupos, provocando timeouts.

  2. Política de contraseñas complejas y expiración
    Windows impone políticas de complejidad y expiración que, combinadas con la forma en que OpenSSH valida contraseñas, pueden generar rechazos silenciosos después de varios intentos exitosos. La caché de credenciales de LSA a veces se invalida de forma inesperada.

  3. Problemas de sincronización de perfil de usuario
    Cuando el usuario que se autentica no tiene un perfil cargado (por ejemplo, una cuenta local sin directorio de perfil), el daemon intenta crear uno bajo el contexto del servicio. Si la ruta del perfil está en una unidad de red o tiene ACLs restrictivas, la creación falla y la conexión se corta.

  4. Configuración de permisos NTFS sobre la carpeta del usuario
    OpenSSH verifica que el directorio home del usuario sea accesible solo por él. Si la ACL permite a grupos como Administrators o Authenticated Users acceso de escritura, el daemon rechaza la sesión por motivos de seguridad, pero el mensaje llega al cliente como un cierre abrupto.

  5. Bugs específicos de la versión 8.9p1‑1 (o versiones cercanas) en Windows
    En la rama de OpenSSH distribuida con Windows Server 2022 se reportó un bug que afecta la autenticación de usuarios locales sin pertenecer a grupos privilegiados. El fallo se manifiesta como desconexiones intermitentes y se soluciona creando un usuario local dedicado al servicio.

Solución

La estrategia consiste en aislar la autenticación a una cuenta local mínima y asegurarse de que el entorno de esa cuenta cumpla los requisitos de OpenSSH. Los pasos genéricos son:

  1. Crear una cuenta local exclusiva para SSH/SFTP

    • Nombre descriptivo (p.ej. sshd_user).
    • Contraseña que cumpla la política de complejidad, pero sin expiración automática.
    • Sin membresías de grupo adicionales; solo la pertenencia implícita a Users.
  2. Asignar un directorio home con permisos estrictos

    • Crear C:\Users\sshd_user (o cualquier ruta que prefiera).
    • Configurar ACLs: FullControl solo para sshd_user y SYSTEM.
    • Eliminar herencia de permisos de carpetas superiores.
  3. Actualizar sshd_config para usar la cuenta recién creada

    • Establecer Match User sshd_user y definir ChrootDirectory o ForceCommand internal-sftp según la necesidad.
    • Asegurarse de que PasswordAuthentication yes (si se usa contraseña) o PubkeyAuthentication yes (si se usan llaves) esté habilitado.
  4. Desactivar expiración de contraseña y políticas de bloqueo para esa cuenta

    • En Local Security PolicyPassword PolicyMaximum password age0 (nunca).
    • En Account Lockout PolicyAccount lockout threshold0 (desactivar bloqueo temporal).
  5. Reiniciar el servicio OpenSSH

    • Restart-Service sshd o net stop sshd && net start sshd.
  6. Validar que el servicio corre bajo la cuenta correcta

    • Verificar en el Task ManagerDetails que el proceso sshd.exe tiene el SID NT SERVICE\sshd.
    • Los sub‑procesos que manejan la sesión deben aparecer con el SID del usuario sshd_user.

Alternativas

  • Uso de autenticación basada en claves: elimina la dependencia de la política de contraseñas y reduce la superficie de error.
  • Crear un grupo de servicio dedicado y añadir la cuenta al mismo, siempre que el grupo no tenga privilegios elevados.
  • Actualizar OpenSSH a la última versión disponible en el repositorio de PowerShell/Win32‑OpenSSH, ya que los parches posteriores corrigen el bug mencionado.

Cuándo aplicar esta solución

Aplica cuando observes:

  • Fallos de SFTP/SSH que aparecen de forma intermitente sin cambios en la red ni en la configuración del daemon.
  • Logs de sshd que muestran Connection closed sin códigos de error claros.
  • La cuenta usada para la autenticación es un dominio o un usuario con pertenencia a grupos administrativos.

No es necesario si:

  • Todas las conexiones son estables y el problema está claramente ligado a una actualización de red o firewall.
  • Se usan exclusivamente llaves públicas y la cuenta ya es local sin membresías adicionales.

Código

# 1. Crear usuario local sin privilegios
net user sshd_user "ContraseñaComplexa123!" /add /expires:never /passwordchg:no

# 2. Quitar al usuario de grupos adicionales (excepto Users)
net localgroup Administrators sshd_user /delete
net localgroup "Remote Desktop Users" sshd_user /delete

# 3. Crear directorio home y establecer ACLs estrictas
mkdir "C:\Users\sshd_user"
icacls "C:\Users\sshd_user" /inheritance:r
icacls "C:\Users\sshd_user" /grant:r "sshd_user:(OI)(CI)F" "SYSTEM:(OI)(CI)F"

# 4. Forzar que la contraseña no expire
wmic useraccount where name='sshd_user' set PasswordExpires=False

# 5. Reiniciar servicio OpenSSH
Restart-Service sshd

Verificación

  1. Conexión básica

    sftp sshd_user@<IP_DEL_SERVIDOR>
    

    La sesión debe abrirse sin solicitar cambio de contraseña.

  2. Revisar logs de sshd

    Get-Content "C:\ProgramData\ssh\logs\sshd.log" -Tail 20 -Wait
    

    No deben aparecer líneas con Failed password o Connection closed después de la autenticación.

  3. Comprobar permisos del home

    icacls "C:\Users\sshd_user"
    

    Sólo sshd_user y SYSTEM deben tener acceso total.

  4. Ejecutar un backup de prueba
    Inicie el proceso de backup SFTP y confirme que el archivo llega al destino sin interrupciones.

Notas adicionales

  • Si el entorno usa cuentas de dominio, crear un trust local y mapearla a un usuario local puede evitar el bug, pero implica mayor complejidad de gestión.
  • En versiones anteriores de Windows Server, el servicio sshd a veces necesita la política Allow log on locally para la cuenta de servicio; verificar que NT SERVICE\sshd está incluido en Log on as a service.
  • Mantener el paquete Win32-OpenSSH actualizado reduce la exposición a bugs conocidos; la instalación se realiza con Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0.
  • Cuando se usa ChrootDirectory, la carpeta raíz del chroot debe ser propiedad de SYSTEM y no escribible por el usuario, de lo contrario el daemon aborta la sesión.

Con estos pasos, la mayoría de los fallos intermitentes de OpenSSH en Windows Server 2022 desaparecen, y los backups SFTP vuelven a ejecutarse de forma estable.