Audit log
Defines named audit logs that Bifröst uses to record security-relevant actions separately from the regular application log. Each flow references one of these entries by name.
If auditlog is omitted or empty, Bifröst creates a disabled default entry. With both audit logging and recording disabled, no signing key, journal, Recording repository or delivery connection is created. Recording can be enabled independently, without an audit journal.
Properties
name
Audit log Name = "default"
The unique name used by flows to reference this audit log. The implicit entry and an omitted name default to default.
enabled
bool = false
Enables the audit journal and security events. Set recording.enabled: true independently to record sessions without an audit journal or audit events.
Enabled audit logs must use distinct identity files and non-overlapping journal directories. Identity files must be outside every enabled journal directory.
failurePolicy
string = "strict"
Controls what happens when this audit log or its session-recording repository fails:
strictpreserves fail-closed behavior. Initialization errors prevent startup, and runtime persistence errors abort the affected operation.bestEffortlogs the first failure, disables this audit log and its recording until restart, but lets the SSH operation continue. Fix the cause and restart Bifröst; persistence does not automatically recover.
Only strict and bestEffort are accepted. Remote-delivery outages continue to use their documented asynchronous retry behavior and do not by themselves disable the local audit log.
identityFile
File Path = "<os specific>"
Signing key for the journal and/or Recording. Bifröst creates an Ed25519 key when an enabled journal or Recording needs one and neither repository contains prior state.
If history exists, a missing or invalid signing key prevents startup. Existing keys must be regular, at most 1 MiB, owned by the Bifröst user, and neither symlinked nor hard-linked:
- Unix: mode
0400or0600. - Windows: a protected DACL limited to the owner,
SYSTEM, and optionallyOWNER RIGHTS.
The default value is different, depending on the platform Bifröst runs on:
- Linux:
/etc/engity/bifroest/auditlog-key - macOS:
/Library/Application Support/Engity/Bifroest/auditlog-key - Windows:
C:\ProgramData\Engity\Bifroest\auditlog-key
directory
File Path = "<os specific>"
Local audit-log directory. It contains the journal, delivery cursors, and temporary work data. Bifröst manages it exclusively; do not modify or rotate its files externally.
The platform defaults are:
- Linux:
/var/lib/engity/bifroest/auditlog - macOS:
/Library/Application Support/Engity/Bifroest/auditlog - Windows:
C:\ProgramData\Engity\Bifroest\auditlog
minimumFreeBytes
uint64 = 268435456
Filesystem space reserved for authenticated and other essential audit events. 0 uses the secure default of 256 MiB rather than disabling the reserve.
When the reserve is reached, Bifröst suppresses pre-authentication detail and counts it in bounded aggregates. A signed journal-reserve marker and pending/final aggregates may still use the emergency reserve. Authenticated events remain synchronous and fail closed; a dedicated filesystem is recommended because other processes can consume the reserved space.
encryptionPublicKey
Optional OpenSSH Ed25519 or RSA public age recipient key, also used by Recording. For an enabled audit journal, Bifröst encrypts confidential fields independently for each event:
- No recipient: signed
.baudit; private fields are readable after decompression. - With a recipient: signed
.beaudit; private fields are compressed and encrypted. Onlyname, optionaldomainandoutcome, plus signed envelope data such as time, record ID, chain and producer remain visible. See the exact field boundary.
With recording alone, the same recipient selects .becast; no .beaudit journal is created.
Encryption does not cover all local state
A Recording lifecycle outbox can contain signed, unencrypted flow and correlation data even with .beaudit. Protect the entire Recording repository and its backups.
Use exactly one recipient and keep its private key offline. It must differ from all server keys, including host, signing, static SSH-environment and SFTP keys; also check dynamically rendered identity paths. A journal with records cannot change recipients: use a new empty journal and retain the old private key for its evidence.
encryptionPublicKeyFile
Loads the single encryption public key from an OpenSSH public-key file when the enabled auditlog is initialized. This is an alternative to encryptionPublicKey; the two properties cannot be combined. The file must exist and contain exactly one supported public key without authorized-key options or certificates.
recording
Configures fail-closed shell and exec recording, local retention, and optional artifact delivery. Recording is disabled by default but can run without the audit journal. See Recording-only.
targets
Optional destinations for sealed audit segments. Recording may inherit these targets even when the journal is disabled; then only sealed Recordings are delivered. See remote targets.
Journal
The local journal is the authoritative, crash-safe source of the audit log. Remote targets replicate sealed journal segments and do not replace local persistence.
Use an access-controlled local filesystem and do not modify managed paths while Bifröst runs. The filesystem is trusted: owners, ACLs and link checks are not Bifröst's defense against concurrent external mutation. Signatures, chains, quotas, structural validation and crash recovery still apply; unsupported links can be rejected as invalid repository state.
See audit events for the recorded security transitions, their structured fields, privacy guarantees, and failure behavior.
Storage and recovery
- Records are signed and flushed.
.bauditand.beauditsegments rotate around 16 MiB; signed hashes link them tohead.cborunder<auditlog-directory>/<producer-id>/. See the format and vectors. - Startup repairs uncommitted tails but rejects invalid committed data and lost records. Large recovery scans can leave
.bifroest-workafter a crash; remove stale work only while Bifröst is stopped. Read-only verification uses an OS temporary directory instead. audit export,audit verifyand merge can read while Bifröst runs. They verify the signed committed state; later writes are not part of that result. Locally, export and verify use the default configuration and the selected auditlog name. Offline, both accept a complete journal copy through--sourceand an independently trusted--expectedProducerIdwithout a configuration.- Export and merge verify before writing redacted, unsigned JSONL.
--with-sensitiveincludes private fields and needs the offline decryption key for.beaudit. - Remote targets deliver only sealed segments, never the signed head or active file. A single downloaded segment is not verifiable as a complete journal. Keep the full journal and an independently trusted chain tip to detect a missing remote suffix.
Examples
Basic audit logs
-
Enable the
defaultaudit log of Bifröst:/etc/engity/bifroest/configuration.yaml 1 2 3 4 5 6 7 8 9 10 11 12
auditlog: - ## 'default' is the default name # name: default enabled: true ## Writes the auditlog into this directory by default # directory: /var/lib/engity/bifroest/auditlog flows: - name: foo ## 'default' auditlog is used by default # auditlog: default # ... -
Start and use Bifröst...
Bifröst writes unencrypted event segments named
*.bauditto the default auditlog directory. The directory also contains signedhead.cborand other managed state; retain the whole journal for verification. -
Read the recorded events of Bifröst:
1 2 3
bifroest audit export default # Verified, redacted JSONL from a signed checkpoint on stdout.The exported JSONL is an unsigned view, not a substitute for the signed journal. Even redacted metadata needs protection; the clear
.bauditfiles also contain confidential fields after decompression. To include those fields, explicitly add--with-sensitivetoaudit exportand protect its plaintext output.To check the journal without JSONL, use
audit verify:bifroest audit verify default. It reports outer or full verification on success.
Encrypted audit events
-
On an offline and trustworthy workstation, generate the recipient key pair:
1 2 3
bifroest key generate \ --identityFile /srv/audit-keys/recipient-key \ --publicFile /srv/audit-keys/recipient-key.pub/srv/audit-keys/recipient-keyshould never reach Bifröst. It is only for the recipient, to be able to decrypt the auditlog, if needed. -
Transfer only the public key to Bifröst's host:
/etc/engity/bifroest/audit-recipient.pub -
Configure Bifröst:
/etc/engity/bifroest/configuration.yaml 1 2 3 4 5 6 7 8
auditlog: - enabled: true encryptionPublicKeyFile: /etc/engity/bifroest/audit-recipient.pub # Only for a NEW empty journal; existing .baudit history cannot switch. # Bifröst creates /etc/engity/bifroest/auditlog-key on first start. flows: - name: foo # ... -
Start and use Bifröst.
Bifröst creates the signing identity and journal automatically when they contain no history. It writes encrypted
.beauditsegments; signed outer metadata remains visible. -
Read events, redacted:
1 2 3
bifroest audit export default # Redacted JSONL from a signed checkpoint; private fields stay encrypted. -
Or, fully decrypted:
-
On the Bifröst host, obtain the producer ID from the server's signing key and retain it through a trusted channel:
1 2 3 4
bifroest audit producer-id \ default # Save this 64-hex value independently; # never derive it from the journal. -
For a stable complete evidence copy, stop Bifröst and copy
/var/lib/engity/bifroest/auditlogto/srv/audit-evidence/auditlogon the offline workstation. Day-to-day redacted reading in step 5 does not require a stop.Keep
head.cbor, all sealed segments and anyactive.beaudittogether. Remote targets only contain sealed segments and cannot replace this copy. -
Export confidential events on the offline workstation. No configuration file or server signing key is needed:
Offline workstation 1 2 3 4 5 6
bifroest audit export \ --source /srv/audit-evidence/auditlog \ --expectedProducerId "<64-hex-producer-id>" \ --decryptionIdentityFile /srv/audit-keys/recipient-key \ --with-sensitive \ --output /srv/audit-evidence/sensitive.jsonlThe decrypted JSONL is unsigned and not encrypted and must be protected like sensitive data.
To verify without exporting events, use
bifroest audit verify --source /srv/audit-evidence/auditlog --expectedProducerId "<64-hex-producer-id>" --decryptionIdentityFile /srv/audit-keys/recipient-key --require-full. Without the private key, encrypted journals can only be verified at outer scope. The offline auditlog label defaults todefault.
-