運維團隊一般會有個需求就是記錄運維或者開發同事在伺服器上的操作記錄,比如進行一些常規審核或者是伺服器被黑了、伺服器日誌被刪的情況需要知道發生過什麼事情,今天和大家分享下我們現在的伺服器的shell和mysql操作日誌記錄的DIY方案。
團隊內部之前有測試過一些堡壘機硬體,但終端操作方面不夠人性化,不夠靈活,而且價格昂貴,硬體容易形成單點故障。當然也接觸過一些開源的方案,比如可以直接用ttyrec對終端進行錄製,並且支援文字匹配,但是在實際使用中發現過嚴重bug,還有另外一些openssh的修改方案也不盡人意。
鑒於上述問題,我們針對bash和mysql的程式碼進行簡單的修改來實現一個低成本、實用效能高的日誌審計方案。
上面截圖前面一部分是mysql的操作日誌,後面部分是shell操作日誌。具體解決方案請往下走
下麵來“開源”這個解決方案,希望對大家有小小幫助。
大家應該有聽說過網路說的bash修改方案,我們從2011年開始使用,中間經歷過很多bug,修複和最佳化過多次版本,下麵會詳細地給出我們現在的線上方案。現在的功能支援大致如下:
-
-
支援遠端透過ssh IP “command”執行和scp時候的日誌記錄
-
-
上述每一個功能串列都是經過多次實踐出來的需求,雖然不是非常完美,但是如果不是刻意來逃避日誌記錄的話,基本可以滿足大家的需求,上述的記錄對應的人員是指多個人同時使用同一個系統帳號的情況,比如root帳號。
基本功能就是需要記錄到每個人的操作記錄,網路上有個方案雛形,修改bashhist.c檔案,701行左右修改bash_syslog_history函式,修改完之後內容:
上面取的是NAME_OF_KEY這個系統變數,我們稱之為指紋,用這個變數來對應到具體的人員,然後將對應的操作記錄到syslog。如果沒有取到這個變數的話,/var/log/messages那裡這個變數就顯示為空了,只知道是某個系統帳號在執行,但無法精確到個人。
接下來重點就是處理NAME_OF_KEY這個指紋變數,原理也比較簡單,每個人登入系統的時候,我們讓他自動執行一個指令碼,然後設定這個變數為具體人就可以了。
別說有人還在利用密碼登入Linux伺服器,太不專業了-_-
在這個檔案裡面~/.ssh/authorized_keys加key的時候,第三列設定為具體的人員,我們是用工號@姓名拼音的樣式,然後透過指令碼進行處理即可。
上面的邏輯比較簡單,首先我們還需要開啟sshd的debug樣式,在/etc/ssh/sshd_config檔案加入:
還可以針對複雜的情況進一步的進行邏輯處理,比如su進行使用者切換的時候,核心思想是跟蹤PID變數,跟蹤的變數主要是/var/log/secure裡面的sshd[ID_NUM]裡面的關鍵詞和ps –ef|grep ID_NUM顯示的第一二列的ID號,進行不斷的匹配跟蹤即可找到最原始的是哪個ID號。
不過這樣還不夠,我們需要支援遠端執行時候也記錄的話就需要在~/.bashrc檔案裡面再加入一行,註意不能放在~/.bash_profile,兩個檔案雖然都是載入使用者指令碼,但是有差異的。在裡面加入的內容:
這個邏輯是BASH_EXECUTION_STRING這個變數在本地執行和遠端執行時候是不一樣的,我們先進行變數判斷,然後再做對應的處理即可,加完了就會發現遠端執行時候也有日誌記錄了(馬賽克處是來源IP):
很早以前找過相關的mysql外掛,也嘗試過audit之類的方案,但結果不是我們需要的效果,我們需要的是運維方面在伺服器上的mysql操作,和mysql的binlog等日誌不是同一個事情,而且和.mysql_history記錄的也不一樣,我們需要精確到同一系統使用者的不同人員。
以下mysql版本是指Percona-Server-5.5。
mysql自帶了syslog日誌功能,但是需要手動配置開啟,配置比較簡單:
在/etc/my.cnf裡面的client欄位加上syslog即可。
效果看起來也還滿意,在/var/log/messages會有相關日誌:
1)在mysqldump時候會報錯:
2)可以輕易地繞過這個日誌,在敲mysql命令列的時候加個引數–no-defaults即可。
3)日誌裡面只有是root帳號操作的,沒有體現出具體是某個人操作的。
我們可以在原始碼裡面就把syslog這個開關開啟,比較容易,找到client/mysql.cc這個檔案,開關邏輯比較簡單,找到以下程式碼:
看意思這裡opt_syslog值就是個開關,wirte_syslog就是功能函式,找到static my_bool定義那裡,把opt_syslog的bool值改為1,然後重新編譯即可。
單純那樣改會發現還有個小問題,就是在shell終端下麵直接mysql可以用-e進行命令操作,比如:
但是按照之前那樣開啟syslog也無法記錄日誌。我們是有記錄shell操作記錄的,這個問題可以忽略,不過一定要顯示的話也是有辦法的,繼續修改程式碼。
稍微看下邏輯分析可以看到是需要滿足connect_flag == CLIENT_INTERACTIVE才寫日誌,找到CLIENT_INTERACTIVE的定義:
原來這個就是互動樣式的定義,所以我們把這個“與”條件去掉即可,改為這樣:
然後再重新編譯,發現順利解決msyql –e執行命令的歷史記錄了。
在實際環境中會有新的問題,比如匯入sql陳述句時候,會生成同樣大小的日誌,比如匯入2G的sql,會生成2G的日誌,這樣明顯不符合我們的需求。
想到我們已經有bash審核了,-e執行時候可以忽略記錄,但是如果在mysql裡面透過source命令取用sql陳述句時候同樣有這個問題,所以還得繼續改程式碼。
找到write_syslog函式,正式寫日誌時候是用的syslog函式,裡面有個for迴圈的邏輯,意思是當sql陳述句很大時候,需要“切割”一下再寫入,所以從這裡入手,把syslog改為定義的MAX_SYSLOG_MESSAGE長度之內就寫,超過的話就直接忽略。
另外之前說需要精確到不同人員,所以我們引入了我們的bash審核裡面的指紋,變數NAME_OF_KEY,然後在mysql.cc裡面引入即可。關鍵修改如下:
搞定,這樣匯入一個2G的sql陳述句,生成不到2m的日誌,一些sql資料的話就忽略截斷了。
這樣雖然是在原始碼裡面寫死了一定有日誌,但是還是可以提供一個備用的引數來取消這個功能。
在引數定義那裡改動,把之前的syslog改為這樣:
這樣就是一個no-syslog的取消開關了,用法就是在my.cnf裡面新增欄位:
上述日誌全部是透過syslog服務記錄到/var/log/messages檔案,更合理的是再傳輸到遠端的日誌中心來統一備案管理。
這個方法比較簡單,在/etc/rsyslog.conf裡面加入配置:
重啟rsyslog服務之後,所有的日誌就會同時傳送一份到LOGSERVER_IP這個伺服器,這裡之前另外有個bash版本是內嵌了日誌傳送的功能,用的udp協議,不會對命令操作有卡頓,不過沒用線上上。
最後我們在日誌伺服器可以搭建個splunk或者開源的logstash日誌分析平臺即可。關於日誌系統,後續我們再詳細介紹下我們現在的CDN日誌系統。
這個段落是額外的參考,我們的定製系統是寫死了配置全部傳送到公網的某一臺日誌中心伺服器,但是我們內網機房也有很多伺服器,這樣會導致在日誌中心那裡無法檢視原始的內網IP,只有辦公網的出口IP,而且不方便每個機器都去更改日誌中心的IP,那樣會很容易漏掉,解決辦法是進行“日誌劫持”。
在我們的juniper防火牆那裡進行日誌攔截,然後轉發到內網的一個日誌中心即可,參考配置:
這樣是在辦公網搭建了另外一個日誌中心伺服器,攔截轉發之後也就可以識別到具體的來源的內網IP了。
這個遠端日誌中心平臺是挺有必要搭建一個,像有時候伺服器上不去了,我們可以上這個日誌中心進行日誌查詢,看發生什麼事情了,另外就是假如機器被別人拿到許可權了,我們可以在這裡看到原始日誌。當然我們機器是都安裝了ossec和lynis會進行安全系統層的安全掃描,不過保留一份原始的日誌是必不可少的。
作者 | 金龍 來源 | 運維軍團 ID | ywjtshare
長按二維碼向我轉賬
受蘋果公司新規定影響,微信 iOS 版的贊賞功能被關閉,可透過二維碼轉賬支援公眾號。