Linux运维人员共用root帐户权限审计

一、应用场景

在中小型企业,公司不同运维人员基本都是以root 账户进行服务器的登陆管理,缺少了账户权限审计制度。不出问题还好,出了问题,就很难找出源头。

这里介绍下,如何利用编译bash 使不同的客户端在使用root 登陆服务器使,记录各自的操作,并且可以在结合ELK 日志分析系统,来收集登陆操作日志

二、环境

服务器:centos 6.5、Development tools、使用密钥认证,SElinux 关闭。

客户端:生成密钥对,用于登录服务器 (2台)

三、搭建部署

服务器操作 : 192.168.1.11

客户机操作 : 192.168.1.71

客户机操作 : 192.168.1.72

1、下载编译bash
mkdir -pv /mydata/software
cd /mydata/software
yum -y install wget
wget http://ftp.gnu.org/gnu/bash/bash-4.1.tar.gz
[root@bogon software]# tar zxf bash-4.1.tar.gz 
[root@bogon software]# cd bash-4.1
[root@bogon bash-4.1]#
2、 先修改下 config-top.h文件,大概91行、104行,由于c 语言中 注释是/**/ ,所以不要删除错了。修改如下:
 [root@bogon bash-4.1]# vim config-top.h
 91 /* #define SSH_SOURCE_BASHRC */  #去注释
 92 
 93 /* Define if you want the case-capitalizing operators (~[~]) and the
 94    `capcase' variable attribute (declare -c). */
 95 #define  CASEMOD_CAPCASE
 96 
 97 /* This is used as the name of a shell function to call when a command
 98    name is not found.  If you want to name it something other than the
 99    default ("command_not_found_handle"), change it here. */
100 /* #define NOTFOUND_HOOK "command_not_found_handle" */
101 
102 /* Define if you want each line saved to the history list in bashhist.c:
103    bash_add_history() to be sent to syslog(). */
104 /* #define SYSLOG_HISTORY */  #去注释
3 修改下bashhist.c 文件,让终端上的命令记录到系统messages 中,并且以指定的格式。并传入获得的变量。修改后的内容如下:(将701-715内容替换为下面内容)
void
bash_syslog_history (line)
    const char *line;
{
  char trunc[SYSLOG_MAXLEN];
    const char *p;
    p = getenv("NAME_OF_KEY");
  if (strlen(line) < SYSLOG_MAXLEN)
    syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY: PID=%d PPID=%d SID=%d  User=%s USER=%s CMD=%s", getpid(), getppid(), getsid(getpid()),  current_user.user_name, p, line);
  else
    {
      strncpy (trunc, line, SYSLOG_MAXLEN);
      trunc[SYSLOG_MAXLEN - 1] = ' ';
      syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY (TRUNCATED): PID=%d  PPID=%d SID=%d User=%s USER=%s CMD=%s", getpid(), getppid(), getsid(getpid()), current_user.user_name, p, trunc);
    }
}
4 配置安装路径,编译安装,编译到/usr/local/目录下
[root@bogon bash-4.1]# ./configure --prefix=/usr/local/bash_new
[root@bogon bash-4.1]# make && make install
if test "bash" = "gettext-tools"; then \
      /bin/sh /mydata/software/bash-4.1/./support/mkinstalldirs /usr/local/bash_new/share/gettext/po; \
      for file in Makefile.in.in remove-potcdate.sin quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot   Makevars.template; do \
        /usr/bin/install -c -m 644 ./$file \
                /usr/local/bash_new/share/gettext/po/$file; \
      done; \
      for file in Makevars; do \
        rm -f /usr/local/bash_new/share/gettext/po/$file; \
      done; \
    else \
      : ; \
    fi
