Implementación del Framework de Ciberseguridad NIST en Linux
El Framework de Ciberseguridad del NIST (NIST CSF) proporciona un conjunto de estándares, directrices y mejores prácticas para gestionar el riesgo de ciberseguridad en infraestructura crítica. Organizado en cinco funciones principales—Identificar, Proteger, Detectar, Responder y Recuperar—el CSF es flexible y se adapta tanto a pequeñas organizaciones como a grandes empresas. Esta guía cubre la implementación práctica del NIST CSF en servidores Linux, con controles técnicos concretos para cada función.
Requisitos Previos
- Servidores Linux: Ubuntu 20.04+, CentOS 8+, Rocky Linux 8+
- Acceso root o privilegios sudo
- Herramientas: auditd, fail2ban, AIDE, nmap, openssl
- Documentación de arquitectura de red e inventario de activos inicial
IDENTIFICAR: Gestión de Activos y Riesgos
La función Identificar (ID) establece el contexto organizacional y la comprensión de los activos que necesitan protección.
Inventario de Activos (ID.AM)
# Script de inventario automático de activos del servidor
cat > /usr/local/bin/nist-inventory.sh << 'EOF'
#!/bin/bash
# NIST CSF ID.AM-1: Inventario de activos físicos y de software
INVENTARIO="/opt/nist-csf/inventario"
mkdir -p "$INVENTARIO"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# Información del sistema
{
echo "=== INVENTARIO DE ACTIVOS NIST CSF ==="
echo "Fecha: $(date)"
echo "Hostname: $(hostname -f)"
echo "IP: $(hostname -I)"
echo ""
echo "--- Sistema Operativo ---"
cat /etc/os-release
echo ""
echo "--- Hardware ---"
lscpu | grep -E "Architecture|CPU\(s\)|Model name"
free -h | head -2
df -h --total | tail -1
echo ""
echo "--- Servicios Activos ---"
systemctl list-units --type=service --state=running --no-pager
echo ""
echo "--- Puertos en Escucha ---"
ss -tlnp
echo ""
echo "--- Paquetes Instalados ---"
dpkg -l 2>/dev/null || rpm -qa 2>/dev/null
} > "$INVENTARIO/asset-inventory-$TIMESTAMP.txt"
echo "Inventario guardado: $INVENTARIO/asset-inventory-$TIMESTAMP.txt"
EOF
chmod +x /usr/local/bin/nist-inventory.sh
/usr/local/bin/nist-inventory.sh
Evaluación de Riesgos (ID.RA)
# Script de evaluación de riesgos técnicos
cat > /usr/local/bin/nist-risk-assess.sh << 'EOF'
#!/bin/bash
# NIST CSF ID.RA: Evaluación de riesgos
REPORTE="/opt/nist-csf/risk-assessment-$(date +%Y%m%d).txt"
mkdir -p /opt/nist-csf
echo "=== EVALUACIÓN DE RIESGOS NIST CSF ===" > "$REPORTE"
echo "Fecha: $(date)" >> "$REPORTE"
# Verificar actualizaciones de seguridad pendientes
echo -e "\n[RIESGO: Actualizaciones pendientes]" >> "$REPORTE"
apt list --upgradable 2>/dev/null | grep -i security | wc -l >> "$REPORTE"
# Verificar puertos abiertos
echo -e "\n[RIESGO: Puertos expuestos]" >> "$REPORTE"
ss -tlnp >> "$REPORTE"
# Verificar cuentas privilegiadas
echo -e "\n[RIESGO: Cuentas privilegiadas]" >> "$REPORTE"
getent group sudo wheel | head -5 >> "$REPORTE"
# Verificar contraseñas débiles o vacías
echo -e "\n[RIESGO: Cuentas sin contraseña]" >> "$REPORTE"
awk -F: '($2 == "" || $2 == "!") {print $1 " - SIN CONTRASEÑA"}' /etc/shadow >> "$REPORTE"
echo "Evaluación guardada: $REPORTE"
EOF
chmod +x /usr/local/bin/nist-risk-assess.sh
PROTEGER: Implementación de Salvaguardas
Gestión de Identidad y Acceso (PR.AC)
# Configurar control de acceso según NIST CSF PR.AC-1
# Implementar política de contraseñas fuerte
cat > /etc/security/pwquality.conf << 'EOF'
# NIST CSF PR.AC-1: Política de contraseñas
minlen = 12
minclass = 3
maxrepeat = 2
maxsequence = 3
ucredit = -1
lcredit = -1
dcredit = -1
ocredit = -1
EOF
# Configurar PAM para usar pwquality
# En /etc/pam.d/common-password (Ubuntu)
grep -q "pam_pwquality" /etc/pam.d/common-password || \
sed -i '/pam_unix.so/i password requisite pam_pwquality.so retry=3' \
/etc/pam.d/common-password
# Configurar SSH con autenticación fuerte
cat > /etc/ssh/sshd_config.d/nist-csf.conf << 'EOF'
# NIST CSF PR.AC-3: Acceso remoto seguro
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin no
Protocol 2
MaxAuthTries 3
LoginGraceTime 60
AllowAgentForwarding no
EOF
systemctl reload sshd
Seguridad de Red (PR.AC-5, PR.PT-4)
# Configurar firewall con UFW (Ubuntu) o firewalld (CentOS)
# Ubuntu/Debian
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow 443/tcp
ufw enable
# Verificar reglas
ufw status verbose
# Para CentOS/Rocky Linux
# firewall-cmd --permanent --add-service=ssh
# firewall-cmd --permanent --add-service=https
# firewall-cmd --reload
# Configurar fail2ban para protección contra fuerza bruta (PR.AC-4)
apt install fail2ban -y
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
backend = systemd
[sshd]
enabled = true
port = ssh
maxretry = 3
bantime = 86400
EOF
systemctl enable --now fail2ban
Capacitación y Concienciación (PR.AT)
# Banner de inicio de sesión con aviso legal (PR.AT-1)
cat > /etc/motd << 'EOF'
=========================================
SISTEMA PRIVADO - ACCESO RESTRINGIDO
=========================================
Este sistema es propiedad de [Empresa].
El acceso no autorizado está prohibido y
puede ser objeto de acciones legales.
Todas las actividades son monitoreadas
y registradas.
=========================================
EOF
cat > /etc/issue.net << 'EOF'
AVISO: Sistema de acceso restringido.
Solo usuarios autorizados pueden continuar.
EOF
# Habilitar banner en SSH
echo "Banner /etc/issue.net" >> /etc/ssh/sshd_config.d/nist-csf.conf
systemctl reload sshd
Protección de Datos (PR.DS)
# NIST CSF PR.DS-1: Protección de datos en reposo
# Verificar y configurar permisos de archivos sensibles
chmod 600 /etc/shadow
chmod 644 /etc/passwd
chmod 600 /etc/ssh/ssh_host_*_key # Claves privadas SSH
chmod 644 /etc/ssh/ssh_host_*_key.pub # Claves públicas SSH
# NIST CSF PR.DS-2: Protección de datos en tránsito
# Verificar configuración TLS
openssl s_client -connect localhost:443 2>/dev/null | grep -E "Protocol|Cipher"
# Configurar eliminación segura de datos
apt install secure-delete # Ubuntu
# Uso: srm -v archivo-sensible.txt
DETECTAR: Monitoreo de Seguridad
Detección de Anomalías (DE.AE)
# Configurar auditd para detección de eventos de seguridad
cat > /etc/audit/rules.d/nist-csf.rules << 'EOF'
# NIST CSF DE.AE-1: Establecer línea base de comportamiento
# Detectar escalada de privilegios
-a always,exit -F arch=b64 -S setuid -F a0=0 -F exe=/usr/bin/sudo -k privilege-escalation
-w /usr/bin/sudo -p x -k sudo-usage
# Detectar modificaciones del sistema
-w /etc/cron.d/ -p wa -k cron-changes
-w /etc/crontab -p wa -k cron-changes
-w /var/spool/cron/ -p wa -k cron-changes
# Detectar inicio de nuevos servicios
-w /etc/systemd/system/ -p wa -k service-changes
-w /lib/systemd/system/ -p wa -k service-changes
# Detectar cambios en binarios del sistema
-w /usr/bin/ -p wa -k bin-changes
-w /usr/sbin/ -p wa -k bin-changes
-w /bin/ -p wa -k bin-changes
# Detectar acceso a claves SSH
-w /root/.ssh/ -p rwa -k ssh-access
-a always,exit -F arch=b64 -S open,openat -F dir=/home -F name=authorized_keys -k ssh-access
EOF
augenrules --load
Monitoreo Continuo (DE.CM)
# Script de monitoreo continuo NIST CSF
cat > /usr/local/bin/nist-monitor.sh << 'EOF'
#!/bin/bash
# NIST CSF DE.CM-1: Monitoreo continuo de la red y el sistema
LOG="/var/log/nist-monitoring.log"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# Verificar nuevas conexiones de red sospechosas
CONNS_EXTERNAS=$(ss -tn state established | tail -n +2 | \
awk '{print $5}' | grep -v "127\." | grep -v "::1" | wc -l)
# Verificar uso de CPU anormal (posible minería de criptomonedas)
CPU_CARGA=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | tr -d ',')
# Verificar procesos con privilegios elevados inusuales
PROC_ROOT=$(ps aux | awk '$1=="root" && $11!~/^\[/ {print $11}' | sort | uniq | wc -l)
echo "$TIMESTAMP CONEXIONES_EXT=$CONNS_EXTERNAS CPU_CARGA=$CPU_CARGA PROC_ROOT=$PROC_ROOT" \
>> "$LOG"
# Alertar si hay valores anormales
if [ "${CPU_CARGA%.*}" -gt 10 ] 2>/dev/null; then
logger -t nist-csf "ALERTA DE.CM: CPU carga alta: $CPU_CARGA"
fi
EOF
chmod +x /usr/local/bin/nist-monitor.sh
echo "*/5 * * * * root /usr/local/bin/nist-monitor.sh" > /etc/cron.d/nist-monitor
RESPONDER: Gestión de Incidentes
Plan de Respuesta (RS.RP)
# Script de respuesta a incidentes NIST CSF
cat > /usr/local/bin/nist-incident-response.sh << 'EOF'
#!/bin/bash
# NIST CSF RS.RP-1: Plan de respuesta a incidentes
INCIDENTE_ID="INC-$(date +%Y%m%d-%H%M%S)"
DIR_INCIDENTE="/opt/nist-csf/incidents/$INCIDENTE_ID"
mkdir -p "$DIR_INCIDENTE"
echo "=== RESPUESTA A INCIDENTE: $INCIDENTE_ID ===" | tee "$DIR_INCIDENTE/timeline.txt"
echo "Inicio: $(date)" | tee -a "$DIR_INCIDENTE/timeline.txt"
# Capturar estado del sistema en el momento del incidente
echo "--- Conexiones activas ---" >> "$DIR_INCIDENTE/system-state.txt"
ss -tnp >> "$DIR_INCIDENTE/system-state.txt"
echo "--- Procesos en ejecución ---" >> "$DIR_INCIDENTE/system-state.txt"
ps aux >> "$DIR_INCIDENTE/system-state.txt"
echo "--- Usuarios conectados ---" >> "$DIR_INCIDENTE/system-state.txt"
who >> "$DIR_INCIDENTE/system-state.txt"
last -n 20 >> "$DIR_INCIDENTE/system-state.txt"
echo "--- Últimas entradas de log ---" >> "$DIR_INCIDENTE/system-state.txt"
journalctl -n 200 --no-pager >> "$DIR_INCIDENTE/system-state.txt"
echo "--- Logs de autenticación ---" >> "$DIR_INCIDENTE/system-state.txt"
tail -100 /var/log/auth.log >> "$DIR_INCIDENTE/system-state.txt" 2>/dev/null
echo "Evidencia de incidente guardada en: $DIR_INCIDENTE"
echo "ID de incidente: $INCIDENTE_ID"
EOF
chmod +x /usr/local/bin/nist-incident-response.sh
Comunicaciones de Incidente (RS.CO)
# Configurar notificación automática de incidentes
cat > /usr/local/bin/nist-alert.sh << 'EOF'
#!/bin/bash
# NIST CSF RS.CO-2: Alertas de incidentes de seguridad
TIPO=$1
DETALLE=$2
DESTINATARIO="[email protected]"
if [ -z "$TIPO" ]; then
echo "Uso: $0 <tipo-incidente> <descripcion>"
exit 1
fi
MENSAJE="Sistema: $(hostname)
Fecha: $(date)
Tipo de incidente: $TIPO
Descripción: $DETALLE
Conexiones activas:
$(ss -tn state established | head -10)
Usuarios conectados:
$(who)"
echo "$MENSAJE" | mail -s "ALERTA NIST CSF: $TIPO en $(hostname)" "$DESTINATARIO"
logger -t nist-csf "INCIDENTE: $TIPO - $DETALLE"
EOF
chmod +x /usr/local/bin/nist-alert.sh
RECUPERAR: Planes de Recuperación
Plan de Recuperación (RC.RP)
# Script de verificación de recuperación post-incidente
cat > /usr/local/bin/nist-recovery-verify.sh << 'EOF'
#!/bin/bash
# NIST CSF RC.RP-1: Verificación post-recuperación
REPORTE="/opt/nist-csf/recovery-verify-$(date +%Y%m%d_%H%M%S).txt"
echo "=== VERIFICACIÓN DE RECUPERACIÓN NIST CSF ===" > "$REPORTE"
echo "Fecha: $(date)" >> "$REPORTE"
# Verificar servicios críticos
echo -e "\n[SERVICIOS]" >> "$REPORTE"
for SERVICIO in ssh nginx apache2 mysql postgresql; do
STATUS=$(systemctl is-active "$SERVICIO" 2>/dev/null || echo "no instalado")
echo "$SERVICIO: $STATUS" >> "$REPORTE"
done
# Verificar integridad del sistema de archivos
echo -e "\n[SISTEMA DE ARCHIVOS]" >> "$REPORTE"
df -h >> "$REPORTE"
# Verificar conectividad de red
echo -e "\n[CONECTIVIDAD]" >> "$REPORTE"
ping -c 3 8.8.8.8 >> "$REPORTE" 2>&1
# Verificar logs recientes de errores
echo -e "\n[ERRORES RECIENTES]" >> "$REPORTE"
journalctl -p err -n 20 --no-pager >> "$REPORTE"
echo "Verificación guardada: $REPORTE"
cat "$REPORTE"
EOF
chmod +x /usr/local/bin/nist-recovery-verify.sh
Evaluación de Madurez
Medir el Nivel de Madurez del CSF
# Script de evaluación del nivel de implementación del NIST CSF
cat > /usr/local/bin/nist-maturity.sh << 'EOF'
#!/bin/bash
# Evaluación de madurez NIST CSF (Tiers 1-4)
PUNTOS=0
TOTAL=10
echo "=== EVALUACIÓN DE MADUREZ NIST CSF ==="
# ID: Inventario de activos
[ -f /opt/nist-csf/inventario/asset-inventory-*.txt ] && \
{ echo "[PASS] ID.AM: Inventario de activos"; PUNTOS=$((PUNTOS+1)); } || \
echo "[FAIL] ID.AM: Sin inventario de activos"
# PR: SSH sin contraseña
grep -q "PasswordAuthentication no" /etc/ssh/sshd_config* 2>/dev/null && \
{ echo "[PASS] PR.AC: SSH solo con claves"; PUNTOS=$((PUNTOS+1)); } || \
echo "[FAIL] PR.AC: SSH permite contraseñas"
# PR: Firewall activo
ufw status 2>/dev/null | grep -q "active" && \
{ echo "[PASS] PR.PT: Firewall activo"; PUNTOS=$((PUNTOS+1)); } || \
firewall-cmd --state 2>/dev/null | grep -q "running" && \
{ echo "[PASS] PR.PT: Firewall activo"; PUNTOS=$((PUNTOS+1)); } || \
echo "[FAIL] PR.PT: Sin firewall activo"
# PR: fail2ban activo
systemctl is-active fail2ban &>/dev/null && \
{ echo "[PASS] PR.AC: fail2ban activo"; PUNTOS=$((PUNTOS+1)); } || \
echo "[FAIL] PR.AC: fail2ban no activo"
# DE: auditd activo
systemctl is-active auditd &>/dev/null && \
{ echo "[PASS] DE.CM: auditd activo"; PUNTOS=$((PUNTOS+1)); } || \
echo "[FAIL] DE.CM: auditd no activo"
# DE: Reglas NIST auditd
auditctl -l 2>/dev/null | grep -q "nist" && \
{ echo "[PASS] DE.AE: Reglas de auditoría NIST"; PUNTOS=$((PUNTOS+1)); } || \
echo "[FAIL] DE.AE: Sin reglas de auditoría NIST"
# RS: Script de respuesta disponible
[ -x /usr/local/bin/nist-incident-response.sh ] && \
{ echo "[PASS] RS.RP: Plan de respuesta disponible"; PUNTOS=$((PUNTOS+1)); } || \
echo "[FAIL] RS.RP: Sin plan de respuesta"
# RC: Backups configurados
crontab -l 2>/dev/null | grep -qi backup || \
ls /etc/cron.d/ | grep -qi backup && \
{ echo "[PASS] RC.RP: Backups configurados"; PUNTOS=$((PUNTOS+1)); } || \
echo "[FAIL] RC.RP: Sin backups configurados"
echo ""
echo "Puntuación: $PUNTOS/$TOTAL"
TIER=$((PUNTOS * 4 / TOTAL))
[ $TIER -lt 1 ] && TIER=1
echo "Nivel de Madurez (Tier): $TIER/4"
EOF
chmod +x /usr/local/bin/nist-maturity.sh
/usr/local/bin/nist-maturity.sh
Solución de Problemas
El script de inventario no captura servicios:
# Verificar que systemctl está disponible
systemctl list-units --type=service --state=running
# Si falla, usar service como alternativa
service --status-all 2>&1 | grep "+"
Reglas de auditoría no se cargan tras reinicio:
systemctl status auditd
ls -la /etc/audit/rules.d/
augenrules --load
systemctl restart auditd
fail2ban bloqueando IPs legítimas:
# Ver IPs actualmente bloqueadas
fail2ban-client status sshd
# Desbloquear una IP específica
fail2ban-client set sshd unbanip 192.168.1.100
# Añadir IP a la lista blanca en jail.local
echo "ignoreip = 127.0.0.1/8 192.168.1.0/24" >> /etc/fail2ban/jail.local
systemctl restart fail2ban
Evaluación de madurez reporta niveles bajos:
# Ejecutar cada sección de implementación faltante
/usr/local/bin/nist-inventory.sh # ID
ufw enable # PR
systemctl enable --now auditd # DE
Conclusión
El Framework de Ciberseguridad del NIST proporciona una estructura completa y adaptable para gestionar el riesgo de seguridad en infraestructura Linux. Implementar los controles de las cinco funciones—Identificar, Proteger, Detectar, Responder y Recuperar—crea una postura de seguridad en capas que reduce el riesgo de brechas y mejora la capacidad de respuesta ante incidentes. Realiza evaluaciones de madurez periódicas para medir el progreso y priorizar las mejoras más urgentes.


