// #region PREPARSE /************************************************************ ****** Parse timestamp and log headers ****** Extract message field for parsing ****** Parse structured data ************************************************************/ /* This parser supports MySQL audit logs generated by mariadb audit plugin. More here: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.MySQL.Options.AuditPlugin.html MariaDB Audit Plugin is only supported for the following RDS for MySQL versions: MySQL 8.0.28 and higher 8.0 versions and All MySQL 5.7 versions Log format: comma separated fields: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.MySQL.Options.AuditPlugin.html#Appendix.MySQL.Options.AuditPlugin.LogFormat [timestamp],[serverhost],[username],[host],[connectionid],[queryid],[operation],[database],[object],[retcode],[connection_type] */ // // preparing rawstring as some fields are in single quotes, example: 'GRANT SELECT ON `test`.`t1` TO \'test\'@\'localhost\'' __rawdata := replace(field=@rawstring, "\"", with="\"\"") | __rawdata := replace(field=__rawdata, "\\\\'", with="myUniqueString") | __rawdata := replace(field=__rawdata, "'", with="\"") | __rawdata := replace(field=__rawdata, "myUniqueString", with="\\\\'") | parseCSV(__rawdata, columns=[@timestamp,Vendor.serverhost,Vendor.username,Vendor.host,Vendor.connectionid,Vendor.queryid,Vendor.operation,Vendor.database,Vendor.object,Vendor.retcode,Vendor.connection_type], delimiter=",", excludeEmpty=true) | parseTimestamp(field="@timestamp", format="yyyyMMdd HH:mm:ss", timezone="UTC") | drop(["__rawdata"]) // #endregion // #region METADATA /************************************************************ ****** Static Metadata Definitions ************************************************************/ | ecs.version := "8.17.0" | Cps.version := "1.0.0" | Parser.version := "1.0.1" | Vendor := "aws" | event.module := "rds" | event.dataset := "rds.mysql-audit" // #endregion // #region NORMALIZATION /************************************************************ ****** Parse unstructured data (i.e. message field) ****** Normalize fields to data model ************************************************************/ | event.kind := "event" | array:append("event.category[]", values=["database"]) | Vendor.object match { /create\s+user|grant|delete\s+user|drop\s+user|flush\s+privileges/i => array:append("event.category[]", values=["iam"]); * => *; } | Vendor.operation match { "CONNECT" => array:append("event.type[]", values=["access", "start"]); "DISCONNECT" => array:append("event.type[]", values=["access", "end"]); * => array:append("event.type[]", values=["access"]); } | Vendor.object match { /create\s+user/i => array:append("event.type[]", values=["user", "creation"]); /drop\s+user/i => array:append("event.type[]", values=["user", "deletion"]); * => * } // Vendor.retcode returns the error number for the query, 0 means no error | case { Vendor.retcode = "0" | event.outcome := "success"; Vendor.retcode != "0" | event.outcome := "failure"; * | event.outcome := "unknown"; } | event.action := lower(Vendor.operation) | event.id := Vendor.queryid | process.name := "mysqld" | user.name := Vendor.username | host.hostname := lower(Vendor.serverhost) // host --> client host /ip | client.ip := Vendor.host | client.user.name := user.name // #endregion // #region POST-NORMALIZATION /************************************************************ ****** Post Normalization ****** Custom parser logic needed after normalization ************************************************************/ // #endregion