Un servidor recién creado y expuesto a Internet empieza a recibir intentos de acceso por SSH en cuestión de minutos. El hardening consiste en reducir la superficie de ataque y dejar rastro de lo que ocurre: menos servicios expuestos, accesos solo con clave, parches al día y registro de los cambios sensibles. En este tutorial aplicarás esas medidas a un servidor Ubuntu 24.04 en un orden seguro, comprobando cada una antes de pasar a la siguiente, y terminarás con una auditoría de Lynis para ver qué queda por mejorar.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS recién instalado, por ejemplo un VPS de CubePath, y su dirección IP (your_server_ip).
  • Acceso como root o con un usuario con sudo.
  • Un equipo local con cliente SSH (Linux, macOS o Windows 10/11 con OpenSSH).
  • Acceso a la consola del servidor desde el panel de tu proveedor, por si te quedas fuera por SSH mientras cambias su configuración.

Paso 1: Actualizar el sistema

Muchas intrusiones aprovechan vulnerabilidades ya corregidas. Antes de nada, instala todas las actualizaciones pendientes:

sudo apt update
sudo apt full-upgrade -y

Si se ha actualizado el kernel, el sistema lo indica con el archivo /var/run/reboot-required. Comprueba si existe y reinicia en ese caso:

[ -f /var/run/reboot-required ] && echo "Reinicio necesario" || echo "No hace falta reiniciar"
sudo reboot

Paso 2: Crear un usuario administrador

Trabajar directamente como root hace que cualquier error o credencial robada tenga el máximo impacto. Crea un usuario propio (sustituye your_user por el nombre que quieras) y añádelo al grupo sudo:

sudo adduser your_user
sudo usermod -aG sudo your_user

adduser te pedirá una contraseña. Úsala solo para sudo; el acceso por SSH será con clave. Comprueba que el usuario tiene permisos de administración:

sudo -l -U your_user
User your_user may run the following commands on server:
    (ALL : ALL) ALL

Paso 3: Configurar el acceso SSH con clave

Las claves SSH no se pueden adivinar por fuerza bruta como una contraseña. Desde tu equipo local, genera una clave Ed25519 si todavía no tienes una:

ssh-keygen -t ed25519 -C "your_user@portatil"

Copia la clave pública al servidor. ssh-copy-id la añade a ~/.ssh/authorized_keys del usuario con los permisos correctos:

ssh-copy-id your_user@your_server_ip

Abre una nueva terminal y comprueba que entras con la clave, sin que te pida la contraseña del usuario:

ssh your_user@your_server_ip

No sigas al paso siguiente hasta que este acceso funcione.

Paso 4: Endurecer la configuración de SSH

