← All rules
// Hardening (posture)mediumeffective runtime

Log rotation actually runs (logrotate is scheduled)

Verify that logrotate is not merely installed but actually scheduled: either logrotate.timer is active, or /etc/cron.daily/logrotate is executable. A perfect logrotate.conf behind a masked timer rotates nothing. This pavois-native growth-* control audits the mechanism that bounds /var/log, not the free space it happens to have today.

Checked against the resolved running state (e.g. sshd -T, sysctl, systemctl show), catches drop-ins and Includes a file read would miss. Caveat: runtime ≠ persistence; a value correct now may not survive a reboot.

A pass proves✓ running now✓ on disk✓ survives rebootthe qualified verdict →
Debian 12CIS 1.1.0Debian 13CIS 1.0.0FedoraRHEL 10 / Rocky 10 / AlmaLinux 10RHEL 8 / Rocky 8 / AlmaLinux 8CIS 4.0.0RHEL 9 / Rocky 9 / AlmaLinux 9CIS 2.0.0Ubuntu 22.04CIS 3.0.0Ubuntu 24.04CIS 1.0.0Ubuntu 26.04

What Pavois checks

The check interrogates the runtime scheduler state, not a configuration file: systemctl is-active logrotate.timer must return active, or /etc/cron.daily/logrotate must carry the executable bit (the older, cron-driven path still used on some images). Either path proves rotation will actually fire. Checking the mere presence of /etc/logrotate.conf would be a false-negative factory: the package can be installed, the rules impeccable, and the timer disabled or masked.

describe command('systemctl is-active logrotate.timer 2>/dev/null | grep -qx active || test -x /etc/cron.daily/logrotate && echo ok || echo ko') do
  its('stdout.strip') { should eq 'ok' }
end

How to verify it is applied

Confirm the schedule, then that it actually fires:

systemctl is-active logrotate.timer
systemctl list-timers logrotate.timer --all
test -x /etc/cron.daily/logrotate && echo cron-path-ok

logrotate --debug /etc/logrotate.conf performs a dry run and prints which files would rotate, without touching them.

Inspect & investigate

Each run leaves a trace in journalctl -u logrotate.service, and logrotate stamps its own state file (/var/lib/logrotate/status on Debian and Ubuntu, /var/lib/logrotate.status on RHEL): every managed log carries the date of its last rotation. A state file whose timestamps are weeks old is the signature of a rotation that has stopped running, visible long before the disk fills.

Remediation

Pavois runs the logrotate-scheduled step: if a logrotate.timer unit file exists, it is enabled and started immediately (systemctl enable --now logrotate.timer); otherwise, on cron-driven images, /etc/cron.daily/logrotate is made executable. The step is guarded by a not_if that re-tests both paths, so an already-scheduled host is left untouched and confkit harden apply stays idempotent.

Pavois applies this with its own harden engine, the plan below, not a shell script:

commandsystemctl list-unit-files logrotate.timer --no-legend 2>/dev/null | grep -q . && systemctl enable --now logrotate.timer 2>/dev/null; test -f /etc/cron.daily/logrotate && chmod +x /etc/cron.daily/logrotate; true
namelogrotate-scheduled
not_ifsystemctl is-active logrotate.timer 2>/dev/null | grep -qx active || test -x /etc/cron.daily/logrotate
resourceexec
pavois harden plan local

where the target is local, a user@host SSH alias, or a container , Docs

Impact & precautions

Near-zero operational risk: this re-enables a scheduler that ships enabled by default on every supported distribution. The one consequence to anticipate is that logs will now actually rotate: any tool holding an open file descriptor on a log, or tailing it by path, must handle rotation (copytruncate, or a postrotate signal to the daemon). Weigh that against the failure mode this family was born from: a pavois-hardened host that shut itself down six seconds into every boot because a log filesystem it had carved out reached 100%, with every control green.

0