基线巡检
基线一般指配置和管理系统的详细描述,或者说是最低的安全要求,包括服务和应用程序设置、操作系统组件的配置、权限和权利分配、管理规则等。云安全中心的基线检查功能支持检测服务器的安全配置,例如服务器上的系统、账号、数据库、弱密码、合规性配置中存在的风险点,提供检测详情说明和基线加固建议。用户可以根据自己的需求,新增、编辑、删除基线检查策略,设置基线检查等级的范围以及自定义弱口令规则。
为规范公司中间件系统的稳定运行和加强公司中间件巡检作业管理工作标准进行,保证各中间件在规定的配置下运行,满足安全、审计等需求。方便看出每个中间件实例配置情况,编写巡检脚本,见此文。
实现原理:
1、读取基准基线文件
2、取各台服务器配置文件
3、格式化基准文件,以便于后续匹配使用
4、依次对获取的配置文件 与 格式化后的基准文件做匹配。
5、将不同配置的项目输出,以便查阅。
如不存在基线的配置,则发出警告
原理图:
代码详情:
1、读取基准基线文件
filedir="/tmp/nbaseline_check"
filepath="/tmp/baseline_check/nginx_baseline.txt"
cmd="curl -o $filepath -u svnauth:this-is-a-token -O http://SVN-URL/artifactory/ops-generic-tools-local/middleware/nginx/baseline/nginx_baseline.txt"
if [ ! -d "$filedir" ]; then
mkdir $filedir
fi
echo command: $cmd
$cmd
cat $filepath
if [ -f $filepath ]; then
#ls -l |grep nginx_baseline.txt
atime=`stat -c %Y $filepath`
btime=$(date +%s)
timediff=$(( atime - btime ))
timedetla=$(( timediff/84600))
if [ "$timedetla" -ge 1 ]; then
echo "不是最新的文件"
else
echo "获取到当天文件" $filepath
fi
else
echo "文件不存在"
fi
2、取各台服务器文件发送到本机,使用expect脚本输入各服务器的密码(亦可使用ssh_pass 或者 ssh免密登录解决此问题 )
#collect-baseline.sh IP.txt
File=`cat ip.txt` #192.168.1.1-192.168.1.2-192.168.1.3
echo $File
OLD_IFS="$IFS"
IFS="-"
array=(${File//-,/}) #按-分割ip
IFS="$OLD_IFS"
for ip in ${array[@]}
do
if [ ! -n "$ip" ] ; then
echo ip is null
break
fi
echo "$ip" >> /tmp/nginx_baseline_check/test.log
download_nginxconf_all.sh $ip &
done
#echo "ip"
wait
WriteLog $1 0 "process succeed."
通过expect脚本,将服务器文件拷贝至本机tmp目录,并通过中转服务器将文件带IP传至中转机。脚本执行步骤将以日志形式保存在本机/tmp/nginx_baseline_check/download.log路径下
#!/usr/bin/expect -f
#download_nginxconf_all.sh $IP
log_file /tmp/nginx_baseline_check/download.log
log_user 0
set date [ exec date "+%Y_%m_%d:%H:%m:%s" ]
set remote_host [lindex $argv 0]
set remote_path [lindex $argv 1]
set err_flag1 0
#set err_flag2 0
#set err_flag3 0
#set err_flag4 0
set timeout 5
spawn ssh user$remote_host
expect "continue connecting" { send "yes\r" ; exp_continue }
expect "password"
send "this_is_my_password/r"
expect "*ermission denied" { send_user "密码错误\n" ; exit 1 }
expect "Connection time out" { send_user "Connection time out@" ; send_user $remote_host ; send_user "\n" ; exit 2 ; }
exec sleep 1
send "sudo -i\r"
send "cp /home/nginxweb/nginx-1.18.0/conf/nginx.conf /tmp/\r"
expect "没有那个文件或目录" { send_user "Not found nginx1.18.0/.../nginx.conf @ $remote_host \n" ; set err_flag1 ; exp_continue }
expect "*o such file or directory" { send_user "Not found nginx1.18.0/.../nginx.conf @ $remote_host \n" ; set err_flag1 ; exp_continue }
expect "是否覆盖" { send "y\r"; expect_continue }
expect "overwrite" { send "y\r"; expect_continue }
send "chmod a+r /tmp/nginx.conf\r"
send "exit\r"
exec sleep 1
send "exit\r"
send_user $date ; send_user "\n"
send_user $remote_host ; send_user "\n"
send_user "err_flag1:" ; send_user err_flag1 ; send_user "\n"
expect eof
spawn scp iapopr@remote_host:/tmp/nginx.conf /tmp/nginx_baseline_check/nginx.conf_$remote_host
expect "password" { send "this_is_my_password/r" }
expect "*ermission denied" { send_user "密码错误\n" ; exit 4 }
if { $err_flag1 * $err_flag2 == 0 }
{
send_user $remote_host ; send_user "download all succeed.\n"
} else
{
send_user $remote_host ; send_user "download all failed.\n"
}
日志模板如下:
not found nginx-1.10.0/../nginx.conf @ 192.168.1.3 --->err_flag2
not found nginx-1.10.2/../nginx.conf@ 192.168.1.3 --->err_flag3
not found tengine-2.1.0/../nginx.conf @ 192.168.1.3 --->err_flag4
2021_10_04:07:10:1633302002
192.168.1.3
err_flag1:0
err_flag2:1
err_flag3:1
err_flag4:1
10.134.14.73 download succeed.
3、比对配置文件与基线文件
默认nginx基线文件不规整,具有空行,注释行等内容,先对基线文件进行预处理,以备后续正则匹配使用。
注:如遇到不等数量空格和空白字符,且需要正则匹配的,将其转换为【\s\+】,以正则匹配。
#!/bin/bash
cd /tmp/nginx_baseline_check/
baseline="/tmp/nginx_baseline_check/nginx_baseline.txt" #获取baseline文件不再赘述
#baseline="/root/scripts/liuli/middleware/nginx/hx1/nginx_baseline";
echo $baseline
echo 0=======
sed -i 's/^[ ]*$//g' $baseline #去除空行或空格行
sed -i 's/^\s*$//g' $baseline #去除空行或空格行
cat $baseline
echo 1=======
sed -i 's/[ ]*$//g' $baseline #去除行末空格
cat $baseline
echo 2=======
sed -i 's/;*$//g' $baseline #去除行末分号
cat $baseline
echo 3=======
sed -i 's/[ ]*$//g' $baseline #去除行末空格
cat $baseline
echo 4======
sed -i 's/^ *#//g' $baseline #去除#开头的行
cat $baseline
echo 5======
#sed -i 's/\\s\+/\\\\s+/g' nginx_baseline #空格替换为\s
sed -i 's/\s\+/\\\\s\\\\+/g' $baseline
cat $baseline
echo 5=======
sed -i '/^\s*$/d ' $baseline #去除空行或空格行
cat $baseline
echo 6=======
sed -i 's/\\\\s\\\\+$//g' $baseline #去除行末空格
cat $baseline
具体处理代码较多,直接查看最后输出结果即可
/tmp/nginx_baseline_check/nginx_baseline.txt
0======= #去除空行或空格行
error_log /data/logs/nginx/error.log warn;
worker_rlimit_nofile 65535;
use epoll;
worker_connections 65535;
multi_accept on;
include mime.types;
default_type application/octet-stream;
access_log /data/logs/nginx/access.log access;
keepalive_timeout 65;
underscores_in_headers on;
server_tokens off;1======= #去除行末空格
error_log /data/logs/nginx/error.log warn;
worker_rlimit_nofile 65535;
use epoll;
worker_connections 65535;
multi_accept on;
include mime.types;
default_type application/octet-stream;
access_log /data/logs/nginx/access.log access;
keepalive_timeout 65;
underscores_in_headers on;
server_tokens off;2======= #去除分号行
error_log /data/logs/nginx/error.log warn;
worker_rlimit_nofile 65535;
use epoll;
worker_connections 65535;
multi_accept on;
include mime.types;
default_type application/octet-stream;
access_log /data/logs/nginx/access.log access;
keepalive_timeout 65;
underscores_in_headers on;
server_tokens off3======= #除去行末空格
error_log /data/logs/nginx/error.log warn;
worker_rlimit_nofile 65535;
use epoll;
worker_connections 65535;
multi_accept on;
include mime.types;
default_type application/octet-stream;
access_log /data/logs/nginx/access.log access;
keepalive_timeout 65;
underscores_in_headers on;
server_tokens off4====== #去除#开头的行
error_log /data/logs/nginx/error.log warn;
worker_rlimit_nofile 65535;
use epoll;
worker_connections 65535;
multi_accept on;
include mime.types;
default_type application/octet-stream;
access_log /data/logs/nginx/access.log access;
keepalive_timeout 65;
underscores_in_headers on;
server_tokens off5====== #空格替换为\s\+
error_log\\s\\+/data/logs/nginx/error.log\\s\\+warn;\\s\\+
worker_rlimit_nofile\\s\\+65535;\\s\\+
use\\s\\+epoll;\\s\\+
worker_connections\\s\\+65535;\\s\\+
multi_accept\\s\\+on;\\s\\+
include\\s\\+mime.types;\\s\\+
default_type\\s\\+application/octet-stream;\\s\\+
access_log\\s\\+/data/logs/nginx/access.log\\s\\+access;\\s\\+
keepalive_timeout\\s\\+65;\\s\\+
underscores_in_headers\\s\\+on;\\s\\+
server_tokens\\s\\+off5======= #去除空行或空格行
error_log\\s\\+/data/logs/nginx/error.log\\s\\+warn;\\s\\+
worker_rlimit_nofile\\s\\+65535;\\s\\+
use\\s\\+epoll;\\s\\+
worker_connections\\s\\+65535;\\s\\+
multi_accept\\s\\+on;\\s\\+
include\\s\\+mime.types;\\s\\+
default_type\\s\\+application/octet-stream;\\s\\+
access_log\\s\\+/data/logs/nginx/access.log\\s\\+access;\\s\\+
keepalive_timeout\\s\\+65;\\s\\+
underscores_in_headers\\s\\+on;\\s\\+
server_tokens\\s\\+off6======= 去除行末空格
error_log\\s\\+/data/logs/nginx/error.log\\s\\+warn;
worker_rlimit_nofile\\s\\+65535;
use\\s\\+epoll;
worker_connections\\s\\+65535;
multi_accept\\s\\+on;
include\\s\\+mime.types;
default_type\\s\\+application/octet-stream;
access_log\\s\\+/data/logs/nginx/access.log\\s\\+access;
keepalive_timeout\\s\\+65;
underscores_in_headers\\s\\+on;
server_tokens\\s\\+off
4、检查正则匹配,使用grep正则匹配配置文件,使用grep的返回值判断是否匹配成功。
#!/bin/bash
#cd /tmp/nginx_baseline_check/
svc_cfg="/tmp/nginx_baseline_check/nginx.conf_*"
baseline_cfg="/tmp/nginx_baseline_check/nginx_baseline.txt"
#echo $svc_cfg
output_file="/tmp/nginx_baseline_check/output.html"
OLD_IFS="$IFS"
IFS="-"
array=(${svc_cfg/ ,/})
IFS="$OLD_IFS"
echo "<html>" > $output_file
echo "<style type='text/css'>
body{
margin: 6px;
padding: 0;
font-size: 12px;
font-family: tahoma, arial;
}
table{
border-collapse: collapse;
}
table th{
text-align: left;
background: #9cf;
padding: 3px;
border: 1px #333 solid;
}
table td{
padding: 3px;
border: none;
border:1px #333 solid;
}
tr:hover,
tr.hover{
background: #9cf;
}
</style>" >> $output_file
echo "<table border='1' cellspacing='0' bordercolor='#000000' style='BORDER-COLLAPSE: collapse'>" >> $output_file
echo "<tr>
<th>IP地址及结果</th>
<th>巡检异常内容</th>
</tr>" >> $output_file
#Local err_flag=0
#Local count=0
for each_config_path in ${array[@]}
do
err_flag=0
echo $each_config_path
count=1
err_info="基线第"
while read LINE
do
echo line No. $count : $LINE
cmd=`grep -n --color $LINE $each_config_path`
# #echo cmd: $cmd
#echo line: $LINE
if [[ $cmd ]] ; then
echo -e "匹配成功:基线行号:$count : 配置文件行号:$cmd\n "
else
echo -e "结果不正常,为空或报错"
echo -e $each_config_path "配置内容与基线不一致,请检查"
err_flag=$[$err_flag +1]
echo err_flag: $err_flag
err_info="$err_info$count 行: 无${LINE//\\s\\+/ }\n"
echo -e err_info: $err_info
fi
count=$[$count+1]
done < $baseline_cfg
if [ $err_flag -ne 0 ] ; then
echo -e "<tr> <td>" >> $output_file
echo -e "${each_config_path:37} 巡检失败 </td>" >> $output_file
echo -e "<td> $err_info </td> </tr> " >> $output_file
else
echo -e "<tr> <td>" >> $output_file
echo -e "${each_config_path:37} 巡检成功 </td> </tr> " >> $output_file
fi
echo "==================================="
done
echo '</table> </html>' >> $output_file
最后生成网页文件,内容如下: