Plan2026/05-decision-seguridad.md

34 KiB

Decision: Capa de seguridad (punto 2)

Contexto

Este servidor fue comprometido con un credential stealer via PAM que opero 4 dias sin ser detectado. Tenemos firewall bien configurado (policy DROP, SSH por IP, bloqueo de mineria) y aun asi entraron. La capa de seguridad debe cubrir lo que el firewall no puede: detectar amenazas que ya estan dentro.

4 subcapas:

  • 2.1 Deteccion de intrusiones y file integrity
  • 2.2 Escaneo de vulnerabilidades
  • 2.3 Gestion de secretos
  • 2.4 Acceso y autenticacion

2.1 Deteccion de intrusiones y file integrity

La pregunta: Wazuh, AIDE, o auditd?

No son excluyentes. Hacen cosas diferentes:

Herramienta Que hace Analogia
auditd Registra eventos del kernel: quien abrio/modifico/creo que fichero, que proceso hizo que syscall La camara de seguridad
AIDE Genera baseline de checksums y alerta si algo cambia La foto del "antes" para comparar
Wazuh HIDS completo: analiza logs + file integrity + rootkit detection + vulnerability detection + compliance + respuesta activa El guardia de seguridad con camaras, alarmas y protocolo

Opcion A: Wazuh (RECOMENDADA)

Que es

Plataforma de seguridad open source (fork de OSSEC). Incluye:

  • HIDS: deteccion de intrusiones basada en host
  • FIM: file integrity monitoring (incluye lo que hace AIDE)
  • Rootkit detection: busca artefactos conocidos de rootkits
  • Log analysis: analiza auth.log, syslog, etc. con reglas de correlacion
  • Vulnerability detection: escanea paquetes instalados contra bases de CVE
  • Active response: puede bloquear IPs, matar procesos, ejecutar acciones automaticas
  • Compliance: reportes CIS, PCI-DSS, GDPR
  • Dashboard: Kibana/OpenSearch integrado, o Grafana via plugin

Que habria detectado en este incidente

Evento Regla Wazuh Tiempo de deteccion
Creacion de /usr/bin/login.sh FIM: fichero nuevo en directorio monitorizado Segundos
Modificacion de /etc/pam.d/common-auth FIM: cambio en fichero critico Segundos
Creacion de /etc/ld.so.preload FIM + rootkit check Segundos
Creacion de /usr/local/sbin/env/ FIM: directorio nuevo en ruta de sistema Segundos
Conexion saliente a 91.208.162.132:10480 Log analysis de firewall + active response Minutos
Exfiltracion de credenciales via curl Log analysis / network anomaly Minutos

Conclusion: el incidente habria durado minutos, no 4 dias.

Arquitectura

                    ┌─────────────────────────────┐
                    │    Wazuh Manager             │
                    │    (servidor central)        │
                    │                              │
                    │  - Recibe eventos de agentes │
                    │  - Evalua reglas             │
                    │  - Genera alertas            │
                    │  - Vulnerability scanner     │
                    │                              │
                    │  Wazuh Dashboard             │
                    │  (o Grafana via plugin)      │
                    └──────────┬──────────────────┘
                               │
              ┌────────────────┼────────────────────┐
              │                │                     │
     ┌────────▼────────┐ ┌────▼──────────┐  ┌──────▼───────┐
     │  Wazuh Agent    │ │  Wazuh Agent  │  │  Wazuh Agent │
     │  (PBS server 1) │ │  (PBS server 2│  │  (PVE node)  │
     │                 │ │              )│  │              │
     │  - FIM          │ │  - FIM       │  │  - FIM       │
     │  - Log analysis │ │  - Log anal. │  │  - Log anal. │
     │  - Rootkit det. │ │  - Rootkit   │  │  - Rootkit   │
     │  - Vuln scan    │ │  - Vuln scan │  │  - Vuln scan │
     └────────────────┘ └──────────────┘  └──────────────┘

Configuracion FIM para PBS/Proxmox

