The audit log
Because every connection passes through the broker, Tessera records what happens without anything installed on your targets. The full log lives in Postgres and is the source of truth.
What’s recorded
Section titled “What’s recorded”- Authentication — logins and their outcome, and lifecycle events (a user disabled or enabled, sessions revoked).
- Connections — every session started and closed, by user and target.
- Activity — SSH commands, database queries, Kubernetes API requests (verb, resource, namespace, name, status), and RDP connect/disconnect.
- Read-only enforcement — commands and statements blocked in read-only sessions.
- Access changes — grants created and revoked, and every just-in-time request with its decision and approver.
- Settings changes — configuration made in the console.
Every entry carries who did it, when, from which address, whether it succeeded, how serious it
is (INFO through CRITICAL) and which part of the controller produced it, so an access review
can be a filter rather than a search.
Rejected attempts are recorded as well as accepted ones: a wrong password, a lockout, a disabled account, a refused session. When the account does not exist the attempted name is deliberately not stored, because people type passwords into the username field and a log that captured them would become a list of passwords readable by everybody entitled to read the log.
Tamper evidence
Section titled “Tamper evidence”Entries are sealed into blocks a few seconds after they are written. Each block hashes the previous block’s hash followed by every row it covers, so changing, removing or reordering a single entry afterwards breaks that block and every block after it. Audit → Verify integrity walks the whole chain and names the block, and where possible the row, that no longer adds up.
Set TESSERA_AUDIT_SIGN_KEY and each block is also signed with a key that is not in the
database. This is what makes the chain worth having: without it, somebody who can write to the
database can simply recompute every hash forward and the result verifies. They cannot reproduce
a signature made with a key they did not compromise.
Be precise about what this defends against, because the boundary matters:
- Database access — covered. Editing rows, deleting them, or rebuilding the chain is detected, including the two shortcuts that look like nothing was touched: emptying a block and marking it pruned, and removing the signatures rather than forging them. With a signing key set, a block that carries no signature is reported exactly like one whose signature is wrong.
- Deleting history through the retention machinery — covered, with one conditional edge.
Every purge records a
chain.prunedentry naming the blocks it retired, so blocks that are marked pruned while no retention pass ever recorded removing them are reported. Retention also removes the oldest first, so a pruned block between two intact ones is reported as a hole in the middle. What remains conditional: with a retention window configured, somebody with database access can retire the oldest blocks earlier than your policy allows, and locally that looks like the janitor doing its job. Thechain.prunedannouncement your SIEM receives for every legitimate purge, and does not receive for that one, is what closes it. - Root on the controller — not covered. Root holds the signing key.
- Deleting the newest blocks — covered only if you export to a SIEM. A chain cannot notice
its own tail being cut off, because nothing follows the missing blocks. Each sealed block is
announced to the SIEM as a
chain.sealedevent carrying its sequence number and hash, and the gap between the last sequence number your SIEM saw and the last one in the database is what makes truncation visible. - Entries written before the upgrade — not covered, and shown as such. Nothing can vouch for a row written before the chain existed, so those are labelled rather than sealed.
The chain checks itself
Section titled “The chain checks itself”Pressing a button is not a control. The controller verifies the whole chain once a day, at
03:17 local time by default, and records the result three ways: as a chain.verified or
chain.problem entry in the log itself, as the two Prometheus metrics
tessera_audit_chain_problems and tessera_audit_last_verify_timestamp_seconds, and as the line
beside the Verify integrity button that says when the last pass ran.
That is the pair worth alerting on, and the second one matters as much as the first: a problem
count of zero that has not been updated for a week means nobody has looked, which on a dashboard
is indistinguishable from fine. Prometheus metrics has the rules.
Change the hour with TESSERA_AUDIT_VERIFY_AT, or set it to off and drive the pass from your
own scheduler.
Verification is also available as GET /api/audit/verify, and the block headers plus the public
key through GET /api/audit/blocks, so an auditor can check the chain on a copy of the database
on a machine you do not control.
Session recording
Section titled “Session recording”Beyond the event log, the full terminal stream of an SSH session can be recorded in asciinema format and replayed in the console. Recording is a per-target toggle (Record sessions on the target) — turn it on where you need it, e.g. production but not a sandbox. A user can retrieve recordings of their own sessions; administrators can access all of them. To bound storage, see Retention.
For the shorter, non-reference version of this, see SSH session recording.
What the signatures are worth
Section titled “What the signatures are worth”The verification reports its signing state alongside its result, because an unsigned chain is not
a broken one, it is a weaker one: hash-linked only, so somebody who can write to the database can
edit a row, recompute every hash forward and have the walk pass. The console says not signed
on each block and the metric tessera_audit_chain_unsigned reads 1, separately from the problem
count, which keeps meaning “the log does not add up”.
Set TESSERA_AUDIT_SIGN_KEY and it stops being a question. The VM installer generates one; under
Docker and Kubernetes you supply it, and
Backups & upgrades says what losing it costs.
Turning signing on later is safe. Blocks sealed before the key existed carry no signature and never will: signing them afterwards would be a claim about when they were written. The controller records the block signing began at, and those earlier blocks are reported as history rather than as tampering, so the chain does not go red for doing this. The console shows partially signed and names the block the signatures start from. Everything from that block onwards is checked as strictly as a chain that was signed from the start, and a signature missing above that point is still the loudest thing the log can say.
When the counters cannot be computed
Section titled “When the counters cannot be computed”The severity figures above the table have three seconds, and the page of rows ten. Over a very wide window on a very large log either can run out, and when it does the figures render as dashes and the page suggests narrowing the filter. They are never rendered as zeroes: “we could not count these” and “there were none” are different answers, and only one of them is safe to print on an audit screen.
Who can read it
Section titled “Who can read it”Reading the audit log is its own permission, View audit, granted under Users. It is read only and carries nothing else: an account holding it can search the log, verify the chain and replay recorded sessions, and cannot grant access, add a target or change a setting.
It used to be part of Manage access, which meant an auditor had to be given the power to hand out access to every server before they could look at the record of who had used one. See Administrators.
Review in the console
Section titled “Review in the console”Open Audit to browse the event log with filters, and Audit → Sessions to see per-session activity — the command list for an SSH session, the queries for a database session — with a play button where recording is enabled. Sessions lists active connections, which an administrator can force-close.
Get it out
Section titled “Get it out”- Export to your SIEM — stream every event as JSON to your collector in real time (Ultimate).
- Prometheus metrics — counts and latencies for dashboards and alerts.
The database always retains the complete log regardless of what you export.
Retention
Section titled “Retention”By default the controller keeps the audit log and session replays forever. To bound growth, set a retention window at startup (see Configuration):
TESSERA_AUDIT_RETENTION_DAYS— delete audit-log entries older than N days.TESSERA_RECORDING_RETENTION_DAYS— delete session replays (.castfiles and their metadata) older than N days.
A background job runs once a day (and once at startup) and removes anything past the window;
0 (the default) disables purging for that class.
Purging works on whole blocks, and the block headers are kept forever. Removing individual rows would break the chain that covers them, so a retention pass would start reporting tampering on a schedule. Keeping the headers costs a few dozen bytes per block and means the chain stays continuous: the events are gone under your policy, and the proof that nothing was taken out of the middle is still there. A purged block is shown as pruned rather than as missing, and the console counts its rows separately from the rows the chain can still show, so retired history is never presented as evidence that still exists.
Retention also removes the oldest blocks first, always, and verification enforces that: a pruned
block sitting between two intact ones is reported as a hole in the middle, because nothing the
product does can produce one. Every purge announces itself as a chain.pruned event carrying the
block range and the cutoff, in the log and in your SIEM. A deletion nobody scheduled is then a
message nobody received. If you need long-term retention beyond the
controller, stream events to your SIEM — that copy is independent of the local
window.
Related
Section titled “Related”- Control mapping — which ISO 27001 and SOC 2 controls this log produces evidence for, and what to export for each.
- Database query audit — recording SQL statements.
We would like to count visits with Google Analytics, which needs a cookie. Nothing is loaded and nothing is stored unless you accept. What this sets.