inotify
、awk
、grep
等工具,来实现对日志文件的实时监控与分析。inotify
命令动态监控日志文件的变动,并结合 sed
命令实时提取和输出新增的登录日志。grep
等工具过滤出登录失败、异常登录等相关信息。#!/bin/bash
# 作者: 阿杰
# 用途: 实时检测登录日志,统计异常登录
# 脚本名称: watch_secure.sh
# 用法: bash watch_seacure.sh
# 日志记录
log_err() {
printf "[$(date +'%Y-%m-%dT%H:%M:%S')]: \033[31mERROR: \033[0m$@\n"
}
log_info() {
printf "[$(date +'%Y-%m-%dT%H:%M:%S')]: \033[32mINFO: \033[0m$@\n"
}
log_warning() {
printf "[$(date +'%Y-%m-%dT%H:%M:%S')]: \033[33mWARNING: \033[0m$@\n"
}
# 初始化Map
declare -A secureMap
init() {
# 行数记录文件
line_file_name="conf/line_file.txt"
# inode存储文件
inode_file="conf/inode.txt"
# 认证失败文件记录
ssh_auth_failed_file="conf/ssh_auth_failed.csv"
# 文件列表
file_array=("$line_file_name" "$inode_file" "$ssh_auth_failed_file")
# inode 文件状态
inode_file_status=0
# 控制是否进行写入 0为可写,1为不可写
write_status=1
oneSecureKey=""
{
if [ ! -d "conf" ];then
mkdir conf
fi
# 检查文件是否存在
for file in ${file_array[@]};do
check_file_exists $file
done
line=$(cat $line_file_name)
if [ -z "$line" ];then
line=0
fi
# 认证失败文件第一次创建
if [ $(wc -l < $ssh_auth_failed_file) -eq 0 ];then
# 时间以月天为单位(None为空账号或不存在账号)
echo "登录认证失败时间,源IP地址,登录账号,连接认证失败次数" > $ssh_auth_failed_file
fi
}
file_name="/var/log/secure"
if [ -z "$(rpm -qa | grep 'inotify-tools')" ];then
yum install -y inotify-tools > /dev/null 2>&1
if [ $? -ne 0 ];then
log_err "[init] inotify-tools 安装失败!"
fi
fi
}
# 检查文件是否存在,不存在则创建
check_file_exists() {
local file_name=$1
if [ ! -f "$file_name" ];then
touch $file_name
if [ $? -ne 0 ];then
log_err "[check_file_exists] file: $file_name 文件创建失败!"
fi
fi
}
# 监听文件事件
watch_file() {
inotifywait -mrq --format '%e' --event create,delete,modify $file_name | while read event ;do
case "$event" in
MODIFY)
start_read_file
;;
# 文件被删除或重新创建
CREATE|DELETE)
# 重置文件行数
line=0
> $line_file_name
check
;;
*)
log_warning "[watch_file] watch file event: $event"
;;
esac
done
}
# 只读一行
read_line_file() {
((line++))
echo $line > $line_file_name
# 不是指定数据退出
if [ $(sed -n "$line p" $file_name | grep 'pam_unix(sshd:auth): authentication failure;' | wc -l ) -ne 1 ];then
return
fi
# 控制是否进行写入
write_status=0
oneSecureKey=$(sed -n "$line p" $file_name |awk -v dateNow=$(date +"%Y") '{
split($0,rhost,"rhost=")
split(rhost[2],rhost," ")
split($0,user," user=")
if (length(user[2])==0) {
user[2]="None"
}
print dateNow":"$1":"$2","rhost[1]","user[2]
}')
log_info "[read_line_file] line: $line data:[$oneSecureKey]"
send_map $oneSecureKey
}
# 往MAP中塞入数据
send_map() {
local key=$1
if [ -n ${secureMap[$key]} ];then
secureMap[$key]=`expr ${secureMap[$key]} + 1`
else
secureMap[$key]=1
fi
}
wirte_all_secure() {
for key in ${!secureMap[@]};do
write_one_secure $key
done
}
write_one_secure() {
local key="$@"
local data=$(grep -w -n "$key" $ssh_auth_failed_file)
if [ -n "$data" ];then
local i=$(echo $data | awk -F: '{print $1}')
local a=$(echo $data | awk -F, '{print $NF}')
sed -i "${i} s#$a#${secureMap[$key]}#" $ssh_auth_failed_file
if [ $? -ne 0 ];then
log_err "[write_secure] 写 $ssh_auth_failed_file 文件失败! data:[$key,${secureMap[$key]}]"
fi
else
# 新数据
echo "$key,${secureMap[$key]}" >> $ssh_auth_failed_file
if [ $? -ne 0 ];then
log_err "[write_secure] 写 $ssh_auth_failed_file 文件失败! data:[$key,${secureMap[$key]}]"
fi
fi
log_info "[write_secure] line: $line status: $write_status data:[$key,${secureMap[$key]}]"
}
# 启动前应先检查是否读取过
check() {
# 检查预存Inode是否一致
check_secure_file_inode
}
# 检查登录日志Inode是否一致
check_secure_file_inode() {
inode=$(ls -i $file_name | awk '{print $1}')
inode_file_data="$(cat $inode_file)"
if [ -n "$inode_file_data" ]; then
if [ $inode -ne $inode_file_data ];then
log_warning "[check_secure_file_inode] secure file inode is inconsistency"
# inode不一致,重置
echo "$inode" > $inode_file
inode_file_status=1
else
inode_file_status=0
fi
else
# 第一次读取
echo "$inode" > $inode_file
inode_file_status=1
fi
}
# 开始读取文件
start_read_file() {
# 第一次读取
if [ $inode_file_status -eq 1 ] ;then
# 使用循环将历史内容读取
while true;do
if [ $line -eq $(wc -l < $file_name) ];then
break
fi
read_line_file
done
wirte_all_secure
elif [ $line -ne $(wc -l < $file_name) ];then
# 使用循环将行数对齐
while true;do
if [ $line -eq $(wc -l < $file_name) ];then
break
fi
read_line_file
if [ $write_status -eq 0 ];then
write_one_secure $oneSecureKey
fi
# 状态设置为1
write_status=1
done
# else
# read_line_file
# if [ $write_status -eq 0 ];then
# write_one_secure $oneSecureKey
# fi
# # 状态设置为1
# write_status=1
fi
}
test_main() {
init
check_secure_file_inode
}
main() {
# 初始化
init
# 内容检查
check
start_read_file
log_info "[main] watch secure startd"
watch_file
}
main
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。