<!-- /var/ossec/etc/ossec.conf (en el agente) -->
<syscheck>
  <!-- Frecuencia de escaneo: cada 5 minutos para criticos -->
  <frequency>300</frequency>

  <!-- FICHEROS CRITICOS - Alerta inmediata en tiempo real -->
  <directories check_all="yes" realtime="yes" report_changes="yes">
    /etc/pam.d
  </directories>
  <directories check_all="yes" realtime="yes" report_changes="yes">
    /etc/ssh
  </directories>
  <directories check_all="yes" realtime="yes">
    /etc/ld.so.preload
  </directories>
  <directories check_all="yes" realtime="yes">
    /root/.ssh/authorized_keys
  </directories>
  <directories check_all="yes" realtime="yes">
    /etc/sudoers,/etc/sudoers.d
  </directories>
  <directories check_all="yes" realtime="yes">
    /etc/cron.d,/etc/crontab
  </directories>
  <directories check_all="yes" realtime="yes">
    /etc/systemd/system
  </directories>

  <!-- BINARIOS DE SISTEMA - Detectar modificaciones/adiciones -->
  <directories check_all="yes" realtime="yes">
    /usr/bin,/usr/sbin,/usr/local/bin,/usr/local/sbin
  </directories>

  <!-- CONFIGURACION PROXMOX/PBS -->
  <directories check_all="yes" realtime="yes">
    /etc/proxmox-backup
  </directories>
  <directories check_all="yes">
    /etc/pve
  </directories>

  <!-- Ignorar ficheros que cambian legitimamente -->
  <ignore>/etc/pve/authkey.pub</ignore>
  <ignore>/etc/pve/authkey.pub.old</ignore>
  <ignore>/etc/pve/priv/authkey.key</ignore>
  <ignore>/etc/proxmox-backup/shadow.json</ignore>
  <ignore type="sregex">/etc/proxmox-backup/.*.cfg</ignore>
  <ignore>/etc/zfs/zpool.cache</ignore>
</syscheck>

<!-- Rootkit detection -->
<rootcheck>
  <rootkit_files>/var/ossec/etc/shared/rootkit_files.txt</rootkit_files>
  <rootkit_trojans>/var/ossec/etc/shared/rootkit_trojans.txt</rootkit_trojans>
  <system_audit>/var/ossec/etc/shared/system_audit_rcl.txt</system_audit>
  <frequency>3600</frequency>
</rootcheck>

Reglas custom para este tipo de ataque

<!-- /var/ossec/etc/rules/local_rules.xml (en el manager) -->
<group name="custom_pbs_security">

  <!-- Detectar pam_exec añadido (el vector exacto de este incidente) -->
  <rule id="100001" level="15">
    <if_sid>550</if_sid>
    <match>pam.d</match>
    <description>Fichero PAM modificado - posible backdoor</description>
  </rule>

  <!-- Detectar ld.so.preload creado o modificado -->
  <rule id="100002" level="15">
    <if_sid>554</if_sid>
    <match>ld.so.preload</match>
    <description>ld.so.preload creado/modificado - posible rootkit</description>
  </rule>

  <!-- Nuevo fichero en /usr/bin que no es de un paquete -->
  <rule id="100003" level="12">
    <if_sid>554</if_sid>
    <match>/usr/bin/|/usr/sbin/</match>
    <description>Nuevo fichero en directorio de sistema</description>
  </rule>

  <!-- Detectar curl a IPs externas desde scripts de sistema -->
  <rule id="100004" level="10">
    <if_sid>530</if_sid>
    <match>curl.*--max-time|nohup.*curl</match>
    <description>Ejecucion sospechosa de curl con nohup</description>
  </rule>

</group>

Integracion con el stack existente

Opcion 1: Wazuh Dashboard (OpenSearch)

  • Dashboard propio de Wazuh con todos los modulos
  • Requiere OpenSearch (fork Elasticsearch) + 4GB RAM extra
  • Mejor experiencia para analisis de seguridad dedicado

Opcion 2: Wazuh + Grafana (via plugin o Loki)

  • Wazuh envia alertas a Loki -> Grafana las muestra junto con metricas y logs
  • No necesita OpenSearch (ahorra 4GB RAM)
  • Un solo panel para todo, pero pierde dashboards especializados de Wazuh

Recomendacion: empezar con Opcion 1 (Wazuh Dashboard completo). La seguridad merece su propio panel especializado. Las alertas criticas se reenvian a Telegram/email igual que el resto.

Recursos

Componente CPU RAM Disco
Wazuh Manager + Dashboard (OpenSearch) 4 vCPU 12 GB 100 GB
Wazuh Agent (por servidor) <0.1 50-100 MB 100 MB

