Skip to content

Instantly share code, notes, and snippets.

@troykelly
Last active April 22, 2025 09:40
Show Gist options
  • Save troykelly/062b93ae2ce9ca555c02154b79981d9f to your computer and use it in GitHub Desktop.
Save troykelly/062b93ae2ce9ca555c02154b79981d9f to your computer and use it in GitHub Desktop.
This script installs and configures auditd on Debian-based systems to log all executed commands—including those run locally (on TTY/console) and over SSH. By monitoring all execve calls, it ensures you have complete visibility into every command executed on the system.

README for install_auditd.sh

Created: 17 Jan 2025
Author: Troy Kelly
Email: [email protected]


Table of Contents

  1. Introduction
  2. Script Overview
  3. System Requirements
  4. Quick Installation
  5. Usage
  6. Configuration Details
  7. Troubleshooting
  8. Author and Contributing

Introduction

This repository contains the script install_auditd.sh, designed to install and configure the powerful auditing daemon, auditd, on Debian-based systems. The script ensures that every command executed on the system (including over SSH) is logged. Additionally, it provides an optional mechanism to send these logs to a remote server via rsyslog.


Script Overview

The script will:

  1. Verify that it is running with root privileges.
  2. Check that the operating system is Debian-based.
  3. Install required packages (auditd and audispd-plugins).
  4. Add or verify the necessary audit rules to capture all execve calls for local (TTY) and SSH sessions.
  5. Optionally configure remote logging via rsyslog if the user provides a remote server string.

IMPORTANT: The script only targets Debian-based systems (e.g., Ubuntu, Debian). It may not work correctly on other distributions.


System Requirements

  • A Debian-based system (e.g., Debian, Ubuntu).
  • Root or sudo privileges to install packages and modify system configuration.
  • (Optional) A remote syslog server if wanting to forward logs off-server.

Quick Installation

Below are several simple ways to install and run install_auditd.sh. All examples must be executed as root or with sudo.

Install via Direct Download

  1. Download the script directly:
    wget https://gist.githubusercontent.com/troykelly/062b93ae2ce9ca555c02154b79981d9f/raw/install_auditd.sh -O install_auditd.sh
    chmod +x install_auditd.sh
  2. Run the script:
    sudo ./install_auditd.sh

Install via curl Piping

This method downloads the script and executes it immediately:

curl -sS https://gist.githubusercontent.com/troykelly/062b93ae2ce9ca555c02154b79981d9f/raw/install_auditd.sh | sudo bash

Note: Always review scripts before piping them directly to bash in a production environment.

Install with Remote Logging

If you have a remote logging server (referred to as <REMOTE_SERVER> below), you can configure auditd to forward logs through rsyslog:

  1. Using an environment variable:

    export LOGGING_REMOTE_SERVER="@log001.public-servers.sy3.aperim.net:1514;RSYSLOG_SyslogProtocol23Format"
    sudo bash install_auditd.sh
  2. Using a command-line parameter (takes precedence over the environment variable):

    sudo bash install_auditd.sh --remote "@log001.public-servers.sy3.aperim.net:1514;RSYSLOG_SyslogProtocol23Format"
# Example 1
curl -sS https://gist.githubusercontent.com/troykelly/062b93ae2ce9ca555c02154b79981d9f/raw/install_auditd.sh \
| sudo bash -s -- --remote "@log001.example.invalid:1514;RSYSLOG_SyslogProtocol23Format"

# Example 2
curl -sS https://gist.githubusercontent.com/troykelly/062b93ae2ce9ca555c02154b79981d9f/raw/install_auditd.sh \
| sudo bash -s -- --remote "logs.example.com:514;RSYSLOG_SyslogProtocol23Format"

# Example 3
curl -sS https://gist.githubusercontent.com/troykelly/062b93ae2ce9ca555c02154b79981d9f/raw/install_auditd.sh \
| sudo bash -s -- --remote "10.0.0.1:10514;RSYSLOG_SyslogProtocol23Format"

Usage

Once installed, auditd will begin auditing commands executed both locally and via SSH. Important details:

  • The main configuration file for the audit rules is located at:
    /etc/audit/rules.d/audit.rules.

  • Logs are written to:
    /var/log/audit/audit.log.

  • If remote logging is configured, the rsyslog configuration is written to:
    /etc/rsyslog.d/99-remote-syslog.conf.

To see the script’s built-in help message, simply run:

sudo bash install_auditd.sh --help

Configuration Details

  1. Audit Rules
    The script inserts rules to monitor all execve calls. These rules ensure every command—whether local or remote—is recorded.

  2. Remote Logging (Optional)

    • If the script detects a remote logging server via either the environment variable (LOGGING_REMOTE_SERVER) or the --remote argument, it will create or update /etc/rsyslog.d/99-remote-syslog.conf to include the line:
      *.*  <REMOTE_SERVER>
    • After configuring, it initiates a reload (or restart) of rsyslog for the changes to take effect.
  3. Service Management

    • auditd is enabled and restarted at the end of the script to confirm it is actively monitoring commands.

