Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Cassandra Audit Logging

Audit logging provides a detailed record of database activity for security monitoring, compliance, and forensic analysis. Introduced in Cassandra 4.0, the audit logging feature captures authentication attempts, authorization decisions, and CQL operations.


FeatureMinimum Version
Basic audit logging4.0
Full query logging (FQL)4.0
Enhanced audit logging4.1+

Pre-4.0 Clusters

Cassandra versions prior to 4.0 do not have built-in audit logging. Third-party solutions or custom implementations using triggers/CDC are required for audit capabilities in older versions.

Audit logging can capture:

CategoryEventsUse Case
AuthenticationLogin attempts, failuresSecurity monitoring
AuthorizationPermission checks, denialsAccess control auditing
DCLGRANT, REVOKE, role changesPrivilege management
DDLCREATE, ALTER, DROP schemaChange management
DMLSELECT, INSERT, UPDATE, DELETEData access auditing
QueryAll CQL statementsCompliance, debugging
Audit event path from CQL handler to audit destinationsAudit event path from CQL handler to audit destinationsCassandra NodeAudit DestinationsCQL HandlerAudit LoggerInclude/ExcludeFiltersLog File(BinAuditLogger)Syslog(remote)Custom LoggerClientCQL queryLog event

Configure audit logging in cassandra.yaml:

cassandra.yaml
# Enable audit logging
audit_logging_options:
enabled: true
logger:
- class_name: BinAuditLogger
# Categories to audit
included_categories: AUTH,DCL,DDL,DML
# Keyspaces to audit (empty = all)
included_keyspaces:
# Keyspaces to exclude from auditing
excluded_keyspaces: system,system_schema,system_auth,system_distributed,system_traces,system_views
# Users to audit (empty = all)
included_users:
# Users to exclude from auditing
excluded_users:
CategoryDescriptionEvents Captured
AUTHAuthentication eventsLogin success/failure, authentication errors
DCLData Control LanguageGRANT, REVOKE, CREATE/ALTER/DROP ROLE
DDLData Definition LanguageCREATE/ALTER/DROP KEYSPACE/TABLE/INDEX/VIEW/TYPE/FUNCTION
DMLData Manipulation LanguageSELECT, INSERT, UPDATE, DELETE, BATCH
QUERYAll queriesEvery CQL statement (high volume)
PREPAREPrepared statementsPREPARE operations
ERRORQuery errorsFailed queries, syntax errors
audit_logging_options:
enabled: true
logger:
- class_name: BinAuditLogger
# Top-level BinAuditLogger settings (not under logger.parameters)
audit_logs_dir: /var/log/cassandra/audit
roll_cycle: HOURLY
block: true
max_queue_weight: 268435456 # 256 MB
max_log_size: 17179869184 # 16 GB
archive_command: /usr/local/bin/archive-audit-logs.sh %path
# Recommended: Don't log DML for high-throughput tables
included_categories: AUTH,DCL,DDL
# Exclude system keyspaces
excluded_keyspaces: system,system_schema,system_auth,system_distributed,system_traces,system_views,system_virtual_schema
# Exclude service accounts from routine logging
excluded_users: monitoring_user,backup_user

BinAuditLogger Configuration

BinAuditLogger settings (roll_cycle, block, max_queue_weight, max_log_size, archive_command) are top-level fields under audit_logging_options, not under logger.parameters. The logger.parameters section only supports key_value_separator and field_separator for output formatting.


Binary format logger optimized for performance:

audit_logging_options:
enabled: true
logger:
- class_name: BinAuditLogger
# BinAuditLogger settings are top-level, not under logger.parameters
audit_logs_dir: /var/log/cassandra/audit
roll_cycle: HOURLY
block: true
max_queue_weight: 268435456
max_log_size: 17179869184

Parameters (top-level under audit_logging_options):

ParameterDefaultDescription
audit_logs_dir${CASSANDRA_LOG_DIR}/auditDirectory for audit log files
roll_cycleHOURLYLog rotation: MINUTELY, HOURLY, DAILY
blocktrueBlock when queue full (vs drop events)
max_queue_weight256 MBMaximum memory for pending events
max_log_size16 GBMaximum total log size before archiving
archive_commandnoneCommand to run when rotating logs

Reading Binary Logs:

Terminal window
# Use auditlogviewer tool to read binary logs
auditlogviewer /var/log/cassandra/audit/
# Filter by time range
auditlogviewer /var/log/cassandra/audit/ --from "2024-01-15 00:00:00" --to "2024-01-15 23:59:59"
# Output to file
auditlogviewer /var/log/cassandra/audit/ > audit_readable.log

Human-readable text format (higher overhead):

