Actualizaciones automáticas de seguridad con unattended-upgrades

La superficie de ataque más explotada en producción no es una configuración de firewall incorrecta ni un puerto abierto de más: es software desactualizado con vulnerabilidades conocidas y parches disponibles que nunca se aplicaron. unattended-upgrades resuelve exactamente ese problema: aplica automáticamente las actualizaciones de seguridad sin que nadie tenga que acordarse de ejecutar apt upgrade.

El paquete funciona como un hook sobre APT. Cuando el temporizador apt-daily-upgrade.timer de systemd dispara (por defecto una vez al día), unattended-upgrades evalúa qué paquetes tienen actualizaciones disponibles en los repositorios configurados y los instala sin intervención manual. La clave del diseño es que por defecto solo actúa sobre el repositorio security, no sobre el repositorio principal. Esto no es un capricho: las actualizaciones de seguridad en Debian siguen una política estricta de cambios mínimos —parchear la vulnerabilidad, nada más—, mientras que las actualizaciones del repositorio principal pueden traer cambios de comportamiento, dependencias nuevas o roturas de API. En producción, esa distinción es fundamental.

Úsalo en cualquier sistema que no tengas bajo un proceso de gestión de parches centralizado (Ansible, Puppet, etc.) y donde un humano no aplique actualizaciones de seguridad al menos semanalmente. Si ya tienes automatización propia, unattended-upgrades es redundante y puede crear conflictos. Donde sí es imprescindible: VPS pequeños, servidores secundarios, entornos con pocos recursos de administración.

Si lo configuras mal —activando actualizaciones de paquetes no-security o habilitando reinicios automáticos sin considerar las ventanas de mantenimiento— puedes encontrarte con un servidor que reinicia solo a las 3 AM en producción, o con una actualización de libc6 que rompe una aplicación que no habías probado.

# Instalar el paquete si no está presente
apt install unattended-upgrades needrestart

# Activarlo interactivamente (genera /etc/apt/apt.conf.d/20auto-upgrades)
dpkg-reconfigure --priority=low unattended-upgrades

# Verificar que el archivo de activación quedó bien
cat /etc/apt/apt.conf.d/20auto-upgrades
# Debe mostrar:
# APT::Periodic::Update-Package-Lists "1";
# APT::Periodic::Unattended-Upgrade "1";

# El archivo principal de configuración
# Editar con tu editor habitual
nano /etc/apt/apt.conf.d/50unattended-upgrades
// /etc/apt/apt.conf.d/50unattended-upgrades
// Solo las líneas relevantes que debes revisar y ajustar

Unattended-Upgrade::Origins-Pattern {
    // Solo actualizaciones de seguridad de Debian stable — dejar así en producción
    "origin=Debian,codename=${distro_codename}-security,label=Debian-Security";

    // Si también quieres aplicar stable-updates (correcciones no-security pero
    // conservadoras), descomenta la siguiente línea solo tras evaluarlo:
    // "origin=Debian,codename=${distro_codename}-updates";
};

// Paquetes que nunca deben actualizarse automáticamente
// El kernel es un candidato obvio si necesitas ventana de mantenimiento
Unattended-Upgrade::Package-Blacklist {
    "linux-image-*";
    "linux-headers-*";
};

// Eliminar dependencias huérfanas tras actualizar
Unattended-Upgrade::Remove-Unused-Dependencies "true";

// Reinicio automático: desactivado por defecto, y bien pensado
// Si lo activas, define una hora explícita para no sorprenderte
Unattended-Upgrade::Automatic-Reboot "false";
// Unattended-Upgrade::Automatic-Reboot-Time "03:30";

// Mandar el resultado por correo (requiere un MTA configurado)
Unattended-Upgrade::Mail "admin@ejemplo.com";
Unattended-Upgrade::MailReport "on-change";
# Simular una ejecución sin instalar nada — útil para verificar la config
unattended-upgrades --dry-run --debug 2>&1 | head -40

# Forzar una ejecución real inmediata (para probar en un sistema nuevo)
unattended-upgrades --debug

# Ver el log de lo que ha hecho en los últimos días
cat /var/log/unattended-upgrades/unattended-upgrades.log

# Comprobar el estado del timer de systemd
systemctl status apt-daily-upgrade.timer
systemctl list-timers apt-daily*

# needrestart: detectar qué servicios usan bibliotecas actualizadas
# pero no han sido reiniciados todavía
needrestart -b   # modo batch, salida parseable
needrestart -r l # listar procesos afectados sin preguntar

# Ver exactamente qué biblioteca obsoleta está usando cada proceso
needrestart -v

Origins-Pattern con ${distro_codename} es la pieza central de la configuración. La variable se expande automáticamente al codename de la release instalada (bookworm en Debian 12), lo que significa que el mismo archivo funciona sin modificación después de un upgrade a la siguiente release. Si en cambio pusieras bookworm literalmente, tendrías que acordarte de actualizar este archivo durante el próximo dist-upgrade.

Package-Blacklist con los kernels merece atención. Actualizar el kernel automáticamente es correcto en muchos contextos, pero requiere reinicio para tener efecto, y ese reinicio no es instantáneo —hay que considerar el fsck, los tiempos de arranque de servicios, el warmup de cachés. En servidores donde controlas las ventanas de mantenimiento, excluir el kernel del automático y aplicarlo manualmente en esa ventana es la decisión más razonable.

Automatic-Reboot "false" es el valor correcto para la mayoría de servidores en producción. El reinicio automático tiene sentido en flotas grandes donde tienes un balanceador que puede drenar el nodo, pero en un servidor único es una interrupción de servicio no planificada. El problema real que esto genera es diferido: actualizas libssl3 pero el proceso de nginx sigue usando la versión anterior hasta que se reinicia. Aquí entra needrestart.

needrestart -b escanea /proc/*/maps buscando ficheros borrados (los .so antiguos que fueron reemplazados pero siguen mapeados en memoria). Cuando ves NEEDRESTART-SVC: nginx.service en su salida, significa que nginx carga en memoria una versión de una biblioteca que ya no existe en disco —la actualización no tiene efecto real hasta que reinicias ese servicio. Ejecutar needrestart -r l tras cada actualización y reiniciar solo los servicios afectados es la alternativa correcta al reinicio completo del sistema.

El log en /var/log/unattended-upgrades/ es tu evidencia de auditoría. Antes de cualquier incidente de seguridad o revisión de cumplimiento, ese log te dice exactamente qué se aplicó y cuándo. Si el log muestra Packages that will be upgraded: openssl con la fecha de hace tres días, tienes la trazabilidad completa.

--dry-run antes de habilitar en producción es obligatorio. Te muestra exactamente qué repositorios evalúa, qué paquetes encontraría para actualizar y si hay algún error de configuración en el archivo .conf, sin tocar nada.

[Ubuntu]: Ubuntu añade por defecto en Origins-Pattern las entradas para sus propios repositorios ${distro_id}:${distro_codename}-security. Ubuntu Pro / Ubuntu Advantage extiende este mecanismo con el repositorio esm-infra, que proporciona parches de seguridad para paquetes del universo y para versiones LTS más allá de los 5 años estándar —activado con pro attach <token> y configurable también en 50unattended-upgrades.

97

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio