Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add audit logging for more MySQL commands #11914

Merged
merged 7 commits into from
Apr 14, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -146,6 +146,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 @@ -179,6 +179,20 @@ func FromEventFields(fields EventFields) (events.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 @@ -287,6 +287,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