Sudo grants ordinary users the powers of root, and every granted power deserves a witness. The classic sudo log, a single line saying that someone ran something as root, records the fact of escalation but not the deed itself: a session where an engineer typed three harmless commands and one catastrophic one looks, from the log, exactly like a session with four harmless ones. The sudo package ships the missing witness under a name that surprises people, sudoreplay, which records entire sudo sessions as replayable transcripts and stores them in a spool directory with metadata enough to answer the questions audits actually ask. This article builds the complete setup: enabling session recording, structuring the spool so it does not eat the disk, replaying and searching sessions, and shipping the evidence to a central log host so that a compromised server cannot erase its own history.

What sudoreplay records and how the machinery works

Session recording in sudo has two halves. The first half is logging: every sudo invocation writes structured event records through syslog or a local file, and with proper configuration those records include the working directory, the terminal, the full command line and the session identifier. The second half is input and output capture: when enabled, sudo forks the command through a recording harness that captures everything typed and everything printed, timestamped, into a spool directory, one subdirectory per session.

The spool lives under /var/log/sudo-sessions by convention, though the path is configurable, and each session directory holds timing data and stream files plus an info file with the metadata. The tool that reads the spool back is sudoreplay, which can list sessions by filter, replay them in real time or faster, and follow a live session as it happens. A mental model that helps: think of it as a flight recorder for terminal sessions, written continuously, indexed by user and time, and readable only by administrators with the keys to the spool.

Two configuration directives in /etc/sudoers drive the whole system. The log_output directive, set via Defaults, turns on output capture for matching commands, and the counterpart input logging exists as well. Because sudoers is validated on every sudo invocation, all changes go through visudo, the editing wrapper that refuses to save a broken file and lock the whole team out of root.

Enabling recording in sudoers safely

The minimal, global stanza looks like this:

Defaults log_output
Defaults iolog_dir=/var/log/sudo-sessions

The first line enables capture for all sudo invocations, the second pins the spool location, and both go into /etc/sudoers or a drop-in under /etc/sudoers.d/, through visudo in either case. The default spool path differs between releases, which is one reason to set it explicitly: a path written in the configuration is a path that survives upgrades and appears in every audit answer the same way.

Selective recording is often the smarter first step, because the noise of routine, scripted sudo calls from automation can bury the human sessions that audits actually want. Recording by user is one line:

Defaults:admin,!backup log_output

which captures sessions for the admin group while excluding the backup account whose scripted invocations fire every hour. The same logic inverted, recording everything except a known-noisy service account, keeps the spool relevant and the disk sane. Whatever the scope, the session identifier links the syslog record and the spool directory, so the classic log line gains a TSID field pointing straight at the replayable transcript.

After enabling, the immediate test is a single sudo ls in one window and sudoreplay -l in another, which lists the session that just happened, with user, tty, start time, duration and the id. Seeing one's own last command appear in the list is the checkpoint where configuration turns into capability.

Reading sessions back with sudoreplay

The replay tool has three modes worth knowing by heart. Listing, with -l and a filter expression, answers who did what and when:

sudoreplay -l user=admin 'fromdate=2026-10-01'

The filter language accepts user, group, tty, command pattern and time ranges in fromdate and todate, which makes targeted audit questions precise instead of archaeological. Replay, by session id, reconstructs the session in a terminal:

sudoreplay 000001

Replay runs at original speed by default, which for a long session is an honesty feature and an endurance problem at once, so the -s flag multiplies speed, -s 10 replays ten times faster, and the space bar suspends playback. The -m flag seeks to a maximum wait, skipping dead air, and in combination the two turn a forty-minute session into a two-minute review. Live following, -f on a running session id, streams a session as it happens, which is the mode that turns sudoreplay into a training and support tool, letting a senior watch a junior's session as it unfolds instead of reading about it afterward.

A small operational detail makes the spool usable long-term: the info file inside each session directory is plain text with the metadata, which means grep over the spool works, but the sanctioned path is sudoreplay -l because it parses dates and filters consistently. Scripts that trawl the spool directly tend to break on format changes between sudo releases, while the tool interface is stable.

Keeping the spool from eating the disk

Session capture grows at the pace of terminal output, and a chatty command in a loop can write gigabytes overnight, so retention policy belongs in the setup rather than in the firefighting calendar. Two mechanisms do the work. The first is sudo's own maxseq setting, which caps the number of session sequence numbers retained, defaults in the hundreds, and prunes the oldest directories when the cap is exceeded. The second is a cron job or systemd timer that deletes session directories older than the compliance window:

find /var/log/sudo-sessions -maxdepth 1 -type d -mtime +90 -exec rm -rf {} +

running weekly, keeps ninety days of sessions on a predictable budget. The compliance window, not intuition, sets the number: if the audit standard says a year, the timer says a year and the disk is sized for it. A quarterly measurement of spool growth converts the sizing question from guesswork into arithmetic.

The companion discipline is access to the spool itself. The directories under the session root belong to root, readable by nobody else, and the one temptation to resist is granting a monitoring system broad read access for the sake of dashboards. The metadata is meant for auditors with a reason, and the standard pattern is a scheduled report generated by root into a location the monitoring can read, containing summaries rather than transcripts.

