3.4 KiB
Introduction
Similar to the approach described in CASSANDRA-12151, we add the concept of an audit specification. An audit has a target (syslog or a table) and a set of events/actions that it wants recorded. We introduce new CQL syntax for Scylla users to describe and manipulate audit specifications.
Prior art:
- Microsoft SQL Server audit description
- pgAudit docs
- MySQL audit_log docs in MySQL and Azure
- DynamoDB can use CloudTrail to log all events
CQL extensions
Create an audit
CREATE AUDIT [IF NOT EXISTS] audit-name WITH TARGET { SYSLOG | table-name }
[ AND TRIGGER KEYSPACE IN (ks1, ks2, ks3) ]
[ AND TRIGGER TABLE IN (tbl1, tbl2, tbl3) ]
[ AND TRIGGER ROLE IN (usr1, usr2, usr3) ]
[ AND TRIGGER CATEGORY IN (cat1, cat2, cat3) ]
;
From this point on, every database event that matches all present triggers will be recorded in the target. When the target is a table, it behaves like the current design.
The audit name must be different from all other audits, unless IF NOT EXISTS precedes it, in which case the existing audit must be identical to the new definition. Case sensitivity and length limit are the same as for table names.
A trigger kind (ie, KEYSPACE, TABLE, ROLE, or CATEGORY) can be
specified at most once.
Show an audit
DESCRIBE AUDIT [audit-name ...];
Prints definitions of all audits named herein. If no names are provided, prints all audits.
Delete an audit
DROP AUDIT audit-name;
Stops logging events specified by this audit. Doesn't impact the already logged events. If the target is a table, it remains as it is.
Alter an audit
ALTER AUDIT audit-name WITH {same syntax as CREATE}
Any trigger provided will be updated (or newly created, if previously
absent). To drop a trigger, use IN *.
Permissions
Only superusers can modify audits or turn them on and off.
Only superusers can read tables that are audit targets; no user can modify them. Only superusers can drop tables that are audit targets, after the audit itself is dropped. If a superuser doesn't drop a target table, it remains in existence indefinitely.
Implementation
Efficient trigger evaluation
namespace audit {
/// Stores triggers from an AUDIT statement.
class triggers {
// Use trie structures for speedy string lookup.
optional<trie> _ks_trigger, _tbl_trigger, _usr_trigger;
// A logical-AND filter.
optional<unsigned> _cat_trigger;
public:
/// True iff every non-null trigger matches the corresponding ainf element.
bool should_audit(const audit_info& ainf);
};
} // namespace audit
To prevent modification of target tables, audit::inspect() will
check the statement and throw if it is disallowed, similar to what
check_access() currently does.
Persisting audit definitions
Obviously, an audit definition must survive a server restart and stay consistent among all nodes in a cluster. We'll accomplish both by storing audits in a system table.