audit_logging_options:
enabled: true
logger:
- class_name: FileAuditLogger

Logs to standard Cassandra log file in readable format:

INFO [Native-Transport-Requests-1] AuditLog.java:89 - user:alice|host:192.168.1.100:9042|source:192.168.1.50|port:52431|timestamp:1705315800000|type:SELECT|category:DML|keyspace:production|table:users|operation:SELECT * FROM production.users WHERE user_id = ?

Implement custom logging for integration with external systems:

public class SyslogAuditLogger implements IAuditLogger {
@Override
public void log(AuditLogEntry entry) {
// Send to syslog, SIEM, or external system
String message = formatEntry(entry);
syslogClient.send(message);
}
@Override
public void stop() {
syslogClient.close();
}
@Override
public boolean isEnabled() {
return true;
}
}
audit_logging_options:
enabled: true
logger:
- class_name: com.example.SyslogAuditLogger
parameters:
- syslog_host: syslog.example.com
- syslog_port: 514
- facility: LOCAL0

audit_logging_options:
enabled: true
# Only audit specific keyspaces
included_keyspaces: production,sensitive_data
# Or exclude specific keyspaces (if included_keyspaces is empty)
excluded_keyspaces: system,system_schema,development,test
audit_logging_options:
enabled: true
# Only audit specific users
included_users: admin_alice,admin_bob,app_production
# Or exclude specific users (if included_users is empty)
excluded_users: monitoring_service,healthcheck_user

No Table-Level Filtering

Cassandra audit logging does not support table-level filtering (included_tables / excluded_tables). Filtering is available at the keyspace, user, and category levels only.

audit_logging_options:
enabled: true
# Compliance minimum: Auth + privilege changes
included_categories: AUTH,DCL
# Security monitoring: Add schema changes
included_categories: AUTH,DCL,DDL
# Full audit (high volume)
included_categories: AUTH,DCL,DDL,DML,QUERY

Each audit log entry contains:

FieldDescriptionExample
userAuthenticated useralice
hostCoordinator node192.168.1.100:9042
sourceClient IP address192.168.1.50
portClient port52431
timestampEvent time (epoch ms)1705315800000
typeOperation typeSELECT, INSERT, CREATE_TABLE
categoryEvent categoryDML, DDL, AUTH
keyspaceTarget keyspaceproduction
tableTarget table (if applicable)users
operationFull CQL statementSELECT * FROM users WHERE id = ?
batch_idBatch identifier (if batch)abc123-def456

Authentication Success:

user:alice|host:192.168.1.100:9042|source:192.168.1.50|port:52431|timestamp:1705315800000|type:LOGIN_SUCCESS|category:AUTH

Authentication Failure:

user:unknown|host:192.168.1.100:9042|source:10.0.0.99|port:54321|timestamp:1705315801000|type:LOGIN_ERROR|category:AUTH|operation:Provided username unknown and/or password are incorrect

DDL Operation:

user:schema_admin|host:192.168.1.100:9042|source:192.168.1.60|port:52500|timestamp:1705315802000|type:CREATE_TABLE|category:DDL|keyspace:production|operation:CREATE TABLE production.new_table (id UUID PRIMARY KEY, data TEXT)

DML Operation:

user:app_service|host:192.168.1.100:9042|source:192.168.1.70|port:52600|timestamp:1705315803000|type:SELECT|category:DML|keyspace:production|table:users|operation:SELECT * FROM production.users WHERE user_id = ?

Permission Change:

user:security_admin|host:192.168.1.100:9042|source:192.168.1.80|port:52700|timestamp:1705315804000|type:GRANT|category:DCL|operation:GRANT SELECT ON KEYSPACE production TO analyst_role

Full Query Logging captures complete query details for debugging and replay:

Terminal window
# Enable via nodetool
nodetool enablefullquerylog --path /var/log/cassandra/fql
# With options
nodetool enablefullquerylog \
--path /var/log/cassandra/fql \
--roll-cycle HOURLY \
--max-log-size 1073741824 \
--blocking true
AspectAudit LoggingFull Query Logging
PurposeSecurity, complianceDebugging, replay
FormatStructured eventsBinary query log
FilteringCategory, user, keyspaceNone (all queries)
PerformanceLower overheadHigher overhead
Toolingauditlogviewerfqltool
Use caseLong-term retentionShort-term analysis
Terminal window
# Dump FQL to readable format
fqltool dump /var/log/cassandra/fql/
# Replay queries against another cluster
fqltool replay \
--keyspace production \
--target 192.168.2.100 \
/var/log/cassandra/fql/
# Compare query results between clusters
fqltool compare \
--keyspace production \
--target1 192.168.1.100 \
--target2 192.168.2.100 \
/var/log/cassandra/fql/