Shipping sudo logs to a central host

A session recorder on the compromised server is a witness the attacker can silence, so the second half of the architecture moves the evidence off the box in real time. The structured log lines that carry the session ids, the commands and the metadata travel through syslog like any other log source, and the shipping machinery is the standard stack: rsyslog forwarding on the sudo host, TLS between hosts for the transit, and a central collector with its own retention.

On the sending side, an rsyslog rule matching the sudo program name, programname contains sudo on Debian-family where sudo logs under its own facility, or the authpriv facility with matching content on RHEL-family, forwards a copy to the collector:

authpriv.* @@logs.example.com:6514

with the double at-sign meaning TLS, given a matching configuration for the certificates. The central host then applies its own retention, its own access rules and its own backups, which closes the loop the local spool cannot close on its own: even a root-level intrusion that wipes the local spool leaves the remote record intact, timestamps, session ids and all.

The interplay between the two stores deserves one honest paragraph. The remote syslog carries the metadata and the command lines, which answers most audit questions and survives the worst incidents. The local spool carries the full transcripts, which are irreplaceable for reconstructing what a session actually did, and which are only as trustworthy as the host they live on. Teams that need transcript-level assurance after a compromise bring the spool into the backup rotation as well, on a schedule that matches how quickly they expect to notice a compromise, a sentence that sounds paranoid until the first incident makes it sound modest.

The rollout and audit-ready checklist

Rollout order mirrors every other security change on a shared system: pilot with the admin group, verify the spool and the replay path with real sessions, then widen the scope and set the retention timer. The pilot catches the two classic surprises early, the disk growth of a forgotten verbose command and the interactive password prompt of a script that never expected to be recorded, both of which are configuration quirks rather than flaws, and both of which are cheap to fix in week one and expensive in month six.

The checklist that leaves a team audit-ready fits on one card. log_output enabled through visudo, scoped deliberately, spool path pinned in the configuration. One recorded session listed, replayed and speed-played, so the replay skill exists before it is needed. Retention automated with a timer and sized to the compliance window. Access to the spool restricted to root, with reports instead of raw access for monitoring. Sudo log lines forwarded to a central collector over TLS, and the collector's retention set independently of the source host. A quarterly spot check, one random session replayed end to end, keeps the whole chain from quietly rotting, because a recording system that nobody has replayed in six months is a promise rather than a capability.
## The logging directives that feed the metadata

Session capture is the headline act, but the metadata around it comes from the classic logging directives, and tuning them is what makes the records answer real questions. The Defaults family in sudoers controls where and how event records travel. On most distributions sudo logs through syslog under the authpriv facility, and the two directives that shape that stream are syslog, which sets the facility and priority pair, and syslog_goodpri, which sets the priority for successful commands. The failure counterpart, badpri, speaks for itself. A common production pair:

Defaults syslog=authpriv
Defaults syslog_goodpri=info
Defaults log_year

The log_year directive appends the year to every entry, which sounds unnecessary until the spool crosses its first January and the timeline questions begin. Sites that prefer a local file over syslog use Defaults logfile=/var/log/sudo.log, and the honest tradeoff is that a local file survives syslog hiccups but dies with the disk, so the central shipping from the previous section matters more, not less, in that mode. Mail delivery, Defaults mailto=root with mail_always or mail_no_user, has aged poorly now that mail on servers is an exception rather than a default, and the modern answer to the same need is the central collector with alerting on the stream.

One directive pairs with sessions so naturally that it belongs in every recording setup: Defaults use_pty. Running commands in a pseudo-terminal closes a class of output interleaving problems and, more importantly, makes the recorded transcript a faithful copy of what the user saw, because the capture harness records a real terminal stream instead of a mash of pipes. It costs nothing measurable and removes a whole category of replay artifacts, so it goes in with the first line of the recording stanza and never comes out.

Answering real audit questions end to end

The test of the whole stack is whether it answers the questions that actually arrive, so it is worth rehearsing one from start to finish. The question lands on a Tuesday: what did the admin account do on the payment host last Friday between 21:00 and midnight, and did anything touch the rate limits file. The first stop is the central collector, where the sudo stream for that host is filtered by time window, which yields the list of sudo invocations with their session ids, commands and working directories, the answer at the level of who ran what.

The second stop is the spool on the host itself, where the session ids from the central list become replayable transcripts:

sudoreplay -l 'fromdate=2026-10-09 21:00' 'todate=2026-10-09 24:00' # sudoreplay -s 20 000034

Replaying at twenty times speed with the -m flag skipping dead air turns an hour of terminal into minutes of review, and the transcript answers what the log lines cannot: what was printed, what was edited, and whether the touch on the rate limits file was a cat, an inspection, or the change that correlates with the incident timeline. The chain from question to answer runs through two systems, three commands and no improvisation, and that repeatability, more than any single feature, is what turns the recording setup from a compliance checkbox into a tool the team reaches for willingly.

The inverse question closes the loop: proving that nothing happened. An empty sudoreplay -l result for a time window, cross-checked against the central stream showing no sudo invocations at all, is a negative answer with evidence behind it, and audits value the negative that comes with a query anyone can rerun far above the negative that comes with a shrug.