您好,登錄后才能下訂單哦!
怎么通過MySQL-Proxy實現數據庫的認證、授權與審計,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
總來的話數據庫里面的賬號就會越來越多,賬號授權也是一個蛋疼的工作。特別是還會有“mysql從刪庫到跑路”的問題,員工離職刪除賬號也會十分的麻煩。對于財大氣粗的財閥來說這個問題很好解決,買一套設備就好了,但是對于創業公司要力爭做到“零元黨”,不然也沒辦法完全體現出自己的價值。
最初的想法是對開源mysql的代理工具做一次二次開發,于是乎開始搜集類似工具的資料。無意中發現mysql-proxy居然預留了6個鉤子允許用戶通過Lua腳本去調用他們,也就是說我們可以自行編寫Lua腳本來掌握“用戶的命運”。
connect_server() 當代理服務器接受到客戶端連接請求時會調用該函數
read_handshake() 當mysql服務器返回握手相應時會被調用
read_auth() 當客戶端發送認證信息時會被調用
read_auth_result(aut) 當mysql返回認證結果時會被調用
read_query(packet) 當客戶端提交一個sql語句時會被調用
read_query_result(inj) 當mysql返回查詢結果時會被調用
顯然,通過上述的read_auth和read_query兩個鉤子函數,我們可以實現對mysql數據庫的認證、授權和審計的工作。
我們的目標是認證、授權和審計,那么read_auth函數可以實現認證和授權,read_query可以實現審計的功能。read_query比較容易實現,只需要get到用戶發來的sql語句寫到消息隊列里就好了,我這里就簡單地寫到redis的list中。
read_auth函數就要相對復雜些,不僅需要對用戶提交的一次性password進行校驗,還需要讀取授權信息,讓用戶登錄到mysql的時候華麗的變身成為我們指定的身份。
1.用戶訪問Openresty,后端的lua腳本會調用公司內部使用的im軟件的消息接口,將生成的一次性口令發送給用戶。與此同時,也會將該口令寫入redis。
2.用戶使用mysql客戶端連接指定的mysql-proxy,此時進入read_auth鉤子函數,先對用戶提交的口令進行確認。然后會去redis請求當前數據庫對應developer、master、owner三個role的授權名單,查看三個名單中是否含有當前用戶,如果有則將用戶以其對應的role跳轉到數據庫上。
3.當認證授權成功結束后,用戶通過上一步授權的role來訪問后端mysql,并且執行的所有sql語句都會進入read_query鉤子函數被記錄到redis的隊列中。
local password =assert(require("mysql.password"))
local proto =assert(require("mysql.proto"))
assert(require("redis"))
--字符串切割
function string:split(sep)
local sep, fields = sep or ":", {}
local pattern = string.format("([^%s]+)", sep)
self:gsub(pattern, function (c) fields[#fields + 1] = c end)
return fields
end
function read_query( packet )
if packet:byte() == proxy.COM_QUERY then
local con = proxy.connection
local redis = Redis.connect('your_redis_ip',6379)
--獲取ip對應的域名
redis:select('3')
local domain = redis:get(con.server.dst.name:split(':')[1])
--將執行的sql語句放入redis隊列中
redis:select('2')
redis:lpush('mysql_command_queue',os.date("%Y-%m-%d%H:%M:%S",os.time())
.. " " .. con.client.src.address .. "" .. con.client.username .. " " ..
domain .. " [" ..packet:sub(2) .. "]")
if packet:sub(2) == "SELECT 1" then
proxy.queries:append(1, packet)
end
end
end
function read_auth()
local names = {}
--developer、master、owner三個角色權限逐級增大
local roles = {[1] = 'developer',[2] = 'master',[3] = 'owner'}
local con = proxy.connection
local s = con.server
local role = ''
--認證
local redis = Redis.connect('your_redis_ip', 6379)
local pass = redis:get(con.client.username)
ifpassword.scramble(s.scramble_buffer, password.hash(pass)) ~=con.client.scrambled_password then
--認證失敗返回錯誤信息
proxy.response.type = proxy.MYSQLD_PACKET_ERR
proxy.response.errmsg ="Password error!"
return proxy.PROXY_SEND_RESULT
end
redis:del(con.client.username)
--獲取ip對應的域名
redis:select('3')
local domain = redis:get(con.server.dst.name:split(':')[1])
redis:select('1')
--獲取用戶對于當前數據庫的role
for i,v inipairs(roles) do
--查詢“domain:role”返回相應的名單并將名單切割為table
names = redis:get(domain .. ":" .. v):split(',')
for k,name in ipairs(names) do
if name == con.client.username then
role = v
break
end
end
end
--無授權信息返回錯誤信息
if role == '' then
proxy.response.type = proxy.MYSQLD_PACKET_ERR
proxy.response.errmsg = "Unauthorized access!"
return proxy.PROXY_SEND_RESULT
end
--最新mysql-proxy加入的新屬性
local protocol_41_default_capabilities = 8 + 512 + 32768
proxy.queries:append(1,
proto.to_response_packet({
username = role,
response = password.scramble(s.scramble_buffer, password.hash(“your_role_password”)),
--最新mysql-proxy加入的新屬性
server_capabilities=protocol_41_default_capabilities
})
)
return proxy.PROXY_SEND_QUERY
end
[root@ip-172-31-24-123 ~]# mysql -u test -h your_mysql-proxy_ip -P your_mysql-proxy_port-pEnter password:Welcome to the MySQL monitor. Commands end with ; or \g.Your MySQL connection id is 30341Server version: 5.7.12 MySQL CommunityServer (GPL)Copyright (c) 2000, 2018, Oracle and/or itsaffiliates. All rights reserved.Oracle is a registered trademark of OracleCorporation and/or itsaffiliates. Other names may be trademarksof their respectiveowners.Type 'help;' or '\h' for help. Type '\c' toclear the current input statement.mysql> select user();+-------------------------+| user() |+-------------------------+| developer@your_ip|+-------------------------+1 row in set (0.01 sec)
顯然,使用用戶名test登錄mysql-proxy,最終跳轉到mysql上時用戶已經變為developer。
用于非業務場景連接數據庫,比如開發運維人員在公司連接數據庫。
管理腳本需要監控每個mysql-proxy進程的狀態,負責他們的啟動和停止,以及將他們的域名解析為ip存入redis中。
授權腳本讀取一個yaml文件,將文件中的授權規則同步到redis中。
每個數據庫中都只需要新建developer、master、owner三個賬號,yaml配置文件中的內容決定用戶使用以上哪種role登錄到mysql。
mysql-proxy需要使用源碼編譯安裝。
啟動mysql-proxy的命令為:
mysql-proxy/bin/mysql-proxy--proxy-address=mysql-proxy_ip:mysql-proxy_port --proxy-backend-addresses=mysql_ip:mysql_port--max-open-files=1024 --user=root --log-file=/var/log/mysql-proxy--log-level=debug --proxy-lua-script=your_lua_file &
關于怎么通過MySQL-Proxy實現數據庫的認證、授權與審計問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。