Terminal window
# Enable audit logging at runtime
nodetool enableauditlog
# With specific categories
nodetool enableauditlog --included-categories AUTH,DCL,DDL
# With keyspace filter
nodetool enableauditlog --included-keyspaces production,sensitive
# Disable audit logging
nodetool disableauditlog
Terminal window
# View current audit logging status
nodetool getauditlog

Audit log rotation is handled automatically by the roll_cycle setting. There is no nodetool command to force audit log rotation. For custom archival, use the archive_command setting or external log rotation tools.

FQL vs Audit Logs

nodetool resetfullquerylog resets Full Query Logging (FQL), not audit logs. FQL and audit logging are separate features.


# cassandra.yaml - custom logger
audit_logging_options:
enabled: true
logger:
- class_name: com.example.SyslogAuditLogger
parameters:
- syslog_host: siem.example.com
- syslog_port: 514
- syslog_protocol: TCP
- syslog_facility: AUTH

RequirementImplementation
10.1Enable audit logging for all authentication
10.2.1Log all individual user access to cardholder data
10.2.2Log all actions by anyone with admin privileges
10.2.4Log invalid access attempts
10.2.5Log changes to authentication mechanisms
10.3Include user ID, event type, date/time, success/fail, origin, resource
10.5Secure audit logs (separate storage, access controls)
10.7Retain logs for at least one year
audit_logging_options:
enabled: true
logger:
- class_name: BinAuditLogger
parameters:
- log_dir: /secure/audit/cassandra
- roll_cycle: DAILY
- max_log_size: 107374182400 # 100 GB
- archive_command: /usr/local/bin/secure-archive.sh %path
included_categories: AUTH,DCL,DDL,DML
excluded_keyspaces: system,system_schema,system_distributed,system_traces
# Log all users - don't exclude any for PCI
ControlImplementation
CC6.1Log all logical access
CC6.2Log authentication events
CC7.2Monitor for unauthorized access
CC7.3Log configuration changes
RequirementImplementation
Access loggingEnable DML auditing for PHI keyspaces
User identificationLog authenticated user for all queries
Integrity controlsUse secure log storage with checksums
RetentionRetain logs for 6 years minimum

ConfigurationPerformance Impact
AUTH only< 1%
AUTH + DCL + DDL1-2%
AUTH + DCL + DDL + DML5-15%
All categories (QUERY)15-30%
  1. Filter aggressively: Only audit what compliance requires
  2. Exclude high-volume tables: Metrics, logs, time-series
  3. Exclude service accounts: Monitoring, health checks
  4. Use async logging: Set block: false (may lose events)
  5. Adequate disk I/O: Use fast storage for audit logs
  6. Separate disk: Don't compete with data I/O
# High-performance configuration
audit_logging_options:
enabled: true
logger:
- class_name: BinAuditLogger
parameters:
- log_dir: /fast-ssd/audit # Dedicated fast storage
- block: false # Don't block on full queue
- max_queue_weight: 536870912 # 512 MB queue
included_categories: AUTH,DCL,DDL # No DML
excluded_keyspaces: system,system_schema,metrics,logs
excluded_users: monitoring,healthcheck

/usr/local/bin/archive-audit-logs.sh
#!/bin/bash
LOG_PATH=$1
ARCHIVE_DIR=/archive/cassandra-audit
RETENTION_DAYS=365
# Compress and archive
gzip -c "$LOG_PATH" > "$ARCHIVE_DIR/$(basename $LOG_PATH).gz"
# Remove original
rm "$LOG_PATH"
# Clean old archives
find "$ARCHIVE_DIR" -name "*.gz" -mtime +$RETENTION_DAYS -delete
/etc/logrotate.d/cassandra-audit
/var/log/cassandra/audit/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 640 cassandra cassandra
postrotate
/usr/bin/nodetool resetfullquerylog 2>/dev/null || true
endscript
}

Terminal window
# Check if audit logging is enabled
nodetool getauditlog
# Verify directory permissions
ls -la /var/log/cassandra/audit/
# Check for errors in system.log
grep -i audit /var/log/cassandra/system.log
Terminal window
# Check audit log size
du -sh /var/log/cassandra/audit/
# Verify archive command is working
cat /var/log/cassandra/system.log | grep archive
# Force cleanup if needed
nodetool disableauditlog
rm -rf /var/log/cassandra/audit/*
nodetool enableauditlog
# Reduce audit scope
audit_logging_options:
included_categories: AUTH,DCL # Remove DDL, DML
# Or exclude high-volume sources
excluded_keyspaces: metrics,logs,events
excluded_users: etl_service,batch_processor