synrc/au is a minimal, zero-dependency Erlang/OTP library for high-assurance audit logging in the ERP.1 three-plane architecture (Security Admin BEAM, System Admin BEAM, Application BEAM).

It enforces strict privilege segregation, fail-secure append-only event logging, distributed CRDT Merkle log merging, and compliance with NIST SP 800-53 Rev. 5 AU (Audit and Accountability) controls.

[!NOTE] For formal mathematical models, theoretical requirements, proof of CRDT convergence, and the complete NIST SP 800-53 Rev. 5 attestation matrix, see the LaTeX article in priv/audit.tex.

Features

  • Zero External Dependencies: Standard Erlang/OTP (crypto, stdlib, kernel, eunit, common_test).
  • NIST Cryptographic Profile: ECDSA P-384 (secp384r1), SHA-384 / SHA-512 chain hashing, HMAC-SHA-512, and RFC 3161 timestamps.
  • Three-Plane Isolation Model:
    • Security Admin BEAM: Holds long-term ECDSA P-384 keys and signs critical events & checkpoints.
    • System Admin BEAM: Central aggregator (audit_core) maintaining append-only hash chains and fail-secure commits.
    • Application BEAM: Capability-limited clients (audit_client) sending session events over bridge channels.
  • Distributed CRDT Merkle Merging: Add-only Merkle-CRDT log merging for multi-node / multi-DC deployments with total order linearization.
  • Pure Offline Verification: Tooling (audit_verify) for independent offline verification of record chains, signatures, and inclusion proofs without running OTP processes.
  • SIEM & Compliance Export: Export to JSON, OSCAL assessment evidence maps, and Syslog/Wazuh CEF formats (audit_export).-

Architecture


 Security Admin BEAM   (Security Plane)                                      
   audit_crypto  : ECDSA P-384 key generation, signing, RFC 3161 TSP        

                 sealed capability channel

 System Admin BEAM     (Control Plane)                                       
   audit_core    : gen_server log aggregator, ETS storage, fail-secure sync 
   audit_chain   : SHA-384 append-only chain, HMAC-SHA-512 integrity        
   audit_merge   : CRDT G-Set multi-node log merging & total ordering       

                 capability bridge

 Application BEAM(s)   (Application Plane)                                   
   audit_client  : Lightweight event generation API                         

Module Index

ModuleDescriptionPlane
audit_clientApplication API for submitting standard & critical audit eventsApplication
audit_coregen_server aggregator, fail-secure synchronous commit (AU-5)System Admin
audit_cryptoECDSA P-384, SHA-384/512, HMAC-SHA-512, RFC 3161 wrappersSecurity Admin
audit_chainGenesis calculation, prev_hash linking, payload serializationSystem Admin
audit_checkpointMerkle tree construction, Merkle roots, signed checkpointsSecurity/System
audit_mergeCRDT G-Set multi-node log merging & total order linearizationSystem Admin
audit_verifyPure offline chain, HMAC, and signature verifierTooling
audit_exportJSON, OSCAL evidence maps, Syslog/Wazuh CEF exportersTooling
audit_archiveCold storage log segmentation & WORM export helperTooling

Quickstart & Examples

1. Start the Audit Service (audit_core)

{PubKey, PrivKey} = audit_crypto:generate_keypair(),
MacKey = audit_crypto:generate_mac_key(),

{ok, _Pid} = audit_core:start_link(#{
    node_id     => <<"node-datacenter-1">>,
    boot_time   => erlang:system_time(millisecond),
    mac_key     => MacKey,
    sec_keypair => {PubKey, PrivKey}
}).

2. Submit Application Audit Events (audit_client)

% Standard application event
ok = audit_client:log(
    application,
    <<"user_session_101">>,
    login,
    <<"/api/v1/auth">>,
    authenticate,
    success,
    #{<<"ip">> => <<"10.0.4.2">>}
).

% Critical event requiring ECDSA P-384 signature & RFC 3161 timestamp
ok = audit_client:log_critical(
    security,
    <<"sec_admin">>,
    cert_issuance,
    <<"CA-Root-2026">>,
    issue_certificate,
    success,
    #{<<"dn">> => <<"CN=SysAdmin">>}
).

3. Generate & Verify Signed Checkpoints

% Retrieve checkpoint from active log
Checkpoint = audit_core:get_checkpoint(),

% Verify signature offline using Security Admin public key
true = audit_checkpoint:verify(Checkpoint, PubKey).

4. Multi-Node CRDT Log Merging (audit_merge)

% Merge log sets from Node A and Node B
LogSetA = audit_merge:add_node_log(audit_merge:new_log_set(), CheckpointA, RecordsA),
LogSetB = audit_merge:add_node_log(audit_merge:new_log_set(), CheckpointB, RecordsB),

MergedSet = audit_merge:merge(LogSetA, LogSetB),

% Verify entire multi-node log set
true = audit_merge:verify_merged(MergedSet, PubKey),

% Linearize into a deterministic global order
OrderedRecords = audit_merge:linearize(MergedSet).

5. Pure Offline Verification (audit_verify)

GenesisHash = audit_chain:genesis_hash(<<"node-datacenter-1">>, BootTime),

case audit_verify:verify_chain(Records, GenesisHash, MacKey, PubKey) of
    ok ->
        io:format("Chain integrity verified successfully!~n");
    {error, {tampered_record, Index, BadRecord}} ->
        io:format("Tampering detected at record #~p!~n", [Index])
end.

6. Export to Wazuh / SIEM Format (audit_export)

% Format record into Syslog / Wazuh CEF line
CEFLine = audit_export:to_siem(Record),

% Export records to JSON
JSONData = audit_export:to_json(Records).

Building & Testing

Compile the application:

rebar3 compile

Run EUnit unit tests:

rebar3 eunit --cover

Run Common Test integration suites:

rebar3 ct --cover

Run full suite with coverage report:

rebar3 do eunit, ct, cover

Documentation & Formal Specification

Detailed formal specifications, theoretical derivations, proofs, and NIST attestation matrices are located in:

Credits

  • Namdak Tonpa