To log executed Linux commands for auditing purposes, the most robust method is configuring the
auditd service with specific rules that track system calls like
execve. This approach captures every command execution across the system, storing details in
/var/log/audit/audit.log without relying on shell-specific variables that might be bypassed. By defining a rule that filters on executable permissions and assigns a key, you ensure that security teams can easily query these events using standard audit tools.
Configuring Audit Rules for Command Execution
The primary mechanism for tracking command execution on modern Linux distributions is the Linux Audit Framework. Unlike shell wrappers which only catch interactive sessions,
auditd operates at the kernel level, ensuring that even non-interactive scripts or privileged commands are recorded. You must create a custom rule file to persist your configuration across reboots.
Create a new file in the
/etc/audit/rules.d/ directory. A common convention is to name this file
command-execution.rules. Inside this file, you will define the rule that tells the kernel what to watch. The syntax requires specifying the architecture, the system call to monitor, and a key for filtering later.
-a always,exit -F arch=b64 -S execve -k command_execution
-a always,exit -F arch=b32 -S execve -k command_execution
This configuration does two critical things. First, it targets the
execve system call, which is used by all user-space programs to execute. Second, it applies the
-k command_execution flag correctly. The
-k flag attaches a symbolic key to the audit record, allowing you to search for these specific events efficiently later. Without this key, you would have to parse through thousands of unrelated system calls to find command executions.
After creating the file, you must reload the audit rules so they take effect immediately. Use the following command to apply the changes:
augenrules --load
If you encounter permission errors, ensure you are running the command as root. You can verify that the rule is active by checking the current loaded rules:
auditctl -l | grep command_execution
You should see both the 64-bit and 32-bit rules listed if the setup was successful.
Verifying Logs and Querying Events
Once the rules are active, any command executed by any user on the system will generate an audit event. These logs are stored in
/var/log/audit/audit.log. To view recent command executions, you can use the
ausearch tool, which is designed specifically for querying audit data.
To see all commands executed since the last boot, run:
ausearch -k command_execution
This output will include the timestamp, the user ID (UID), the process ID (PID), and the full path of the executable that was run. For a more concise view, you can filter for specific users or commands. For example, to see all commands executed by the root user:
ausearch -k command_execution -ui 0
The
-ui flag specifies the User ID. Using
0 targets the root account. You can also combine this with other filters, such as searching for a specific command name using the
-fa flag to filter by filename.
It is important to note that
auditd does not log the arguments passed to the command by default due to performance and security concerns regarding sensitive data like passwords. If you need argument logging, you must enable it via kernel parameters or use additional monitoring tools, but this increases disk I/O significantly.
Managing Log Rotation and Storage
Continuous logging of every command can generate substantial volume, especially on busy servers. The
auditd daemon includes built-in log rotation mechanisms, but you should configure them appropriately to prevent disk space exhaustion.
Edit the
/etc/audit/auditd.conf file to adjust settings. Key parameters include:
- max_log_file: Defines the maximum size of a single log file before rotation.
- max_log_file_action: Determines what happens when the limit is reached. Common values are
rotate, keep_logs, or syslog.
- num_logs: Sets the number of rotated log files to keep.
For example, setting
max_log_file = 50 and
num_logs = 5 ensures that you retain approximately 250MB of historical audit data. Adjust these values based on your storage capacity and compliance requirements.
If you need to forward these logs to a remote server for centralized analysis, consider integrating with existing logging infrastructure. While this article focuses on local logging, understanding how to handle remote forwarding is crucial for enterprise environments. For insights on managing remote log streams, you may want to review
How to Forward /var/log/yum.log to Remote Logging Server using rsyslog.conf?. This provides context on handling high-volume log streams securely.
Frequently Asked Questions
Does auditd log commands run by background services?
Yes, because
auditd monitors the
execve system call at the kernel level, it captures command executions regardless of whether they are initiated interactively or by background daemons. Any process that forks and executes a new binary will trigger the rule.
Can I log the arguments passed to the command?
By default,
auditd does not log command arguments to protect sensitive information like passwords and to reduce disk usage. Enabling argument logging requires modifying kernel parameters or using specialized tools, which can significantly impact system performance.
What happens if the audit log disk fills up?
Depending on your configuration in
auditd.conf, the system can either rotate old logs, stop logging entirely, or send alerts via syslog. It is critical to set appropriate thresholds to prevent the audit daemon from halting operations, which could leave the system unmonitored.
Is auditd compatible with containers?
Audit rules apply to the host kernel, so they will capture commands executed within containers if those containers share the host's namespace. However, isolated containers with their own namespaces may not reflect host-level audit rules unless specifically configured to propagate audit events.
How do I troubleshoot missing audit logs?
First, verify that the
auditd service is running with
systemctl status auditd. Then, check the permissions on the log directory and ensure your rule file was loaded successfully using
augenrules --load. If issues persist, check the system journal for audit-related errors.