Audit & compliance.
Last updated
Audit log
What it is. A complete, tamper-evident record of everything that happens — logins, query submissions and decisions, datasource changes, channel edits. It's your answer to "who did what, when" for security reviews and compliance. Records are append-only and cryptographically chained, so a deleted or altered entry is detectable after the fact (query result data is never stored).
What makes the AccessFlow audit log tamper-evident?
Every row is append-only and carries an HMAC-SHA256 hash chained to the row before it, so altering or deleting any entry breaks the chain and is detectable. The database role the application uses has no UPDATE or DELETE privilege on the table — a separate writer role only inserts.
Configure it. Nothing to switch on — it captures automatically. Review it
at /admin/audit-log:
/admin/audit-log — filter, paginate, verify the HMAC chain, and export to CSV.- Filter and search. Narrow by action, resource type, actor user id, or resource id; an optional start/end date pair scopes the window.
- Verify chain. The Verify chain button re-walks every row's HMAC link in order and surfaces the first mismatch — useful as a recurring auditor check.
- Export CSV. Streams the current filter as RFC 4180 CSV with the same columns shown in the UI. Long-running exports respect the same query budget as the table view (use date filters to keep them bounded).
Tune it. The chain-signing key defaults to a per-deployment value derived
from ENCRYPTION_KEY; set AUDIT_HMAC_KEY (hex, ≥ 32 bytes)
explicitly when you want to manage or rotate it yourself. Inserts run through a dedicated
AUDIT_DB_USER / AUDIT_DB_PASSWORD role that has no UPDATE / DELETE
rights on the log.
Audit sinks (SIEM & WORM streaming)
What it is. External audit sinks stream the tamper-evident audit log to the systems your SOC already watches — a SIEM, a syslog collector, your own HTTPS endpoint — and archive it to write-once (WORM) object storage. Delivery is at-least-once off a durable per-sink cursor: a slow or dead destination never blocks audit writes, and each sink retries forever with backoff, so nothing is lost while a receiver is down (receivers de-duplicate on the immutable event id). Every streamed event carries its hash-chain links, so an exported window can be verified independently of the database.
Configure it. Manage sinks at /admin/audit-sinks (requires
the AUDIT_SINK_MANAGE permission; admins hold it). Pick one of four types —
secret fields are write-only: encrypted at rest and shown masked as
******** afterwards:
- Splunk HEC —
url(the full HTTP Event Collector endpoint) andtoken(masked); optionalindexandsource. - Syslog / CEF —
host,port, andprotocol(TCPorTLS; TLS validates against the system truststore — there is deliberately no skip-verify option). Events arrive as RFC 5424 syslog frames carrying CEF. - Signed HTTPS batches —
urlandsecret(masked). Batches are JSON arrays signed with the sameX-AccessFlow-SignatureHMAC-SHA256 contract as webhook notifications. - S3 Object Lock (WORM) —
bucket,region,access_key_id,secret_access_key(masked), andretention_days; optionalprefix, custom S3-compatibleendpoint,retention_mode(COMPLIANCE, the immutable default, orGOVERNANCE), andsegment_max_age. Audit rows are written as periodic JSONL segments under an Object Lock retention, each with a sibling.sigdigital signature you can verify offline against the published signing certificate.
The list shows per-sink delivery health — cursor position, last success, last error, consecutive failures, next retry, and how many events the sink is behind — and a Test button that synchronously pushes one synthetic event through the sink (for S3 it uploads a small unlocked test object, so trying a sink never creates immutable data).
Tune it. ACCESSFLOW_AUDIT_SINKS_DRAIN_INTERVAL (streaming
cadence, default PT30S), ACCESSFLOW_AUDIT_SINKS_BATCH_SIZE
(rows per delivery, default 500), and
ACCESSFLOW_AUDIT_SINKS_MAX_BATCHES_PER_TICK (per-sink catch-up cap per
tick, default 5).
aws s3api create-bucket
--object-lock-enabled-for-bucket) — Object Lock cannot be enabled on an existing
plain bucket — and the IAM principal needs s3:PutObject and
s3:PutObjectRetention. COMPLIANCE mode is immutable for
everyone until the retention expires; GOVERNANCE allows privileged
override.
Compliance reports & signed exports
What it is. Ready-made compliance reporting with audit-grade exports. Two pre-built reports answer common auditor questions over a chosen period: classified-data access (which executed queries touched PII / PCI / PHI / GDPR / FINANCIAL / SENSITIVE data, joined to your data-classification tags) and a regulatory audit trail of DDL / DELETE operations with the approvers' names. Use it to hand a regulator or internal auditor evidence they can verify themselves.
Configure it. Build and export reports from the compliance dashboard at
/admin/auditor — open to the read-only AUDITOR role and to
admins. Each report exports as a digitally signed PDF or CSV that an
auditor can verify offline against the public key at
/api/v1/admin/compliance/signing-certificate; every export is itself recorded
in the audit log with its content hash, so it's tamper-evident
end to end.
Tune it. ACCESSFLOW_COMPLIANCE_MAX_REPORT_PERIOD (largest
window, default P366D) and ACCESSFLOW_COMPLIANCE_MAX_ROWS (row
cap before a report is marked truncated, default 50000). Signing reuses
JWT_PRIVATE_KEY — no extra secret required.
/admin/auditor — the read-only Auditor role builds and signs compliance reports over the immutable query snapshots.Data lifecycle & right-to-erasure
Admin. Define retention/erasure rules at
/admin/lifecycle/policies — per datasource, target a table / column set /
classification tag with a retention window (ISO-8601, e.g. P30D or
P7Y) plus arbitrary conditions (a structured, parameter-bound
predicate builder and a JSqlParser-validated raw-WHERE escape hatch — SQL
datasources only) and an action: hard-delete, soft-delete,
or pseudonymize (salted SHA-256 / format-preserving / tokenization), with an
optional cron schedule. A dry-run preview reports impact
without executing. The scan job stages eligible work (honouring the cron); tune it with
ACCESSFLOW_LIFECYCLE_POLICY_SCAN_INTERVAL (default PT1H). Staged
runs now execute automatically through the proxy —
ACCESSFLOW_LIFECYCLE_POLICY_EXECUTION_INTERVAL (default PT5M).
Any user can file a right-to-erasure request at
/lifecycle/erasure using the same rich configuration (subject
identifier and/or target table + conditions). It flows through AI-assisted scope detection
and review-plan-based peer review: any eligible REVIEWER or
admin reviews it at /lifecycle/erasure-reviews (per the datasource review plan,
multi-stage; the submitter can never approve their own), and stale reviews auto-reject via
ACCESSFLOW_LIFECYCLE_REVIEW_TIMEOUT (default PT168H). Approved
requests are executed through the proxy — soft-deleted rows vanish from reads,
DELETEs become marker updates, aged PII resolves to an irreversible salted hash
at read time — with tamper-evident proof-of-deletion audit records and a
retention-adherence compliance export. Tune the executor with
ACCESSFLOW_LIFECYCLE_ERASURE_EXECUTION_INTERVAL (default PT1M).
Personalized dashboard & weekly digest
The default post-login home (/dashboard) is self-scoped — every user sees
only their own data, no admin role required: pending approvals as a reviewer, their recent
queries with status/risk trend sparklines, an AI optimization-suggestion backlog they can
dismiss or open in the editor, and their own behavioural-anomaly alerts. Widgets are
customizable (show/hide, collapse, drag-and-drop reorder) and persist per browser. Users can
export the week's summary as a digitally signed PDF/CSV on demand, and opt
in to a weekly email digest delivered to their email and any configured chat
channels. The digest job is clustered-safe; tune it with
ACCESSFLOW_DASHBOARD_WEEKLY_DIGEST_POLL_INTERVAL (how often the job wakes,
default P1D) and ACCESSFLOW_DASHBOARD_WEEKLY_DIGEST_PERIOD (minimum
gap between digests per user, default P7D).