In enterprise Linux environments, tracking command execution is critical for security audits and compliance. The common practice of admins using sudo -i
creates a logging gap where commands run as root lose the original user context. While the SUDO_USER
environment variable exists, most logging solutions don't capture this metadata.
We'll implement a comprehensive logging solution that captures:
1. Original username (SUDO_USER)
2. Effective username (who actually executed the command)
3. Full command with arguments
4. Precise timestamp
5. Hostname context
Method 1: Enhanced auditd Configuration
Modify /etc/audit/audit.rules
:
-a exit,always -F arch=b64 -F euid=0 -S execve -k ROOT_CMDS
-a exit,always -F arch=b32 -F euid=0 -S execve -k ROOT_CMDS
Then create a custom format in /etc/audit/auditd.conf
:
log_format = ENHANCED
name_format = HOSTNAME
Method 2: Bash History Injection
Add to /etc/bash.bashrc
or user profiles:
function log_command {
local real_user=$(whoami)
local sudo_user=${SUDO_USER:-$real_user}
logger -p local6.notice -t "CMD_AUDIT" "[$real_user|$sudo_user] $BASH_COMMAND"
}
trap log_command DEBUG
Method 3: Sudoers Logging Enhancement
Add to /etc/sudoers
:
Defaults log_host, log_year, logfile="/var/log/sudo.log"
Defaults log_input, log_output
Defaults iolog_dir="/var/log/sudo-io/%{user}"
For centralized logging, configure rsyslog to forward logs:
template(name="CmdAudit" type="string"
string="%timegenerated% %HOSTNAME% [%syslogtag%] %msg%\n")
if $syslogtag == 'CMD_AUDIT' then {
action(type="omfile" file="/var/log/cmd_audit.log" template="CmdAudit")
stop
}
For containerized environments, add this to your Dockerfile:
RUN echo 'export PROMPT_COMMAND=\'history -a >(tee -a ~/.bash_history | logger -t "$(whoami)[$SUDO_USER]")'\'' >> /etc/profile
Example log output would appear as:
Jan 19 22:28:46 prod-server01 CMD_AUDIT: [root|ksoviero] yum install random-pkg
In enterprise Linux environments where admins routinely use sudo -i
to gain root access, traditional logging solutions often fail to capture the crucial link between elevated privileges and the original user. The SUDO_USER
environment variable holds this relationship, but most logging mechanisms don't preserve it.
The most reliable approach combines bash history enhancements with syslog forwarding. Create a custom bashrc snippet for root:
# /root/.bashrc addition
function log_command {
if [ -n "$SUDO_USER" ]; then
logger -p local6.notice -t SUDO_CMDS "[$(whoami)|$SUDO_USER] $BASH_COMMAND"
else
logger -p local6.notice -t DIRECT_CMDS "[$(whoami)] $BASH_COMMAND"
fi
}
trap log_command DEBUG
Configure rsyslog to handle these messages by adding to /etc/rsyslog.d/command-audit.conf
:
# Command audit rules
local6.notice /var/log/command-audit.log
& stop
For enterprise-grade auditing, combine with auditd rules:
# /etc/audit/rules.d/command-logging.rules
-a always,exit -F arch=b64 -F euid=0 -S execve -k root_cmds
-a always,exit -F arch=b32 -F euid=0 -S execve -k root_cmds
After implementation, test with:
sudo -i
echo "Test command"
exit
tail -n 10 /var/log/command-audit.log
Expected output should resemble:
Jan 19 22:28:46 hostname SUDO_CMDS: [root|username] echo "Test command"
For high-traffic environments, consider:
- Log rotation policies
- Centralized log collection
- Rate limiting to prevent DoS
- Filesystem partitioning for audit logs
If you prefer using Snoopy, modify the source to include SUDO_USER:
// In snoopy.c, modify the output format
if (getenv("SUDO_USER") != NULL) {
snprintf(message, sizeof(message), "[%s|%s] %s",
username, getenv("SUDO_USER"), cmd);
} else {
snprintf(message, sizeof(message), "[%s] %s",
username, cmd);
}