public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/aide] rawhide: Add systemd timer for daily integrity checks and /etc/aide.d/ drop-in directory
@ 2026-06-11  9:49 Patrik Koncity
  0 siblings, 0 replies; only message in thread
From: Patrik Koncity @ 2026-06-11  9:49 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/aide
            Branch : rawhide
            Commit : 2187d5d393d017b590b1945c06abb3555bd67a84
            Author : Patrik Koncity <pkoncity@redhat.com>
            Date   : 2026-06-09T13:36:29+02:00
            Stats  : +138/-19 in 6 file(s)
            URL    : https://src.fedoraproject.org/rpms/aide/c/2187d5d393d017b590b1945c06abb3555bd67a84?branch=rawhide

            Log:
            Add systemd timer for daily integrity checks and /etc/aide.d/ drop-in directory

- Add aide-check.service and aide-check.timer for scheduled daily
  integrity checks with low CPU/IO priority.
- Add /etc/aide.d/ drop-in directory for modular configuration
- Update aide.conf to include /etc/aide.d/*.conf files.
- Update README.quickstart with systemd timer usage instructions

---
diff --git a/README.quickstart b/README.quickstart
index 87adc63..92e42dc 100644
--- a/README.quickstart
+++ b/README.quickstart
@@ -20,21 +20,28 @@
    compared with the AIDE database. Prior to running a check manually,
    ensure that the AIDE binary and database have not been modified
    without your knowledge.
-   
-   Caution! 
-   
-   With the default setup, an AIDE check is not run periodically as a
-   cron job. It cannot be guaranteed that the AIDE binaries, config
-   file and database are intact. It is not recommended that you run
-   automated AIDE checks without verifying AIDE yourself frequently.
-   In addition to that, AIDE does not implement any password or
-   encryption protection for its own files.
-   
-   It is up to you how to put a file integrity checker to good effect
-   and how to set up automated checks if you think it adds a level of
-   safety (e.g. detecting failed/incomplete compromises or unauthorized
-   modification of special files). On a compromised system, the
-   intruder could disable the automated check. Or he could replace the
-   AIDE binary, config file and database easily when they are not
-   located on read-only media. 
+
+6) To schedule daily integrity checks, enable the systemd timer:
+
+   systemctl enable --now aide-check.timer
+
+   View results with: journalctl -u aide-check
+   Check timer status with: systemctl status aide-check.timer
+
+   The timer runs daily with low CPU/IO priority to minimize impact
+   on production workloads. It is disabled by default — only enable
+   it after initializing the database (steps 2-4).
+
+   Caution!
+
+   It cannot be guaranteed that the AIDE binaries, config file and
+   database are intact. It is not recommended that you run automated
+   AIDE checks without verifying AIDE yourself frequently. In addition
+   to that, AIDE does not implement any password or encryption
+   protection for its own files.
+
+   It is up to you how to put a file integrity checker to good effect.
+   On a compromised system, the intruder could disable the automated
+   check. Or he could replace the AIDE binary, config file and database
+   easily when they are not located on read-only media.
 

diff --git a/aide-check.service b/aide-check.service
new file mode 100644
index 0000000..8946759
--- /dev/null
+++ b/aide-check.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=AIDE file integrity check
+Documentation=man:aide(1) man:aide.conf(5)
+
+[Service]
+Type=oneshot
+ExecStart=/usr/sbin/aide --check
+SuccessExitStatus=0 1 2 3 4 5 6 7
+Nice=19
+IOSchedulingClass=idle

diff --git a/aide-check.timer b/aide-check.timer
new file mode 100644
index 0000000..5bbfa1e
--- /dev/null
+++ b/aide-check.timer
@@ -0,0 +1,11 @@
+[Unit]
+Description=Daily AIDE file integrity check
+Documentation=man:aide(1) man:aide.conf(5)
+
+[Timer]
+OnCalendar=daily
+AccuracySec=1h
+Persistent=true
+
+[Install]
+WantedBy=timers.target

diff --git a/aide-include-permission-checks.patch b/aide-include-permission-checks.patch
new file mode 100644
index 0000000..012b640
--- /dev/null
+++ b/aide-include-permission-checks.patch
@@ -0,0 +1,66 @@
+diff --git a/src/conf_eval.c b/src/conf_eval.c
+index 5774ce6..6503709 100644
+--- a/src/conf_eval.c
++++ b/src/conf_eval.c
+@@ -580,9 +580,9 @@ static void include_file(const char* file, bool execute, int include_depth, char
+     }
+ }
+ 
+-void check_permissions(const char* path, struct stat *st, int linenumber, char *filename, char* linebuf) {
++static void check_permissions(const char* path, struct stat *st, const char *directive, int linenumber, char *filename, char* linebuf) {
+     if ((st->st_uid != geteuid() && st->st_uid != 0) || (st->st_mode & 002) != 0 || (st->st_mode & 020) != 0) {
+-        LOG_CONFIG_FORMAT_LINE(LOG_LEVEL_ERROR, "'@@x_include': bad ownership or modes for '%s' (please ensure it is neither group- nor world-writable and owned by the current user or root)", path)
++        LOG_CONFIG_FORMAT_LINE(LOG_LEVEL_ERROR, "'%s': bad ownership or modes for '%s' (please ensure it is neither group- nor world-writable and owned by the current user or root)", directive, path)
+         exit(INVALID_CONFIGURELINE_ERROR);
+     }
+ }
+@@ -611,13 +611,13 @@ static void include_directory(const char* dir, const char* rx, bool execute, cha
+ 
+     struct stat fs;
+ 
+-    if (execute) {
+-        if (stat(dir,&fs) == -1) {
+-            LOG_CONFIG_FORMAT_LINE(LOG_LEVEL_ERROR, "'@@x_include': stat for '%s' failed: %s", dir, strerror(errno))
+-            exit(INVALID_CONFIGURELINE_ERROR);
+-        }
+-        check_permissions(dir, &fs, linenumber, filename, linebuf);
++    /* stat() follows symlinks; we intentionally check the target's ownership
++     * and mode rather than the symlink node itself */
++    if (stat(dir,&fs) == -1) {
++        LOG_CONFIG_FORMAT_LINE(LOG_LEVEL_ERROR, "'%s': stat for '%s' failed: %s", execute?"@@x_include":"@@include", dir, strerror(errno))
++        exit(INVALID_CONFIGURELINE_ERROR);
+     }
++    check_permissions(dir, &fs, execute?"@@x_include":"@@include", linenumber, filename, linebuf);
+ 
+     n = scandir(dir, &namelist, dirfilter, alphasort);
+     if (n == -1) {
+@@ -660,9 +660,8 @@ static void include_directory(const char* dir, const char* rx, bool execute, cha
+                 log_msg(LOG_LEVEL_DEBUG,"%s: skip '%s' (reason: file name does not match regex '%s')", dir, namelist[i]->d_name, rx);
+             } else {
+                 int exec = execute && S_IXUSR&fs.st_mode;
+-                if (exec) {
+-                    check_permissions(filepath, &fs, linenumber, filename, linebuf);
+-                }
++                /* pass directive name (not exec flag) so the error names the directive the user wrote */
++                check_permissions(filepath, &fs, execute?"@@x_include":"@@include", linenumber, filename, linebuf);
+                 log_msg(LOG_LEVEL_CONFIG,"%s: %s '%s'", dir, exec?"execute":"include", namelist[i]->d_name);
+                 include_file(filepath, exec, include_depth, nested_rule_prefix);
+             }
+@@ -701,14 +700,15 @@ static void eval_include_statement(include_statement statement, int include_dept
+     } else {
+     struct stat fs;
+     if (lstat(path,&fs) == -1) {
+-        LOG_CONFIG_FORMAT_LINE(LOG_LEVEL_ERROR, "'@@include': lstat for '%s' failed: %s", path, strerror(errno))
++        LOG_CONFIG_FORMAT_LINE(LOG_LEVEL_ERROR, "'%s': lstat for '%s' failed: %s", statement.execute?"@@x_include":"@@include", path, strerror(errno))
+         exit(INVALID_CONFIGURELINE_ERROR);
+     }
+     if (S_ISREG(fs.st_mode)) {
++        check_permissions(path, &fs, statement.execute?"@@x_include":"@@include", linenumber, filename, linebuf);
+         LOG_CONFIG_FORMAT_LINE_PREFIX(LOG_LEVEL_CONFIG, "include file '%s' (depth: %d)", path, include_depth)
+         include_file(path, statement.execute && S_IXUSR&fs.st_mode, include_depth, rule_prefix);
+     } else {
+-        LOG_CONFIG_FORMAT_LINE(LOG_LEVEL_ERROR, "'@@include': '%s' is not a regular file", path);
++        LOG_CONFIG_FORMAT_LINE(LOG_LEVEL_ERROR, "'%s': '%s' is not a regular file", statement.execute?"@@x_include":"@@include", path);
+         exit(INVALID_CONFIGURELINE_ERROR);
+     }
+     }

diff --git a/aide.conf b/aide.conf
index 56ba1da..cbbf01e 100644
--- a/aide.conf
+++ b/aide.conf
@@ -23,8 +23,8 @@ database_add_metadata=yes
 # Warn about unrestricted rules during config check (default: false)
 config_check_warn_unrestricted_rules=false
 
-# Number of workers for parallel processing (default: 1, can use percentage)
-num_workers=1
+# Number of workers for parallel processing (AIDE default: 1, overridden to 4 here)
+num_workers=4
 
 # Default.
 log_level=warning
@@ -138,6 +138,9 @@ LOG = p+ftype+u+g+n+ANF+ARF+selinux+xattrs
 # but we want to know when the data inside them changes - updated with modern hash
 DATAONLY = ftype+p+l+n+u+g+s+acl+selinux+xattrs+sha256
 
+# Read /etc/aide.d/*.conf files
+@@include /etc/aide.d ^[a-zA-Z0-9_-]+\.conf$
+
 # Next decide what directories/files you want in the database.
 
 /boot   NORMAL

diff --git a/aide.spec b/aide.spec
index 7b1c7a4..4e84d64 100644
--- a/aide.spec
+++ b/aide.spec
@@ -13,6 +13,10 @@ Source2:        gpgkey-aide.gpg
 Source3:        aide.conf
 Source4:        README.quickstart
 Source5:        aide.logrotate
+Source6:        aide-check.service
+Source7:        aide-check.timer
+
+Patch0:         aide-include-permission-checks.patch
 
 BuildRequires:  gcc
 BuildRequires:  make
@@ -27,6 +31,7 @@ BuildRequires:  libattr-devel
 BuildRequires:  e2fsprogs-devel
 BuildRequires:  audit-libs-devel
 BuildRequires:  autoconf automake libtool
+BuildRequires:  systemd-rpm-macros
 # For verifying signatures
 BuildRequires:  gnupg2
 # For being able to run 'make check'
@@ -69,6 +74,11 @@ install -Dpm0644 -t %{buildroot}%{_sysconfdir} %{SOURCE3}
 install -Dpm0644 %{SOURCE5} %{buildroot}%{_sysconfdir}/logrotate.d/aide
 mkdir -p %{buildroot}%{_localstatedir}/log/aide
 mkdir -p -m0700 %{buildroot}%{_localstatedir}/lib/aide
+# Create /etc/aide.d/
+mkdir -p -m0700 %{buildroot}%{_sysconfdir}/aide.d
+# Install systemd timer and service for scheduled integrity checks
+install -Dpm0644 %{SOURCE6} %{buildroot}%{_unitdir}/aide-check.service
+install -Dpm0644 %{SOURCE7} %{buildroot}%{_unitdir}/aide-check.timer
 
 %files
 %license COPYING
@@ -79,8 +89,20 @@ mkdir -p -m0700 %{buildroot}%{_localstatedir}/lib/aide
 %{_mandir}/man5/*.5*
 %config(noreplace) %attr(0600,root,root) %{_sysconfdir}/aide.conf
 %config(noreplace) %{_sysconfdir}/logrotate.d/aide
+%dir %attr(0700,root,root) %{_sysconfdir}/aide.d
 %dir %attr(0700,root,root) %{_localstatedir}/lib/aide
 %dir %attr(0700,root,root) %{_localstatedir}/log/aide
+%{_unitdir}/aide-check.service
+%{_unitdir}/aide-check.timer
+
+%post
+%systemd_post aide-check.timer
+
+%preun
+%systemd_preun aide-check.timer
+
+%postun
+%systemd_postun_with_restart aide-check.timer
 
 %changelog
 %autochangelog

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-06-11  9:49 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-11  9:49 [rpms/aide] rawhide: Add systemd timer for daily integrity checks and /etc/aide.d/ drop-in directory Patrik Koncity

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox