Recording That Passes an Audit: Exemptions, Retention and the Evidence Trail
Compliance recording isn’t “turn recording on.” It’s being able to answer, months later, questions like: was this specific call recorded? why not? where is it now? can you produce it, and prove it wasn’t altered?
RustPBX’s recording pipeline is built to make those answers routine. Here’s the operational playbook.
Start With the Policy, Not the Switch
The master switch is simple:
[recording]
enabled = true
type = "local" # local | http | s3 | sipflow
auto_start = true
What matters is where exceptions live:
- Per-trunk — record only carrier-facing traffic, or exclude a partner whose jurisdiction forbids it
- Per-app exemptions — list routed applications that must opt out (the “agent pauses recording for card numbers” pattern)
- Because these are config, they go through Git: the audit answer to “which calls are not recorded, and why” is a commit diff, not tribal knowledge
Segments Are the Unit of Evidence
A call is not one artifact. A consult transfer is two conversations; hold/resume changes context. Recording produces per-segment files, each with its own id and metadata, all linked to the same session_id.
That property is what makes selective production possible: hand the auditor the exact segment where the disputed statement occurred, not a 40-minute call with a timestamp they have to trust.
Storage That Won’t Lose Evidence
- Upload retry worker — a failed upload retries with backoff. Nothing is silently dropped because an object store hiccuped.
- Presigned downloads — evidence is produced via time-limited URLs; the console never proxies large media, and access is logged.
- Lifecycle rules — retention lives in object storage policy (e.g., 180/360 days), where it’s auditable independently of the PBX.
- Archive addon — long-term retention exports for programs that outlive hot storage.
The Three-Channel Evidence Model
For a thorough program, don’t rely on audio alone:
| Channel | Proves |
|---|---|
| Recording (audio) | What was said |
| SipFlow (signaling + RTP) | What was signaled, when, to whom — independent of the recorder |
| CDR (structured) | Route, timings, hangup cause, media quality, session id |
All three key off session_id, so a single call reconciles into one story. If a recording is disputed, the signaling capture and CDR corroborate it — and vice versa. This triangulation is what turns “we have recordings” into “we can demonstrate the record is complete.”
Retention Without Guesswork
- Decide retention per channel (audio vs. packets vs. records) — they have different sizes and lifetimes
- Keep exports (CSV/archives) for the structured record; keep objects for media
- Document the clock: all nodes on NTP, because timestamps are part of the evidence
- Test restoration annually — an archive never restored is a hope, not a plan
A Compliance Runbook Skeleton
- Define what must be recorded and what must not (per trunk/app), in config under Git
- Capture with per-segment recording + SipFlow always-on
- Store with retry, presigned access, and object-storage lifecycle
- Reconcile any call: CDR → segments → SipFlow ladder
- Produce evidence via presigned URLs with access logging
- Prove integrity: exports, timestamps, and the config history
Guides: Operations Manual, Basic Setup → Storage, and the SipFlow addon.