Outcome
By the end of this lesson, you will be able to query the audit log for specific events and explain what is captured in request and response bodies.
| Prerequisites | L1-L4 |
| Time | 11 minutes |
1. Concept
The audit log is the complete record of every action in ZopNight that changed anything.
Every request that creates, updates or deletes is captured on the way through, with both what was asked for and what came back. Entries appear immediately, kept separately per organisation, and are written to permanent storage every minute.
Three things rest on it: the evidence a SOC 2 or ISO 27001 audit asks for, answering “who did this”, and piecing together what happened after the fact.
What gets logged
EVENT CLASS LOGGED? BODY CAPTURED?─────────────────────────────────────────────────────────────────────Schedule created / updated / deleted Yes YesOverride applied / cancelled Yes YesAuto-remediation triggered Yes YesManual start / stop Yes YesGroup created / updated / member changed Yes YesResource attached / detached from schedule Yes YesCloud account connected / updated / deleted Yes No (whole body dropped)Notification channel changed Yes No (whole body dropped)RBAC role / policy changed Yes YesSAML / OAuth config changed Yes YesDashboard mutations Yes YesMCP tool call, read or write Yes Request only for readsDiscovery sync run (success/failure) No N/AREST read operations (GET) No N/AEvery mutation is captured. REST reads are not (the volume would be enormous and read access is already restricted by RBAC). MCP is the exception: every MCP tool call is audited, reads included, with source mcp, so you can see exactly what an assistant looked at and did. Discovery syncs are background jobs, not API requests, so they do not appear here.
What the log entry looks like
AUDIT LOG ENTRY─────────────────────────────────────────────────────────Timestamp: 2026-05-19 14:23:47 UTCOrg ID: org_abc123User: jane@zopcloud.com (api_key_xxx)Method: POSTPath: /orgs/org_abc123/overridesStatus: 201 CreatedLatency: 87ms
REQUEST BODY:{ "resourceUid": "i-0abc123", "targetName": "demo-api-1", "action": "force_on", "reason": "Acme Corp demo Sat 2pm", "expiresAt": "2026-05-26T08:00:00Z"}
RESPONSE BODY:{ "id": "ov_5678", "status": "active", "created_at": "2026-05-19T14:23:47Z"}The audit log is rich enough to reconstruct any past mutation. The request body shows what the user asked for; the response shows what ZopNight returned. Both together pinpoint the exact event.
Sensitive data redaction
Secrets are kept out of storage in two ways:
WHERE THE SECRET IS WHAT IS STORED─────────────────────────────────────────────────────────REST calls under cloud-accounts, connect, The row (who, when, path,integrations, ai, app-secrets, basic-auth, status), with NO body at alland notifications/channelsMCP tool calls The body, with each secret field replaced by [REDACTED]REST has no per-field list of which values are secret, so for those paths the whole body is dropped. MCP tools declare their secret fields, so only those values are replaced, except that an MCP call that touches one of the paths above has its whole body dropped too, just like REST. That is why a notification channel’s Slack token, signing secret or webhook URL never reaches the audit log: the request and the response are both left out. One thing is NOT masked: the user’s email is stored in full. Treat access to the audit log accordingly.
The redaction is at storage time, not at view time. There is no way to retrieve a dropped or redacted value through the audit log.
Querying the audit log
The Audit Log page exposes filters:
FILTERS─────────────────────────────────────────────────────────Time range: [Last 7 days ▾] or custom rangeMethod: [Any ▾] POST / PUT / PATCH / DELETEResource: [Any path ▾] /schedules /overrides /resources etc.Status: [Any ▾] success / failureUser: [Any user ▾]Source: [Any ▾] ui / api / mcpSearch: [free-text] searches request and response bodies
Sort by: Timestamp (default), latency, statusA typical query: “all override creations by jane@zopcloud.com in the last 30 days”: three filters, results in seconds.
Server-side filtering and pagination
Audit logs are large at scale. The Audit Log page uses server-side filtering and numbered pages, with a page-size selector.
For programmatic access:
# Pull last 7 days of override events to JSONcurl -s "https://api.zop.dev/audit-logs?method=POST&resource=overrides&startDate=2026-05-13&endDate=2026-05-20&page=1&size=50" \ -H "Authorization: Bearer ${PAT}" \ > overrides_last_week.jsonThe same query that the UI runs is available as an API call. Useful for exporting to SIEM, building custom dashboards, or audit evidence collection.
Common query patterns
PATTERN 1: "Who created this schedule?" Filter: method=POST, resource=schedules, search=business-hours-eu Returns: the create event with user, timestamp, full request body.
PATTERN 2: "All overrides in the last quarter" Filter: method=POST, resource=overrides, startDate=2026-02-01, endDate=2026-04-30 Returns: list of all override creations with reason, expiry, target.
PATTERN 3: "Failed actions from yesterday" Filter: status=failed, startDate=2026-05-19, endDate=2026-05-20 Returns: every mutating call that returned an error. Useful for debugging.
PATTERN 4: "Changes to roles" Filter: resource=roles, method=POST,PUT,PATCH,DELETE Returns: every role create, edit and delete. Audit-relevant.The audit log is a relational queryable surface. The right query gives the right answer in seconds.
Compliance use
For SOC 2 / ISO 27001 audits, the audit log produces evidence:
AUDITOR QUESTION EVIDENCE FROM AUDIT LOG─────────────────────────────────────────────────────────────────────"Who can create overrides?" Query: all override creations last 12 months. List of users."How are SAML config changes controlled?" Query: SAML config mutations. Show: which users (Admin only)."How do you track who started/stopped Query: manual start/stop events. production resources?" User, timestamp, justification."What's your auditable history of Query: rotation events for credential rotations?" cloud accounts. Show monthly."Show me 3 examples of approval-gated Query: auto-remediation events changes." with approval. Random sample.Every question maps to a query. Every query returns reproducible evidence. The auditor can run the same queries (with appropriate access) and verify.
Export and long-term retention
STEP WHAT HAPPENS─────────────────────────────────────────────────────────Filter Narrow the Audit Logs page to the window and actions you needExport Start a CSV export of the filtered viewexport.ready When the export finishes, this notification carries a signed download link (it is also emailed)Archive Store the CSV in your own archiveThere is no built-in export to S3 or GCS and no customer-facing event stream. If a regulation asks for years of retention, keep the CSV exports in storage you control. Redis Streams are internal transport only: entries are written there first and synced to the database every minute.
Performance
The Redis Streams + MySQL design balances real-time visibility with durable storage:
WRITE LATENCY <10ms (Redis Stream)SYNC TO MySQL Every 60 secondsQUERY LATENCY (UI) <100ms typicalQUERY LATENCY (API) <500ms with paginationDATA SIZE Mid-size org: ~50 MB/month, ~600 MB/yearAt scale (1,000+ resources, 10,000+ schedule firings per day), the audit log volume grows but stays queryable. Server-side filtering avoids full-table scans.
2. Demo
A compliance audit walked through:
SECURITY ASKS: "How do you control who can rotate cloud account credentials? Show me last quarter's rotations."
T+0 Auditor opens the Audit Log page.
T+30 sec Filter: path under /cloud-accounts method = POST from = 2026-02-01 to = 2026-04-30
T+45 sec Result: 7 rotation events in the period.
T+1 min For each event: - User who initiated (Admin in all cases: RBAC enforced) - Cloud account rotated - Timestamp - Success status
T+2 min Click into one event. There is no body: calls under /cloud-accounts never store one, so a credential cannot leak here. The row's user, path, status and timestamp are the evidence.
T+3 min Auditor copies the URL of the filtered view + screenshot of the 7 events. Adds to compliance evidence package.
T+5 min Compliance evidence collected. Auditor satisfied: rotations are Admin-only, audit-logged, with full body context.Five minutes to produce audit evidence that would take hours from raw logs.
3. Hands-on (7 min)
1. Open the Audit Log page.2. Filter to the last 7 days, method=POST.3. Browse the events: note the diversity of paths (schedules, overrides, resources, etc.).4. Click into one event. Read the request and response body.5. Try a more specific filter: - Filter to your own user (or a sample user) - See all your recent mutations6. Use the search field to find a specific event by name (e.g., search for a schedule name).7. For audit prep: try to answer "Who modified the RBAC role 'Editor' in the last 90 days?" via filters.
If the answer is "no one": that's also useful evidence (nounauthorized RBAC changes).4. Knowledge check
Q1
The Audit Log captures:
A. All of the actions, including every single one of the read calls that are made
B. Only critical actions
C. Only failed actions
D. All mutating API calls (POST, PUT, PATCH, DELETE) with bodies, plus every MCP tool call
Show answer
Correct: D. REST reads (GET) are not logged (volume too high, read access already RBAC-restricted). MCP tool calls are the exception: they are audited, reads included, with source mcp. Discovery syncs are not API calls and are not logged.
Q2
A REST request to connect a cloud account carries a credential in its body. The audit log stores:
A. The full credential value
B. The credential, encrypted
C. The request row (who, when, path, status) with the body omitted
D. The body, with [REDACTED] written into the credential field only
Show answer
Correct: C. Calls under the cloud-accounts prefix never have their body stored, because REST has no per-field list of secrets and dropping the body is the only fail-closed choice. Field-level [REDACTED] is what MCP tool calls get. Either way the credential never reaches the log.
Q3
A SOC 2 auditor asks: “Show me three examples of approval-gated auto-remediations from last quarter.” The Audit Log approach is:
A. Manually inspect every single event in the whole of the log and then build the evidence pack by hand
B. Filter: path matches auto-remediation, method=POST, body contains approval reference, date range = last quarter
C. Generate a custom report
D. Wait for the next audit
Show answer
Correct: B. Return random sample of 3. The query produces reproducible evidence in seconds. Filter-based queries are the canonical way to produce audit evidence. Reproducible (auditor can re-run) and fast (seconds to results).
5. Apply
The audit log surface:
- Audit Logs page: filterable, paginated UI
- Audit API: same data, programmatic access
- CSV export: export the filtered view; the
export.readynotification carries the download link. Store exports in your own archive for long-term retention
For deeper coverage of audit-as-evidence patterns, see the Architect track’s audit logging module.
Module quiz
You have now completed all six lessons of M1.6. Take the module quiz: 10 questions, 80% to pass.
What’s next
M1.7: Red Hat OpenShift (ROSA). After it comes M1.8, the capstone.