2.4 Audit log, Trash and change safety
Mistakes happen, even to careful admins: the wrong subnet selected, a script with a bad filter, a colleague who thought a zone was unused. SpatiumDDI gives you three safety nets: confirmations that slow you down before a risky change, Trash to undo a deletion afterwards, and an audit log that records every change and can prove it hasn’t been altered.
This module covers all three, and their limits, which matter as much: a subnet in Trash takes its DNS names offline until a superadmin restores it, and forwarding to a SIEM is best-effort.
What you’ll learn
Section titled “What you’ll learn”- Delete through the two-step Danger zone, and restore a whole batch from Trash
- Know what Trash covers, what happens to DNS while something sits there, and how long it keeps things
- Read the audit log, refusals included, and prove that nobody has altered it
- Forward audit events to a SIEM, and know what “best-effort” means there
- Use change-safety habits: previews, typed confirmations, two-person approval and maintenance mode
Watch it first
Section titled “Watch it first”The video deletes a scratch subnet through the Danger zone, restores it from Trash, and then follows the whole story, including a refused request, in the audit log. The walkthrough repeats the clicks.
Transcript
0:00Module 2.4: the audit log, Trash, and change safety. Mistakes happen, even to careful admins. You'll delete something on purpose, bring it back, and then see how the audit log tells the whole story.
0:14Start with something that's safe to break: a scratch subnet in the campus block, 10.20.99.0/24, named Scratch.
0:25Now delete it, the way you'd delete anything important. Deleting lives on the “Danger zone” tab, behind two confirmations. The second one spells out exactly what happens: the subnet, its DHCP scopes and its reverse zone move to Trash, its DNS records stop resolving, and a superadmin can restore it all together for 30 days.
0:47Deleted items wait in Administration, Trash, with who deleted them and when. Everything removed by one action shares a batch. Restore the subnet, and SpatiumDDI first tells you how many rows come back with it, here its reverse zone and gateway. After the retention window, thirty days by default, a nightly sweep removes them for good.
1:09Back in IPAM, refresh the tree, and Scratch is where it was, with its addresses intact and their DNS records published again. A deletion that used to mean a restore from backup is now a two-click undo.
1:22Every change lands in the audit log: who did what, to which object, from which address, and whether it worked. Filter by resource type, and the top of the list tells our scratch subnet's story: created, moved to Trash, and restored.
1:38Refusals are recorded too: here's Jordan's denied attempt from module 2.1. Each entry is chained to the one before it by a hash, so any tampering breaks the chain, and this badge confirms it's intact. Export PDF gives auditors a report, and you can forward the log to your SIEM over syslog or a webhook.
1:59You've undone a deletion from Trash, and traced every step, including a refusal, in a log that proves it hasn't been altered. Next: keeping watch with dashboards, logs and alerts, and then the last safety net, backups.

Deleting on purpose: the Danger zone
Section titled “Deleting on purpose: the Danger zone”Deleting a subnet is deliberately slow. It lives on the Danger zone tab of the subnet’s Edit dialog, behind two confirmations:
- Delete this subnet… opens Delete Subnet, which explains the impact: addresses leased through DHCP are revoked along with their DDNS records, while manually allocated addresses go to Trash with the subnet, and their DNS records stop resolving until a superadmin restores it. Continue moves on.
- Delete subnet spells out what moves to Trash: the subnet, its DHCP scopes and any reverse zone created for it that no other subnet still uses. The DNS records published for its addresses stop resolving while it’s there, and a superadmin can restore everything together within 30 days, which publishes those records again. You tick “I understand … will be moved to Trash.” before Move to Trash is enabled.
IP spaces, blocks, DNS zones and records, and DHCP scopes (with their pools and static reservations) also go to Trash when you delete them, and so do customers, overlays and services when their Network modules are on. Individual IP addresses are the exception: they never go to Trash on their own. Deleting one from the UI can instead leave it in the subnet as an orphan, which you can restore later, or remove it for good. Choose Mark as Orphan if you might want it back, rather than Delete Permanently.
Administration → Trash lists soft-deleted objects, newest first, and only superadmins can open it: an IPAM Editor can move a subnet to Trash but can’t bring it back. Filter by Type, by Since (a date and time), or by name or CIDR, and set Order to Oldest first (purged first) to see what the purge removes next. Each row shows Type, Name / CIDR, Deleted at, Deleted by and Batch size, with two actions:
- Restore brings the object back, together with everything deleted with it: one delete stamps the parent and all its children with a single batch. Restoring a subnet brings back its addresses, its DHCP scopes and its reverse zone, and publishes its DNS records again; restoring a zone brings back its records. The confirmation says how big the batch is: for an empty Scratch subnet, “Restore 10.20.99.0/24 Scratch (Subnet) and the 2 other rows deleted with it?” (its reverse zone and its gateway’s PTR record).
- Delete removes the row permanently. After that, only a backup brings it back.
A row whose parent is still in Trash, such as a subnet whose block was deleted too, can’t come back on its own: the restore dialog offers to restore the parent first. If a live object now clashes with the one you’re restoring (say someone has already recreated the same CIDR), the dialog shows the conflict instead of overwriting anything. Resolve the clash and restore again: a subnet, zone or scope comes back whole or not at all. The one exception is a batch of DNS records deleted together in a bulk delete, where Restore the others brings back the records that don’t clash and then lists what stayed in Trash.
A nightly purge permanently removes whatever has been in Trash longer than the retention window, set under Settings → Data Retention → Trash: 30 days by default, up to 365, and 0 turns the purge off.
Scripts get the same safety net. The default DELETE on a subnet is a soft delete; only ?permanent=true, which needs a superadmin, takes the hard path, and that refuses a subnet that still holds addresses or scopes unless you add ?force=true.
What happens to DNS while a subnet is in Trash
Section titled “What happens to DNS while a subnet is in Trash”Moving a subnet to Trash withdraws the A, AAAA and PTR records SpatiumDDI published for its addresses, the gateway’s PTR included, and puts them in Trash in the same batch. In the Academy lab, the names stopped resolving within a couple of seconds, and Restore brought them back as quickly.
Records you created by hand are left alone, so to take a hand-made name out of service, delete or change the record itself. If someone recreates one of the withdrawn records by hand while the subnet sits in Trash, the restore refuses and names the record. On 2026.09.04-1 a trashed subnet’s names kept resolving until the purge, so update any runbook that relied on that.
The audit log
Section titled “The audit log”Every change writes an audit row in the same database transaction as the change itself, before the API answers. A change that isn’t audited doesn’t happen: an audit gap and a rolled-back write are the same event.
Administration → Audit Log shows Timestamp, User, Action, Resource, Summary, Result and IP, with a filter under every column except Timestamp. Each row also keeps the old and new values and the list of changed fields. Actions you’ll meet in this course:
| Action | Recorded when |
|---|---|
create, update, delete |
An object is created, changed or permanently deleted |
soft_delete, restore |
An object moves to Trash, or comes back (trashing a subnet also writes one for each DNS record it withdrew) |
login |
Anyone signs in, successfully or not, including unknown usernames |
bulk_allocate, dns-sync |
A bulk allocation, or an applied Sync DNS |
backup_created, backup_target_run_success, backup_restore_drill |
Backup work (module 2.6) |
write, access and others, with result denied |
The server refused a request for lack of permission; access on superadmin is a superadmin-only page (module 2.1) |
The Result column tells success from denied, and sign-ins record failure for a wrong password. A superadmin passes every permission check, so a superadmin’s requests never appear as permission denied rows; a refused password confirmation, or an attempt to remove the last superadmin, still writes one. Export PDF produces an auditor-facing report of the last 30 days of changes, grouped by user, resource and action.
Proving nothing was altered
Section titled “Proving nothing was altered”A log that the database administrator could quietly edit wouldn’t convince an auditor. SpatiumDDI’s audit log is append-only: database triggers block updates and deletes, and every row is hash-chained to the one before it.
The Chain verified badge at the top of the page re-checks the newest 1,000 rows each time you open the page; hover over it to see the range it covered. A break shows Tampering detected (N) instead. Scripts and monitoring can check the whole chain:
curl -s -H "Authorization: Bearer $TOKEN" "$SPATIUM/api/v1/audit/integrity"A healthy chain answers {"ok": true, "rows_checked": N, "breaks": [], "partial": false}, with the first_seq and last_seq it walked; add ?max_rows=1000&newest=true to run the badge’s check. The call needs a session or token whose owner may read the audit log. A nightly job checks the rows added since its last run, re-walks the whole chain about once a week, and opens a critical audit-chain-broken alert if it finds a break.
Forwarding to a SIEM
Section titled “Forwarding to a SIEM”An audit trail that lives only on the box it describes can be lost with the box. Settings → Audit Event Forwarding sends every audit row to targets you add:
| Kind | Options |
|---|---|
| Syslog | UDP, TCP or TLS; RFC 5424 with JSON (the default), CEF or LEEF; RFC 3164; or bare JSON lines |
| HTTP webhook | Generic JSON, or formatted for Slack, Microsoft Teams (a Workflows webhook URL) or Discord |
| Email (SMTP) | STARTTLS, SSL or plain, to a list of recipients |
Each target can filter by minimum severity and by resource type, and has a test action that sends a synthetic event; it proves the connection, not that alerts get through (module 2.5). The same targets deliver alerts, so one SIEM destination covers both. Credential-shaped fields in the forwarded old and new values arrive as [redacted].
Delivery is best-effort. Forwarding runs after the change commits, so a dead collector never blocks or rolls back a change, and one failing target doesn’t affect the others.
The flip side is that an event can be lost if a collector is down. If you need at-least-once delivery, point a webhook at a durable queue and let that be the store. Some rows written by scheduled background tasks may not forward in this release. The audit log itself stays in PostgreSQL and is never pruned.
Change-safety habits
Section titled “Change-safety habits”The tools only help if you use them. Habits that keep Ridgeline’s changes safe:
- Know which install you’re on. The environment banner from Lab 1 labels every page, the sign-in page included.
- Back up before anything risky. A manual backup takes seconds (module 2.6), and Trash doesn’t cover everything.
- Preview, then commit. Sync DNS shows exactly what it will change before Apply. Splitting, merging and resizing a subnet preview the result first, then make you type the CIDR back before they commit.
- Ask for a second pair of eyes. With the
governance.approvalsfeature module on (it’s off by default) and a matching approval policy enabled, deleting a subnet, block, IP space, DNS zone, DHCP scope or DHCP server group queues a change request instead. Another operator who has the Change Approver role and the permission the change needs approves it, from the Change Requests page; the audit log records both people. - Freeze writes during a change window. Settings → Security → Maintenance Mode makes every write return
503for everyone except superadmins. Reads keep working, and so do the agents, so DNS and DHCP keep serving. - Read the audit log afterwards. Filter on your own user and check that the rows match what you meant to do.
Hands-on lab
Section titled “Hands-on lab”Break it, restore it, prove it
You will:
- Create a scratch subnet with one host, and resolve the host's name
- Delete the subnet through the Danger zone, and see the name stop resolving
- Restore it from Trash, and see the name come back
- Trace the create, delete and restore in the audit log
Before you start: Finish Lab 3 first, so the campus block 10.20.0.0/16 exists. Sign in as admin: only a superadmin can restore from Trash. You need dig in a terminal, as in Lab 8.
-
Open IPAM, select the block
10.20.0.0/16, and click New Subnet. -
Enter the network
10.20.99.0/24and the nameScratch, and click Create. It inherits the block’s DNS settings, so SpatiumDDI also creates its reverse zone,99.20.10.in-addr.arpa. -
Open
10.20.99.0/24, click Allocate IP, choose Specific IP, and allocate10.20.99.10with the hostnamescratch-01. -
Resolve it. BIND9 answers
10.20.99.10:Terminal window dig @127.0.0.1 -p 1053 +short scratch-01.corp.example.edu -
With
10.20.99.0/24open, click Edit, open the Danger zone tab, and click Delete this subnet…. -
In Delete Subnet, read what happens to leased and manual addresses, and click Continue.
-
In Delete subnet, read what moves to Trash, tick “I understand …” and click Move to Trash.
-
Run the same
digagain. Within a couple of seconds it prints nothing: moving the subnet to Trash withdrew the record. Without+short, the answer’s header showsstatus: NXDOMAIN. -
Open Administration → Trash. The subnet’s batch holds five rows: the subnet, its reverse zone and three DNS records (
scratch-01’s A and PTR, and the gateway’s PTR). Click Restore on10.20.99.0/24 Scratch; the dialog says how many other rows come back with it. Click Restore to confirm. -
Open IPAM and click Refresh IP spaces, the refresh icon above the tree.
10.20.99.0/24is back in the campus block, withscratch-01. -
Run the
digonce more. BIND9 answers10.20.99.10again. -
Open Administration → Audit Log and set the filter under Resource to
subnet. The newest10.20.99.0/24rows showcreate,soft_deleteandrestore, and the header shows Chain verified.
./lab/check.sh 9Knowledge check
Section titled “Knowledge check”Go deeper
Section titled “Go deeper”- IPAM §15.16, Soft delete and Trash: what’s soft-deletable, batches, DNS withdrawal and the purge
- System administration §0 and §2.7: the Trash page, restoring under a parent, data retention and the nightly chain check
- Trashing a subnet withdraws its DNS records (#1906): why the behavior changed in 1.0.0-beta.1
- Observability §5: the audit log, forwarding targets, formats, redaction and delivery guarantees
- Data model: audit log: the hash chain and what each row records
- Troubleshooting: subnet delete is refused: the permanent-delete path and
force=true - System administration §5: maintenance mode and its exempt paths
- Permissions: Change Approver: two-person approval and the
change_requestresource