make[1]: Leaving directory `/mydata/software/bash-4.1/po'
5、编译完成后,将新的bash 追加到 /etc/shells 中,并修改root用户的登陆shell 环境为新编译的shell
[root@bogon bash-4.1]# echo "/usr/local/bash_new/bin/bash" >> /etc/shells 
[root@bogon bash-4.1]# cat !$
cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
/usr/local/bash_new/bin/bash
[root@bogon bash-4.1]# vim /etc/passwd
root:x:0:0:root:/root:/usr/local/bash_new/bin/bash
6、注销当前root用户,重新登陆后,查看/var/log/messages,如下就可以看到记录了操作命令

Nov  8 11:17:24 localhost -bash: HISTORY: PID=11723 PPID=11721 SID=11723  User=root USER=(null) CMD=cd /mydata/
Nov 8 11:17:26 localhost -bash: HISTORY: PID=11723 PPID=11721 SID=11723 User=root USER=(null) CMD=mkdir test
Nov 8 11:17:28 localhost -bash: HISTORY: PID=11723 PPID=11721 SID=11723 User=root USER=(null) CMD=cd test/
Nov 8 11:17:32 localhost -bash: HISTORY: PID=11723 PPID=11721 SID=11723 User=root USER=(null) CMD=touch a.txt
Nov 8 11:17:41 localhost -bash: HISTORY: PID=11723 PPID=11721 SID=11723 User=root USER=(null) CMD=echo “wgli.vip” > a.txt

四、SSH客户端生成密钥部分
1 在client1上(192.168.1.71)操作,用户zhangsan

[root@bogon ~]# ssh-keygen -t rsa -C “root@zhangsan-71”
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory ‘/root/.ssh’.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
26:8e:47:f2:c3:c2:3f:02:5b:33:8a:34:13:fa:7f:43 root@zhangsan-71
The key’s randomart image is:
+–[ RSA 2048]—-+
| |
| |
| |
| . |
|. . . o S |
|.+..+BEo |
|.oo=++ |
|. + .++. |
| ..o.o |
+—————–+

-C 注释 (加上这个也是为了最后进行对服务器访问人员进行辨别的一个关键点)
2、将公钥上传到服务器上的.ssh/authorized_keys 文件中。ssh-copy-id 命令会自动在服务器上创建.ssh/authorized_keys文件,即使该目录不存在,并自动赋予600权限。

[root@bogon ~]# ssh-copy-id -i .ssh/id_rsa.pub root@192.168.1.11
The authenticity of host ‘192.168.1.11 (192.168.1.11)’ can’t be established.
RSA key fingerprint is d8:b1:ae:96:11:e7:15:c0:78:61:9b:45:75:ad:f2:22.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added ‘192.168.1.11’ (RSA) to the list of known hosts.
reverse mapping checking getaddrinfo for bogon [192.168.1.11] failed - POSSIBLE BREAK-IN ATTEMPT!
root@192.168.1.11’s password:
Now try logging into the machine, with “ssh ‘root@192.168.1.11’”, and check in:

.ssh/authorized_keys

to make sure we haven’t added extra keys that you weren’t expecting.

3、client 2(192.168.1.72) 上同样的操作,用户lisi
[root@bogon ~]# ssh-keygen -t rsa -C “root@lisi-72”
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory ‘/root/.ssh’.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
e7:78:33:ce:a5:45:cd:01:da:ca:9d:f9:67:32:ed:41 root@lisi-72
The key’s randomart image is:
+–[ RSA 2048]—-+
| . |
| o . |
| . . . |
| . o = . |
| S + = oE |
| + . … |
| . = o +.+|
| + *.|
| + .|
+—————–+

[root@bogon ~]# ssh-copy-id -i .ssh/id_rsa.pub root@192.168.1.11
The authenticity of host ‘192.168.1.11 (192.168.1.11)’ can’t be established.
RSA key fingerprint is d8:b1:ae:96:11:e7:15:c0:78:61:9b:45:75:ad:f2:22.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added ‘192.168.1.11’ (RSA) to the list of known hosts.
reverse mapping checking getaddrinfo for bogon [192.168.1.11] failed - POSSIBLE BREAK-IN ATTEMPT!
root@192.168.1.11’s password:
Now try logging into the machine, with “ssh ‘root@192.168.1.11’”, and check in:

.ssh/authorized_keys

to make sure we haven’t added extra keys that you weren’t expecting.

4、现在去服务器上验证下该文件
[root@walle ~]# cat .ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAzoD5xJmYGawtoKC3vv337K2UoIw1EAwn8XDE0aJVgckBZNH36Vhs1M/6KgRfdLBtVzqnFMw7c9qAxlpoy3q5/3ajcmMeVwKETEJqD5gHQYZ0dGv/rktRWoochCi7WTEJq1M0aqE8GaMKxHVW0+SBLP1pw7pEh5UtwQsJ/JcoKNR3GRfO3I1OYBTrvTG+IRxq7xCsoFKPsZYgsHw20fVscgwRINFgY5gDKxAxiobMQUSyy5ZYvrqutYNTWZIrzbfMUi3PvmcQswOBGCyTGYgxm/5CG4lhsdUfcpR6OrrxKJs0/YHuUkLbb/wAPuz1DpSFSrBfC77X10IxTREIqZFUvw== root@zhangsan-71
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAwoBXpTUJ1Z5Dbu+hywdcimeRwemnl8TON1lCtn5o7c9phcAcgxK4qoDiyncmrMztVwmezJJxum0sMqUlJHipdwPQJUaGb0Xu3JVNRUTz8KcpTitRjcZaMqOgS/UA9ltq1cmEqHhDPbyU+zZZfe115t5K0WJgg2hsKqgJVep/RX96jTC+iGMKUSkvQRZBbVz86shxZUBdfIjh08afwC+SeqrJQ3IRAqwX1xWkWYrKW42V+5kS0g6wIBpI/1nM0yKl0KqE8cj9qF+kiXK9rUJqOVg5q6YudQyVmQX1uyrYXtO3REYETi2ki2owKWorDebs7yZkQjba1dvTvOle8syqdQ== root@lisi-72

5、现在上面两个客户端已经可以免密钥登陆了,现在去服务器上配置,并创建脚本
五、配置服务器
1、在log目录下创建一个 keys 文件,用于登陆时存进去公钥,之后对其进行取出判断的

[root@walle ~]# touch /var/log/keys

2、创建检测脚本,内容如下:
[root@walle ~]# cat /etc/CheckUser.sh
#!/bin/bash
#conding:utf-8
pid=$PPID
#在自己home目录得到所有的key,如果/var/log/keys 没有的时候,添加进去
while read line
do
grep “$line” /var/log/keys >/dev/null || echo “$line” >> /var/log/keys
done < $HOME/.ssh/authorized_keys
#得到每个key的指纹
cat /var/log/keys | while read LINE
do
NAME=$(echo $LINE | awk ‘{print $3}’)
echo $LINE >/tmp/keys.log.$pid
KEY=$(ssh-keygen -l -f /tmp/keys.log.$pid | awk ‘{print $2}’)
grep “$KEY $NAME” /var/log/ssh_key_fing >/dev/null || echo “$KEY $NAME” >> /var/log/ssh_key_fing
done
#如果是root用户,secure文件里面是通过PPID号验证指纹
if [ $UID == 0 ]
then
ppid=$PPID
else
#如果不是root用户,验证指纹的是另外一个进程号
ppid=/bin/ps -ef | grep $PPID |grep 'sshd:' |awk '{print $3}'
fi
#得到RSA_KEY和NAME_OF_KEY,用来bash4.1得到历史记录
RSA_KEY=/bin/egrep 'Found matching RSA key' /var/log/secure | /bin/egrep "$ppid" | /bin/awk '{print $NF}' | tail -1
if [ -n “$RSA_KEY” ];then
NAME_OF_KEY=/bin/egrep "$RSA_KEY" /var/log/ssh_key_fing | /bin/awk '{print $NF}'
fi
#把NAME_OF_KEY设置为只读
readonly NAME_OF_KEY
export NAME_OF_KEY
/bin/rm /tmp/keys.log.$pid

3、配置 profile,在文件末尾添加一行内容,如下:
[root@walle ~]# echo “test -f /etc/CheckUser.sh && . /etc/CheckUser.sh” >> /etc/profile

4、在/etc/bashrc 末尾添加下面内容:
[root@walle ~]# tail -1f /etc/bashrc
test -z “$BASH_EXECUTION_STRING” || { test -f /etc/CheckUser.sh && . /etc/CheckUser.sh; logger -t -bash -s “HISTORY $SSH_CLIENT USER=$NAME_OF_KEY CMD=$BASH_EXECUTION_STRING “ >/dev/null 2>&1;}

5、修改sshd 配置文件,开启debug 模式,并重启sshd服务
[root@walle ~]# sed -i ‘s/#LogLevel INFO/LogLevel DEBUG/g’ /etc/ssh/sshd_config
[root@walle ~]# service sshd restart
Stopping sshd: [ OK ]
Starting sshd: [ OK ]

六、验证
1、在client1 上进行登陆,并创建个文件试下(zhangsan)

Nov  8 17:33:45 walle -bash: HISTORY: PID=10371 PPID=10369 SID=10371  User=root USER=root@zhangsan-71 CMD=cd /mydata/software/
Nov 8 17:33:52 walle -bash: HISTORY: PID=10371 PPID=10369 SID=10371 User=root USER=root@zhangsan-71 CMD=mkdir a.txt
Nov 8 17:33:55 walle -bash: HISTORY: PID=10371 PPID=10369 SID=10371 User=root USER=root@zhangsan-71 CMD=ls -lh a.txt/
Nov 8 17:34:05 walle -bash: HISTORY: PID=10371 PPID=10369 SID=10371 User=root USER=root@zhangsan-71 CMD=echo AA > a.txt/

2、在client2 上进行登陆,并创建个文件试下(lisi)
Nov  8 17:35:49 walle -bash: HISTORY: PID=10438 PPID=10436 SID=10438  User=root USER=root@lisi-72 CMD=cd /mydata/software/
Nov 8 17:35:51 walle -bash: HISTORY: PID=10438 PPID=10436 SID=10438 User=root USER=root@lisi-72 CMD=rm -rf a.txt/

 

通过上图,可以看出,不通用户的客户端通过公钥登陆的方式,分辨出了谁操作了什么,什么时候操作的
七、结束
 通过这种方式,极大的解决了多root 用户登陆操作,无法审计的问题。并且可以结合日志转发,将系统日志转发到其它服务器,即使主机被黑了,也能具体的审查登陆时间以及做了哪些操作。 
-------------本文结束感谢您的阅读-------------