VM dedicada recomendada: no compartir con la VM de monitoring (VictoriaMetrics/Loki/Grafana). Si Wazuh detecta un problema, debe estar en infra separada.

Despliegue

# Manager (VM dedicada)
curl -sO https://packages.wazuh.com/4.9/wazuh-install.sh
bash wazuh-install.sh -a  # instalacion all-in-one

# Agent (en cada servidor, via Ansible)
apt-get install wazuh-agent
# Configurar manager IP y registrar

Opcion B: AIDE + auditd (ligero, sin servidor central)

Cuando tiene sentido

  • Si no quereis/podeis mantener un Wazuh Manager
  • Como complemento a Wazuh (belt and suspenders)
  • Para servidores aislados sin conectividad al manager

AIDE (file integrity)

# Instalar y generar baseline
apt install aide
aide --init
mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db

# Check diario via cron
0 5 * * * /usr/bin/aide --check | mail -s "AIDE $(hostname)" seguridad@empresa.com

# Tras cambios legitimos, regenerar baseline
aide --update

Configuracion para PBS:

# /etc/aide/aide.conf.d/99_pbs_custom.conf
/etc/pam.d Full
/etc/ssh Full
/etc/ld.so.preload Full
/usr/bin Full
/usr/sbin Full
/usr/local/bin Full
/usr/local/sbin Full
/root/.ssh Full
/etc/cron.d Full
/etc/systemd/system Full

auditd (registro de eventos)

# /etc/audit/rules.d/pbs-security.rules

# Monitorizar cambios en PAM
-w /etc/pam.d/ -p wa -k pam_changes

# Monitorizar ld.so.preload
-w /etc/ld.so.preload -p wa -k ld_preload

# Monitorizar SSH config
-w /etc/ssh/ -p wa -k ssh_changes

# Monitorizar authorized_keys
-w /root/.ssh/authorized_keys -p wa -k ssh_keys

# Monitorizar crontabs
-w /etc/crontab -p wa -k cron_changes
-w /etc/cron.d/ -p wa -k cron_changes
-w /var/spool/cron/ -p wa -k cron_changes

# Monitorizar creacion de ficheros en /usr/bin
-w /usr/bin/ -p wa -k system_binaries
-w /usr/sbin/ -p wa -k system_binaries
-w /usr/local/bin/ -p wa -k local_binaries
-w /usr/local/sbin/ -p wa -k local_binaries

# Monitorizar sudoers
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers

# Monitorizar systemd
-w /etc/systemd/system/ -p wa -k systemd_changes

# Monitorizar ejecucion de herramientas sospechosas
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/curl -k suspicious_exec
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/wget -k suspicious_exec
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/base64 -k suspicious_exec

Limitaciones sin Wazuh

  • auditd registra pero no alerta (hay que leer los logs o enviarlos a Loki)
  • AIDE detecta cambios pero solo en el check programado (no real-time)
  • No hay correlacion de eventos entre servidores
  • No hay vulnerability scanning
  • No hay active response

Opcion C: Lynis (auditoria puntual, no monitoring continuo)

Que es

Script de auditoria de seguridad que escanea el sistema y da puntuacion con recomendaciones. No es un agente permanente.

Uso

apt install lynis
lynis audit system

Donde encaja

  • Ejecutar tras el despliegue inicial de cada servidor (baseline)
  • Ejecutar periodicamente (mensual) para verificar drift
  • Generar informe de hardening pendiente
  • No reemplaza ni a Wazuh ni a auditd, es complementario

Comparativa 2.1

Aspecto Wazuh AIDE + auditd Lynis
Deteccion real-time Si (FIM + log analysis) auditd si, AIDE no No (puntual)
File integrity Si (integrado) AIDE (cron) Check puntual
Rootkit detection Si No Basico
Vulnerability scan Si No Basico
Log analysis Si (reglas de correlacion) Hay que leer logs No
Active response Si (bloquear IP, matar proceso) No No
Alertas Si (email, Telegram, webhook) Manual (cron + mail) Informe
Servidor central Si (Manager) No No
RAM por servidor 50-100 MB 10-20 MB Solo durante scan
Complejidad Media-alta Baja Nula

DECISION 2.1 (confirmada)

Wazuh como pilar principal + auditd como complemento en todos los servidores + Lynis como check puntual post-despliegue.

  • Wazuh: deteccion continua, alertas, correlacion, vulnerability scanning
  • auditd: registro granular de quien hizo que (forensics, compliance)
  • Lynis: auditoria de hardening tras cada despliegue y revision trimestral

Visualizacion: Wazuh Dashboard propio (OpenSearch). La seguridad merece su panel especializado con modulos dedicados (FIM, rootkits, vulnerabilidades, compliance). Al no tener experiencia previa en HIDS, los dashboards especializados aceleran el aprendizaje. Alertas criticas se reenvian a Telegram/email igualmente.

Lynis como checklist: se ejecuta en 4 momentos:

  1. Instalacion nueva (baseline)
  2. Post-hardening (verificar que Ansible aplico todo)
  3. Revision periodica trimestral (detectar drift)
  4. Post-incidente (evaluar estado tras limpieza)

Overhead por servidor: 50-100MB RAM del agente Wazuh. Perfectamente asumible en servidores de 32-256GB (pasa completamente desapercibido).

Recursos VM Wazuh: 4 vCPU, 12 GB RAM (8 Manager + 4 Dashboard/OpenSearch), 100 GB disco. VM dedicada separada de monitoring.


2.2 Escaneo de vulnerabilidades

Que necesitamos

Dos tipos de escaneo:

Tipo Que busca Desde donde
Interno (host) Paquetes con CVEs, configuraciones debiles Dentro de cada servidor
Externo (red) Puertos abiertos, servicios expuestos, CVEs accesibles Desde fuera del servidor

Escaneo interno: ya cubierto por Wazuh

Wazuh incluye vulnerability detection que escanea los paquetes instalados contra bases de CVE (NVD, Debian Security). Si hemos desplegado Wazuh, esto ya esta cubierto.

Escaneo externo: OpenVAS/Greenbone

Herramienta Que hace Recursos
OpenVAS/Greenbone Escaner de vulnerabilidades de red. Escanea puertos, servicios, prueba CVEs conocidos. VM dedicada: 4 vCPU, 8 GB RAM, 20 GB disco

Frecuencia: scan semanal o tras cambios significativos. No mantener scaneando continuamente (consume muchos recursos y puede afectar servicios).

Alternativa ligera: Nuclei (escaner basado en templates, mucho mas ligero que OpenVAS). Ideal para servicios web (paneles Proxmox, PBS GUI, PowerDNS Admin).

Escaneo de contenedores: Trivy

Para la VM del DNS y cualquier otra VM con Docker:

# Escanear imagenes en uso
trivy image powerdns/pdns-auth
trivy image mariadb:latest
trivy image traefik:latest

# Escanear docker-compose
trivy config /opt/30-powerdns/docker-compose.yml

# Escanear filesystem de la VM
trivy fs --scanners vuln,misconfig /

Frecuencia: tras cada docker pull o actualizacion de imagenes.

Modelo de responsabilidad: VMs Linux vs Windows

Tipo Quien gestiona Que hacemos nosotros
Hosts Proxmox/PBS Nosotros Wazuh agent + todo el stack de seguridad
VMs Linux Nosotros (mayoria) Wazuh agent + auditd + hardening
VMs Windows El cliente Solo monitoring externo

Para VMs Windows de clientes (IaaS):

  • Monitorizar desde fuera: Uptime Kuma (disponibilidad), trafico anomalo desde el host (mineria, C2, DDoS)
  • NO instalar agentes dentro, NO gestionar parches, NO escanear vulnerabilidades
  • Si la VM "se desmadra", tenemos visibilidad de red/recursos para orientar al cliente

DECISION 2.2 (confirmada)

Herramienta Ambito Frecuencia Prioridad
Wazuh vuln detection Paquetes en hosts + VMs Linux gestionadas Continuo (ya viene con Wazuh) Fase 1 (gratis, ya incluido)
Trivy Imagenes Docker en VMs Tras updates de imagenes Fase 2
Nuclei Servicios web expuestos (PBS:8007, PVE:8006, paneles) Semanal (programado en Semaphore) Fase 2 (mes 2-3)
OpenVAS Escaneo de red completo Mensual Aparcado salvo requisitos de compliance (ISO 27001, PCI-DSS)
VMs Windows Solo monitoring externo (red, disponibilidad) Continuo desde el host Siempre

