引言
-
背景介紹:在伺服器的運維管理中,及時監控系統的登入日誌對保障系統的安全至關重要。透過實時監控登入日誌,運維人員可以發現潛在的異常登入行為,防止系統被非法訪問。
-
問題引入:如何實現實時監控登入日誌,並及時響應潛在的安全風險?
實時監控登入日誌的意義
-
安全性:透過監控登入日誌,可以迅速發現惡意登入、暴力破解等異常行為。
-
合規性:確保滿足各種合規要求,記錄所有使用者的登入行為。
解決方案概述
-
監控目標:關注登入日誌中的關鍵資訊,例如登入時間、IP 地址、使用者名稱、登入方式等。
-
技術選型:透過編寫 Bash 指令碼,結合inotify、awk、grep 等工具,來實現對日誌檔案的實時監控與分析。
指令碼實現原理
-
實時監控:利用 inotify 命令動態監控日誌檔案的變動,並結合 sed 命令實時提取和輸出新增的登入日誌。
-
日誌篩選:透過 grep 等工具過濾出登入失敗、異常登入等相關資訊。
-
報警機制:指令碼可以配置成在監控到異常行為時,自動傳送通知郵件
指令碼示例
1 #!/bin/bash 2 # 作者: 阿杰 3 # 用途: 實時檢測登入日誌,統計異常登入 4 # 指令碼名稱: watch_secure.sh 5 # 用法: bash watch_seacure.sh 6 7 # 日誌記錄 8 log_err() { 9 printf "[$(date +'%Y-%m-%dT%H:%M:%S')]: \033[31mERROR: \033[0m$@\n" 10 } 11 12 log_info() { 13 printf "[$(date +'%Y-%m-%dT%H:%M:%S')]: \033[32mINFO: \033[0m$@\n" 14 } 15 16 log_warning() { 17 printf "[$(date +'%Y-%m-%dT%H:%M:%S')]: \033[33mWARNING: \033[0m$@\n" 18 } 19 20 # 初始化Map 21 declare -A secureMap 22 23 init() { 24 # 行數記錄檔案 25 line_file_name="conf/line_file.txt" 26 # inode儲存檔案 27 inode_file="conf/inode.txt" 28 # 認證失敗檔案記錄 29 ssh_auth_failed_file="conf/ssh_auth_failed.csv" 30 31 # 檔案列表 32 file_array=("$line_file_name" "$inode_file" "$ssh_auth_failed_file") 33 # inode 檔案狀態 34 inode_file_status=0 35 # 控制是否進行寫入 0為可寫,1為不可寫 36 write_status=1 37 38 oneSecureKey="" 39 40 { 41 if [ ! -d "conf" ];then 42 mkdir conf 43 fi 44 # 檢查檔案是否存在 45 for file in ${file_array[@]};do 46 check_file_exists $file 47 done 48 line=$(cat $line_file_name) 49 if [ -z "$line" ];then 50 line=0 51 fi 52 # 認證失敗檔案第一次建立 53 if [ $(wc -l < $ssh_auth_failed_file) -eq 0 ];then 54 # 時間以月天為單位(None為空賬號或不存在賬號) 55 echo "登入認證失敗時間,源IP地址,登入賬號,連線認證失敗次數" > $ssh_auth_failed_file 56 fi 57 58 } 59 60 file_name="/var/log/secure" 61 if [ -z "$(rpm -qa | grep 'inotify-tools')" ];then 62 yum install -y inotify-tools > /dev/null 2>&1 63 if [ $? -ne 0 ];then 64 log_err "[init] inotify-tools 安裝失敗!" 65 fi 66 fi 67 68 69 } 70 # 檢查檔案是否存在,不存在則建立 71 check_file_exists() { 72 local file_name=$1 73 if [ ! -f "$file_name" ];then 74 touch $file_name 75 if [ $? -ne 0 ];then 76 log_err "[check_file_exists] file: $file_name 檔案建立失敗!" 77 fi 78 fi 79 } 80 81 82 83 # 監聽檔案事件 84 watch_file() { 85 inotifywait -mrq --format '%e' --event create,delete,modify $file_name | while read event ;do 86 case "$event" in 87 MODIFY) 88 start_read_file 89 ;; 90 # 檔案被刪除或重新建立 91 CREATE|DELETE) 92 # 重置檔案行數 93 line=0 94 > $line_file_name 95 check 96 ;; 97 *) 98 log_warning "[watch_file] watch file event: $event" 99 ;; 100 esac 101 done 102 } 103 104 # 只讀一行 105 read_line_file() { 106 ((line++)) 107 echo $line > $line_file_name 108 # 不是指定資料退出 109 if [ $(sed -n "$line p" $file_name | grep 'pam_unix(sshd:auth): authentication failure;' | wc -l ) -ne 1 ];then 110 return 111 fi 112 # 控制是否進行寫入 113 write_status=0 114 oneSecureKey=$(sed -n "$line p" $file_name |awk -v dateNow=$(date +"%Y") '{ 115 split($0,rhost,"rhost=") 116 split(rhost[2],rhost," ") 117 split($0,user," user=") 118 if (length(user[2])==0) { 119 user[2]="None" 120 } 121 print dateNow":"$1":"$2","rhost[1]","user[2] 122 }') 123 log_info "[read_line_file] line: $line data:[$oneSecureKey]" 124 125 send_map $oneSecureKey 126 } 127 128 # 往MAP中塞入資料 129 send_map() { 130 local key=$1 131 if [ -n ${secureMap[$key]} ];then 132 secureMap[$key]=`expr ${secureMap[$key]} + 1` 133 else 134 secureMap[$key]=1 135 fi 136 } 137 138 wirte_all_secure() { 139 for key in ${!secureMap[@]};do 140 write_one_secure $key 141 done 142 } 143 144 write_one_secure() { 145 local key="$@" 146 local data=$(grep -w -n "$key" $ssh_auth_failed_file) 147 if [ -n "$data" ];then 148 local i=$(echo $data | awk -F: '{print $1}') 149 local a=$(echo $data | awk -F, '{print $NF}') 150 sed -i "${i} s#$a#${secureMap[$key]}#" $ssh_auth_failed_file 151 if [ $? -ne 0 ];then 152 log_err "[write_secure] 寫 $ssh_auth_failed_file 檔案失敗! data:[$key,${secureMap[$key]}]" 153 fi 154 else 155 # 新資料 156 echo "$key,${secureMap[$key]}" >> $ssh_auth_failed_file 157 if [ $? -ne 0 ];then 158 log_err "[write_secure] 寫 $ssh_auth_failed_file 檔案失敗! data:[$key,${secureMap[$key]}]" 159 fi 160 fi 161 log_info "[write_secure] line: $line status: $write_status data:[$key,${secureMap[$key]}]" 162 } 163 164 165 166 # 啟動前應先檢查是否讀取過 167 check() { 168 # 檢查預存Inode是否一致 169 check_secure_file_inode 170 } 171 172 # 檢查登入日誌Inode是否一致 173 check_secure_file_inode() { 174 inode=$(ls -i $file_name | awk '{print $1}') 175 inode_file_data="$(cat $inode_file)" 176 if [ -n "$inode_file_data" ]; then 177 if [ $inode -ne $inode_file_data ];then 178 log_warning "[check_secure_file_inode] secure file inode is inconsistency" 179 # inode不一致,重置 180 echo "$inode" > $inode_file 181 inode_file_status=1 182 else 183 inode_file_status=0 184 fi 185 else 186 # 第一次讀取 187 echo "$inode" > $inode_file 188 inode_file_status=1 189 fi 190 } 191 192 # 開始讀取檔案 193 start_read_file() { 194 # 第一次讀取 195 if [ $inode_file_status -eq 1 ] ;then 196 # 使用迴圈將歷史內容讀取 197 while true;do 198 if [ $line -eq $(wc -l < $file_name) ];then 199 break 200 fi 201 read_line_file 202 done 203 wirte_all_secure 204 elif [ $line -ne $(wc -l < $file_name) ];then 205 # 使用迴圈將行數對齊 206 while true;do 207 if [ $line -eq $(wc -l < $file_name) ];then 208 break 209 fi 210 read_line_file 211 if [ $write_status -eq 0 ];then 212 write_one_secure $oneSecureKey 213 fi 214 # 狀態設定為1 215 write_status=1 216 done 217 # else 218 # read_line_file 219 # if [ $write_status -eq 0 ];then 220 # write_one_secure $oneSecureKey 221 # fi 222 # # 狀態設定為1 223 # write_status=1 224 fi 225 } 226 227 test_main() { 228 init 229 check_secure_file_inode 230 231 } 232 233 main() { 234 # 初始化 235 init 236 # 內容檢查 237 check 238 start_read_file 239 log_info "[main] watch secure startd" 240 watch_file 241 } 242 243 main