Skip to content

Commit

Permalink
Add audit logging for more MySQL commands (#11914)
Browse files Browse the repository at this point in the history
  • Loading branch information
greedy52 committed Apr 14, 2022
1 parent a6b30fe commit 2e09b58
Show file tree
Hide file tree
Showing 11 changed files with 4,622 additions and 906 deletions.
4,846 changes: 3,944 additions & 902 deletions api/types/events/events.pb.go

Large diffs are not rendered by default.

132 changes: 132 additions & 0 deletions api/types/events/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1884,6 +1884,13 @@ message OneOf {
events.MySQLStatementBulkExecute MySQLStatementBulkExecute = 78;
events.RenewableCertificateGenerationMismatch RenewableCertificateGenerationMismatch = 79;
events.Unknown Unknown = 80;
events.MySQLInitDB MySQLInitDB = 81;
events.MySQLCreateDB MySQLCreateDB = 82;
events.MySQLDropDB MySQLDropDB = 83;
events.MySQLShutDown MySQLShutDown = 84;
events.MySQLProcessKill MySQLProcessKill = 85;
events.MySQLDebug MySQLDebug = 86;
events.MySQLRefresh MySQLRefresh = 87;
}
}

Expand Down Expand Up @@ -2150,3 +2157,128 @@ message MySQLStatementBulkExecute {
// Parameters are the parameters used to execute the prepared statement.
repeated string Parameters = 6 [ (gogoproto.jsontag) = "parameters" ];
}

// MySQLInitDB is emitted when a MySQL client changes the default schema for
// the connection.
message MySQLInitDB {
// Metadata is a common event metadata.
Metadata Metadata = 1
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// User is a common user event metadata.
UserMetadata User = 2
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// SessionMetadata is a common event session metadata.
SessionMetadata Session = 3
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// Database contains database related metadata.
DatabaseMetadata Database = 4
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// SchemaName is the name of the schema to use.
string SchemaName = 5 [ (gogoproto.jsontag) = "schema_name" ];
}

// MySQLCreateDB is emitted when a MySQL client creates a schema.
message MySQLCreateDB {
// Metadata is a common event metadata.
Metadata Metadata = 1
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// User is a common user event metadata.
UserMetadata User = 2
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// SessionMetadata is a common event session metadata.
SessionMetadata Session = 3
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// Database contains database related metadata.
DatabaseMetadata Database = 4
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// SchemaName is the name of the schema to create.
string SchemaName = 5 [ (gogoproto.jsontag) = "schema_name" ];
}

// MySQLDropDB is emitted when a MySQL client drops a schema.
message MySQLDropDB {
// Metadata is a common event metadata.
Metadata Metadata = 1
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// User is a common user event metadata.
UserMetadata User = 2
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// SessionMetadata is a common event session metadata.
SessionMetadata Session = 3
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// Database contains database related metadata.
DatabaseMetadata Database = 4
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// SchemaName is the name of the schema to drop.
string SchemaName = 5 [ (gogoproto.jsontag) = "schema_name" ];
}

// MySQLShutDown is emitted when a MySQL client asks the server to shut down.
message MySQLShutDown {
// Metadata is a common event metadata.
Metadata Metadata = 1
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// User is a common user event metadata.
UserMetadata User = 2
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// SessionMetadata is a common event session metadata.
SessionMetadata Session = 3
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// Database contains database related metadata.
DatabaseMetadata Database = 4
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
}

// MySQLProcessKill is emitted when a MySQL client asks the server to terminate
// a connection.
message MySQLProcessKill {
// Metadata is a common event metadata.
Metadata Metadata = 1
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// User is a common user event metadata.
UserMetadata User = 2
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// SessionMetadata is a common event session metadata.
SessionMetadata Session = 3
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// Database contains database related metadata.
DatabaseMetadata Database = 4
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// ProcessID is the process ID of a connection.
uint32 ProcessID = 5 [ (gogoproto.jsontag) = "process_id" ];
}

