--- title: "How to Audit Linux Activity with auditd on Ubuntu 24.04" description: "Install and configure auditd on Ubuntu 24.04, write persistent rules to track changes to users, sudo, SSH and kernel modules, and search the logs with ausearch." category: "Server Security" language: en source: https://cubepath.com/docs/server-security/auditing-with-auditd-on-linux updated: 2026-09-25 --- # How to Audit Linux Activity with auditd on Ubuntu 24.04 The Linux Audit framework records security-relevant events directly from the kernel: who changed a file, which commands ran with root privileges, when a kernel module was loaded. `auditd` is the user-space daemon that writes those events to disk, and it is the standard answer to questions like "who edited `/etc/sudoers` last night?". In this tutorial you will install auditd on Ubuntu 24.04, configure log retention, write a persistent rule set for the events that matter on a typical server, and search the results with `ausearch` and `aureport`. ## Prerequisites To follow this tutorial, you will need: - A server running Ubuntu 24.04 LTS on x86_64, for example a CubePath VPS, with a non-root user that has `sudo` privileges. - Some free disk space for the audit logs. The configuration in this guide keeps up to 500 MB. The syscall rules in this guide use `arch=b64` and `arch=b32` filters for x86_64. On arm64 servers, drop the `b32` lines and note that some legacy syscalls (for example `unlink` and `rename`) do not exist there; use only their `*at` variants. ## Step 1 - Installing auditd Install the daemon and its tools: ```bash sudo apt update sudo apt install auditd ``` The package enables and starts the service. Check that it is running: ```bash sudo systemctl status auditd ``` ```output ● auditd.service - Security Auditing Service Loaded: loaded (/usr/lib/systemd/system/auditd.service; enabled; preset: enabled) Active: active (running) since Thu 2026-09-25 10:02:11 UTC; 8s ago ``` Then query the kernel side of the audit system: ```bash sudo auditctl -s ``` ```output enabled 1 failure 1 pid 2317 rate_limit 0 backlog_limit 8192 lost 0 backlog 0 ``` `enabled 1` means the kernel is auditing, and `lost 0` means no events have been dropped. You will come back to the `lost` counter in the troubleshooting section. ## Step 2 - Configuring log retention The daemon settings are in `/etc/audit/auditd.conf`. The Ubuntu defaults keep only five files of 8 MB each, which a busy server can fill in a day. Open the file: ```bash sudo nano /etc/audit/auditd.conf ``` Adjust these keys and leave the rest as they are: ```ini max_log_file = 50 num_logs = 10 max_log_file_action = ROTATE space_left = 75 space_left_action = SYSLOG admin_space_left = 50 admin_space_left_action = SUSPEND disk_full_action = SUSPEND ``` With these values auditd keeps ten files of 50 MB in `/var/log/audit/`, rotating the oldest out. The three `*_action` keys decide what happens when the partition runs low (`space_left` and `admin_space_left` are in megabytes): first a warning to syslog, then auditd stops writing until space is freed. `SUSPEND` keeps the server running; `HALT` is only appropriate on systems where running without audit is not allowed. Restart the daemon to apply the changes: ```bash sudo systemctl restart auditd ``` ## Step 3 - Understanding audit rules There are three kinds of rules, all written in the syntax that `auditctl` accepts: - **Control rules** configure the audit system itself, for example `-b 8192` (kernel buffer size) or `-e 2` (lock the configuration). - **File watches** (`-w`) record access to a file or directory. `-p` selects the access type: `r` read, `w` write, `x` execute, `a` attribute change. - **Syscall rules** (`-a always,exit`) record system calls that match a set of filters (`-F`), such as the architecture, the user or the path. Every rule should carry a key (`-k name`), a label that you later use to search the logs. You can add a rule at runtime to try it out. It will be lost at the next restart: ```bash sudo auditctl -w /etc/hosts -p wa -k hosts_change sudo auditctl -l ``` ```output -w /etc/hosts -p wa -k hosts_change ``` Remove all runtime rules again before continuing: ```bash sudo auditctl -D ``` ## Step 4 - Writing a persistent rule set On Ubuntu, persistent rules live in `/etc/audit/rules.d/`. At startup, `augenrules` concatenates every `*.rules` file in that directory in alphabetical order into `/etc/audit/audit.rules` and loads it. The package already installs `audit.rules` there, which clears existing rules (`-D`), sets the buffer size and the failure mode. Create a new file for your rules: ```bash sudo nano /etc/audit/rules.d/50-server.rules ``` Add the following rules: ```text ## Identity: users, groups and passwords -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 ## Privilege configuration -w /etc/sudoers -p wa -k sudoers -w /etc/sudoers.d/ -p wa -k sudoers ## SSH server configuration and authorized keys of root -w /etc/ssh/sshd_config -p wa -k sshd_config -w /etc/ssh/sshd_config.d/ -p wa -k sshd_config -w /root/.ssh/ -p wa -k root_ssh ## Scheduled tasks -w /etc/crontab -p wa -k cron -w /etc/cron.d/ -p wa -k cron -w /var/spool/cron/ -p wa -k cron ## Every command run as root by a logged-in user (via sudo, su or a root shell) -a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -F auid!=unset -k root_exec -a always,exit -F arch=b32 -S execve -F euid=0 -F auid>=1000 -F auid!=unset -k root_exec ## Kernel module loading and unloading -a always,exit -F arch=b64 -S init_module,finit_module,delete_module -k modules -a always,exit -F arch=b32 -S init_module,finit_module,delete_module -k modules ## System time changes -a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -k time_change -a always,exit -F arch=b32 -S adjtimex,settimeofday,clock_settime -k time_change -w /etc/localtime -p wa -k time_change ## Files deleted or renamed by real users (not system services) -a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F auid>=1000 -F auid!=unset -k delete -a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F auid>=1000 -F auid!=unset -k delete ``` A few details are worth understanding: - `auid` is the **audit user ID**: the UID a person logged in with. It stays the same after `sudo` or `su`, which is how auditd knows who was really behind an action run as root. `auid!=unset` excludes processes that were never started from a login, such as system daemons. - The `root_exec` rules record every program executed with root privileges by a person who logged in with a normal account (UID 1000 or higher), including every command typed in a `sudo -i` shell. Commands started by system services are not recorded, which keeps the volume manageable. - Each syscall rule has a `b64` and a `b32` version, because a 64-bit process can also call the 32-bit syscall interface and would otherwise evade the rule. Load the new rules and list them: ```bash sudo augenrules --load sudo auditctl -l ``` ```output -w /etc/passwd -p wa -k identity -w /etc/group -p wa -k identity -w /etc/shadow -p wa -k identity ... -a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -F auid!=-1 -F key=root_exec ``` If `augenrules` prints an error, it names the rule and line that failed. The Ubuntu package also ships ready-made rule sets for compliance frameworks (STIG, PCI DSS, OSPP) in `/usr/share/doc/auditd/examples/rules/`, which you can copy into `/etc/audit/rules.d/` if you need them. ## Step 5 - Testing the rules Trigger a few events. Add a test user, which modifies `/etc/passwd`, `/etc/shadow` and `/etc/group`: ```bash sudo useradd audittest ``` Search the log by key with `ausearch`. The `-i` flag translates numeric UIDs, syscalls and timestamps into readable text: ```bash sudo ausearch -k identity -i --start today ``` ```output ---- type=PROCTITLE msg=audit(09/25/2026 10:31:42.118:412) : proctitle=useradd audittest type=PATH msg=audit(09/25/2026 10:31:42.118:412) : item=1 name=/etc/passwd inode=3159 nametype=CREATE ... type=SYSCALL msg=audit(09/25/2026 10:31:42.118:412) : arch=x86_64 syscall=rename success=yes exit=0 ... auid=your_user uid=root gid=root euid=root ... comm=useradd exe=/usr/sbin/useradd key=identity ``` The `SYSCALL` record shows the important part: the command (`useradd`), the effective user (`root`) and the person who ran it (`auid=your_user`). Now test the `root_exec` rule: ```bash sudo cat /etc/shadow > /dev/null sudo ausearch -k root_exec -i --start recent ``` `--start recent` means the last 10 minutes. You will see `EXECVE` records with the full command lines (`sudo cat /etc/shadow` and `cat /etc/shadow`) and your user as `auid`, even though the command ran as root. Remove the test user when you are done: ```bash sudo userdel audittest ``` ## Step 6 - Searching and reporting `ausearch` filters events and `aureport` summarizes them. These are the searches you will use most: ```bash sudo ausearch -k sudoers -i sudo ausearch -ua your_user -i --start yesterday sudo ausearch -f /etc/ssh/sshd_config -i sudo ausearch -m USER_LOGIN --success no -i ``` They find, in order: changes to sudo configuration, everything done by a given login user since yesterday, every event touching a file, and failed logins. For an overview, start with the summary report: ```bash sudo aureport --summary ``` Then drill down with the specific reports: ```bash sudo aureport -au --failed -i sudo aureport -k --summary sudo aureport -x --summary ``` The first lists failed authentication attempts, the second counts events per rule key (useful to find a noisy rule), and the third shows which executables generated the most events. Both tools accept `--start` and `--end` with values such as `today`, `yesterday`, `this-week`, `recent` or an explicit date and time (`--start 09/24/2026 18:00:00`, in your locale's date format). ## Step 7 - Locking the configuration (optional) An attacker who gains root can simply delete your audit rules. To prevent that, make the rules immutable: once loaded, they cannot be changed until the next reboot. Create a file that sorts last: ```bash sudo nano /etc/audit/rules.d/99-finalize.rules ``` Add a single line: ```text -e 2 ``` Load the rules: ```bash sudo augenrules --load sudo auditctl -s | grep enabled ``` ```output enabled 2 ``` From now on, any `auditctl` change fails with `Operation not permitted`, and changing the rules requires editing the files and rebooting. Enable this only after your rule set is stable. ## Step 8 - Forwarding audit events off the server Local audit logs can be deleted by someone with root access. Sending a copy to another system makes tampering visible. The simplest option is the syslog plugin, which passes every event to rsyslog (and from there to your central log server or SIEM): ```bash sudo nano /etc/audit/plugins.d/syslog.conf ``` Change `active = no` to: ```ini active = yes ``` Restart auditd: ```bash sudo systemctl restart auditd ``` Events now also appear in the journal and in `/var/log/syslog`, tagged `audisp-syslog`. Configure rsyslog to forward them to your log server over TCP or TLS. To send events directly to another auditd server instead, the `audispd-plugins` package provides the `audisp-remote` plugin, documented in `man audisp-remote.conf`. ## Troubleshooting **`auditctl -s` shows a growing `lost` counter.** The kernel buffer overflowed during a burst of events. Raise `-b 8192` in `/etc/audit/rules.d/audit.rules` (for example to `-b 32768`) and look for a noisy rule with `sudo aureport -k --summary`. **`augenrules --load` reports `Error sending add rule data request (Invalid argument)`.** A syscall in the rule does not exist on this architecture (common on arm64) or a field is misspelled. Check the line it reports. **Rules disappear after a reboot.** They were added with `auditctl` only. Put them in a file under `/etc/audit/rules.d/`. **`/var/log/audit/` fills the disk.** Lower `max_log_file` or `num_logs`, and find the rule responsible with `aureport -k --summary`. Watches on busy directories and syscall rules without `auid` filters are the usual cause. **`auditctl` returns `Operation not permitted` for every change.** The configuration is locked with `-e 2`. Remove `99-finalize.rules`, make your changes and reboot. ## Conclusion Your server now records changes to accounts, sudo and SSH configuration, root command execution, kernel modules and time, keeps the logs rotated, and can forward them to a central system. Start small and check the per-key summary regularly to keep the rule set useful rather than noisy. As next steps, forward the events to a central log platform, add watches for your own application configuration files, and review failed authentications with `aureport -au --failed` as part of your routine.