OpenVAS descartado por ahora: con Wazuh + Nuclei cubrimos el 90%. OpenVAS requiere VM dedicada (4 vCPU, 8GB RAM) y solo aporta valor marginal sin compliance obligatorio.


2.3 Gestion de secretos e identidad

El problema real

En este entorno encontramos:

  • Contraseñas en docker-compose.yml en texto plano (PDNS_API_KEY=secret, MYSQL_ROOT_PASSWORD)
  • Contraseña de PBS en scripts (modificar.sh recibe password como argumento)
  • API tokens en ficheros de configuracion
  • Password de root capturada y enviada al atacante
  • ~50 contraseñas distintas para diferentes servicios, compartidas por chat

Dos estrategias complementarias

No basta con custodiar secretos (guardarlos bien). Tambien hay que reducir la cantidad de secretos (SSO):

Estrategia Que hace Herramienta
Custodiar secretos Guardar 50 contraseñas de forma segura Vaultwarden
Reducir secretos Tener 1 login con MFA que abre todo (SSO) Authentik

Authentik: Identity Provider centralizado

Que es: Identity Provider open source (SSO, SAML, OAuth2, OIDC, LDAP provider). UI moderna e intuitiva.

Por que Authentik y no Keycloak/Authelia:

Aspecto Authentik Keycloak Authelia
UI Moderna, intuitiva Funcional pero anticuada Minima (solo login)
LDAP provider Si (emite LDAP) Si No
Proxy de autenticacion Si (protege apps sin SSO nativo) No nativo Si (es su funcion)
MFA integrado TOTP, WebAuthn, Duo TOTP, WebAuthn TOTP, WebAuthn
Flows personalizables Si (drag & drop) Si (mas complejo) No
Recursos 2 vCPU, 2 GB RAM 2 vCPU, 4 GB RAM 1 vCPU, 512 MB RAM
Comunidad Creciente, muy activa Grande, madura Pequeña

Que servicios se ponen detras de Authentik (SSO):

Servicio Soporte SSO Como
Proxmox VE OpenID Connect (nativo desde PVE 7) Configuracion directa
Proxmox Backup Server OpenID Connect (nativo) Configuracion directa
Grafana OAuth2/OIDC nativo Configuracion directa
Netbox OAuth2/OIDC nativo Plugin SSO
Forgejo OAuth2/OIDC nativo Configuracion directa
Semaphore OIDC nativo Configuracion directa
Wazuh Dashboard SAML/OpenID Configuracion en OpenSearch
Vaultwarden SSO nativo (v1.29+) Configuracion directa
PowerDNS Admin OAuth2 nativo Configuracion directa
n8n OAuth2 nativo Configuracion directa
Uptime Kuma No nativo Authentik proxy delante
phpMyAdmin No nativo Authentik proxy delante

Impacto: un tecnico, una cuenta, un MFA, acceso a todo. Baja de la empresa = desactivar 1 cuenta, no 50.

Evolucion de la gestion de secretos

FASE 0 (actual):
  50 contraseñas distintas → en la cabeza, en un .txt, en Telegram

FASE 1 (dia 1 - Vaultwarden + .env):
  50 contraseñas distintas → custodiadas en Vaultwarden
  Secretos en docker-compose → ficheros .env con chmod 600

FASE 2 (dia 1 - Authentik):
  1 cuenta Authentik con MFA → abre PVE, PBS, Grafana, Netbox,
                                 Forgejo, Semaphore, Wazuh...
  ~10 contraseñas residuales → custodiadas en Vaultwarden
                                (APIs, root de emergencia, clientes)

FASE 3 (mes 6+ - HashiCorp Vault):
  Authentik → humanos
  Vault → maquinas (Ansible, CI/CD, API tokens con rotacion)
  Vaultwarden → secretos residuales del equipo

Orden de despliegue critico

Authentik debe desplegarse ANTES que los demas servicios en el servidor nuevo. Si no, cada servicio nace con contraseña local y hay que reconfigurarlo despues.

Orden correcto:

Dia 1: Forgejo (git) → para versionar todo desde el minuto 0
Dia 1: Authentik → para que todo lo siguiente ya nazca con SSO
Dia 1: Vaultwarden → con SSO de Authentik
Dia 2: Wazuh Manager → con SSO
Dia 2: VictoriaMetrics + Grafana → con SSO
Dia 3: Loki + Alloy
Dia 3: Netbox → con SSO
Dia 4: Semaphore → con SSO
...    Todo nace autenticado contra Authentik

