写点什么

运维防背锅的办法之一:命令审计

作者:蝉翼2u
  • 2024-07-21
    广东
  • 本文字数:3180 字

    阅读完需:约 10 分钟

运维防背锅的办法之一:命令审计

需求

运维工程师在工作中经常会遇到这样的问题:


  • 服务器的文件被删除了,谁干的?

  • 服务器的整个服务被删除了,谁干的?

  • 服务器上启动了一个奇怪的进程占据了大量的 CPU,谁干的?


这个时候,如果我们找不到始作俑者,那毫无疑问得运维自己背锅。如果有证据证明是别人干的,我们才能坦然地(甩锅)找到对应的人问清楚原因。这个时候,我们就需要做好服务器的命令审计。


下面,给大家介绍一种非常简单实用的服务器命令审计方式,设置一个命令审计日志系统,非常好用!

配置

我们只需要把这一段代码执行,就完成了配置:


# 创建目录和文件sudo mkdir -p /var/log/cmd_auditsudo touch /var/log/cmd_audit/audit.log
# 设置目录和文件权限sudo chmod 755 /var/log/cmd_auditsudo chmod 662 /var/log/cmd_audit/audit.log
# 设置文件仅允许追加属性sudo chattr +a /var/log/cmd_audit/audit.log
# 写入内容到 /etc/profile.d/cmd_audit.shsudo tee /etc/profile.d/cmd_audit.sh > /dev/null << 'EOF'################## Audit ##################export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROLHISTTIMEFORMAT="%Y/%m/%d %T"; export HISTTIMEFORMAT
# 定义审计命令audit_command='{ thisHistID=`history 1 | awk "{print \\$1}"`; lastCommand=`history 1 | awk "{\\$1=\"\"; print}"`; user=`id -un`; pwd=`pwd`; whoStr=(`who -u am i`); realUser=${whoStr[0]}; logMonth=${whoStr[2]}; logDay=${whoStr[3]}; logTime=${whoStr[4]}; pid=${whoStr[6]}; ip=${whoStr[7]}; if [ ${thisHistID}x != ${lastHistID}x ]; then echo -E `date "+%Y/%m/%d %H:%M:%S"` $user\($realUser\)@$ip[IP:$pid][PWD:$pwd][LOGIN:$logMonth $logDay $logTime] --- $lastCommand; lastHistID=$thisHistID; fi; } >> $HISTORY_FILE'
# 检查和设置 PROMPT_COMMANDif [ -z "${PROMPT_COMMAND_READONLY}" ]; then if [ -z "${PROMPT_COMMAND}" ]; then export PROMPT_COMMAND="$audit_command" else export PROMPT_COMMAND="$PROMPT_COMMAND; $audit_command" fi export HISTORY_FILE=/var/log/cmd_audit/audit.log export PROMPT_COMMAND_READONLY=1 readonly PROMPT_COMMAND_READONLYfi################## Audit_end ##############
EOF
# 使配置立即生效source /etc/profile.d/cmd_audit.sh
复制代码


你可以直接复制后粘贴到服务器上,也可以执行下面这条命令帮你配置完成:


curl -s http://8.138.10.37/tools/setup_cmd_audit.sh | tee /tmp/setup_cmd_audit.sh && read -p "可以执行此文件吗? (y/n): " user_input && [ "$user_input" = "y" ] && bash /tmp/setup_cmd_audit.sh && rm /tmp/setup_cmd_audit.sh
复制代码

效果

执行后,登录到服务器上操作的命令行都会被记录到/var/log/audit/cmd_audit.log,我们看看效果:


[root@devops ~]# tail -f /var/log/cmd_audit/audit.log 2024/07/21 19:11:32 root(root)@[IP:(172.30.0.254)][PWD:/root][LOGIN:2024-07-21 19:11 .] --- 2024/07/21 19:10:46 date2024/07/21 19:11:38 root(root)@[IP:(172.30.0.254)][PWD:/root][LOGIN:2024-07-21 19:11 .] --- 2024/07/21 19:11:37 top2024/07/21 19:11:40 root(root)@[IP:(172.30.0.254)][PWD:/root][LOGIN:2024-07-21 19:11 .] --- 2024/07/21 19:11:40 touch demo2024/07/21 19:11:43 root(root)@[IP:(172.30.0.254)][PWD:/root][LOGIN:2024-07-21 19:11 .] --- 2024/07/21 19:11:43 rm -rf demo# 这是root切换到jaywin用户2024/07/21 19:11:59 jaywin(root)@[IP:(172.30.0.254)][PWD:/home/jaywin][LOGIN:2024-07-21 19:11 .] --- 2024/07/21 19:08:17 touch2024/07/21 19:12:05 jaywin(root)@[IP:(172.30.0.254)][PWD:/home/jaywin][LOGIN:2024-07-21 19:11 .] --- 2024/07/21 19:12:05 touch somefile
复制代码


