#!/usr/bin/env bash # Wonder Cohen - The Hague The Netherlands # shell_history_audit.sh – put in /etc/profile.d # Logs every interactive-bash command (including within sudo) to /var/log/history # Author: Roy Cohen Last-update: 2025-06-23 ### Installation notes: ## Create the script # /etc/profile.d/shell_history_audit.sh ## Create log directory and group # sudo groupadd -f historylog # sudo mkdir -p /var/log/history # sudo chown root:historylog /var/log/history # sudo chmod 1770 /var/log/history ## Create the error log # sudo touch /var/log/history_audit_errors.log # sudo chown root:historylog /var/log/history_audit_errors.log # sudo chmod 666 /var/log/history_audit_errors.log ## Secure script # sudo chmod 644 /etc/profile.d/shell_history_audit.sh # sudo chown root:root /etc/profile.d/shell_history_audit.sh ## Make log files append-only (optional) # sudo find /var/log/history -type f -exec chattr +a {} \; # ## Sudo environment setting # visudo # Defaults env_keep += "HISTFILE HISTTIMEFORMAT" # ############################################################################## # Config – change these once HISTDIR="/var/log/history" AUDITGROUP="historylog" # group allowed to read the logs LOG_MODE=0640 # -rw-r----- root:historylog DIR_MODE=1770 # drwxrwx--T root:historylog AUTO_LOGOUT=3600 # seconds ERRLOG="/var/log/history_audit_errors.log" ############################################################################## # Skip for non-interactive shells [[ $- != *i* ]] && return ############################################################################## # Auto-logout readonly TMOUT="$AUTO_LOGOUT" export TMOUT ############################################################################## # Determine source user (for sudo tracking) if [[ -n "${SUDO_USER:-}" && $SUDO_USER != "$USER" ]]; then SRC="$SUDO_USER" else SRC=$(logname 2>/dev/null || echo "$USER") fi LOGFILE="$HISTDIR/${USER}_${SRC}.log" ############################################################################## # Create logfile if directory is writable and it doesn't exist if [[ -w "$HISTDIR" && ! -e "$LOGFILE" ]]; then touch "$LOGFILE" # we have permission chmod "$LOG_MODE" "$LOGFILE" 2>/dev/null || true chown "$USER:$AUDITGROUP" "$LOGFILE" 2>/dev/null || true fi ############################################################################## # Check group membership (user must be in $AUDITGROUP) if ! id -nG "$USER" | grep -qw "$AUDITGROUP"; then logger -t shell_history_audit "DENIED: $USER is not in $AUDITGROUP group. History logging skipped." return 0 fi ############################################################################## # Activate history logging only when logfile exists & is writable if [[ -w "$LOGFILE" ]]; then export HISTFILE="$LOGFILE" export HISTSIZE= export HISTFILESIZE= export HISTIGNORE='' export HISTCONTROL='ignoreboth' export HISTTIMEFORMAT='%F %T ' shopt -s histappend case "${PROMPT_COMMAND:-}" in *history\ -a*) : ;; *) PROMPT_COMMAND="history -a${PROMPT_COMMAND:+; $PROMPT_COMMAND}" ;; esac else # Log error (optional) echo "$(date '+%F %T') WARN: Could not activate logging for $USER to $LOGFILE" >> "$ERRLOG" 2>/dev/null || true fi