1. Introducción a SSH

1.1. ¿Qué es SSH?

SSH (Secure Shell) es un protocolo criptográfico diseñado para establecer canales de comunicación seguros entre un cliente y un servidor en entornos no confiables. Su propósito principal es permitir la administración remota de sistemas y la transferencia de datos de forma protegida frente a ataques de interceptación, manipulación o suplantación.

Desde una perspectiva de ciberseguridad, SSH proporciona las siguientes propiedades fundamentales:

  • Confidencialidad: El tráfico se cifra mediante algoritmos criptográficos robustos, evitando que un tercero pueda inspeccionar el contenido de la comunicación.

  • Integridad: Incorpora mecanismos criptográficos que permiten detectar modificaciones no autorizadas en los datos transmitidos.

  • Autenticación: Verifica la identidad del servidor y del usuario mediante contraseñas, claves públicas o métodos avanzados de autenticación.

  • Resistencia a ataques: Sustituye a protocolos inseguros como Telnet, rsh o rlogin, mitigando riesgos de eavesdropping, session hijacking y robo de credenciales.

SSH se ha consolidado como un estándar esencial en la administración segura de infraestructuras, siendo ampliamente utilizado en sistemas operativos Unix/Linux, dispositivos de red y entornos de computación en la nube.

Esquema básico de una conexión SSH. Imagen obtenida de https://www.ssh.com/academy/ssh[SSH Academy]
Figura 1. Esquema básico de una conexión SSH. Imagen obtenida de SSH Academy

1.2. Arquitectura general del protocolo SSH

El protocolo SSH se organiza en una arquitectura modular compuesta por tres capas lógicamente diferenciadas.

  1. Capa de transporte (Transport Layer)

    Esta capa constituye la base del protocolo. Su función principal es establecer un canal cifrado y autenticado entre cliente y servidor. Para ello, gestiona la negociación de algoritmos criptográficos (cifrado simétrico, intercambio de claves, MAC - Message Authentication Code, compresión), proporciona confidencialidad e integridad del tráfico y autentica al servidor mediante su clave de host.

  2. Capa de autenticación (User Authentication Layer)

    Tras establecerse el canal seguro, esta capa se encarga de autenticar al usuario ante el servidor. SSH admite múltiples métodos de autenticación, tales como contraseña, clave pública, autenticación basada en certificados, agentes SSH, Kerberos (GSSAPI), o combinaciones de varios factores.

  3. Capa de conexión (Connection Layer)

    Una vez completada la autenticación, esta capa habilita la multiplexación de múltiples canales lógicos dentro de la misma sesión SSH. Cada canal puede utilizarse para diferentes propósitos: terminal interactiva (PTY), ejecución remota de comandos, transferencia de archivos mediante SCP o SFTP, reenvío de puertos (port forwarding) o túneles TCP. Su flexibilidad permite adaptar SSH a numerosos casos de uso sin necesidad de establecer conexiones adicionales.

Capas del protocolo SSH. Imagen obtenida de https://www.mysoftkey.com/security/ssh-secure-shell-protocol-for-secure-remote-login/[mysoftkey]
Figura 2. Capas del protocolo SSH. Imagen obtenida de mysoftkey

2. Instalación y configuración básica de SSH

2.1. Instalación del servidor SSH

En esta práctica vamos a utilizar OpenSSH, la implementación más común y ampliamente adoptada del protocolo SSH.

En sistemas basados en Debian/Ubuntu, la instalación del servidor SSH (OpenSSH) se realiza con los siguientes comandos:

sudo apt update
sudo apt install openssh-server -y

Tras su instalación, el servicio se inicia automáticamente.

2.2. Verificación del estado del servicio

El estado del servidor SSH puede comprobarse mediante:

sudo systemctl status ssh

A continuación, se muestra un ejemplo de salida del comando:

● ssh.service - OpenBSD Secure Shell server                                           (1)
     Loaded: loaded (/usr/lib/systemd/system/ssh.service; disabled; preset: enabled)  (2)
     Active: active (running) since Fri 2025-12-05 20:55:25 UTC; 23h ago              (3)
TriggeredBy: ● ssh.socket                                                             (4)
       Docs: man:sshd(8)
             man:sshd_config(5)
    Process: 1039 ExecStartPre=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS)
   Main PID: 1041 (sshd)
      Tasks: 1 (limit: 2320)
     Memory: 3.4M (peak: 20.1M)
        CPU: 363ms
     CGroup: /system.slice/ssh.service
             └─1041 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"
1 El servicio se llama ssh.service y se corresponde al servidor OpenSSH.
2 El archivo unit de systemd (/usr/lib/systemd/system/ssh.service) está cargado, pero el servicio está configurado como deshabilitado para iniciarse automáticamente durante el arranque del sistema (disabled). El valor de preset: enabled indica que según la política de presets del sistema definida en /usr/lib/systemd/system-preset/, el servicio debería estar habilitado por defecto.
3 El servicio está en active (running) para aceptar conexiones entrantes.
4 El servicio está configurado para utilizar la activación por socket de systemd (ssh.socket). Se trata de una funcionalidad de systemd que permite que un servicio no esté arrancado de forma permanente, sino que se inicie automáticamente cuando alguien intenta conectar a un socket. En este caso, systemd está escuchando en el puerto 22 y cuando llega una conexión inicia el servicio ssh.service y le entrega el socket ya abierto para que gestione la sesión.
Se recomienda la lectura del artículo Systemd Socket Activation Explained.

2.3. Archivos principales de configuración

2.3.1. Archivos en el servidor

Estos archivos controlan la configuración del daemon SSH (sshd) y los mecanismos de autenticación de los usuarios en el sistema.

  • /etc/ssh/sshd_config

