From 9af9f43ee575ba76931ab7d21aa23fa948e98b9e Mon Sep 17 00:00:00 2001 From: Kunal Mehta Date: Wed, 6 Nov 2024 17:16:12 -0500 Subject: [PATCH] Clean out old OSSEC diff and state files These files are never pruned by OSSEC so they tend to accumulate, which can be a big deal for very big binary files like the ones in /boot. A script triggered by a daily timer will now clean up old state and diff files that are more than a year old. Fixes #7325. --- .../common/test_basic_configuration.py | 25 ++++++++++++++ .../system/securedrop-cleanup-ossec.service | 7 ++++ .../system/securedrop-cleanup-ossec.timer | 10 ++++++ .../usr/bin/securedrop-cleanup-ossec.py | 33 +++++++++++++++++++ securedrop/debian/rules | 2 ++ securedrop/debian/securedrop-config.install | 1 + 6 files changed, 78 insertions(+) create mode 100644 securedrop/debian/config/lib/systemd/system/securedrop-cleanup-ossec.service create mode 100644 securedrop/debian/config/lib/systemd/system/securedrop-cleanup-ossec.timer create mode 100755 securedrop/debian/config/usr/bin/securedrop-cleanup-ossec.py diff --git a/molecule/testinfra/common/test_basic_configuration.py b/molecule/testinfra/common/test_basic_configuration.py index 97b9697d11..9ab153c28a 100644 --- a/molecule/testinfra/common/test_basic_configuration.py +++ b/molecule/testinfra/common/test_basic_configuration.py @@ -1,3 +1,5 @@ +import time + import testutils from testinfra.host import Host @@ -21,3 +23,26 @@ def test_system_time(host: Host) -> None: c = host.run("timedatectl show") assert "NTP=yes" in c.stdout assert "NTPSynchronized=yes" in c.stdout + + +def test_ossec_cleanup(host: Host) -> None: + with host.sudo(): + c = host.run("mkdir -p /var/ossec/queue/diff/local/boot/appinfra-test") + assert c.rc == 0 + c = host.run("echo 'test' > /var/ossec/queue/diff/local/boot/appinfra-test/state.123456789") + assert c.rc == 0 + # change the mtime on the file to be 2 years ago + c = host.run( + "touch -d '2 years ago' /var/ossec/queue/diff/local/boot/appinfra-test/state.123456789" + ) + assert c.rc == 0 + c = host.run("systemctl start securedrop-cleanup-ossec") + assert c.rc == 0 + while host.service("securedrop-cleanup-ossec").is_running: + time.sleep(1) + assert not host.file( + "/var/ossec/queue/diff/local/boot/appinfra-test/state.123456789" + ).exists + # cleanup + c = host.run("rm -r /var/ossec/queue/diff/local/boot/appinfra-test") + assert c.rc == 0 diff --git a/securedrop/debian/config/lib/systemd/system/securedrop-cleanup-ossec.service b/securedrop/debian/config/lib/systemd/system/securedrop-cleanup-ossec.service new file mode 100644 index 0000000000..236070148d --- /dev/null +++ b/securedrop/debian/config/lib/systemd/system/securedrop-cleanup-ossec.service @@ -0,0 +1,7 @@ +[Unit] +Description=Cleanup OSSEC diff queue + +[Service] +Type=oneshot +ExecStart=/usr/bin/securedrop-cleanup-ossec.py +User=root diff --git a/securedrop/debian/config/lib/systemd/system/securedrop-cleanup-ossec.timer b/securedrop/debian/config/lib/systemd/system/securedrop-cleanup-ossec.timer new file mode 100644 index 0000000000..33ee35e1de --- /dev/null +++ b/securedrop/debian/config/lib/systemd/system/securedrop-cleanup-ossec.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Cleanup OSSEC diff queue + +[Timer] +OnCalendar=daily +Persistent=true +RandomizedDelaySec=5m + +[Install] +WantedBy=timers.target diff --git a/securedrop/debian/config/usr/bin/securedrop-cleanup-ossec.py b/securedrop/debian/config/usr/bin/securedrop-cleanup-ossec.py new file mode 100755 index 0000000000..6017f6bfd6 --- /dev/null +++ b/securedrop/debian/config/usr/bin/securedrop-cleanup-ossec.py @@ -0,0 +1,33 @@ +#!/usr/bin/python3 +""" +Delete OSSEC diff/state files older than a year + +Runs as root on both app and mon servers +""" + +import os +import re +from datetime import datetime, timedelta + +OSSEC_DIFFS = "/var/ossec/queue/diff/local/" +KEEP_DAYS = 365 +# Match e.g. state.1667271785 +RE_REMOVE = re.compile(r"^(state|diff)\.\d+$") + + +def main() -> None: + cutoff_date = datetime.now() - timedelta(days=KEEP_DAYS) + + for root, dirs, files in os.walk(OSSEC_DIFFS): + for file in files: + if RE_REMOVE.match(file): + file_path = os.path.join(root, file) + modified_time = os.path.getmtime(file_path) + file_modified_date = datetime.fromtimestamp(modified_time) + if file_modified_date < cutoff_date: + os.remove(file_path) + print(f"Deleted file: {file_path} (Last modified: {file_modified_date})") + + +if __name__ == "__main__": + main() diff --git a/securedrop/debian/rules b/securedrop/debian/rules index 1578eaa1ad..57f753447f 100755 --- a/securedrop/debian/rules +++ b/securedrop/debian/rules @@ -84,6 +84,7 @@ override_dh_systemd_enable: dh_systemd_enable --no-enable securedrop-clean-tmp.service dh_systemd_enable --no-enable securedrop-remove-pending-sources.service dh_systemd_enable --no-enable securedrop-remove-packages.service + dh_systemd_enable --no-enable securedrop-cleanup-ossec.service dh_systemd_enable # This is basically the same as the enable stanza above, just whether the @@ -93,4 +94,5 @@ override_dh_systemd_start: dh_systemd_start --no-start securedrop-clean-tmp.service dh_systemd_start --no-start securedrop-remove-pending-sources.service dh_systemd_start --no-start securedrop-remove-packages.service + dh_systemd_start --no-start securedrop-cleanup-ossec.service dh_systemd_start diff --git a/securedrop/debian/securedrop-config.install b/securedrop/debian/securedrop-config.install index 818f3739ed..8f110dd73b 100644 --- a/securedrop/debian/securedrop-config.install +++ b/securedrop/debian/securedrop-config.install @@ -1,3 +1,4 @@ debian/config/etc / debian/config/lib / debian/config/opt / +debian/config/usr /