Vaultwarden (gestor de contraseñas para el equipo)

Que es: fork self-hosted de Bitwarden. Gestor de contraseñas para equipos.

Que resuelve:

  • Contraseñas residuales (APIs, root de emergencia, credenciales de clientes)
  • Generacion de contraseñas fuertes
  • Audit log de quien accedio a que secreto
  • Eliminacion de contraseñas en chats/post-its

Despliegue: un contenedor Docker, 256MB RAM, 1GB disco.

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    volumes:
      - ./data:/data
    environment:
      - ADMIN_TOKEN=${ADMIN_TOKEN}
      - SIGNUPS_ALLOWED=false

HashiCorp Vault (secretos para automatizacion) - MES 6+

Cuando implementar: cuando Ansible este en produccion y la automatizacion lo justifique. No antes.

Que resuelve:

  • Secretos en docker-compose.yml → referencia a Vault
  • Passwords en playbooks → Ansible lee de Vault
  • API tokens → rotacion automatica
  • Certificados → PKI interna

DECISION 2.3 (confirmada)

Fase Herramienta Que cubre Esfuerzo
Dia 1 Vaultwarden Custodiar contraseñas del equipo 30 min
Dia 1 Ficheros .env (chmod 600) Sacar secretos de docker-compose 1h
Dia 1 Authentik SSO + MFA centralizado para todos los paneles 1-2 dias
Mes 6+ HashiCorp Vault Secretos para automatizacion (Ansible, CI/CD) 1 semana

Recursos Authentik: 2 vCPU, 2 GB RAM, 20 GB disco (contenedor Docker o VM ligera).


2.4 Acceso y autenticacion

El problema real

  • SSH con password habilitado (cloud-init lo reactivo)
  • Solo clave SSH de david@ansible como acceso
  • Sin MFA
  • Sin registro centralizado de quien accede a que servidor
  • Sin grabacion de sesiones SSH (no hay audit de que hizo cada tecnico)
  • PBS:8007 abierto a internet con autenticacion basica

Paneles web: ya cubierto por Authentik (2.3)

Con Authentik desplegado, todos los paneles web (PVE, PBS, Grafana, Netbox, Forgejo, Wazuh, etc.) tienen SSO + MFA centralizado. No hace falta configurar TOTP por separado en cada panel.

SSH: Bastion host con grabacion de sesiones

Por que bastion y no Teleport

Se evaluo Teleport pero se descarto por:

  • Licencia AGPL con riesgo de features migrando a enterprise (patron HashiCorp)
  • Cliente propietario (tsh): no es SSH estandar, requiere instalar software en cada maquina de tecnico
  • Complejidad adicional para Ansible (requiere configurar proxy SSH especial)

El bastion SSH usa SSH estandar (OpenSSH ProxyJump, disponible desde 2016):

Cliente Soporte ProxyJump (-J)
Linux (OpenSSH) Si, nativo
macOS Terminal / iTerm Si, nativo
Windows 10/11 (OpenSSH) Si, preinstalado
MobaXterm Si
WinSCP Si (transferencia de ficheros)
Ansible Si (ansible_ssh_common_args)
PuTTY No directo (config propia, pero casi nadie lo usa ya)

Como funciona

┌──────────┐     ┌─────────────────────────────┐     ┌──────────────┐
│ Tecnico  │────▶│   BASTION (VM pequeña)       │────▶│ Servidor PBS │
│          │     │                              │     └──────────────┘
│ ssh -J   │     │ - ForceCommand graba sesion  │────▶│ Servidor PVE │
│ bastion  │     │   (script/asciinema)         │     └──────────────┘
│ servidor │     │ - Grabacion → Loki           │────▶│ Servidor DNS │
│          │     │ - Audit log completo         │     └──────────────┘
└──────────┘     │ - Solo IP permitida en       │
                 │   firewalls de servidores     │
                 └─────────────────────────────┘

Los servidores destino solo aceptan SSH desde el bastion:

# Firewall de cada servidor de produccion (via Ansible)
iptables -A INPUT -p tcp --dport 22 -s IP_BASTION -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP

No hay forma de saltarse el bastion.

Configuracion del tecnico (una sola vez)

# ~/.ssh/config del tecnico
Host bastion
    HostName bastion.empresa.local
    User david
    IdentityFile ~/.ssh/id_ed25519

