Skip to content

feat: audit open line and log ID in the journal - #157

Merged
groupsky merged 10 commits into
mainfrom
feat/40-audit-open-log-id
Nov 5, 2026
Merged

groupsky merged 10 commits into
mainfrom
feat/40-audit-open-log-id

Conversation

@groupsky

@groupsky groupsky commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Refs #40

The broker writes audit open SEQ:HASH LOGID to the journal when it opens the audit log. Anchors carry the log ID (the SHA-256 of line 1). nodkey audit verify --anchors checks that each audit open head equals the last anchor of that log before it.

Progress

  • A test: an entry appended while the broker was stopped is found by audit verify with the journal lines.
  • A test: a deleted log that starts again at seq 1 is found.
  • A test: a log that a person moved away on purpose (new log ID) is not reported as a cut.
  • DESIGN.md section 9 and THREAT-MODEL.md T17 describe the check.
  • A test or a documented manual check shows that a false audit anchor line from other broker output is not read as an anchor.

Choices

  • Log ID = SHA-256 of line 1. No new field in the log format, and verify can compute it from the log alone.
  • An open line of a new log has a zero log ID. Line 1 does not exist yet. Verify counts these lines as "new log starts" and does not check them.
  • Other logs are shown, not failed. A deleted log and a log moved away on purpose look the same in the journal. audit verify prints "other log in the journal: ID …, up to entry N". The person decides whether it was moved on purpose, and can check that log with the same journal.
  • Anchor lines without a log ID (from earlier versions) still count, as anchors of the log being checked.
  • No separate journal stream (SyslogIdentifier=nodkey-audit). The leaner option: every line of the broker goes through its logger, which starts each line with time= and escapes line breaks, so no other broker line can read as an anchor or an open line. journalctl -u nodkey already limits the lines to the broker's unit, which journald sets and a process cannot fake. A separate stream would need the journal socket and changes to the sandbox of the unit. Test: noAnchorLine in cmd/nodkey/broker_test.go now also runs audit.ReadJournal on the broker's output.
  • A crash after the sync but before the anchor reaches the journal makes the next open line differ from the last anchor, so verify reports it. That fails closed; the docs say so.

Security review

Round 1 found nothing serious; it found no way to make a changed log pass. Findings and what I did:

  1. One missing anchor (failed stderr write, failed sync, power cut) makes the open check fail from then on. Docs fixed (setup.md, THREAT-MODEL.md T17): they no longer say such an entry is harmless, and they show the --since way out. Reporting every gap and accepting a known gap: Audit verify: report every open gap, accept a known gap, and give old anchors a log ID #158.
  2. Old anchor lines (no log ID) of more than one log fail after an upgrade and a moved log. Docs fixed: check with --since. Code fix: Audit verify: report every open gap, accept a known gap, and give old anchors a log ID #158.
  3. A journal that lost its oldest lines fails. Docs fixed (setup.md section 12). Fail closed is kept on purpose: an open line with no anchor before it is also what a replaced log looks like.
  4. A deleted or replaced log exits 0 and only prints "other log in the journal". Kept: it looks the same as a log moved away on purpose, which the issue says must not be a cut. Exit code for scripts: Audit verify: report every open gap, accept a known gap, and give old anchors a log ID #158.
  5. gofmt: fixed.

…heck them

Open writes "audit open SEQ:HASH LOGID" once, before any entry of the
start; Append adds the log ID to each anchor line. ReadJournal reads the
lines in order, with the old form too, and VerifyJournal checks the open
lines against the last anchor of the log before them (#40).
An entry added while the broker was stopped, a deleted, moved and
replaced log, old-form anchors, false journal lines, and a torn line.
SEQ:HASH must be in the form that Anchor.String writes, and a carriage
return counts only before a newline (security review, #40).
@groupsky
groupsky marked this pull request as ready for review November 5, 2026 08:42
@groupsky
groupsky merged commit 35ae28a into main Nov 5, 2026
7 checks passed
@groupsky
groupsky deleted the feat/40-audit-open-log-id branch November 5, 2026 08:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant