Los logs de auditoría registran quién hizo qué en un servidor: cambios en usuarios y contraseñas, uso de sudo, modificaciones de configuración críticas. Normas como PCI DSS, ISO 27001 o SOC 2 exigen conservarlos durante un periodo mínimo y demostrar que no se han alterado. En este tutorial configurarás auditd en Ubuntu 24.04 con un conjunto de reglas útil, ajustarás la rotación local y crearás un archivado diario a un bucket S3 con Object Lock, que impide borrar o modificar los archivos durante el periodo de retención. También aprenderás a buscar eventos en los logs locales y archivados.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con un usuario no root con privilegios
sudo. - Un bucket S3 (en AWS o en un proveedor compatible con S3 que soporte Object Lock) y unas credenciales de acceso con permiso para subir objetos a él. El paso 5 muestra cómo crear el bucket en AWS.
- Unos cientos de MB libres en
/varpara los logs locales. El volumen depende de las reglas y de la actividad del servidor.
Paso 1: Instalar auditd
Instala el demonio de auditoría y sus plugins:
sudo apt update
sudo apt install auditd audispd-plugins
El servicio queda activo al terminar la instalación. Compruébalo:
sudo systemctl status auditd --no-pager
sudo auditctl -s
enabled 1
failure 1
pid 1234
rate_limit 0
backlog_limit 8192
lost 0
backlog 0
...
enabled 1 indica que la auditoría del kernel está activa. Los eventos se escriben en /var/log/audit/audit.log.
Paso 2: Añadir reglas de auditoría
Sin reglas, auditd solo registra eventos básicos como inicios de sesión. Las reglas se guardan en archivos .rules dentro de /etc/audit/rules.d/ y augenrules las combina al cargarlas. Crea un archivo de reglas:
sudo nano /etc/audit/rules.d/50-cumplimiento.rules
Añade estas reglas, basadas en las recomendaciones de CIS:
## Cambios en usuarios, grupos y contraseñas
-w /etc/passwd -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/gshadow -p wa -k identity
-w /etc/security/opasswd -p wa -k identity
## Cambios en la configuración de sudo
-w /etc/sudoers -p wa -k scope
-w /etc/sudoers.d/ -p wa -k scope
## Configuración de SSH
-w /etc/ssh/sshd_config -p wa -k sshd
-w /etc/ssh/sshd_config.d/ -p wa -k sshd
## Cambios de hora del sistema
-a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -k time-change
-w /etc/localtime -p wa -k time-change
## Uso de comandos privilegiados por usuarios reales
-a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -k privileged
-a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -k privileged
-a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -k privileged
## Carga y descarga de módulos del kernel
-a always,exit -F arch=b64 -S init_module,finit_module,delete_module -k modules
## Accesos denegados a archivos
-a always,exit -F arch=b64 -S open,openat,truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access
-a always,exit -F arch=b64 -S open,openat,truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access
Cada regla tiene una clave (-k) que después sirve para buscar sus eventos. Las reglas -w vigilan archivos (w = escritura, a = cambio de atributos), y las -a always,exit registran llamadas al sistema. auid es el ID del usuario que inició la sesión, que se conserva aunque luego use sudo; auid!=unset excluye procesos del sistema que nunca iniciaron sesión.
Carga las reglas y lístalas:
sudo augenrules --load
sudo auditctl -l
-w /etc/passwd -p wa -k identity
-w /etc/group -p wa -k identity
...
-a always,exit -F arch=b64 -S open,truncate,ftruncate,openat -F exit=-EACCES -F auid>=1000 -F auid!=-1 -F key=access
Comprueba que funcionan creando y borrando un usuario de prueba:
sudo useradd auditprueba
sudo userdel auditprueba
sudo ausearch -k identity -i --start recent | tail -n 5
Deberías ver eventos SYSCALL con comm=useradd y comm=userdel, y tu usuario en el campo auid.
Paso 3: Ajustar el almacenamiento y la rotación local
auditd rota sus propios logs según /etc/audit/auditd.conf. No uses logrotate sobre /var/log/audit/audit.log: auditd no se enteraría del cambio de archivo y podría perder eventos.
Abre el archivo de configuración:
sudo nano /etc/audit/auditd.conf
Localiza y ajusta estas claves (el resto déjalas como están):
log_group = adm
max_log_file = 100
num_logs = 10
max_log_file_action = ROTATE
space_left = 500
space_left_action = SYSLOG
admin_space_left = 100
admin_space_left_action = SUSPEND
disk_full_action = SUSPEND
Qué controla cada una:
max_log_filees el tamaño máximo de cada archivo en MB; al alcanzarlo,ROTATElo renombra aaudit.log.1y conserva hastanum_logsarchivos (1 GB en total con estos valores).space_leftyadmin_space_leftson umbrales de espacio libre en MB en la partición de logs. Al bajar del primero se envía un aviso a syslog; al bajar del segundo auditd deja de escribir (SUSPEND) para no llenar el disco.log_group = admpermite a los administradores del grupoadmleer los logs sinsudo.
Notaalgunas normas exigen detener el sistema antes que perder eventos de auditoría (
admin_space_left_action = HALT). Es una decisión de cumplimiento, no técnica: valora si prefieres que el servidor se pare o que siga funcionando sin auditoría.
Pide a auditd que relea su configuración enviándole la señal HUP, sin detener la auditoría:
sudo kill -HUP "$(pidof auditd)"
sudo grep DAEMON_CONFIG /var/log/audit/audit.log | tail -n 1
La línea mostrada es el último evento DAEMON_CONFIG y debe incluir res=success. Si ves res=failed, revisa la sintaxis del archivo.
Para forzar una rotación manual en cualquier momento, envía la señal USR1 al demonio:
sudo kill -USR1 "$(pidof auditd)"
ls -l /var/log/audit/
-rw-r----- 1 root adm 1204 Sep 25 10:20 audit.log
-rw-r----- 1 root adm 482317 Sep 25 10:20 audit.log.1
Paso 4: Instalar AWS CLI y configurar las credenciales
Ubuntu 24.04 no incluye AWS CLI en sus repositorios. Instala la versión 2 con el instalador oficial:
sudo apt install unzip
curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o awscliv2.zip
unzip -q awscliv2.zip
sudo ./aws/install
aws --version
aws-cli/2.x.x Python/3.x.x Linux/6.8.0-xx-generic exe/x86_64.ubuntu.24
En servidores arm64 usa awscli-exe-linux-aarch64.zip. El archivado se ejecutará como root, así que configura las credenciales para root:
sudo aws configure
Introduce la clave de acceso, la clave secreta y la región (por ejemplo eu-west-1). Usa unas credenciales dedicadas cuyo único permiso sea s3:PutObject sobre el bucket de auditoría: si el servidor se ve comprometido, no deben servir para borrar el histórico.
Si usas un proveedor compatible con S3 distinto de AWS, anota la URL de su endpoint: la usarás en el paso 6.
Paso 5: Crear un bucket con Object Lock
Object Lock aplica un modelo WORM (escribir una vez, leer muchas): mientras dure la retención, nadie puede borrar ni sobrescribir los objetos. Solo se puede activar al crear el bucket. Si ya tienes un bucket con Object Lock, salta al paso 6.
Crea el bucket en AWS, sustituyendo your_audit_bucket por un nombre único. En regiones distintas de us-east-1 añade --create-bucket-configuration LocationConstraint=<región>:
aws s3api create-bucket \
--bucket your_audit_bucket \
--region us-east-1 \
--object-lock-enabled-for-bucket
Define una retención por defecto para todos los objetos nuevos. PCI DSS exige conservar al menos 12 meses de logs de auditoría; ajusta los días a la norma que te aplique:
aws s3api put-object-lock-configuration \
--bucket your_audit_bucket \
--object-lock-configuration '{"ObjectLockEnabled":"Enabled","Rule":{"DefaultRetention":{"Mode":"GOVERNANCE","Days":365}}}'
Comprueba la configuración:
aws s3api get-object-lock-configuration --bucket your_audit_bucket
Advertenciaen modo
GOVERNANCE, un usuario con el permisos3:BypassGovernanceRetentiontodavía puede borrar objetos, lo que es útil mientras pruebas. En modoCOMPLIANCEnadie puede borrarlos antes de que venza la retención, ni siquiera la cuenta raíz de AWS. Cambia aCOMPLIANCEsolo cuando el proceso esté validado.
Paso 6: Crear el script de archivado diario
El script rota el log de auditoría, comprime el archivo recién rotado con un nombre que incluye servidor y fecha, calcula su suma SHA-256, sube ambos al bucket y borra las copias locales de más de 30 días.
Primero crea un archivo de configuración con el nombre del bucket:
sudo nano /etc/default/audit-archive
AUDIT_BUCKET=your_audit_bucket
# Solo para proveedores compatibles con S3 distintos de AWS:
# AWS_ENDPOINT_URL=https://s3.your_provider.example
Crea el script:
sudo nano /usr/local/sbin/audit-archive
#!/usr/bin/env bash
# Rota el log de auditd y archiva el archivo rotado en S3 con su suma SHA-256.
set -euo pipefail
: "${AUDIT_BUCKET:?AUDIT_BUCKET no está definido}"
LOG_DIR=/var/log/audit
ARCHIVE_DIR=/var/lib/audit-archive
LOCAL_DAYS=30
host="$(hostname -s)"
stamp="$(date -u +%Y%m%dT%H%M%SZ)"
name="${host}-audit-${stamp}.log.gz"
mkdir -p "$ARCHIVE_DIR"
chmod 700 "$ARCHIVE_DIR"
# Pedir a auditd que rote y esperar a que aparezca el archivo rotado
kill -USR1 "$(pidof auditd)"
sleep 5
gzip -c "${LOG_DIR}/audit.log.1" > "${ARCHIVE_DIR}/${name}"
(cd "$ARCHIVE_DIR" && sha256sum "$name" > "${name}.sha256")
dest="s3://${AUDIT_BUCKET}/${host}/$(date -u +%Y/%m)/"
aws s3 cp --only-show-errors "${ARCHIVE_DIR}/${name}" "$dest"
aws s3 cp --only-show-errors "${ARCHIVE_DIR}/${name}.sha256" "$dest"
find "$ARCHIVE_DIR" -type f -mtime "+${LOCAL_DAYS}" -delete
echo "Archivado ${name} en ${dest}"
Hazlo ejecutable solo para root y pruébalo a mano, cargando la configuración como hará systemd:
sudo chmod 700 /usr/local/sbin/audit-archive
sudo bash -c 'set -a; . /etc/default/audit-archive; set +a; /usr/local/sbin/audit-archive'
Archivado web01-audit-20260925T103000Z.log.gz en s3://your_audit_bucket/web01/2026/09/
Comprueba que el objeto está en el bucket y tiene retención:
sudo aws s3 ls s3://your_audit_bucket/web01/2026/09/
sudo aws s3api get-object-retention --bucket your_audit_bucket --key web01/2026/09/web01-audit-20260925T103000Z.log.gz
{
"Retention": {
"Mode": "GOVERNANCE",
"RetainUntilDate": "2027-09-25T10:30:00.000Z"
}
}
Notaauditd también rota por tamaño al llegar a
max_log_file. Si un servidor genera más de 100 MB de auditoría al día, algún archivo rotado podría no archivarse. Aumentamax_log_fileo programa el archivado con más frecuencia.
Paso 7: Programar el archivado con un timer de systemd
Crea el servicio:
sudo nano /etc/systemd/system/audit-archive.service
[Unit]
Description=Archivar logs de auditd en S3
After=network-online.target auditd.service
Wants=network-online.target
[Service]
Type=oneshot
EnvironmentFile=/etc/default/audit-archive
ExecStart=/usr/local/sbin/audit-archive
Crea el timer, que lo ejecuta cada día a las 00:05:
sudo nano /etc/systemd/system/audit-archive.timer
[Unit]
Description=Archivado diario de logs de auditd
[Timer]
OnCalendar=*-*-* 00:05:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
Persistent=true hace que, si el servidor estaba apagado a esa hora, el archivado se ejecute al arrancar. Activa el timer y comprueba la próxima ejecución:
sudo systemctl daemon-reload
sudo systemctl enable --now audit-archive.timer
systemctl list-timers audit-archive.timer
NEXT LEFT LAST PASSED UNIT ACTIVATES
Fri 2026-09-26 00:07:12 UTC 13h left - - audit-archive.timer audit-archive.service
Tras la primera ejecución automática, revisa el resultado con sudo journalctl -u audit-archive.service -n 20.
Paso 8: Verificar la integridad de un archivo archivado
Para demostrar que un log no se ha modificado, descárgalo junto con su suma y compruébala:
mkdir -p ~/verificacion && cd ~/verificacion
sudo aws s3 cp s3://your_audit_bucket/web01/2026/09/web01-audit-20260925T103000Z.log.gz .
sudo aws s3 cp s3://your_audit_bucket/web01/2026/09/web01-audit-20260925T103000Z.log.gz.sha256 .
sha256sum -c web01-audit-20260925T103000Z.log.gz.sha256
web01-audit-20260925T103000Z.log.gz: OK
La suma protege frente a corrupción, y Object Lock frente a borrados y sobrescrituras: juntos cubren el requisito de integridad de la mayoría de auditorías.
Paso 9: Buscar eventos en los logs
ausearch busca en los logs de /var/log/audit/ y -i traduce IDs numéricos a nombres. Algunos ejemplos útiles:
sudo ausearch -k privileged -i --start today
sudo ausearch -k identity -i --start this-week
sudo ausearch -ua 1000 -i --start yesterday
aureport genera resúmenes. Por ejemplo, intentos de autenticación y eventos por clave de regla:
sudo aureport -au --start today
sudo aureport -k --summary
Key Summary Report
===========================
total key
===========================
412 access
37 privileged
6 identity
Para buscar en un archivo archivado, descomprímelo y pásalo a ausearch con -if:
gunzip -k web01-audit-20260925T103000Z.log.gz
sudo ausearch -if web01-audit-20260925T103000Z.log -k privileged -i
Paso 10 (opcional): Hacer las reglas inmutables
Un atacante con acceso root podría desactivar las reglas con auditctl -D antes de actuar. Para evitarlo, añade como última regla -e 2, que bloquea la configuración hasta el siguiente reinicio:
sudo nano /etc/audit/rules.d/99-finalize.rules
-e 2
Carga las reglas y comprueba el estado:
sudo augenrules --load
sudo auditctl -s | head -n 1
enabled 2
Importantecon
enabled 2, cualquier cambio en las reglas requiere reiniciar el servidor. Activa este paso solo cuando las reglas estén estabilizadas.
Solución de problemas
ausearch no encuentra eventos de una clave. Comprueba con sudo auditctl -l que la regla está cargada. Si editaste los archivos de rules.d pero no ejecutaste augenrules --load, las reglas nuevas no están activas.
El log crece demasiado deprisa. Averigua qué regla genera más eventos con sudo aureport -k --summary. La regla access suele ser la más ruidosa en servidores con aplicaciones que prueban rutas sin permiso; elimínala o limítala a directorios concretos con -F dir=.
El archivado falla con AccessDenied o InvalidRequest. Revisa sudo journalctl -u audit-archive.service. AccessDenied indica que las credenciales no tienen s3:PutObject sobre el bucket. En proveedores compatibles con S3, un InvalidRequest al subir a un bucket con Object Lock suele deberse a que falta AWS_ENDPOINT_URL o a que el proveedor no soporta Object Lock.
gzip: /var/log/audit/audit.log.1: No such file or directory. auditd no rotó a tiempo o max_log_file_action no es ROTATE. Revisa auditd.conf y aumenta el sleep del script si el disco es lento.
Conclusión
Has configurado auditd con reglas orientadas a cumplimiento, una rotación local que no pierde eventos y un archivado diario a S3 con Object Lock y sumas SHA-256 que protege el histórico frente a borrados y alteraciones. Como siguientes pasos puedes añadir una regla de ciclo de vida en el bucket para mover los objetos antiguos a una clase de almacenamiento más barata, enviar los eventos en tiempo real a un SIEM con un plugin de audispd-plugins como au-remote, o revisar periódicamente los informes de aureport en busca de actividad inesperada.