// MySQLDebug is emitted when a MySQL client asks the server to dump internal
// debug info to stdout.
message MySQLDebug {
// Metadata is a common event metadata.
Metadata Metadata = 1
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// User is a common user event metadata.
UserMetadata User = 2
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// SessionMetadata is a common event session metadata.
SessionMetadata Session = 3
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// Database contains database related metadata.
DatabaseMetadata Database = 4
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
}

// MySQLRefresh is emitted when a MySQL client sends refresh commands.
message MySQLRefresh {
// Metadata is a common event metadata.
Metadata Metadata = 1
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// User is a common user event metadata.
UserMetadata User = 2
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// SessionMetadata is a common event session metadata.
SessionMetadata Session = 3
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// Database contains database related metadata.
DatabaseMetadata Database = 4
[ (gogoproto.nullable) = false, (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
// Subcommand is the string representation of the subcommand.
string Subcommand = 5 [ (gogoproto.jsontag) = "subcommand" ];
}
28 changes: 28 additions & 0 deletions api/types/events/oneof.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,34 @@ func ToOneOf(in AuditEvent) (*OneOf, error) {
out.Event = &OneOf_MySQLStatementBulkExecute{
MySQLStatementBulkExecute: e,
}
case *MySQLInitDB:
out.Event = &OneOf_MySQLInitDB{
MySQLInitDB: e,
}
case *MySQLCreateDB:
out.Event = &OneOf_MySQLCreateDB{
MySQLCreateDB: e,
}
case *MySQLDropDB:
out.Event = &OneOf_MySQLDropDB{
MySQLDropDB: e,
}
case *MySQLShutDown:
out.Event = &OneOf_MySQLShutDown{
MySQLShutDown: e,
}
case *MySQLProcessKill:
out.Event = &OneOf_MySQLProcessKill{
MySQLProcessKill: e,
}
case *MySQLDebug:
out.Event = &OneOf_MySQLDebug{
MySQLDebug: e,
}
case *MySQLRefresh:
out.Event = &OneOf_MySQLRefresh{
MySQLRefresh: e,
}
case *RenewableCertificateGenerationMismatch:
out.Event = &OneOf_RenewableCertificateGenerationMismatch{
RenewableCertificateGenerationMismatch: e,
Expand Down
22 changes: 22 additions & 0 deletions lib/events/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,28 @@ const (
// statement protocol.
DatabaseSessionMySQLStatementBulkExecuteEvent = "db.session.mysql.statements.bulk_execute"

// DatabaseSessionMySQLInitDBEvent is emitted when a MySQL client changes
// the default schema for the connection.
DatabaseSessionMySQLInitDBEvent = "db.session.mysql.init_db"
// DatabaseSessionMySQLCreateDBEvent is emitted when a MySQL client creates
// a schema.
DatabaseSessionMySQLCreateDBEvent = "db.session.mysql.create_db"
// DatabaseSessionMySQLDropDBEvent is emitted when a MySQL client drops a
// schema.
DatabaseSessionMySQLDropDBEvent = "db.session.mysql.drop_db"
// DatabaseSessionMySQLShutDownEvent is emitted when a MySQL client asks
// the server to shut down.
DatabaseSessionMySQLShutDownEvent = "db.session.mysql.shut_down"
// DatabaseSessionMySQLProcessKillEvent is emitted when a MySQL client asks
// the server to terminate a connection.
DatabaseSessionMySQLProcessKillEvent = "db.session.mysql.process_kill"
// DatabaseSessionMySQLDebugEvent is emitted when a MySQL client asks the
// server to dump internal debug info to stdout.
DatabaseSessionMySQLDebugEvent = "db.session.mysql.debug"
// DatabaseSessionMySQLRefreshEvent is emitted when a MySQL client sends
// refresh commands.
DatabaseSessionMySQLRefreshEvent = "db.session.mysql.refresh"

// SessionRejectedReasonMaxConnections indicates that a session.rejected event
// corresponds to enforcement of the max_connections control.
SessionRejectedReasonMaxConnections = "max_connections limit reached"
Expand Down
14 changes: 14 additions & 0 deletions lib/events/codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,20 @@ const (
MySQLStatementFetchCode = "TMY05I"
// MySQLStatementBulkExecuteCode is the db.session.mysql.statements.bulk_execute event code.
MySQLStatementBulkExecuteCode = "TMY06I"
// MySQLInitDBCode is the db.session.mysql.init_db event code.
MySQLInitDBCode = "TMY07I"
// MySQLCreateDBCode is the db.session.mysql.create_db event code.
MySQLCreateDBCode = "TMY08I"
// MySQLDropDBCode is the db.session.mysql.drop_db event code.
MySQLDropDBCode = "TMY09I"
// MySQLShutDownCode is the db.session.mysql.shut_down event code.
MySQLShutDownCode = "TMY10I"
// MySQLProcessKillCode is the db.session.mysql.process_kill event code.
MySQLProcessKillCode = "TMY11I"
// MySQLDebugCode is the db.session.mysql.debug event code.
MySQLDebugCode = "TMY12I"
// MySQLRefreshCode is the db.session.mysql.refresh event code.
MySQLRefreshCode = "TMY13I"

// DatabaseCreateCode is the db.create event code.
DatabaseCreateCode = "TDB03I"
Expand Down
14 changes: 14 additions & 0 deletions lib/events/dynamic.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,20 @@ func FromEventFields(fields EventFields) (apievents.AuditEvent, error) {
e = &events.MySQLStatementFetch{}
case DatabaseSessionMySQLStatementBulkExecuteEvent:
e = &events.MySQLStatementBulkExecute{}
case DatabaseSessionMySQLInitDBEvent:
e = &events.MySQLInitDB{}
case DatabaseSessionMySQLCreateDBEvent:
e = &events.MySQLCreateDB{}
case DatabaseSessionMySQLDropDBEvent:
e = &events.MySQLDropDB{}
case DatabaseSessionMySQLShutDownEvent:
e = &events.MySQLShutDown{}
case DatabaseSessionMySQLProcessKillEvent:
e = &events.MySQLProcessKill{}
case DatabaseSessionMySQLDebugEvent:
e = &events.MySQLDebug{}
case DatabaseSessionMySQLRefreshEvent:
e = &events.MySQLRefresh{}
case KubeRequestEvent:
e = &events.KubeRequest{}
case MFADeviceAddEvent:
Expand Down
15 changes: 15 additions & 0 deletions lib/srv/db/mysql/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,21 @@ func (e *Engine) receiveFromClient(clientConn, serverConn net.Conn, clientErrCh
case *protocol.Quit:
return

case *protocol.InitDB:
e.Audit.EmitEvent(e.Context, makeInitDBEvent(sessionCtx, pkt))
case *protocol.CreateDB:
e.Audit.EmitEvent(e.Context, makeCreateDBEvent(sessionCtx, pkt))
case *protocol.DropDB:
e.Audit.EmitEvent(e.Context, makeDropDBEvent(sessionCtx, pkt))
case *protocol.ShutDown:
e.Audit.EmitEvent(e.Context, makeShutDownEvent(sessionCtx, pkt))
case *protocol.ProcessKill:
e.Audit.EmitEvent(e.Context, makeProcessKillEvent(sessionCtx, pkt))
case *protocol.Debug:
e.Audit.EmitEvent(e.Context, makeDebugEvent(sessionCtx, pkt))
case *protocol.Refresh:
e.Audit.EmitEvent(e.Context, makeRefreshEvent(sessionCtx, pkt))

case *protocol.StatementPreparePacket:
e.Audit.EmitEvent(e.Context, makeStatementPrepareEvent(sessionCtx, pkt))
case *protocol.StatementExecutePacket:
Expand Down
89 changes: 89 additions & 0 deletions lib/srv/db/mysql/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,92 @@ func makeStatementBulkExecuteEvent(session *common.Session, packet *protocol.Sta
StatementID: packet.StatementID(),
}
}

// makeInitDBEvent creates an audit event for MySQL init DB command.
func makeInitDBEvent(session *common.Session, packet *protocol.InitDB) events.AuditEvent {
return &events.MySQLInitDB{
Metadata: common.MakeEventMetadata(session,
libevents.DatabaseSessionMySQLInitDBEvent,
libevents.MySQLInitDBCode),
UserMetadata: common.MakeUserMetadata(session),
SessionMetadata: common.MakeSessionMetadata(session),
DatabaseMetadata: common.MakeDatabaseMetadata(session),
SchemaName: packet.SchemaName(),
}
}

// makeCreateDBEvent creates an audit event for MySQL create DB command.
func makeCreateDBEvent(session *common.Session, packet *protocol.CreateDB) events.AuditEvent {
return &events.MySQLCreateDB{
Metadata: common.MakeEventMetadata(session,
libevents.DatabaseSessionMySQLCreateDBEvent,
libevents.MySQLCreateDBCode),
UserMetadata: common.MakeUserMetadata(session),
SessionMetadata: common.MakeSessionMetadata(session),
DatabaseMetadata: common.MakeDatabaseMetadata(session),
SchemaName: packet.SchemaName(),
}
}

// makeDropDBEvent creates an audit event for MySQL drop DB command.
func makeDropDBEvent(session *common.Session, packet *protocol.DropDB) events.AuditEvent {
return &events.MySQLDropDB{
Metadata: common.MakeEventMetadata(session,
libevents.DatabaseSessionMySQLDropDBEvent,
libevents.MySQLDropDBCode),
UserMetadata: common.MakeUserMetadata(session),
SessionMetadata: common.MakeSessionMetadata(session),
DatabaseMetadata: common.MakeDatabaseMetadata(session),
SchemaName: packet.SchemaName(),
}
}

// makeShutDownEvent creates an audit event for MySQL shut down command.
func makeShutDownEvent(session *common.Session, packet *protocol.ShutDown) events.AuditEvent {
return &events.MySQLShutDown{
Metadata: common.MakeEventMetadata(session,
libevents.DatabaseSessionMySQLShutDownEvent,
libevents.MySQLShutDownCode),
UserMetadata: common.MakeUserMetadata(session),
SessionMetadata: common.MakeSessionMetadata(session),
DatabaseMetadata: common.MakeDatabaseMetadata(session),
}
}

// makeProcessKillEvent creates an audit event for MySQL process kill command.
func makeProcessKillEvent(session *common.Session, packet *protocol.ProcessKill) events.AuditEvent {
return &events.MySQLProcessKill{
Metadata: common.MakeEventMetadata(session,
libevents.DatabaseSessionMySQLProcessKillEvent,
libevents.MySQLProcessKillCode),
UserMetadata: common.MakeUserMetadata(session),
SessionMetadata: common.MakeSessionMetadata(session),
DatabaseMetadata: common.MakeDatabaseMetadata(session),
ProcessID: packet.ProcessID(),
}
}

// makeDebugEvent creates an audit event for MySQL debug command.
func makeDebugEvent(session *common.Session, packet *protocol.Debug) events.AuditEvent {
return &events.MySQLDebug{
Metadata: common.MakeEventMetadata(session,
libevents.DatabaseSessionMySQLDebugEvent,
libevents.MySQLDebugCode),
UserMetadata: common.MakeUserMetadata(session),
SessionMetadata: common.MakeSessionMetadata(session),
DatabaseMetadata: common.MakeDatabaseMetadata(session),
}
}

// makeRefreshEvent creates an audit event for MySQL refresh command.
func makeRefreshEvent(session *common.Session, packet *protocol.Refresh) events.AuditEvent {
return &events.MySQLRefresh{
Metadata: common.MakeEventMetadata(session,
libevents.DatabaseSessionMySQLRefreshEvent,
libevents.MySQLRefreshCode),
UserMetadata: common.MakeUserMetadata(session),
SessionMetadata: common.MakeSessionMetadata(session),
DatabaseMetadata: common.MakeDatabaseMetadata(session),
Subcommand: packet.Subcommand(),
}
}
Loading

0 comments on commit 2e09b58

Please sign in to comment.