并且,这个审计文件只能追加,任何用户都无法修改,删除!只有超级管理员才能查看,其他普通用户都无法查看!

解释

这个设置的原理是通过配置特殊变量PROMPT_COMMAND ,在每次显示提示符之前执行指定的命令。简而言之,它允许你在每次命令提示符出现之前运行一段代码。这在审计、日志记录和其他自动化任务中非常有用。


接下来说明下具体原理,这里涉及到几个知识点,我们根据脚本的内容一一来讲:


# 下面的配置保证了审计文件只有管理员才有权限操作!# 设置目录和文件权限sudo chmod 755 /var/log/cmd_audit    # 755表示目录权限是rwxr-xr-x,允许所有用户执行,以便在这个目录下的文件,能写入用户的命令sudo chmod 662 /var/log/cmd_audit/audit.log # 622表示文件权限是-rw-rw--w-,不允许其他用户查看文件内容
# 设置文件仅允许追加属性sudo chattr +a /var/log/cmd_audit/audit.log # chattr+a表示此文件仅允许追加操作,任何用户都无法修改文件内容或删除文件!
复制代码


以下是命令审计日志系统的重点解释:


export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL
复制代码


  • export 命令将指定的环境变量导出到当前环境,使它们在当前会话及其子进程中都可用。

  • PATH:指定可执行文件的搜索路径。

  • USER:当前用户的用户名。

  • LOGNAME:当前用户的登录名。

  • MAIL:当前用户的邮件目录。

  • HOSTNAME:当前主机的名称。

  • HISTSIZE:命令历史记录的最大条数。

  • HISTCONTROL:控制历史记录的行为。


HISTTIMEFORMAT="%Y/%m/%d %T"; export HISTTIMEFORMAT
复制代码


  • HISTTIMEFORMAT:设置历史记录中的时间格式。在这种情况下,时间格式为 YYYY/MM/DD HH:MM:SS

  • export HISTTIMEFORMAT:将 HISTTIMEFORMAT 变量导出到当前环境,使其在所有子进程中也可用。


audit_command='{ thisHistID=`history 1 | awk "{print \\$1}"`; lastCommand=`history 1 | awk "{\\$1=\"\"; print}"`; user=`id -un`; pwd=`pwd`; whoStr=(`who -u am i`); realUser=${whoStr[0]}; logMonth=${whoStr[2]}; logDay=${whoStr[3]}; logTime=${whoStr[4]}; pid=${whoStr[6]}; ip=${whoStr[7]}; if [ ${thisHistID}x != ${lastHistID}x ]; then echo -E `date "+%Y/%m/%d %H:%M:%S"` $user\($realUser\)@$ip[IP:$pid][PWD:$pwd][LOGIN:$logMonth $logDay $logTime] --- $lastCommand; lastHistID=$thisHistID; fi; } >> $HISTORY_FILE'
复制代码


thisHistID=`history 1 | awk "{print \\$1}"` # 获取当前历史IDlastCommand=`history 1 | awk "{\\$1=\"\"; print}"` # 获取最后一条命令user=`id -un`;pwd=`pwd` # 获取当前用户和当前路径# 获取用户登录信息whoStr=(`who -u am i`) # 用户登录信息realUser=${whoStr[0]} #  用户名logMonth=${whoStr[2]} # 登录时间logDay=${whoStr[3]}logTime=${whoStr[4]}pid=${whoStr[6]} # 登录会话IDip=${whoStr[7]}   # 登录的客户端IP
复制代码


if [ ${thisHistID}x != ${lastHistID}x ]; then     echo -E `date "+%Y/%m/%d %H:%M:%S"` $user\($realUser\)@$ip[IP:$pid][PWD:$pwd][LOGIN:$logMonth $logDay $logTime] --- $lastCommand    lastHistID=$thisHistIDfi
复制代码


  • 检查历史记录 ID 是否变化并记录审计信息


if [ -z "${PROMPT_COMMAND_READONLY}" ]; then    if [ -z "${PROMPT_COMMAND}" ]; then        export PROMPT_COMMAND="$audit_command"    else        export PROMPT_COMMAND="$PROMPT_COMMAND; $audit_command"    fi    export HISTORY_FILE=/var/log/cmd_audit/audit.log    export PROMPT_COMMAND_READONLY=1    readonly PROMPT_COMMAND_READONLYfi
复制代码


  • 配置 PROMPT_COMMAND 环境变量,并设置为只读,放置其他用户私自修改导致命令审计失败


注意

  1. 你最好在服务器初始化时做好此项配置;

  2. 你最好结合用户权限管理系统来使用,才能真正发挥这个配置的功能;


下一期,我们会简单谈谈如何实现一个用户权限管理系统,敬请期待~

发布于: 刚刚阅读数: 5
用户头像

蝉翼2u

关注

努力提升自己 2022-05-29 加入

一名工作多年的老运维。

评论

发布
暂无评论
运维防背锅的办法之一:命令审计_程序员_蝉翼2u_InfoQ写作社区