Es el archivo principal de configuración del servidor SSH. Define métodos de autenticación permitidos, algoritmos criptográficos, puertos de escucha, control de acceso y parámetros de seguridad. Cualquier modificación requiere reiniciar o recargar el servicio.

  • /etc/ssh/sshd_config.d/*.conf

Conjunto de archivos suplementarios que se cargan mediante la directiva Include. Facilitan la modularidad de la configuración, permitiendo separar políticas (acceso, listas de control, criptografía, etc.) sin alterar el archivo principal.

  • ~/.ssh/authorized_keys

Cada usuario del servidor tendrá un directorio ~/.ssh/ y un archivo authorized_keys donde se almacenan las claves públicas autorizadas para la autenticación.

  • /etc/ssh/ssh_host_*: Conjunto de claves de identidad del servidor (host keys). Permiten al cliente verificar que se conecta al servidor legítimo. Incluyen claves como:

    • ssh_host_rsa_key

    • ssh_host_ecdsa_key

    • ssh_host_ed25519_key

2.3.2 Archivos en el cliente

Estos archivos controlan la configuración del cliente SSH y el almacenamiento de las claves utilizadas para autenticarse frente a servidores remotos.

  • /etc/ssh/ssh_config

Archivo global que define el comportamiento predeterminado del cliente SSH para todos los usuarios del sistema. Permite especificar parámetros por host, algoritmos preferidos, tiempos de espera, reenvío de puertos, etc.

  • ~/.ssh/: Directorio local donde se almacenan claves y configuraciones específicas del usuario. Contiene claves, configuraciones y elementos necesarios para la autenticación y la verificación de servidores remotos. Los elementos más relevantes son:

    • id_rsa, id_ed25519, etc.: Claves privadas del usuario.

    • id_rsa.pub, id_ed25519.pub, etc.: Claves públicas correspondientes.

    • known_hosts: Archivo que almacena las claves públicas de los servidores a los que el usuario se ha conectado previamente, permitiendo verificar su identidad en conexiones futuras.

    • config: Archivo opcional para definir configuraciones personalizadas por host o grupo de hosts.

2.4. Archivos de configuración del servicio en systemd

En esta sección se analizan los archivos unit que utiliza systemd para gestionar el servicio SSH. Para comprender el comportamiento del servicio, su ciclo de vida y su interacción con la activación por socket, es fundamental revisar tanto la unidad de servicio (ssh.service) como la unidad de socket (ssh.socket).

2.4.1. Archivo de configuración de ssh.service

El archivo ssh.service define cómo se inicia, detiene, recarga y supervisa el demonio sshd dentro del ecosistema de systemd. Incluye atributos como dependencias, verificaciones previas al arranque, comportamiento ante fallos y parámetros de ejecución.

Para consultar el contenido completo de la unidad tal como lo interpreta systemd, podmeos utilizar el siguiente comando:

sudo systemctl cat ssh

La salida mostrará el contenido del archivo /usr/lib/systemd/system/ssh.service y cualquier archivo de configuración adicional que modifique o extienda la unidad en /etc/systemd/system/ssh.service y /etc/systemd/system/ssh.service.d/*.conf.

# /usr/lib/systemd/system/ssh.service
[Unit]                                                  (1)
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]                                               (2)
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755

[Install]                                               (3)
1 La sección Unit define los metadatos, dependencias y condiciones para ejecutar la unidad.
2 La sección Service define la configuración del proceso del servicio.
3 La sección Install define cómo debe habilitarse el servicio al arrancar el sistema. En este archivo está vacía porque, en muchas distribuciones, ssh.service se gestiona a través de ssh.socket para proporcionar activación por socket.

2.4.1. Archivo de configuración de ssh.socket

Además del servicio principal (ssh.service), SSH puede gestionarse mediante una unidad de socket (ssh.socket). Este archivo define el socket TCP a través del cual systemd escucha las conexiones entrantes en el puerto 22 y, cuando se recibe una solicitud, activa automáticamente el servicio correspondiente. Este mecanismo, conocido como socket activation, permite que el demonio sshd no tenga que permanecer ejecutándose de forma continua.

Para consultar el archivo unit de socket utilizado por systemd, podemos utilizar el siguiente comando:

sudo systemctl cat ssh.socket

La salida del comando mostrará algo similar a esto:

# /usr/lib/systemd/system/ssh.socket
[Unit]
Description=OpenBSD Secure Shell server socket
Before=sockets.target ssh.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Socket]
ListenStream=22                                     (1)
Accept=no                                           (2)
FreeBind=yes                                        (3)

[Install]
WantedBy=sockets.target
RequiredBy=ssh.service
1 Indica que systemd debe escuchar en el puerto TCP 22 para conexiones entrantes, en lugar de mantener el servicio sshd activo permanentemente.
2 Indica que el socket no crea instancias por conexión, sino que systemd activa una única instancia de ssh.service y le pasa el descriptor del socket ya abierto. Esto es lo adecuado para tener un único proceso encargado de gestionar múltiples conexiones.
3 Permite que systemd cree el socket aunque la interfaz de red aún no esté disponible.

3. Autenticación mediante usuario y contraseña

3.1. Funcionamiento general

La autenticación basada en credenciales tradicionales se fundamenta en la presentación de un nombre de usuario y una contraseña que permiten verificar la identidad del solicitante. Durante el proceso de conexión, el cliente SSH transmite al servidor el identificador del usuario, tras lo cual el servidor inicia el mecanismo de autenticación correspondiente.

La validación de la contraseña se realiza mediante los métodos habilitados en el sistema, que pueden incluir:

  • Mecanismos locales de autenticación, como la verificación del hash almacenado en /etc/shadow.

  • PAM (Pluggable Authentication Modules), que permite integrar políticas centralizadas, autenticación multifactor, restricciones basadas en tiempo o en la complejidad de la contraseña, entre otros controles.

Este método constituye el enfoque más básico y ampliamente soportado por SSH, sin embargo, su seguridad depende en gran medida de la calidad de las credenciales y de las políticas de protección implementadas en el servidor.


3.2. Conexión básica con usuario y contraseña

La forma más elemental de establecer una sesión SSH consiste en autenticar al usuario mediante una contraseña asociada a su cuenta en el servidor remoto. La sintaxis general del comando es:

ssh usuario@direccion_ip

Al ejecutarlo, el cliente SSH iniciará el proceso de conexión y posteriormente solicitará la contraseña del usuario especificado. Una vez validada, se establecerá un canal cifrado que permitirá interactuar de manera segura con el sistema remoto.

Ejemplo:

En este caso, el cliente intentará acceder a la cuenta ubuntu en el servidor con dirección 172.16.11.164, solicitando la contraseña correspondiente para completar la autenticación.

ssh ubuntu@172.16.11.164

Si es la primera vez que se conecta al servidor, le aparecerá un mensaje similar a este:

The authenticity of host '172.16.11.164 (172.16.11.164)' can't be established.    (1)
ED25519 key fingerprint is SHA256:sEDex5Co18/qbO+gjWLcOxv+JNk+dmVasaNUHgsicHw.    (2)
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?              (3)
1 SSH está informando que no puede verificar la identidad del servidor remoto porque no existe ninguna entrada previa para ese host en el archivo ~/.ssh/known_hosts.
2 SSH muestra la huella digital o fingerprint de la clave pública del servidor. El fingerprint es un hash de la clave pública. En el mensaje se muestra el agoritmo de clave pública que se ha utilizado (ED25519) y el valor del fingerprint en formato SHA256.
3 Si seleccionamos yes entonces la clave pública del servidor se añadirá al archivo de host conocidos, known_hosts, para que no nos vuelva a aparecer este mensaje en futuras conexiones.

3.3. Limitaciones y riesgos

El mecanismo de autenticación basado en usuario y contraseña presenta diversas limitaciones inherentes que lo convierten en una opción menos robusta frente a otros métodos disponibles. Entre los principales riesgos se encuentran:

  • Exposición a ataques de fuerza bruta y diccionario: Los atacantes pueden automatizar intentos masivos de autenticación, especialmente si el servicio SSH está expuesto a Internet y no existen medidas complementarias como rate limiting o fail2ban.

  • Uso de credenciales débiles, previsibles o reutilizadas: Las contraseñas elegidas por los usuarios suelen no cumplir estándares adecuados de entropía, y su reutilización en múltiples servicios incrementa significativamente la superficie de ataque.

  • Dependencia total del canal cifrado para proteger las credenciales: Aunque SSH proporciona cifrado fuerte, la seguridad del método depende de la integridad del canal. Cualquier degradación criptográfica, proxy malicioso (MITM) o configuración insegura podría comprometer las credenciales durante la autenticación.

  • Mayor superficie de ataque en comparación con mecanismos basados en claves: La existencia de un vector de entrada mediante contraseña, aunque no se conozca la credencial, permite que un atacante interactúe con el servicio, registre intentos y evalúe patrones de respuesta del servidor.

Debido a estas limitaciones, la autenticación por contraseña suele deshabilitarse en entornos de producción, especialmente en sistemas expuestos a redes no confiables, optando por mecanismos más seguros como la autenticación mediante claves públicas o el uso de gestores de identidades centralizados.

4. Autenticación mediante clave pública/privada

4.1. Conceptos fundamentales

La autenticación basada en clave pública se apoya en el uso de criptografía asimétrica, un modelo en el que cada usuario dispone de un par de claves con funciones complementarias. Este método elimina la necesidad de transmitir contraseñas y proporciona un nivel de seguridad significativamente superior frente a ataques de fuerza bruta o de interceptación.

El par de claves está compuesto por:

  • Clave privada: Reside exclusivamente en el sistema del cliente y nunca debe ser compartida ni transferida. Su protección es crítica, ya que constituye el elemento que permite demostrar la identidad del usuario durante el proceso de autenticación.

  • Clave pública: Se copia al servidor y se almacena en el archivo ~/.ssh/authorized_keys dentro del directorio del usuario correspondiente. Esta clave actúa como referencia para validar la autenticación, sin revelar información que permita reconstruir la clave privada.

El proceso de autenticación se basa en un desafío criptográfico: el servidor envía un reto generado aleatoriamente que el cliente debe firmar con su clave privada. Si la firma resultante coincide con la verificación realizada mediante la clave pública almacenada en el servidor, la identidad del cliente queda autenticada. Todo este procedimiento se realiza dentro del canal cifrado proporcionado por SSH, garantizando confidencialidad e integridad.


4.2. Tipos de claves compatibles

SSH admite distintos algoritmos de criptografía asimétrica para la generación de pares de claves, cada uno con características específicas en términos de seguridad, rendimiento y compatibilidad. Los tipos más relevantes son:

  • ED25519: Basado en la curva elíptica Edwards25519, ofrece un excelente equilibrio entre seguridad, rendimiento y tamaño de clave reducido. Es resistente a una amplia gama de ataques criptográficos modernos y presenta un conjunto de parámetros bien definidos, lo que evita problemas de implementación. Actualmente se considera la opción recomendada en la mayoría de escenarios.

  • RSA: Es uno de los algoritmos más utilizados debido a su extensa compatibilidad con sistemas heredados y herramientas de automatización. No obstante, su seguridad depende directamente del tamaño de la clave, por lo que se recomienda utilizar longitudes mínimas de 4096 bits en entornos de seguridad elevada. Aunque sigue siendo seguro cuando se implementa adecuadamente, su eficiencia es inferior a la de las curvas elípticas modernas.

  • ECDSA: Basado en curvas elípticas del estándar NIST, ofrece buen rendimiento y claves de tamaño reducido. Sin embargo, su adopción en entornos de alta seguridad es más limitada debido a preocupaciones sobre la confianza en los parámetros estandarizados y la preferencia por alternativas con diseños más transparentes, como Ed25519.


4.3. Ventajas frente a la autenticicación por contraseña

La autenticación mediante clave pública ofrece múltiples beneficios frente a los mecanismos tradicionales basados en contraseña, especialmente en entornos donde se requiere un elevado nivel de seguridad. Entre sus principales ventajas destacan:

  • Mayor resistencia frente a ataques de fuerza bruta y diccionario: Las claves públicas poseen una entropía significativamente superior a cualquier contraseña humana, lo que hace computacionalmente inviable su descubrimiento por medios exhaustivos.

  • Eliminación de la necesidad de transmitir credenciales sensibles: En este modelo no se envía ninguna contraseña a través del canal, sino que la autenticación se realiza mediante un proceso de firma criptográfica. Esto reduce el riesgo asociado a la interceptación o captura de credenciales.

  • Facilidad para automatizar procesos de forma segura: El uso de claves (especialmente con agentes SSH o claves protegidas por passphrase) permite integrar accesos no interactivos en scripts, herramientas de orquestación y tareas programadas sin comprometer la seguridad del entorno.

  • Reducción del riesgo de compromiso de cuentas: Al eliminar la dependencia de contraseñas, que suelen ser débiles, predecibles o reutilizadas, se mitigán vectores de ataque asociados a errores humanos. Además, las claves privadas se pueden proteger con passphrase y mecanismos adicionales como hardware tokens o agentes criptográficos.

En conjunto, estas características convierten la autenticación por clave pública en la opción recomendada para sistemas en producción, especialmente aquellos expuestos a redes no confiables.


4.4. Conexión básica mediante clave pública/privada

Una vez configurado el par de claves y almacenada la clave pública en el servidor, el cliente puede autenticarse utilizando su clave privada. Si esta clave se encuentra en la ubicación predeterminada (~/.ssh/id_ed25519 o ~/.ssh/id_rsa), el cliente SSH la detectará automáticamente y la conexión puede realizarse simplemente mediante:

ssh usuario@direccion_ip

Ejemplo:

ssh ubuntu@172.16.11.20

En situaciones donde la clave privada se encuentre en una ubicación distinta o tenga un nombre personalizado, es posible especificar explícitamente su ruta mediante la opción -i:

ssh -i path_to_private_key usuario@direccion_ip

Ejemplo:

ssh -i ~/.ssh/mi_clave_privada.pem ubuntu@172.16.11.20

El cliente SSH utilizará la clave indicada para firmar el desafío enviado por el servidor, completando así el proceso de autenticación sin necesidad de emplear contraseñas.

5. Generación de un par de claves SSH

5.1. Comando estándar para generar claves

La herramienta ssh-keygen permite generar un par de claves para autenticación SSH. Para crear una clave moderna y segura basada en el algoritmo Ed25519, se emplea el siguiente comando:

ssh-keygen -t ed25519

Al ejecutarlo, el sistema iniciará un asistente interactivo en el que solicitará:

  1. La ubicación del archivo que contendrá la clave privada (por defecto: ~/.ssh/id_ed25519).

  2. Una passphrase opcional, utilizada para cifrar la clave privada y añadir una capa adicional de protección ante posibles accesos no autorizados.

El uso de passphrase es altamente recomendable en entornos de seguridad reforzada.


5.2. Ubicación y permisos

De forma predeterminada, las claves generadas por ssh-keygen se guardan en el directorio personal del usuario, dentro de ~/.ssh/. La estructura habitual es:

  • Clave privada: ~/.ssh/id_ed25519

  • Clave pública: ~/.ssh/id_ed25519.pub

La clave privada debe mantenerse bajo estricta protección, ya que constituye el elemento principal de autenticación. Para garantizar su confidencialidad, es imprescindible aplicar permisos restrictivos:

chmod 600 ~/.ssh/id_ed25519

Asimismo, el directorio ~/.ssh debe poseer permisos adecuados para evitar accesos indebidos:

chmod 700 ~/.ssh

El cumplimiento de estas políticas de permisos es esencial para evitar la exposición accidental de claves y asegurar la integridad del mecanismo de autenticación.


5.3. Protección mediante passphrase

Para incrementar la seguridad del par de claves, es recomendable proteger la clave privada mediante una passphrase. Esta passphrase cifra el contenido de la clave privada de modo que, incluso si un atacante lograra obtener acceso al archivo, no podría utilizarla sin conocer la passphrase asociada.

Este mecanismo añade una capa adicional de protección frente a:

  • Pérdidas o robos de dispositivos.

  • Accesos no autorizados a cuentas de usuario.

  • Compromisos accidentales del directorio ~/.ssh.

La passphrase debe poseer suficiente entropía y seguir las buenas prácticas de construcción de contraseñas seguras. Su uso puede combinarse con herramientas como ssh-agent, que permiten desbloquear la clave de manera temporal para facilitar conexiones sucesivas sin sacrificar seguridad.

6. Copia de la clave pública al servidor

Una vez generado el par de claves, es necesario transferir la clave pública al servidor para habilitar la autenticación basada en claves. SSH ofrece métodos automatizados y manuales para realizar este procedimiento de forma segura.

6.1. Método automatizado mediante ssh-copy-id

La forma más sencilla y fiable de instalar la clave pública en el servidor es utilizando el comando:

ssh-copy-id usuario@direccion_ip

Este comando:

  1. Establece una conexión inicial por contraseña.

  2. Verifica la existencia del directorio ~/.ssh en el servidor (y lo crea si es necesario).

  3. Añade de forma segura el contenido de la clave pública local a ~/.ssh/authorized_keys.

  4. Ajusta los permisos del directorio y del archivo para evitar errores de autenticación.

Este método minimiza errores de formato, evita duplicados en authorized_keys y garantiza permisos adecuados.


6.2. Método manual

En entornos donde no se dispone de ssh-copy-id, la instalación puede realizarse manualmente. Los pasos son:

  1. Copiar el contenido de la clave pública local, por ejemplo:

    cat ~/.ssh/id_ed25519.pub
  2. Pegar dicho contenido en el servidor dentro del archivo:

    ~usuario/.ssh/authorized_keys

    Puede hacerse mediante:

    • Conexión SSH inicial por contraseña.

    • Transferencia segura con scp o sftp.

    • Creación manual del archivo mediante un editor de texto.

  3. Establecer los permisos adecuados en el servidor:

    chmod 700 ~/.ssh
    chmod 600 ~/.ssh/authorized_keys

    Los permisos son críticos, si son demasiado permisivos sshd rechazará la clave por motivos de seguridad.


6.3. Verificación del acceso

Una vez instalada la clave pública, la autenticación puede verificarse mediante:

ssh usuario@direccion_ip

Si la configuración es correcta:

  • No se solicitará contraseña.

  • Si la clave privada está protegida con passphrase, el sistema pedirá dicha passphrase.

  • El servidor autenticará al cliente mediante firma criptográfica.

En caso de fallo, es recomendable revisar:

  • Permisos del directorio y archivos del usuario en el servidor.

  • Presencia correcta de la clave en authorized_keys.

  • Logs del servidor (/var/log/auth.log o journalctl -u sshd) para diagnosticar errores.

7. Configuración avanzada del cliente SSH

7.1. Archivo de configuración del usuario

El archivo ~/.ssh/config permite personalizar el comportamiento del cliente SSH para conexiones específicas o para un conjunto de servidores. Su uso facilita la automatización, reduce la necesidad de recordar parámetros complejos y permite definir políticas uniformes para distintos entornos.

Este archivo es interpretado por el cliente SSH en cada conexión y tiene prioridad sobre la configuración global del sistema (/etc/ssh/ssh_config).

Ejemplo de configuración básica

Host servidor_remoto
  HostName 172.16.11.20
  User usuario
  IdentityFile ~/.ssh/id_ed25519

Parámetros principales

  • Host: Define un alias que el usuario utilizará al ejecutar ssh. Admite patrones (por ejemplo, Host srv-*).

  • HostName: Especifica la dirección IP o el nombre DNS del servidor remoto.

  • User: Nombre de usuario que se utilizará para la conexión SSH.

  • IdentityFile: Ruta de la clave privada que el cliente empleará para autenticarse.

Conexión utilizando el alias definido

Una vez configurado el bloque Host, la conexión se simplifica a:

ssh servidor_remoto

El cliente utilizará automáticamente los parámetros definidos en el archivo.


7.2. Configuración de múltiples servidores

El archivo ~/.ssh/config puede contener varios bloques Host, cada uno con su propia configuración personalizada. Esto permite gestionar servidores con distintos usuarios, claves o parámetros de conexión:

Host produccion
  HostName 203.0.113.10
  User admin
  IdentityFile ~/.ssh/id_ed25519_prod

Host laboratorio
  HostName 192.168.1.50
  User ubuntu
  IdentityFile ~/.ssh/id_ed25519_lab

7.3. Opciones avanzadas recomendadas

Además de los parámetros básicos, SSH permite configurar opciones avanzadas para mejorar la seguridad y la usabilidad:

Host produccion
  HostName 203.0.113.10
  User admin
  IdentityFile ~/.ssh/id_ed25519_prod
  ForwardAgent no                                 (1)
  StrictHostKeyChecking yes                       (2)
  Compression yes                                 (3)
  Port 2222                                       (4)
1 ForwardAgent: Controla si el agente SSH puede reenviar claves a través de la conexión. Es recomendable mantenerlo en no para evitar usos indebidos.
2 StrictHostKeyChecking: Requiere que la clave del servidor esté previamente registrada en known_hosts. Actívalo (yes) en entornos sensibles para evitar ataques de tipo Man-in-the-Middle.
3 Compression: Habilita la compresión de datos, útil en enlaces lentos o de baja capacidad.
4 Port: Especifica el puerto remoto del servicio SSH, si es distinto del estándar (22).

7.4. Uso de patrones y herencia de configuración

El archivo config admite el uso de comodines para aplicar configuraciones comunes:

Host *.miempresa.com
  User admin
  IdentityFile ~/.ssh/id_ed25519_corporativa
  StrictHostKeyChecking yes

Esto significa que todas las conexiones SSH cuyo destino termine en .miempresa.com usarán automáticamente los parámetros definidos en el archivo de configuración.

Por ejemplo, podría conectarse a varios servidores dentro del dominio:

ssh servidor1.miempresa.com
ssh servidor2.miempresa.com
ssh servidor3.miempresa.com

También se pueden crear bloques globales aplicables a todos los hosts:

Host *
  ServerAliveInterval 60
  ServerAliveCountMax 3

8. ssh-agent

El ssh-agent es un componente del cliente SSH que permite gestionar claves privadas de forma segura en memoria. Su función principal es almacenar claves descifradas temporalmente, evitando que el usuario tenga que introducir la passphrase en cada conexión.

Una vez cargada una clave en ssh-agent, el cliente SSH delega la operación de firma criptográfica al agente, lo que facilita la automatización y mejora la usabilidad sin comprometer la seguridad.


8.1. Visualizar las claves cargadas en el agente

Para enumerar las claves privadas actualmente almacenadas en el agente, se utiliza:

ssh-add -l

Este comando muestra el tipo de clave, su huella digital (fingerprint) y la ruta del archivo asociado. Si no hay claves cargadas, el comando lo indicará explícitamente.


8.2. Eliminar todas las claves del agente

Para vaciar el agente y eliminar todas las claves previamente cargadas:

ssh-add -D

Esta acción es útil en contextos de seguridad reforzada o cuando se desea limpiar el entorno antes de iniciar una nueva sesión de trabajo.


8.3. Eliminar una clave específica del agente

Si se desea retirar únicamente una clave concreta del agente, se puede especificar su ruta:

ssh-add -d /ruta/a/tu/clave_privada

El agente dejará de ofrecer dicha clave durante futuras autenticaciones.


8.4. Iniciar un nuevo agente SSH sin claves cargadas

En muchos entornos, especialmente en shells no interactivos o en scripts, puede ser necesario iniciar un agente manualmente:

eval "$(ssh-agent -s)"

Este comando:

  1. Ejecuta un nuevo proceso ssh-agent.

  2. Exporta las variables de entorno necesarias (SSH_AUTH_SOCK y SSH_AGENT_PID).

  3. Deja el agente listo para recibir claves mediante ssh-add.


8.5. Añadir claves al agente

Aunque comúnmente se carga automáticamente cuando se usa una clave con passphrase, también puedes añadir una clave manualmente:

ssh-add ~/.ssh/id_ed25519

Si la clave está cifrada, el sistema solicitará la passphrase una única vez, tras lo cual la clave permanecerá disponible en memoria mientras el agente siga activo.


8.6. Buenas prácticas de seguridad con ssh-agent

  • Utiliza passphrase robustas para proteger las claves privadas cargadas en memoria.

  • Evita reenviar el agente (ForwardAgent yes) salvo en casos estrictamente necesarios.

  • Elimina las claves cuando finalices la sesión (ssh-add -D).

  • En entornos de escritorio, asegúrate de que el agente se bloquea al suspender o cerrar sesión.

9. Hardening del servidor SSH

El bastionado o hardening del servidor SSH consiste en aplicar medidas para reducir su superficie de ataque, controlar quién puede acceder y reforzar la configuración criptográfica y de autenticación. SSH es uno de los servicios más frecuentemente atacados en entornos expuestos, por lo que su configuración segura es esencial.

Vamos a aplicar las recomendaciones publicadas por el CIS (Center for Internet Security) en los CIS Benchmarks, que son guías reconocidas que ofrecen controles estandarizados y evaluables diseñados para mejorar la seguridad del sistema.. En nuestro caso, vamos a seguir el CIS Ubuntu Linux 24.04 LTS Benchmark v1.0.0. En el sitio oficial del CIS puede encontrar documentación similar para otras distribuciones y sistemas operativos.

Todas las configuraciones que se muestran a continuación pueden aplicarse en el archivo principal de configuración del servidor SSH, /etc/ssh/sshd_config, o en archivos adicionales dentro del directorio /etc/ssh/sshd_config.d/, que se incluyen automáticamente mediante la directiva Include.

Una vez aplicados los cambios, es necesario reiniciar o recargar el servicio SSH para que tengan efecto:

sudo systemctl restart ssh

9.1. Configuración básica y control de acceso

9.1.1. Restricción del acceso root

Prohibir el acceso directo del usuario root obliga a iniciar sesión con una cuenta normal y escalar privilegios mediante sudo, lo que:

  • Reduce el riesgo de explotación directa de la cuenta root.

  • Facilita auditoría y trazabilidad de comandos.

  • Impide ataques de fuerza bruta dirigidos a la cuenta root.

PermitRootLogin no

Esta configuración evita el acceso directo como superusuario.

CIS Ubuntu Linux 24.04 LTS Benchmark v1.0.0:

  • CIS 5.1.20 Ensure sshd PermitRootLogin is disabled (Automated)

9.1.2. Limitar usuarios autorizados

La variable AllowUsers permite definir una lista blanca de usuarios autorizados. Cualquier cuenta que no esté incluida en esta lista será rechazada de forma automática.

Esto reduce significativamente la superficie de ataque, ya que evita intentos de acceso contra cuentas que no deberían utilizar SSH y limita el impacto de credenciales comprometidas.

AllowUsers usuario1 usuario2

También es posible denegar el acceso a usuarios específicos mediante la directiva DenyUsers.

DenyUsers usuario3 usuario4

CIS Ubuntu Linux 24.04 LTS Benchmark v1.0.0:

  • CIS 5.1.4 Ensure sshd access is configured (Automated)

9.1.3. Restricción por grupos

La directiva AllowGroups permite definir control de acceso basado en membresía de grupos. Es una forma más escalable de gestionar privilegios en sistemas con múltiples usuarios.

AllowGroups grupo_ssh

También es posible denegar el acceso grupos específicos mediante la directiva DenyGroups.

DenyGroups grupo_no_ssh

CIS Ubuntu Linux 24.04 LTS Benchmark v1.0.0:

  • CIS 5.1.4 Ensure sshd access is configured (Automated)

9.1.4. Cambiar el puerto por defecto

SSH escucha por defecto en el puerto 22, un valor ampliamente conocido y habitual en escaneos automatizados masivos orientados a identificar servicios vulnerables.

Modificar el puerto no constituye una medida de seguridad pero puede utilizarse como medida complementaria para reducir la exposición del servicio y reducir la visibilidad del servicio frente a ataques automatizados que sólo explorar puertos estándar.

#Port 22
Port 2222
El cambio de puerto no forma parte de los controles recomendados por el CIS Benchmark, ya que CIS no considera esta práctica una mejora de seguridad medible.

9.2. Fortalecer la autenticación

9.2.1. Priorizar la autenticación con claves SSH

El uso de claves SSH es mucho más seguro que usar contraseñas, por este motivo se recomienda deshabilitar la autenticación por contraseña siempre que sea posible y forzar el uso de claves públicas.

Para generar un par de claves SSH debe ejeucta el comando ssh-keygen en la máquina cliente y luego copiar la clave pública al servidor con ssh-copy-id.

Una vez que hayas verificado que puedes acceder con tu clave, deshabilita la autenticación por contraseña en el servidor con las siguientes directivas.

PasswordAuthentication no
PubkeyAuthentication yes

9.2.2. Deshabilitar contraseñas vacías

Aunque hayamos deshabilitado la autenticación por contraseña, es recomendable asegurarse de que no existen cuentas con contraseñas vacías en el sistema. Esto previene accesos no autorizados en caso de que la configuración de SSH cambie accidentalmente o sea comprometida.

PermitEmptyPasswords no

CIS Ubuntu Linux 24.04 LTS Benchmark v1.0.0:

  • CIS 5.1.19. Ensure sshd PermitEmptyPasswords is disabled (Automated)


9.3. Configuración del protocolo y criptografía

9.3.1. Usar solo el protocolo SSHv2

La versión 1 del protocolo SSH está completamente obsoleta y presenta múltiples vulnerabilidades conocidas. Por este motivo, todos los servidores actuales implementan exclusivamente SSHv2, que ofrece algoritmos fuertes, integridad robusta y soporte adecuado para autenticación mediante claves públicas.

Protocol 2

9.4. Límites de conexión y tiempos de espera

La configuración de límites de conexión y tiempos de espera contribuye a mitigar ataques de fuerza bruta, reducir el consumo innecesario de recursos y mejorar el control sobre sesiones persistentes o abandonadas. Estas medidas no sustituyen a controles más robustos como la autenticación mediante claves o el uso de firewalls, pero complementan eficazmente la protección del servicio SSH.

9.4.1. Reducir el tiempo de gracia para el login

La directiva LoginGraceTime define el intervalo máximo durante el cual un cliente puede mantener una conexión abierta sin autenticarse. Reducir este valor limita el tiempo disponible para intentos automatizados y evita que conexiones no válidas consuman recursos innecesariamente. Un valor entre 20 y 60 segundos suele ser razonable.

LoginGraceTime 60s

CIS Ubuntu Linux 24.04 LTS Benchmark v1.0.0:

  • CIS 5.1.13 Ensure sshd LoginGraceTime is configured (Automated)

9.4.2. Limitar los intentos de autenticación

La directiva MaxAuthTries establece el número máximo de intentos de autenticación permitidos por conexión. Un valor reducido dificulta ataques de fuerza bruta y minimiza la posibilidad de adivinar credenciales válidas. El CIS recomienda configurar un valor igual o inferior a 4.

MaxAuthTries 3

CIS Ubuntu Linux 24.04 LTS Benchmark v1.0.0:

  • CIS 5.1.19. CIS 5.1.16. Ensure sshd MaxAuthTries is configured (Automated)

9.4.3. Configurar timeouts para sesiones inactivas

Las directivas ClientAliveInterval y ClientAliveCountMax controlan la detección y desconexión automática de sesiones inactivas. Esto reduce el riesgo de que sesiones abandonadas permanezcan abiertas, lo que podría facilitar accesos indebidos.

ClientAliveInterval 300     (1)
ClientAliveCountMax 2       (2)
1 El servidor envía un mensaje de keepalive cada 300 segundos.
2 Si no obtiene respuesta tras 2 intentos, la sesión se cierra automáticamente.

9.5. Registro y monitorización

Una política de registro adecuada es esencial para la detección de incidentes, la trazabilidad de acciones y el análisis forense. SSH proporciona mecanismos para mejorar la visibilidad de las actividades realizadas en el servicio.

9.5.1. Mejorar el logging

Establecer un nivel de registro más detallado permite capturar información adicional, como intentos de autenticación fallidos, reenvío de puertos y apertura de canales. Esto facilita la monitorización en tiempo real y el análisis posterior de eventos.

Para configurar el nivel de log utilizamos la directiva LogLevel.

LogLevel INFO

El valor del nivel de log por defecto es INFO que es el nivel mínimo recomendado por el CIS. Para realizar auditorías se puede aumentar a VERBOSE y si necesitásemos más información podríamos configurarlo en DEBUG1, DEBUG2 o DEBUG3, aunque estos modos no se recomiendan en producción.

Nivel Descripción

QUIET

Registra solo mensajes críticos. Suprime la mayoría de eventos y errores. Poco recomendado porque dificulta auditoría.

FATAL

Registra únicamente errores fatales que impiden la ejecución del servidor.

ERROR

Registra errores importantes pero no fatales.

INFO

Es el valor por defecto. Registra eventos generales: intentos de conexión, autenticaciones, fallos, aperturas/cierres de sesión. Este es el nivel mínimo recomendado por CIS.

VERBOSE

Añade detalles adicionales, incluidos información sobre reenvío de puertos, parámetros de autenticación y decisiones de control de acceso. Muy útil para auditoría.

DEBUG

Nivel de depuración. Registra información detallada del flujo interno del servidor SSH, incluida negociación criptográfica. No recomendado en producción.

DEBUG1

Alias de DEBUG.

DEBUG2

Más detallado que DEBUG. Puede mostrar información sensible y un alto volumen de logs. Solo usar temporalmente.

DEBUG3

Máxima verbosidad. Muestra absolutamente todo. Exclusivamente para diagnósticos complejos. Nunca usar en entornos de producción.

CIS Ubuntu Linux 24.04 LTS Benchmark v1.0.0:

  • CIS 5.1.14. CIS 5.1.14. Ensure sshd LogLevel is configured (Automated)

9.5.2. Añadir un banner de advertencia

Configurar un banner de advertencia permite mostrar un mensaje legal antes del proceso de autenticación. Este aviso cumple dos funciones principales:

  • Informar explícitamente de que el acceso está restringido a usuarios autorizados.

  • Respaldar la capacidad legal de la organización para actuar ante accesos no autorizados, al establecer claramente que toda actividad puede ser monitorizada.

La directiva para configurar el banner de advertencia es Banner. En esta directiva hay que indicar la ruta del archivo que contiene el mensaje que se quiere mostrar.

Banner /etc/ssh/ssh_banner

En el ejemplo anterior, el archivo que contiene el mensaje de advertencia está en al ruta /etc/ssh/ssh_banner y puede contener el siguiente texto:

-----------------------------------------------------------------
|                    ACCESO NO AUTORIZADO                       |
| Toda la actividad en este sistema es monitoreada y grabada.   |
| Desconéctese inmediatamente si no es un usuario autorizado.   |
-----------------------------------------------------------------

CIS Ubuntu Linux 24.04 LTS Benchmark v1.0.0:

  • CIS 5.1.5 Ensure sshd Banner is configured (Automated)


9.6 Herramientas Complementarias

9.6.1 Instalación de Fail2Ban

Fail2Ban es un servicio que monitoriza los logs (incluidos los de SSH) y banea automáticamente las direcciones IP que muestran comportamiento malicioso, como repetidos intentos de login fallidos. Es altamente recomendable instalarlo y configurarlo.

Para instalar Fail2Ban en sistemas basados en Debian/Ubuntu podemos ejecutar:

sudo apt update
sudo apt install fail2ban -y

9.7 Consejos

Después de editar el archivo de configuración sshd_config, siempre es recomendable verificar la sintaxis antes de reiniciar el servicio:

sshd -t

Si este comando no devuelve nada, la configuración es correcta. Si hay un error, lo indicará.

Para recinicair el servicio SSH y aplicar los cambios realizados en la configuración:

sudo systemctl restart sshd
Mantén tu sesión actual abierta mientras abres una nueva terminal para probar el acceso. Así, si algo sale mal, no te quedarás fuera del servidor.

10. Port Knocking

10.1. Concepto general

El port knocking es una técnica de control de acceso que consiste en mantener un servicio completamente cerrado o no visible desde el exterior, hasta que un cliente autorizado realiza una secuencia específica de intentos de conexión a determinados puertos.

Solo tras detectar la secuencia correcta, el servidor ejecuta reglas de firewall que permiten, durante un intervalo de tiempo definido, el acceso al puerto del servicio protegido.

Aunque se considera una forma de security by obscurity y no debe utilizarse como única medida de seguridad, puede complementar otras defensas como:

  • Autenticación por clave pública.

  • Firewalls restrictivos.

  • Fail2ban u otros mecanismos anti-fuerza bruta.

Su valor radica en que reduce la visibilidad del servicio SSH, dificultando la enumeración y ralentizando los escaneos automatizados.


10.2. Implementación mediante knockd

La herramienta knockd es una de las implementaciones más extendidas para port knocking. Funciona escuchando paquetes entrantes en la interfaz de red configurada y detectando secuencias válidas de knocks.

Funcionamiento general

  1. El cliente ejecuta una secuencia de conexiones a puertos específicos.

  2. knockd detecta la secuencia y ejecuta comandos configurados (normalmente reglas de firewall).

  3. Se abre temporalmente el puerto SSH o se cierra una vez finalizada la sesión o transcurrido un tiempo límite.

Ejemplo de secuencias

  • Secuencia de apertura: 7000, 8000, 9000

  • Secuencia de cierre: 9000, 8000, 7000

Estas secuencias se definen en /etc/knockd.conf, junto con las acciones asociadas.

Acciones típicas con knockd

Las acciones suelen manipular reglas del firewall mediante iptables o nftables, por ejemplo:

  • Añadir una regla temporal que permita el acceso al puerto 22 (SSH) desde la IP del cliente.

  • Eliminar la regla una vez cerrada la sesión o tras un timeout configurado.


10.3. Reglas básicas de iptables

Aunque port knocking puede integrarse con nftables, todavía es común encontrar implementaciones basadas en iptables. Las siguientes operaciones son esenciales para administrar reglas generadas por knockd.

Mostrar todas las reglas con salida detallada

sudo iptables -L -v

Mostrar todas las reglas con números de línea

sudo iptables -L -n --line-numbers

Mostrar únicamente la cadena INPUT con numeración

sudo iptables -L INPUT -n --line-numbers

Eliminar una regla específica

Para eliminar una regla, se indica la cadena y el número de línea:

sudo iptables -D INPUT NUMERO_DE_LÍNEA

Eliminar todas las reglas de todas las tablas

sudo iptables -F

Notas relevantes

  • Si knockd añade reglas dinámicamente, estas pueden aparecer al final de la cadena INPUT.

  • El número de línea cambia cada vez que se añade o elimina una regla, por lo que debe verificarse antes de ejecutar el comando.

  • En sistemas modernos basados en systemd, algunas distribuciones recomiendan migrar a nftables, pero muchos scripts de port knocking siguen utilizando iptables por compatibilidad.


10.4. Consideraciones de seguridad

Aunque port knocking añade una capa adicional de ocultación, presenta limitaciones:

  • Puede ser susceptible a ataques de sniffing si la secuencia no se cifra (a menos que se use Single Packet Authorization).

  • El replay de secuencias puede permitir accesos no autorizados si no se implementan mecanismos de expiración por IP.

  • No sustituye un proceso de hardening completo del servicio SSH.

Para entornos de alta seguridad se recomienda evaluar Single Packet Authorization (SPA), como fwknop, que mejora notablemente la protección del mecanismo.

11. Automatización con Cloud-Init

Cloud-Init es una herramienta ampliamente utilizada en entornos de computación en la nube que nos permite automatizar la configuración inicial de instancias virtuales. Entre sus múltiples funcionalidades, destaca la capacidad de gestionar la configuración de SSH o la creación de usuarios con acceso seguro, entre otras muchas opciones.

En la documentación oficial de Cloud-Init podemos encontrar una amplia variedad de ejemplos.

11.1. Ejemplo de configuración de acceso por SSH con contraseña

#cloud-config
password: nueva_password
chpasswd: { expire: False }
ssh_pwauth: True
  • La primera línea con el texto #cloud-config es obligatoria.

  • La clave password indica cuál será la nueva contraseña del usuario de la imagen.

  • La clave chpasswd indica que la contraseña no caduca y no tiene que ser cambiada después de iniciar sesión la primera vez.

  • La clave ssh_pwauth indica que se habilita el acceso por SSH con contraseña.

11.2. Ejemplo de configuración de acceso por SSH con clave pública/privada

El siguiente ejemplo muestra un archivo cloud-init para configurar un usuario con autenticación mediante clave pública, crear un grupo específico para gestionar accesos SSH y deshabilitar la autenticación por contraseña. Esta configuración es adecuada para entornos de producción o sistemas donde se requiere un hardening sólido de SSH.

#cloud-config

# Crear grupo para acceso SSH seguro
groups:
  - sshmembers

# Crear usuario con privilegios de administrador
users:
  - name: josejuan
    groups: sudo, sshmembers
    shell: /bin/bash
    sudo: "ALL=(ALL) NOPASSWD:ALL"    # Permite usar sudo sin contraseña
    ssh_authorized_keys:
      - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJEBeglT5bBTExgslszMsAvsV4v0/Bcdu3IquALzaxJA josejuan@LenovoCelia

# Deshabilitar autenticación por contraseña
ssh_pwauth: false

11.3. Ejemplo de configuración de accesso por SSH con clave pública/privada y hardening de SSH

El siguiente ejemplo muestra un archivo cloud-init que no solo configura el acceso mediante clave pública, sino que además aplica un bastionado del servicio SSH mediante la creación de un archivo de configuración dedicado en /etc/ssh/sshd_config.d/. Este enfoque modular permite mantener políticas de seguridad específicas sin modificar directamente el archivo principal sshd_config.

#cloud-config

# Crear grupo para acceso SSH seguro
groups:
  - sshmembers

# Crear usuario con privilegios de administrador
users:
  - name: josejuan
    groups: sudo, sshmembers
    shell: /bin/bash
    sudo: "ALL=(ALL) NOPASSWD:ALL"    # Permite usar sudo sin contraseña
    ssh_authorized_keys:
      - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJEBeglT5bBTExgslszMsAvsV4v0/Bcdu3IquALzaxJA josejuan@LenovoCelia

# Deshabilitar autenticación por contraseña
ssh_pwauth: false

# Bastionado de SSH utilizando un archivo de cofiguración adicional
write_files:
  - path: /etc/ssh/sshd_config.d/99-hardening.conf
    owner: root:root
    permissions: '0644'
    content: |
      # Deshabilitar acceso directo al usuario root
      PermitRootLogin no

      # Reforzar autenticación
      PasswordAuthentication no
      KbdInteractiveAuthentication no

      # Control de acceso basado en usuarios y grupos
      AllowUsers josejuan
      AllowGroups sshmembers

      # Opciones adicionales de seguridad recomendadas
      X11Forwarding no
      PermitEmptyPasswords no
      MaxAuthTries 3
      LoginGraceTime 30
      ClientAliveInterval 120
      ClientAliveCountMax 2

# Reiniciar el servicio SSH para aplicar cambios
runcmd:
  - systemctl restart ssh

11.4. Ejemplo de configuración de port knocking

El siguiente ejemplo muestra cómo configurar port knocking en una instancia mediante cloud-init utilizando la herramienta knockd. Este mecanismo permite mantener el puerto SSH cerrado por defecto y abrirlo únicamente cuando un cliente autorizado envía una secuencia específica de “knocks” (intentos de conexión a puertos definidos).

#cloud-config

# Configuración temporal para permitir el acceso inicial por contraseña.
# Esta configuración DEBE ser reemplazada posteriormente por autenticación
# mediante claves públicas.
password: password
chpasswd: { expire: False }
ssh_pwauth: True

# Paquetes necesarios para la implementación de port knocking
packages:
  - knockd
  - iptables

# Configuración del servicio knockd
write_files:
  - path: /etc/knockd.conf
    permissions: '0644'
    owner: root:root
    content: |
      [options]
             logfile = /var/log/knockd.log

      # Secuencia para abrir temporalmente el acceso SSH
      [openSSH]
             sequence    = 7000,8000,9000
             seq_timeout = 10
             command     = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
             tcpflags    = syn

      # Secuencia para cerrar el acceso SSH
      [closeSSH]
             sequence    = 9000,8000,7000
             seq_timeout = 10
             command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
             tcpflags    = syn

runcmd:
  # Bloquear SSH por defecto
  - iptables -A INPUT -p tcp --dport 22 -j DROP

  # Detectar la interfaz usando la ruta por defecto
  - IFACE=$(ip route get 8.8.8.8 | awk '{print $5}')

  # Habilitar knockd
  - sed -i "s/START_KNOCKD=0/START_KNOCKD=1/" /etc/default/knockd
  - sed -i "s/\#KNOCKD_OPTS=\"-i eth1\"/KNOCKD_OPTS=\"-i $IFACE\"/" /etc/default/knockd

  # Configuramos el inicio automático de knockd y reiniciamos el servicio
  - systemctl enable knockd
  - systemctl restart knockd

Configuración de knockd

Observe que en la secuencia para abrir temporalmente el acceso SSH se ha utilizado el modificar -I en la regla de iptables:

/sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT

Esto se hace para que la regla se inserte al principio de la cadena INPUT, garantizando que tenga prioridad sobre la regla que bloquea el puerto SSH.

Cómo obtener el nombre de la interfaz de red

En la sección runcmd estamos reemplazando la interfaz eth1 por la interfaz de red predeterminada de nuestra instancia. Para obtener el nombre de la interfaz, usamos el comando ip route get 8.8.8.8 | awk '{print $5}'.

Cómo usar nmap para comprobar los puertos abiertos

Una vez que se haya iniciado la isntancia, podemos comprobar qué puertos de la instancia están abiertos usando la herramienta nmap.

nmap -p- IP_DE_LA_INSTANCIA
nmap -sV IP_DE_LA_INSTANCIA

Cómo usar nc (netcat) para enviar la secuencia de knock

Para abrir el puerto SSH, debemos enviar la secuencia de knock. Podemos utilizar la herramienta nc (netcat):

nc 3.238.197.84 7000; nc 3.238.197.84 8000; nc 3.238.197.84 9000

Después de enviar la secuencia, podemos volver a escanear los puertos para verificar que el puerto SSH (22) está abierto y ya podríamos conectarnos por SSH.

11.5. Ejemplo completo: Hardening de SSH y configuración de port knocking

#cloud-config

# ==============================================================
# 1. Hardening básico: usuario, grupos y autenticación
# ==============================================================

groups:
  - sshmembers

users:
  - name: josejuan
    groups: sudo, sshmembers
    shell: /bin/bash
    sudo: "ALL=(ALL) NOPASSWD:ALL"
    ssh_authorized_keys:
      - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJEBeglT5bBTExgslszMsAvsV4v0/Bcdu3IquALzaxJA josejuan@LenovoCelia

# Deshabilitar autenticación por contraseña
ssh_pwauth: false


# ==============================================================
# 2. Archivos de configuración (hardening SSH + knockd)
# ==============================================================

write_files:

  # 2.1. Archivo de hardening del servicio SSH
  - path: /etc/ssh/sshd_config.d/99-hardening.conf
    owner: root:root
    permissions: '0644'
    content: |
      # Deshabilitar acceso directo al usuario root
      PermitRootLogin no

      # Reforzar autenticación
      PasswordAuthentication no
      KbdInteractiveAuthentication no

      # Control de acceso
      AllowUsers josejuan
      AllowGroups sshmembers

      # Opciones de seguridad adicionales
      X11Forwarding no
      PermitEmptyPasswords no
      MaxAuthTries 3
      LoginGraceTime 30
      ClientAliveInterval 120
      ClientAliveCountMax 2


  # 2.2. Configuración del servicio knockd
  - path: /etc/knockd.conf
    owner: root:root
    permissions: '0644'
    content: |
      [options]
        logfile = /var/log/knockd.log

      # Secuencia de apertura de SSH
      [openSSH]
        sequence    = 7000,8000,9000
        seq_timeout = 10
        command     = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
        tcpflags    = syn

      # Secuencia de cierre de SSH
      [closeSSH]
        sequence    = 9000,8000,7000
        seq_timeout = 10
        command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
        tcpflags    = syn


# ==============================================================
# 3. Instalación de paquetes necesarios
# ==============================================================

packages:
  - knockd
  - iptables


# ==============================================================
# 4. Comandos de ejecución al final del aprovisionamiento
# ==============================================================

runcmd:
  # Aplicar configuración del servicio SSH
  - systemctl restart ssh

  # Bloquear puerto SSH por defecto
  - iptables -A INPUT -p tcp --dport 22 -j DROP

  # Detectar la interfaz de red por defecto
  - IFACE=$(ip route get 8.8.8.8 | awk '{print $5}')

  # Activar knockd y establecer interfaz detectada
  - sed -i "s/START_KNOCKD=0/START_KNOCKD=1/" /etc/default/knockd
  - sed -i "s/#KNOCKD_OPTS=\"-i eth1\"/KNOCKD_OPTS=\"-i $IFACE\"/" /etc/default/knockd

  # Habilitar servicio knockd en el arranque
  - systemctl enable knockd
  - systemctl restart knockd

Referencias