Host *.infra
    ProxyJump bastion
    User root
    IdentityFile ~/.ssh/id_ed25519

Uso diario (nada cambia):

# SSH normal, transparente, el tecnico ni nota el bastion:
ssh servidor-pbs.infra
ssh servidor-pve.infra
scp fichero.tar.gz servidor-pbs.infra:/tmp/

# Ansible tambien funciona sin cambios:
ansible all -m ping
ansible-playbook -i inventory/netbox.yml playbooks/hardening.yml

Grabacion de sesiones

El bastion usa ForceCommand en sshd_config para grabar cada sesion con script o asciinema:

  • Cada sesion se guarda con: fecha, usuario, servidor destino, duracion
  • Se puede reproducir con scriptreplay o asciinema play
  • Los logs van a Loki para busqueda centralizada
  • No es un video bonito como Teleport, pero es texto completo con replay y timing

Recursos

VM bastion: 1 vCPU, 1 GB RAM, 20 GB disco. Minima.

Hardening SSH (Ansible playbook, dia 1)

Cada servidor nuevo nace con este hardening aplicado automaticamente:

# Hardening SSH base
- PasswordAuthentication: "no"
- KbdInteractiveAuthentication: "no"
- PermitRootLogin: "prohibit-password"  # solo clave
- MaxAuthTries: 3
- LoginGraceTime: 30
- AllowUsers: "root david"  # solo usuarios conocidos
# Neutralizar cloud-init SSH override
- /etc/cloud/cloud.cfg.d/99-ssh-hardening.cfg: "ssh_pwauth: false"
# Firewall: SSH solo desde bastion
- iptables: -A INPUT -p tcp --dport 22 -s IP_BASTION -j ACCEPT
# Fail2ban
- Instalar y configurar con ban de 1h tras 5 intentos

Fail2ban (dia 1)

# /etc/fail2ban/jail.d/custom.conf
[sshd]
enabled = true
port = ssh
filter = sshd
maxretry = 5
findtime = 600
bantime = 3600
action = %(action_mwl)s

[proxmox]
enabled = true
port = 8006
filter = proxmox
maxretry = 5
bantime = 3600

CrowdSec (semana 2)

Que es: IPS colaborativo open source. Analiza logs, detecta ataques, y comparte IPs maliciosas con la comunidad.

Diferencia con Fail2ban:

  • Fail2ban: reactivo, local, solo tu ves tus ataques
  • CrowdSec: proactivo, colaborativo, bloqueas IPs que atacan a otros antes de que te ataquen a ti

Complementa a Fail2ban, no lo reemplaza.

curl -s https://install.crowdsec.net | bash
cscli collections install crowdsecurity/sshd
cscli collections install crowdsecurity/linux

Flujo de acceso completo para un tecnico

Tecnico quiere acceder a:

  Panel PVE/PBS/Grafana/Netbox/Wazuh/Forgejo:
    → Authentik SSO → MFA → acceso
    → 1 cuenta, 1 password, 1 TOTP

  SSH a un servidor:
    → ssh servidor.infra (transparente, pasa por bastion)
    → Clave SSH (sin password)
    → Bastion graba toda la sesion
    → Fail2ban + CrowdSec protegen
    → auditd registra todo dentro del servidor
    → Wazuh alerta si algo raro

  Secreto de un cliente:
    → Vaultwarden (SSO via Authentik) → buscar → copiar
    → Audit log de quien accedio

DECISION 2.4 (confirmada)

Fase Accion Herramienta
Dia 1 SSO + MFA para todos los paneles web Authentik
Dia 1 Bastion SSH con grabacion de sesiones VM bastion + asciinema
Dia 1 Hardening SSH en cada servidor nuevo Ansible playbook
Dia 1 Fail2ban en cada servidor nuevo Ansible playbook
Cada servidor nuevo Firewall: SSH solo desde bastion Ansible playbook
Semana 2 CrowdSec en servidores expuestos Ansible playbook

Resumen Capa 2 completa (DECISIONES FINALES)