En Ubuntu 24.04, /etc/ssh/sshd_config incluye al principio todos los archivos /etc/ssh/sshd_config.d/*.conf, en orden alfabético, y para cada opción sshd se queda con el primer valor que encuentra. Algunas imágenes cloud crean 50-cloud-init.conf con PasswordAuthentication yes, así que tu archivo debe tener un nombre que se ordene antes, como 00-hardening.conf:

sudo nano /etc/ssh/sshd_config.d/00-hardening.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
LoginGraceTime 30
X11Forwarding no
AllowUsers your_user

Qué hace cada opción:

  • PermitRootLogin no: nadie puede entrar directamente como root.
  • PasswordAuthentication no y KbdInteractiveAuthentication no: desactivan el acceso con contraseña, solo se aceptan claves.
  • MaxAuthTries 3 y LoginGraceTime 30: menos intentos por conexión y menos tiempo para autenticarse.
  • X11Forwarding no: un servidor no necesita reenviar aplicaciones gráficas.
  • AllowUsers your_user: solo los usuarios de la lista pueden iniciar sesión por SSH. Añade más nombres separados por espacios si hace falta.

Valida la sintaxis antes de aplicar nada. Si no hay errores, el comando no muestra nada:

sudo sshd -t

Comprueba los valores efectivos, que confirman que ningún otro archivo los está pisando:

sudo sshd -T | grep -Ei '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|maxauthtries|allowusers)'
permitrootlogin no
maxauthtries 3
kbdinteractiveauthentication no
passwordauthentication no
allowusers your_user

Aplica los cambios reiniciando el servicio, que en Ubuntu se llama ssh:

sudo systemctl restart ssh

Desde una segunda terminal, verifica que sigues entrando con tu usuario y que root ya no puede:

ssh your_user@your_server_ip
ssh root@your_server_ip
root@your_server_ip: Permission denied (publickey).

Paso 5: Activar el firewall con UFW

UFW viene instalado en Ubuntu, pero desactivado. La política recomendada es denegar todo el tráfico entrante y permitir solo lo que usas. Permite SSH primero, para no cortar tu propia conexión. La regla limit permite SSH pero bloquea temporalmente una IP que abra 6 o más conexiones en 30 segundos:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw limit OpenSSH

Si el servidor va a servir web, abre también HTTP y HTTPS:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Activa el firewall (responde y al aviso de que puede cortar conexiones SSH; la regla anterior mantiene la tuya) y revisa las reglas:

sudo ufw enable
sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp (OpenSSH)           LIMIT IN    Anywhere
80/tcp                     ALLOW IN    Anywhere
443/tcp                    ALLOW IN    Anywhere
22/tcp (OpenSSH (v6))      LIMIT IN    Anywhere (v6)
80/tcp (v6)                ALLOW IN    Anywhere (v6)
443/tcp (v6)               ALLOW IN    Anywhere (v6)

Paso 6: Instalar parches de seguridad automáticamente

unattended-upgrades instala cada día las actualizaciones del repositorio de seguridad de Ubuntu. Viene preinstalado en Ubuntu Server; instálalo por si acaso y actívalo:

sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

Responde Yes en la pantalla que aparece. Comprueba que ha quedado activado:

cat /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

Las actualizaciones del kernel solo se aplican al reiniciar. Si aceptas reinicios automáticos en una ventana de poco tráfico, añádelo en un archivo propio para no modificar el del paquete:

sudo nano /etc/apt/apt.conf.d/52unattended-upgrades-local
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";

Haz una simulación para confirmar que la configuración es válida:

sudo unattended-upgrade --dry-run --debug 2>&1 | tail -5

Los resultados de cada ejecución quedan en /var/log/unattended-upgrades/unattended-upgrades.log.

Paso 7: Revisar los servicios expuestos

Cada puerto abierto es una posible entrada. Lista los procesos que escuchan en la red:

sudo ss -tulpn
Netid State  Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
udp   UNCONN 0      0      127.0.0.54:53       0.0.0.0:*         users:(("systemd-resolve",pid=512,fd=16))
udp   UNCONN 0      0      127.0.0.53%lo:53    0.0.0.0:*         users:(("systemd-resolve",pid=512,fd=14))
tcp   LISTEN 0      4096   127.0.0.53%lo:53    0.0.0.0:*         users:(("systemd-resolve",pid=512,fd=15))
tcp   LISTEN 0      4096   0.0.0.0:22          0.0.0.0:*         users:(("sshd",pid=801,fd=3),("systemd",pid=1,fd=100))

Lo que escucha en 127.0.0.x solo es accesible desde el propio servidor. Revisa cualquier servicio en 0.0.0.0 o [::] que no reconozcas. Para ver qué servicios arrancan con el sistema:

systemctl list-unit-files --type=service --state=enabled

Si encuentras uno que no usas, detenlo y desactívalo (sustituye nombre_del_servicio), o desinstala directamente el paquete:

sudo systemctl disable --now nombre_del_servicio

Paso 8: Ajustar parámetros de red y del kernel

Algunos parámetros del kernel reducen la información expuesta y la exposición a ataques de red sencillos. Ubuntu ya trae valores seguros para varios de ellos (como tcp_syncookies o dmesg_restrict); este archivo los fija explícitamente y añade los que faltan:

sudo nano /etc/sysctl.d/99-hardening.conf
# No aceptar ni enviar redirecciones ICMP
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

# Rechazar paquetes con enrutamiento de origen
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0

# Registrar paquetes con direcciones imposibles
net.ipv4.conf.all.log_martians = 1

# Protección frente a SYN flood
net.ipv4.tcp_syncookies = 1

# Ocultar direcciones del kernel y el buffer de dmesg a usuarios sin privilegios
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1

Carga todos los archivos de /etc/sysctl.d/ y comprueba un par de valores:

sudo sysctl --system > /dev/null
sysctl net.ipv4.conf.all.accept_redirects kernel.kptr_restrict
net.ipv4.conf.all.accept_redirects = 0
kernel.kptr_restrict = 2

Paso 9: Registrar cambios sensibles con auditd

auditd registra a nivel de kernel quién modifica archivos críticos, incluso si luego se borran los logs de la aplicación. Instálalo:

sudo apt install auditd

Crea un archivo de reglas que vigile usuarios, grupos, sudo y la configuración de SSH. La opción -p wa registra escrituras y cambios de atributos, y -k asigna una etiqueta para buscar después:

sudo nano /etc/audit/rules.d/50-hardening.rules
-w /etc/passwd -p wa -k identidad
-w /etc/shadow -p wa -k identidad
-w /etc/group -p wa -k identidad
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers
-w /etc/ssh/sshd_config -p wa -k sshd
-w /etc/ssh/sshd_config.d/ -p wa -k sshd

Carga las reglas y compruébalas:

sudo augenrules --load
sudo auditctl -l
-w /etc/passwd -p wa -k identidad
-w /etc/shadow -p wa -k identidad
-w /etc/group -p wa -k identidad
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d -p wa -k sudoers
-w /etc/ssh/sshd_config -p wa -k sshd
-w /etc/ssh/sshd_config.d -p wa -k sshd

Pruébalo creando y borrando un usuario de prueba, y busca los eventos con la etiqueta identidad:

sudo useradd prueba-audit && sudo userdel prueba-audit
sudo ausearch -k identidad -i --start today | tail -5

Verás entradas con el comando ejecutado (comm=useradd) y el usuario que lo lanzó (auid=your_user).

Paso 10: Comprobar AppArmor y bloquear ataques de fuerza bruta

Ubuntu activa AppArmor por defecto, que limita qué puede hacer cada programa con perfil aunque sea comprometido. Confirma que está cargado:

sudo aa-status | head -3
apparmor module is loaded.
120 profiles are loaded.
48 profiles are in enforce mode.

Con SSH limitado a claves, los intentos de fuerza bruta ya no pueden tener éxito, pero siguen llenando los logs y consumiendo recursos. Fail2Ban bloquea en el firewall las IP que acumulan fallos. Instálalo; en Ubuntu la jaula de SSH viene activada:

sudo apt install fail2ban
sudo fail2ban-client status sshd

La guía de Fail2Ban de esta misma sección explica cómo ajustar tiempos de bloqueo, listas blancas y jaulas para otros servicios.

Paso 11: Auditar el resultado con Lynis

Lynis revisa cientos de puntos de configuración y te da una lista priorizada de sugerencias. Instálalo desde los repositorios de Ubuntu y lanza una auditoría:

sudo apt install lynis
sudo lynis audit system

Al final del informe verás el índice de hardening y las rutas de los resultados:

  Hardening index : 72 [##############      ]
  Tests performed : 262
...
  - Test and debug information      : /var/log/lynis.log
  - Report data                     : /var/log/lynis-report.dat

Revisa la sección Suggestions del informe. No todas aplican a cada servidor (por ejemplo, las que piden particiones separadas); prioriza las que afectan a servicios expuestos y a cuentas de usuario. Vuelve a ejecutar Lynis tras cada cambio importante para comparar el índice.

Solución de problemas

  • Te has quedado fuera por SSH: entra por la consola web del panel, revisa /etc/ssh/sshd_config.d/00-hardening.conf (normalmente un AllowUsers con un nombre mal escrito) y ejecuta sudo sshd -t && sudo systemctl restart ssh.
  • SSH sigue aceptando contraseñas: algún archivo de /etc/ssh/sshd_config.d/ con un nombre anterior al tuyo en orden alfabético define PasswordAuthentication yes. Localízalo con grep -ri passwordauthentication /etc/ssh/sshd_config /etc/ssh/sshd_config.d/.
  • Un servicio deja de responder tras activar UFW: falta la regla de su puerto. Añádela con sudo ufw allow puerto/tcp y compruébalo con sudo ufw status numbered.

Conclusión

Tu servidor Ubuntu 24.04 ya solo acepta acceso SSH con clave y sin root, filtra el tráfico entrante con UFW, instala parches de seguridad por sí mismo, expone únicamente los servicios necesarios y registra los cambios en usuarios, sudo y SSH. El hardening no es una tarea única: repítelo con cada servicio nuevo que instales.

Como siguientes pasos puedes:

  • Ajustar Fail2Ban con tiempos de bloqueo progresivos y jaulas para tus aplicaciones web.
  • Configurar copias de seguridad automáticas y comprobar que sabes restaurarlas.
  • Centralizar los logs y los eventos de auditd en otro servidor para que un atacante no pueda borrarlos.