Jedan od velikih nedostataka MySQL-a za ozbiljno enterprise okruzenje je auditing. Nekakav minimalan auditing koji enterprise uglavnom zahteva je log
– ko se ulogovao
– kada se ulogovao
– odakle se ulogovao
– da li je logovanje bilo uspesno ili ne
– kada se odlogovao sa servera
Za web je ovo nepotrebno (bez potrebe bi u logu imali informaciju kada se web server zakacio/otkacio) ali za enterprise moze da bude vrlo korisno a vrlo cesto i neophodno, pogotovo kada enterprise aplikacije projektuju polupismeni developeri kojima baza radi autentifikaciju i user permissioning a ne aplikacija „posto im je tako lakse“.
Kao sto rekoh, MySQL ima jako slabu / nikakvu podrsku za auditing. Sve sto MySQL moze je da upali „general query log“ i da u log fajl pise SVE (ko se okacio, kad, i stra je sve radio), ali to ima 2 mane
1. general query log trosi resurse (i do 20% usporenja ne high load aplikacijama)
2. general query log ne pamti neuspele konekcije
Kako je mysql-proxy postao vrlo popularan i koristi se vrlo cesto (sto za load balancing sto u neke druge svrhe) a i sastavni je deo MySQL Enterprise Monitor-a gde sve konekcije idu kroz MEM agent kako bi MEM mogao da pravi analizu upita, koristenje proxy-a za auditing uopste nije tako lose resenje.
Kako bi auditing radio, potrebno je instalirati mysql-proxy (ili agent), namestiti mysql da prima konekcije samo sa proxy-a (staviti ga na neki zaseban port i setovati firewall) a proxy podici na standardnom 3306 portu te ce vase aplikacije bez znanja sav traffic usmeriti kroz proxy.
Skript koji radi neki basic auditing bi izgledao:
function read_auth_result( auth )
local state = auth.packet:byte()
if state == proxy.MYSQLD_PACKET_OK then
print( os.date('%Y-%m-%d %H:%M:%S') .. ":AUTH OK:"
.. proxy.connection.server.thread_id .. ":"
.. proxy.connection.client.username .. ":"
.. proxy.connection.client.src.name .. "->"
.. proxy.connection.server.dst.name )
elseif state == proxy.MYSQLD_PACKET_ERR then
print( os.date('%Y-%m-%d %H:%M:%S') .. ":AUTH FAILED: "
.. proxy.connection.server.thread_id .. ":"
.. proxy.connection.client.username .. ":"
.. proxy.connection.client.src.name .. "->"
.. proxy.connection.server.dst.name )
else
print( os.date('%Y-%m-%d %H:%M:%S') .. ":AUTH UNKNOWN "
.. string.format("%q", auth.packet) .. ":"
.. proxy.connection.client.username .. ":"
.. proxy.connection.client.src.name .. "->"
.. proxy.connection.server.dst.name )
end
end
function disconnect_client()
if proxy.connection.server.thread_id then
print( os.date('%Y-%m-%d %H:%M:%S') .. ":DISCONNECT:"
.. proxy.connection.server.thread_id .. ":"
.. proxy.connection.client.username .. ":"
.. proxy.connection.client.src.name .. "->"
.. proxy.connection.server.dst.name )
end
end
Ako pogledamo, skript nam loguje vreme, username, thread na mysql-u i sors/destination adrese konekcije. Vidimo kada je neko pokusao da se uloguje na mysql, da li je uspeo ili ne i kada se otkacio.
Log izgleda otprilike ovako:
2010-02-08 17:21:22:AUTH OK:31:arhimed:127.0.0.1:44440->127.0.0.1:3306
2010-02-08 17:21:33:DISCONNECT:31:arhimed:127.0.0.1:44440->127.0.0.1:3306
2010-02-08 17:21:38:AUTH FAILED: 32:arhime:127.0.0.1:44587->127.0.0.1:3306
2010-02-08 17:21:38:DISCONNECT:32:arhime:127.0.0.1:44587->127.0.0.1:3306
2010-02-08 17:21:43:AUTH FAILED: 33:arhie:127.0.0.1:44622->127.0.0.1:3306
2010-02-08 17:21:43:DISCONNECT:33:arhie:127.0.0.1:44622->127.0.0.1:3306
Ako hocemo da logujemo i osnovne podatke o upitima koje korisnik izvrsava onda mozemo prosiriti lua skript:
function read_auth_result( auth )
local state = auth.packet:byte()
if state == proxy.MYSQLD_PACKET_OK then
print( os.date('%Y-%m-%d %H:%M:%S') .. ":AUTH OK:"
.. proxy.connection.server.thread_id .. ":"
.. proxy.connection.client.username .. ":"
.. proxy.connection.client.src.name .. "->"
.. proxy.connection.server.dst.name )
elseif state == proxy.MYSQLD_PACKET_ERR then
print( os.date('%Y-%m-%d %H:%M:%S') .. ":AUTH FAILED: "
.. proxy.connection.server.thread_id .. ":"
.. proxy.connection.client.username .. ":"
.. proxy.connection.client.src.name .. "->"
.. proxy.connection.server.dst.name )
else
print( os.date('%Y-%m-%d %H:%M:%S') .. ":AUTH UNKNOWN "
.. string.format("%q", auth.packet) .. ":"
.. proxy.connection.client.username .. ":"
.. proxy.connection.client.src.name .. "->"
.. proxy.connection.server.dst.name )
end
end
function disconnect_client()
if proxy.connection.server.thread_id then
print( os.date('%Y-%m-%d %H:%M:%S') .. ":DISCONNECT:"
.. proxy.connection.server.thread_id .. ":"
.. proxy.connection.client.username .. ":"
.. proxy.connection.client.src.name .. "->"
.. proxy.connection.server.dst.name )
end
end
function read_query( packet )
if string.byte(packet) == proxy.COM_QUERY then
proxy.queries:append(1, packet, {resultset_is_needed = true} )
return proxy.PROXY_SEND_QUERY
end
end
function read_query_result( inj )
local res = assert(inj.resultset)
local raw_len = assert(res.raw):len()
local packet = assert(inj.query)
local flags = res.flags
if res.affected_rows then
ar = res.affected_rows
else
ar = "0"
end
print( os.date('%Y-%m-%d %H:%M:%S')
.. ":QUERY:" .. proxy.connection.server.thread_id .. ":"
.. inj.query .. ":"
.. (inj.query_time / 1000) .. "ms" .. ":"
.. (inj.response_time / 1000) .. "ms" .. ":"
.. raw_len .. ":"
.. tostring(res.flags.no_good_index_used) .. ":"
.. tostring(res.flags.no_index_used) .. ":"
.. res.warning_count .. ":"
.. res.query_status .. ":"
.. ar
)
end
pa nam sada log izgleda malo drugacije:
2010-02-08 17:21:22:AUTH OK:31:arhimed:127.0.0.1:44440->127.0.0.1:3306
2010-02-08 17:21:22:QUERY:31:select @@version_comment limit 1:0.092ms:0.095ms:1:false:false:0:0:0
2010-02-08 17:21:23:QUERY:31:select * from mysql.user:0.281ms:0.305ms:1:false:true:0:0:0
2010-02-08 17:21:24:QUERY:31:select * from mysql.user:0.278ms:0.299ms:1:false:true:0:0:0
2010-02-08 17:21:25:QUERY:31:select * from mysql.user:0.272ms:0.293ms:1:false:true:0:0:0
2010-02-08 17:21:28:QUERY:31:select * from mysql.db:0.229ms:0.243ms:1:false:true:0:0:0
2010-02-08 17:21:33:DISCONNECT:31:arhimed:127.0.0.1:44440->127.0.0.1:3306
2010-02-08 17:21:38:AUTH FAILED: 32:arhime:127.0.0.1:44587->127.0.0.1:3306
2010-02-08 17:21:38:DISCONNECT:32:arhime:127.0.0.1:44587->127.0.0.1:3306
2010-02-08 17:21:43:AUTH FAILED: 33:arhie:127.0.0.1:44622->127.0.0.1:3306
2010-02-08 17:21:43:DISCONNECT:33:arhie:127.0.0.1:44622->127.0.0.1:3306