Troubleshooting

  • Script Must Be Run as Root
    If you see “This script must be run as root” or a permissions error, prepend sudo or switch to the root user.

  • Non-Debian System
    If running on a system without /etc/debian_version, the script will exit with an error indicating that it is Debian-only.

  • Remote Logging Not Working
    Check that your remote logging server is accessible and that the correct address/port is used. Also ensure that any firewall restrictions have been updated to allow outbound traffic on the relevant port.

  • Changes Not Reflected
    Ensure services are restarted if you manually modify configurations:

    systemctl restart auditd
    systemctl reload rsyslog

Author and Contributing

Feel free to open an Issue or send a Pull Request if you discover any problems or improvements.


Happy auditing! If you have any questions, contact the author at [email protected].

#!/usr/bin/env bash
#
# install_auditd.sh
#
# Description:
# Installs and configures auditd on a Debian-based system to log ALL commands
# executed by users—both locally (TTY) and over SSH. Configures the forwarding
# of audit events into syslog (which, by default, is then handled by rsyslog).
# If a remote server is specified, a corresponding rsyslog snippet is created
# to forward all logs (*.*) to that remote.
#
# This script checks for two possible plugin configurations:
# 1) /etc/audisp/plugins.d/syslog.conf (older, separate audisp-syslog plugin).
# 2) /etc/audit/plugins.d/af_unix.conf (newer, built-in “af_unix” plugin).
#
# Whichever plugin file exists will be configured to forward Auditd logs to
# syslog. If neither file exists, an error is triggered.
#
# Each configuration step is idempotent—running this script multiple times
# will not add duplicate lines or break the system’s final state.
#
# Usage:
# curl -sS https://your.example.url/install_auditd.sh | sudo bash -s -- --remote "@graylog.example.com:514"
# (Ensure you run as root or with sudo.)
#
# You can pass the remote server in one of two ways:
# 1) As an environment variable LOGGING_REMOTE_SERVER="@graylog.example.com:514"
# 2) Via the --remote CLI parameter. CLI takes precedence over environment.
#
# Example:
# sudo bash install_auditd.sh --remote "@logserver.mydomain:6514;RSYSLOG_SyslogProtocol23Format"
#
# This will install and configure Auditd, enable either syslog.conf or
# af_unix.conf depending on which is present, and it will place a snippet
# under /etc/rsyslog.d/99-remote-syslog.conf if that remote is not already
# part of the rsyslog configuration.
#
# Shell Options:
# -E Inherit trap on functions
# -e Exit immediately if a command fails
# -u Treat unset variables as errors
# -o pipefail Return the exit code of the first failed command in a pipeline
set -Eeuo pipefail
# Trap function to catch errors and unexpected exits.
trap 'catchError $?' ERR
###############################################################################
# Globals
###############################################################################
readonly SCRIPT_NAME="${0##*/}"
readonly AUDIT_RULES_FILE="/etc/audit/rules.d/audit.rules"
readonly AUDIT_RULES_B64="-a always,exit -F arch=b64 -S execve -k exec_commands"
readonly AUDIT_RULES_B32="-a always,exit -F arch=b32 -S execve -k exec_commands"
# Paths for old-style vs. new-style plugin configuration:
readonly AUDISP_SYSLOG_CONF="/etc/audisp/plugins.d/syslog.conf"
readonly AF_UNIX_CONF="/etc/audit/plugins.d/af_unix.conf"
# -----------------------------------------------------------------------------
# Remote logging global variables
# -----------------------------------------------------------------------------
# Store the CLI-provided remote value (if any).
REMOTE_SERVER_CLI=""
# Store the environment-based remote value (if any).
: "${LOGGING_REMOTE_SERVER:=""}"
###############################################################################
# Functions
###############################################################################
# -----------------------------------------------------------------------------
# catchError: Print an error message upon a script error or unexpected exit.
#
# Args:
# $1 (int): The exit code of the command that triggered the ERR trap.
# -----------------------------------------------------------------------------
catchError() {
local -r exit_code="$1"
echo "[ERROR] The script '${SCRIPT_NAME}' exited unexpectedly with code ${exit_code}."
echo " Check the output above for details."
exit "${exit_code}"
}
# -----------------------------------------------------------------------------
# checkRoot: Verify that the script is run as root (or via sudo).
# -----------------------------------------------------------------------------
checkRoot() {
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
echo "[ERROR] This script must be run as root or with sudo privileges."
exit 1
fi
}
# -----------------------------------------------------------------------------
# checkDebian: Verify we're running on a Debian-based system.
# -----------------------------------------------------------------------------
checkDebian() {
if [[ ! -f "/etc/debian_version" ]]; then
echo "[ERROR] This script is intended for Debian-based systems only."
exit 1
fi
}
# -----------------------------------------------------------------------------
# installPackages: Install auditd and audispd-plugins if not already installed.
#
# This is idempotent because apt-get handles already-installed packages gracefully.
# -----------------------------------------------------------------------------
installPackages() {
echo "[INFO] Installing required packages: auditd, audispd-plugins..."
apt-get update -y
DEBIAN_FRONTEND=noninteractive apt-get install -y auditd audispd-plugins
echo "[INFO] Package installation completed."
}
# -----------------------------------------------------------------------------
# configureAuditRules: Append rules for execve calls if missing, capturing
# all commands (both local and SSH). Idempotent by checking for existing lines.
# -----------------------------------------------------------------------------
configureAuditRules() {
echo "[INFO] Configuring audit rules..."
# Make sure the file exists before appending.
if [[ ! -f "${AUDIT_RULES_FILE}" ]]; then
touch "${AUDIT_RULES_FILE}"
fi
# Only add if missing.
if ! grep -q "${AUDIT_RULES_B64}" "${AUDIT_RULES_FILE}" 2>/dev/null; then
echo "${AUDIT_RULES_B64}" >> "${AUDIT_RULES_FILE}"
echo "[INFO] Added b64 execve audit rule."
else
echo "[INFO] b64 execve audit rule already present. Skipping..."
fi
# Only add if missing.
if ! grep -q "${AUDIT_RULES_B32}" "${AUDIT_RULES_FILE}" 2>/dev/null; then
echo "${AUDIT_RULES_B32}" >> "${AUDIT_RULES_FILE}"
echo "[INFO] Added b32 execve audit rule."
else
echo "[INFO] b32 execve audit rule already present. Skipping..."
fi
echo "[INFO] Audit rules have been appended if necessary."
}
# -----------------------------------------------------------------------------
# configureAudispSyslogPlugin: Enable the “syslog.conf” plugin if found.
# This older plugin is used by distributions providing /etc/audisp/plugins.d/syslog.conf.
# Example lines typically include:
# active = yes
# direction = out
# path = /sbin/audisp-syslog
# type = always
# args = LOG_INFO
# format = string
#
# We only fix up “active” and “args” because path, direction, type, and format
# can differ per distribution.
# -----------------------------------------------------------------------------
configureAudispSyslogPlugin() {
echo "[INFO] Found old-style plugin at '${AUDISP_SYSLOG_CONF}'. Enabling it."
# Ensure "active = yes" (idempotent).
if grep -Eq '^[[:space:]]*active[[:space:]]*=' "${AUDISP_SYSLOG_CONF}"; then
sed -i 's|^[#[:space:]]*active[[:space:]]*=.*|active = yes|' "${AUDISP_SYSLOG_CONF}"
else
echo "active = yes" >> "${AUDISP_SYSLOG_CONF}"
fi
echo "[INFO] 'active = yes' set in '${AUDISP_SYSLOG_CONF}'."
# Ensure "args = LOG_INFO" (idempotent).
if grep -Eq '^[[:space:]]*args[[:space:]]*=' "${AUDISP_SYSLOG_CONF}"; then
sed -i 's|^[#[:space:]]*args[[:space:]]*=.*|args = LOG_INFO|' "${AUDISP_SYSLOG_CONF}"
else
echo "args = LOG_INFO" >> "${AUDISP_SYSLOG_CONF}"
fi
echo "[INFO] 'args = LOG_INFO' set in '${AUDISP_SYSLOG_CONF}'."
}
# -----------------------------------------------------------------------------
# configureAfUnixPlugin: Enable the newer “af_unix” plugin at /etc/audit/plugins.d/af_unix.conf
# used by Debian 12 (Bookworm) with auditd 3.x. This plugin typically looks like:
# active = yes
# direction = out
# path = builtin_af_unix
# type = builtin
# args = LOG_INFO
# format = string
# -----------------------------------------------------------------------------
configureAfUnixPlugin() {
echo "[INFO] Found newer built-in af_unix plugin at '${AF_UNIX_CONF}'. Enabling it."
# Ensure "active = yes".
if grep -Eq '^[[:space:]]*active[[:space:]]*=' "${AF_UNIX_CONF}"; then
sed -i 's|^[#[:space:]]*active[[:space:]]*=.*|active = yes|' "${AF_UNIX_CONF}"
else
echo "active = yes" >> "${AF_UNIX_CONF}"
fi
echo "[INFO] 'active = yes' set in '${AF_UNIX_CONF}'."
# Ensure "args = LOG_INFO".
if grep -Eq '^[[:space:]]*args[[:space:]]*=' "${AF_UNIX_CONF}"; then
sed -i 's|^[#[:space:]]*args[[:space:]]*=.*|args = LOG_INFO|' "${AF_UNIX_CONF}"
else
echo "args = LOG_INFO" >> "${AF_UNIX_CONF}"
fi
echo "[INFO] 'args = LOG_INFO' set in '${AF_UNIX_CONF}'."
}
# -----------------------------------------------------------------------------
# configureAuditToSyslog: Since Debian Bookworm’s audisp-syslog plugin may not
# exist, check for either syslog.conf or af_unix.conf, and configure whichever
# is present. If neither is found, exit with an error. This ensures we can
# forward audit events to syslog in an idempotent way.
# -----------------------------------------------------------------------------
configureAuditToSyslog() {
# If old-style syslog.conf is present:
if [[ -f "${AUDISP_SYSLOG_CONF}" ]]; then
configureAudispSyslogPlugin
return
fi
# Else if the newer af_unix.conf is present:
if [[ -f "${AF_UNIX_CONF}" ]]; then
configureAfUnixPlugin
return
fi
# If neither conf is present, user may be on a system with different packaging.
echo "[ERROR] No recognized Auditd-to-Syslog plugin found."
echo "[ERROR] Neither '${AUDISP_SYSLOG_CONF}' nor '${AF_UNIX_CONF}' is present."
echo " Verify the correct plugin is installed for your distribution."
exit 1
}
# -----------------------------------------------------------------------------
# restartAuditd: Ensure auditd is enabled and restarted to apply changes.
# Idempotent because systemd doesn't duplicate services if they're already enabled.
# -----------------------------------------------------------------------------
restartAuditd() {
echo "[INFO] Enabling and restarting auditd..."
systemctl enable auditd
systemctl restart auditd
echo "[INFO] auditd service is now active and running."
}
# -----------------------------------------------------------------------------
# parseArgs: Parse command line arguments for remote logging or help.
# -----------------------------------------------------------------------------
parseArgs() {
while [[ "$#" -gt 0 ]]; do
case "$1" in
--remote)
if [[ -z "${2:-}" ]]; then
echo "[ERROR] --remote requires a server argument."
exit 1
fi
REMOTE_SERVER_CLI="$2"
shift 2
;;
-h|--help)
echo "Usage: ${SCRIPT_NAME} [--remote <server>]"
echo "Optional environment variable LOGGING_REMOTE_SERVER can also be set."
echo "If both are set, the command line parameter takes precedence."
exit 0
;;
*)
echo "[ERROR] Unknown option: $1"
echo "Use --help for usage details."
exit 1
;;
esac
done
}
# -----------------------------------------------------------------------------
# configureRemoteLogging: If a remote server is provided (CLI or environment),
# create a snippet under /etc/rsyslog.d/99-remote-syslog.conf if it’s not
# already in non-commented lines of any existing config. This is idempotent.
# -----------------------------------------------------------------------------
configureRemoteLogging() {
local remote="${REMOTE_SERVER_CLI:-${LOGGING_REMOTE_SERVER}}"
if [[ -z "${remote}" ]]; then
echo "[INFO] Remote logging not configured because no remote server was provided."
return
fi
echo "[INFO] Attempting to configure remote rsyslog to: ${remote}"
# If the line already exists (non-commented), do nothing.
if grep -RsI -v '^[[:space:]]*#' "/etc/rsyslog.conf" "/etc/rsyslog.d" 2>/dev/null \
| grep -q "${remote}"; then
echo "[INFO] Remote server '${remote}' is already present in the configuration."
else
echo "[INFO] Remote server not found in existing configuration."
echo "[INFO] Creating /etc/rsyslog.d/99-remote-syslog.conf with '*.* ${remote}'"
cat <<EOF > /etc/rsyslog.d/99-remote-syslog.conf
*.* ${remote}
EOF
# Reload/r estart rsyslog to apply.
echo "[INFO] Reloading rsyslog service..."
systemctl reload rsyslog || systemctl restart rsyslog
echo "[INFO] Remote logging to '${remote}' has been configured."
fi
}
# -----------------------------------------------------------------------------
# main: Main function to orchestrate the steps.
# -----------------------------------------------------------------------------
main() {
parseArgs "$@"
checkRoot
checkDebian
installPackages
configureAuditRules
configureAuditToSyslog
restartAuditd
configureRemoteLogging
echo "[INFO] All commands (local & SSH) are now being audited."
echo "[INFO] Logs are stored in /var/log/audit/audit.log (by default)."
echo "[INFO] If remote logging was configured, logs (including audit events) are forwarded via rsyslog."
echo "[INFO] Script completed successfully."
}
# -----------------------------------------------------------------------------
# Script entry point
# -----------------------------------------------------------------------------
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment