You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
## Summary
This PR makes additional improvements to platform-wide querying
performance, adjusts the clickhouse audit log schema to use the correct
timestamp for the request, adds support for querying by the user's UID,
and adjusts the user-scoped projection to use the user's UID value
instead of the username.
## Details
- **Filter by User's UID** - Filtering by UID can be valuable to filter
down to a specific user using a stable identifier instead of an email
which can be changed by the user. UIDs are also only in place for users
of the platform. Internal components that authenticate with certificates
do not have UIDs. This gives us a clean way of filtering out internal
components from audit logs.
- **Request Received Timestamp** - I swapped to using the
`.requestReceivedTimestamp` field of the audit log to represent the
audit log's timestamp since it's the timestamp when the request was
received by the apiserver. The `.stageTimestamp` is used by the
collection pipeline to calculate delays in the pipeline because the
timestamp indicates when the audit log was generated by the apiserver.
- **User UID for user scope** - I swapped to using the user's UID as the
filtering / sorting column when querying the audit log system through
the user scope since the UID is the stable identifier for the user and
is the value that's provided in the user's extra information.
- **Hourly timestamp buckets** - Updated all projections to use the same
hourly time bucketing introduced in #23.
---
Relates to datum-cloud/enhancements#536
Copy file name to clipboardExpand all lines: docs/api.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -78,7 +78,7 @@ _Appears in:_
78
78
| --- | --- | --- | --- |
79
79
|`startTime`_string_| StartTime is the beginning of your search window (inclusive).<br /><br />Format Options:<br />- Relative: "now-30d", "now-2h", "now-30m" (units: s, m, h, d, w)<br /> Use for dashboards and recurring queries - they adjust automatically.<br />- Absolute: "2024-01-01T00:00:00Z" (RFC3339 with timezone)<br /> Use for historical analysis of specific time periods.<br /><br />Examples:<br /> "now-30d" → 30 days ago<br /> "2024-06-15T14:30:00-05:00" → specific time with timezone offset |||
80
80
|`endTime`_string_| EndTime is the end of your search window (exclusive).<br /><br />Uses the same formats as StartTime. Commonly "now" for current moment.<br />Must be greater than StartTime.<br /><br />Examples:<br /> "now" → current time<br /> "2024-01-02T00:00:00Z" → specific end point |||
81
-
| `filter` _string_ | Filter narrows results using CEL (Common Expression Language). Leave empty to get all events.<br /><br />Available Fields:<br /> verb - API action: get, list, create, update, patch, delete, watch<br /> auditID - unique event identifier<br /> stageTimestamp - when this stage occurred (RFC3339 timestamp)<br /> user.username - who made the request (user or service account)<br /> responseStatus.code - HTTP response code (200, 201, 404, 500, etc.)<br /> objectRef.namespace - target resource namespace<br /> objectRef.resource - resource type (pods, deployments, secrets, configmaps, etc.)<br /> objectRef.name - specific resource name<br /><br />Operators: ==, !=, <, >, <=, >=, &&, \|\|, in<br />String Functions: startsWith(), endsWith(), contains()<br /><br />Common Patterns:<br /> "verb == 'delete'" - All deletions<br /> "objectRef.namespace == 'production'" - Activity in production namespace<br /> "verb in ['create', 'update', 'delete', 'patch']" - All write operations<br /> "responseStatus.code >= 400" - Failed requests<br /> "user.username.startsWith('system:serviceaccount:')" - Service account activity<br /> "objectRef.resource == 'secrets'" - Secret access<br /> "verb == 'delete' && objectRef.namespace == 'production'" - Production deletions<br /><br />Note: Use single quotes for strings. Field names are case-sensitive.<br />CEL reference: https://cel.dev | | |
81
+
| `filter` _string_ | Filter narrows results using CEL (Common Expression Language). Leave empty to get all events.<br /><br />Available Fields:<br /> verb - API action: get, list, create, update, patch, delete, watch<br /> auditID - unique event identifier<br /> requestReceivedTimestamp - when the API server received the request (RFC3339 timestamp)<br /> user.username - who made the request (user or service account)<br /> user.uid - unique user identifier (stable across username changes)<br /> responseStatus.code - HTTP response code (200, 201, 404, 500, etc.)<br /> objectRef.namespace - target resource namespace<br /> objectRef.resource - resource type (pods, deployments, secrets, configmaps, etc.)<br /> objectRef.name - specific resource name<br /><br />Operators: ==, !=, <, >, <=, >=, &&, \|\|, in<br />String Functions: startsWith(), endsWith(), contains()<br /><br />Common Patterns:<br /> "verb == 'delete'" - All deletions<br /> "objectRef.namespace == 'production'" - Activity in production namespace<br /> "verb in ['create', 'update', 'delete', 'patch']" - All write operations<br /> "responseStatus.code >= 400" - Failed requests<br /> "user.username.startsWith('system:serviceaccount:')" - Service account activity<br /> "user.uid == '550e8400-e29b-41d4-a716-446655440000'" - Specific user by UID<br /> "objectRef.resource == 'secrets'" - Secret access<br /> "verb == 'delete' && objectRef.namespace == 'production'" - Production deletions<br /><br />Note: Use single quotes for strings. Field names are case-sensitive.<br />CEL reference: https://cel.dev | | |
82
82
|`limit`_integer_| Limit sets the maximum number of results per page.<br />Default: 100, Maximum: 1000.<br /><br />Use smaller values (10-50) for exploration, larger (500-1000) for data collection.<br />Use continue to fetch additional pages. |||
83
83
|`continue`_string_| Continue is the pagination cursor for fetching additional pages.<br /><br />Leave empty for the first page. If status.continue is non-empty after a query,<br />copy that value here in a new query with identical parameters to get the next page.<br />Repeat until status.continue is empty.<br /><br />Important: Keep all other parameters (startTime, endTime, filter, limit) identical<br />across paginated requests. The cursor is opaque - copy it exactly without modification. |||
84
84
@@ -96,7 +96,7 @@ _Appears in:_
96
96
97
97
| Field | Description | Default | Validation |
98
98
| --- | --- | --- | --- |
99
-
|`results`_Event array_| Results contains matching audit events, sorted newest-first.<br /><br />Each event follows the Kubernetes audit.Event format with fields like:<br /> verb, user.username, objectRef.\{namespace,resource,name\}, stageTimestamp,<br /> responseStatus.code, requestObject, responseObject<br /><br />Empty results? Try broadening your filter or time range.<br />Full documentation: https://kubernetes.io/docs/reference/config-api/apiserver-audit.v1/|||
99
+
|`results`_Event array_| Results contains matching audit events, sorted newest-first.<br /><br />Each event follows the Kubernetes audit.Event format with fields like:<br /> verb, user.username, objectRef.\{namespace,resource,name\}, requestReceivedTimestamp,<br /> stageTimestamp, responseStatus.code, requestObject, responseObject<br /><br />Empty results? Try broadening your filter or time range.<br />Full documentation: https://kubernetes.io/docs/reference/config-api/apiserver-audit.v1/|||
100
100
|`continue`_string_| Continue is the pagination cursor.<br />Non-empty means more results are available - copy this to spec.continue for the next page.<br />Empty means you have all results. |||
101
101
|`effectiveStartTime`_string_| EffectiveStartTime is the actual start time used for this query (RFC3339 format).<br /><br />When you use relative times like "now-7d", this shows the exact timestamp that was<br />calculated. Useful for understanding exactly what time range was queried, especially<br />for auditing, debugging, or recreating queries with absolute timestamps.<br /><br />Example: If you query with startTime="now-7d" at 2025-12-17T12:00:00Z,<br />this will be "2025-12-10T12:00:00Z". |||
102
102
|`effectiveEndTime`_string_| EffectiveEndTime is the actual end time used for this query (RFC3339 format).<br /><br />When you use relative times like "now", this shows the exact timestamp that was<br />calculated. Useful for understanding exactly what time range was queried.<br /><br />Example: If you query with endTime="now" at 2025-12-17T12:00:00Z,<br />this will be "2025-12-17T12:00:00Z". |||
// Provide helpful suggestions for common fields that aren't filterable
390
-
return"", fmt.Errorf("field '%s.%s' is not available for filtering. Available fields: auditID, verb, stageTimestamp, objectRef.apiGroup, objectRef.namespace, objectRef.resource, objectRef.name, user.username, user.groups, responseStatus.code", baseObject, field)
395
+
return"", fmt.Errorf("field '%s.%s' is not available for filtering. Available fields: auditID, verb, requestReceivedTimestamp, objectRef.apiGroup, objectRef.namespace, objectRef.resource, objectRef.name, user.username, user.uid, user.groups, responseStatus.code", baseObject, field)
0 commit comments