┌─────────────────────────────────────────────────────┐
│                  CAPA 2: SEGURIDAD                   │
├─────────────────────────────────────────────────────┤
│                                                      │
│  2.1 DETECCION                                       │
│  ┌───────────────────────────────────┐               │
│  │  Wazuh Manager + Dashboard        │               │
│  │  (VM dedicada, 4vCPU, 12GB RAM)   │               │
│  │  - FIM (file integrity real-time) │               │
│  │  - Log analysis + correlacion     │               │
│  │  - Rootkit detection              │               │
│  │  - Vulnerability detection        │               │
│  │  - Active response                │               │
│  │  + auditd en cada servidor        │               │
│  │  + Lynis post-despliegue/trimest. │               │
│  └───────────────────────────────────┘               │
│                                                      │
│  2.2 VULNERABILIDADES                                │
│  ┌───────────────────────────────────┐               │
│  │  Wazuh vuln detection (continuo)  │               │
│  │  Trivy (contenedores Docker)      │               │
│  │  Nuclei (servicios web, semanal)  │               │
│  │  OpenVAS: DESCARTADO (salvo       │               │
│  │           compliance futuro)      │               │
│  │  VMs Windows: solo monitoring     │               │
│  │               externo (red/disp.) │               │
│  └───────────────────────────────────┘               │
│                                                      │
│  2.3 SECRETOS E IDENTIDAD                            │
│  ┌───────────────────────────────────┐               │
│  │  Authentik (SSO + MFA, dia 1)     │               │
│  │  - PVE, PBS, Grafana, Netbox,     │               │
│  │    Forgejo, Semaphore, Wazuh,     │               │
│  │    Vaultwarden, PowerDNS Admin    │               │
│  │  Vaultwarden (secretos residuales)│               │
│  │  .env con permisos 600 (interim)  │               │
│  │  HashiCorp Vault (mes 6+)         │               │
│  └───────────────────────────────────┘               │
│                                                      │
│  2.4 ACCESO                                          │
│  ┌───────────────────────────────────┐               │
│  │  Bastion SSH con grabacion        │               │
│  │  (SSH estandar, ProxyJump -J)     │               │
│  │  Hardening SSH (Ansible, dia 1)   │               │
│  │  Fail2ban (dia 1)                 │               │
│  │  CrowdSec (semana 2)             │               │
│  │  Teleport: DESCARTADO             │               │
│  │  (AGPL, cliente propietario)      │               │
│  └───────────────────────────────────┘               │
│                                                      │
└─────────────────────────────────────────────────────┘

Recursos Capa 2:
- VM Wazuh: 4 vCPU, 12 GB RAM, 100 GB disco
- VM Bastion: 1 vCPU, 1 GB RAM, 20 GB disco
- Authentik: 2 vCPU, 2 GB RAM, 20 GB disco (contenedor)
- Vaultwarden: contenedor Docker, 256 MB RAM
- Wazuh agent por servidor: 50-100 MB RAM
- CrowdSec por servidor: ~50 MB RAM
- Fail2ban por servidor: ~30 MB RAM
- auditd: ya instalado, 0 extra

Prioridades de despliegue Capa 2

Contexto: se monta un servidor nuevo desde cero. La infra existente esta cerrada y se migrara progresivamente. Cada servicio nuevo nace ya con SSO, monitoring y seguridad desde el minuto 0.

Prioridad Que Esfuerzo Impacto
Dia 1 Authentik (SSO + MFA) 1-2h Todo lo que se despliegue despues ya nace con SSO
Dia 1 Vaultwarden (con SSO) 30min Secretos custodiados desde el dia 1
Dia 1 Bastion SSH + grabacion 2h Toda sesion SSH queda registrada
Dia 1 Hardening SSH + Fail2ban (Ansible) 2h Cierra la puerta principal
Semana 1 Wazuh Manager + Dashboard (con SSO) 1 dia Deteccion de intrusiones activa
Semana 1 Wazuh agents en servidores criticos 2h FIM + rootkit detection
Semana 2 auditd en todos los servidores (Ansible) 2h Registro forense completo
Semana 2 CrowdSec en servidores con puertos publicos 2h Inteligencia de amenazas colaborativa
Mes 1 Wazuh agents en todos los servidores 1 dia Cobertura completa
Mes 1 Lynis baseline en todos los servidores 2h Hardening score por servidor
Mes 2 Trivy en VMs con Docker 2h Vulnerabilidades en contenedores
Mes 2-3 Nuclei scans semanales 2h Vulnerabilidades en servicios web
Mes 6+ HashiCorp Vault 1 semana Secretos automatizados