SElinux 导致 Keepalived 检测脚本无法执行

哈喽大家好,我是咸鱼

今天我们来看一个关于 Keepalived 检测脚本无法执行的问题

一位粉丝后台私信我,说他部署的 keepalived 集群 vrrp_script 模块中的脚本执行失败了,但是手动执行这个脚本却没有任何问题

在这里插入图片描述
这个问题也是咸鱼第一次遇到,为了能让更多的小伙伴以后不会踩这个坑,便有了今天这篇文章

前言

在正式开始之前,我们先来简单复习一下 Keepalived 中的资源检测功能

vrrp_script 模块

Keepalived 中,vrrp_script 模块是用于定义和配置虚拟路由冗余协议(VRRP)的自定义脚本检查,这个模块专门用于对集群中的服务资源进行监控

vrrp_script 模块搭配使用的是 track_script 模块,这个模块中可以引入监控脚本、命令组合、Shell 语句来实现对服务资源的监控

track_script 通过调用 vrrp_script,可以灵活地定义需要监测的服务或资源,例如网络连接、服务状态、系统资源等

当监测到故障时,Keepalived 可以触发状态转移,将主节点切换到备用节点,以确保服务的高可用性

  • 通过 killall -l 命令监测

killall 命令会发送一个信号给进程,以信号 0 为例,如果发现进程关闭或者异常,将返回状态码 1,反之进程运行正常,状态码返回0

vrrp_script nginx_check {script "killall -0 nginx"interval 2
}track_script {nginx_check
}
  • 通过端口监测

检测端口的运行状态也是较常见的监控方式

vrrp_script nginx_check {script "</dev/tcp/127.0.0.1/80"interval 2fall 2rise 1
}track_script {nginx_check
}

其中 fall表示检测到失败的最大次数(如果请求失败两次,就认为该节点发生了故障)

rise 表示如果请求一次成功,就认为该节点恢复正常

  • 通过 shell 语句监测
vrrp_script nginx_check {script "if [ $(pidof nginx | wc -l) -eq 0 ]; then exit 1; else exit 0; fi"interval 2fall 2rise 1
}track_script {nginx_check
}
  • 通过脚本监测
vrrp_script nginx_check {script "/etc/keepalived/nginx_check.sh"interval 2fall 2rise 1
}track_script {nginx_check
}

问题

在介绍完了 keepalived 的监测功能之后,我们来看下这个问题

我根据他的描述复现了这个场景:keepalived 通过监测上游网络来判断该节点是否正常运行,如果到上游的网络不通,则认为该节点发生了故障

检测脚本如下:

[root@localhost ~]# cat /etc/keepalived/check.sh 
#!/bin/bash
# 检查上行链路
check_route="192.168.149.135"
ping -c 3 $check_route >/dev/null 2>&1
result=$?
echo "${date}----checking..... result:${result}" >> /tools/log.log
if [ $? -eq 0 ]; thenexit 0          # 正常
elseexit 1          # 链路异常
fi

一切准备就绪之后启动 keepalived 服务发现报 Keepalived_vrrp[2653]: /etc/keepalived/check.sh exited with status 1

[root@localhost ~]# systemctl status keepalived.service 
● keepalived.service - LVS and VRRP High Availability MonitorLoaded: loaded (/usr/lib/systemd/system/keepalived.service; disabled; vendor preset: disabled)Active: active (running) since 三 2023-08-14 23:53:49 CST; 4min 56s ago...
814 23:53:49 localhost.localdomain Keepalived_vrrp[2653]: /etc/keepalived/check.sh exited with status 1
...

说明脚本没有执行成功,返回状态码 1 了,我尝试着手动执行,发现脚本没有任何问题

[root@localhost ~]# sh /etc/keepalived/check.sh 
[root@localhost ~]# echo $?
0

排查

首先看一下 /var/log/messages(如果 keepalived 没有专门指定日志文件路径,这个便是默认的日志文件路径)

...
Aug 14 23:53:49 localhost Keepalived_vrrp[17889]: SECURITY VIOLATION - scripts are being executed but script_security not enabled
...
Aug 14 23:53:49 localhost Keepalived_vrrp[17889]: /etc/keepalived/check.sh exited with status 1
...

SECURITY VIOLATION - scripts are being executed but script_security not enabled 这条信息引起了我的注意

”安全违规-脚本正在执行,但 script_security 未启用“,看输出应该是 keepalived 进程想要执行该脚本,但是受到了安全限制

既然是跟系统安全相关的,我们就先来看看这个脚本的权限吧

# 查看脚本权限
[root@localhost ~]# ll /etc/keepalived/check.sh 
-rwxr-xr-x. 1 root root 281 89 15:52 /etc/keepalived/check.sh# 查看是 keepalived 进程的属主
[root@localhost ~]# ps -ef | grep keep
root      19163      1  0 01:00 ?        00:00:00 /usr/sbin/keepalived -D
...

由上面的输出我们可以得知 keepalived 进程的属主是 root ,而 root 用户是可以去执行这个脚本的(有 x 权限)

权限没问题,我们再来查看下 /var/log/audit/audit.log

/var/log/audit/audit.log 是一个存储系统审计日志的文件

这个文件记录了系统中发生的各种安全事件、用户操作和系统行为,以及与安全相关的信息

系统审计日志是用来监控系统活动、检测潜在的安全问题和追踪系统事件的重要工具之一

...
type=SYSCALL msg=audit(1692033018.624:12555): arch=c000003e syscall=4 success=no exit=-13 a0=190abc0 a1=7ffd028eafc0 a2=7ffd028eafc0 a3=7ffd028eaae0 items=0 ppid=19472 pid=19473 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="check.sh" exe="/usr/bin/bash" subj=system_u:system_r:keepalived_t:s0 key=(null)type=AVC msg=audit(1692033018.624:12555): avc:  denied  { getattr } for  pid=19473 comm="check.sh" path="/usr/bin/ping" dev="dm-0" ino=50555278 scontext=system_u:system_r:keepalived_t:s0 tcontext=system_u:object_r:ping_exec_t:s0 tclass=file permissive=0
...

我们现在来看一下上面日志输出表示什么

先看第一段:

type=SYSCALL: 这个部分是系统调用事件类型。arch=c000003e syscall=4 success=no exit=-13: 这里描述了系统调用的详细信息,包括系统调用号、是否成功等

  • subj=system_u:system_r:keepalived_t:s0:描述了进程的安全上下文信息
  • 后面内容则是一些更多与系统调用相关的信息,如参数、进程信息、用户信息等

再看第二段:

type=AVC: 这个部分指示了事件类型为 AVC(Access Vector Cache),是 SELinux 的访问控制事件,

  • avc: denied { getattr }: 表示操作是一个 getattr(获取属性)操作,但是被拒绝。
  • pid=19473 comm="check.sh": 进程 ID 是 19473,进程名称是 check.sh
  • path="/usr/bin/ping": 文件路径是 /usr/bin/ping,表示被操作的文件。
  • scontext=system_u:system_r:keepalived_t:s0: 发起操作的进程的安全上下文。
  • tcontext=system_u:object_r:ping_exec_t:s0: 被操作文件的安全上下文。
  • tclass=file: 被操作对象的类型是文件。
  • permissive=0: 表示 SELinux 不是处于宽松模式

总结一下:

这个是 SELinux 的审计日志,这两条日志记录了一个操作,即 keepalived 进程试图通过执行 check.sh" 脚本访问 /usr/bin/ping 文件,但被 SELinux 拒绝了

解决

排查到这思路就逐渐清晰起来了,这是因为 SELinux 权限导致的,在解决这个问题之前,我们先来简单复习一下 SELinux (后面我会专门写一篇文章来介绍 SELinux)

SELinux(Security Enhanced Linux,安全强化的 Linux) ,由美国国家安全局(NSA)开发的

为什么要开发 SELinux

我们知道系统的账户主要分为系统管理员(root)和普通用户,这两种身份能否使用系统上面的文件资源则与 rwx 权限设置有关

所以当某个进程想要对文件进行读写操作时,系统就会根据该进程的属主和属组去比对文件权限,只有通过权限检查,才能够进一步操作文件

这种方式被称为自主访问控制(Discretionary Access Control, DAC),DAC 是 Linux 操作系统中的一种基本权限控制机制,用于限制用户对系统资源的访问权限

但是 DAC 的一大问题就是当用户获取到进程之后,他可以通过这个进程与自己所获得的权限去处理对应的文件资源

万一用户对系统不熟悉,就很容易导致资源误用的问题出现

举个例子,你们公司的新人为了自身方便,将网页所在目录 /var/www/html 目录的权限设置成了 777,则代表所有进程都可以对该目录进行读写

如果黑客接触到了某个进程,就极有可能向你的系统里面写入某些东西

为了避免 DAC 的问题,便有了 SELinux

SELinux MAC 机制

SELinux 引入了强制访问控制(Mandatory Access Control, MAC)机制

强制访问控制(MAC,Mandatory Access Control)是 Linux 操作系统中一种更加严格和细粒度的访问控制机制,用于加强对系统资源的保护和控制

MAC 有趣的地方在于它可以针对特定的进程与特定的文件资源来管理权限,即使你是 root 用户,在使用不同的进程时你所能获取的权限也不一定是 root

在这里插入图片描述
安全上下文

前面我们知道,SELinux 是通过 MAC 的方式来管理进程的权限的

它控制的主体是【进程】,而【目标】则是该【进程】能否读取的文件资源

  • 主体

SELinux 主要管理的就是进程,进程和主体可以画上等号

  • 目标

主体能否读写的目标一般就是文件资源

除了策略指定之外,主体与目标的安全上下文必须一致才能够顺利读写

安全上下文有点类似于文件系统的 rwx ,如果设置错误,主体就无法读写目标资源了

在这里插入图片描述
安全上下文存放在文件的 inode 内,可以通过 ll -Z 命令去查看(前提是 SELinux 是开启着的)

回到我们的案例上来,日志输出说进程 check.sh 试图获取 /usr/bin/ping 的属性(getattr)操作,但被 SELinux 拒绝了

但是我们发现没有这个进程

[root@localhost ~]# ps -ef | grep check

也就是说,由于 SELinux 权限问题 ,keepalived 一开始想要调用 check.sh 脚本就失败了

我们分别来看一下 keepalived 进程和 check.sh 的安全上下文

[root@localhost ~]# ps -eZ | grep keepalived 
system_u:system_r:keepalived_t:s0 19609 ?       00:00:00 keepalived[root@localhost ~]# ll -Z /etc/keepalived/check.sh 
-rwxr-xr-x. root root system_u:object_r:etc_t:s0       /etc/keepalived/check.sh

可以看到 keepalived 进程的安全上下文类型为 keepalived_t;而 check.sh 的安全上下文是 etc_t

即——主体与目标的安全上下文并不一致,就算有 rwx 权限也无法执行

  • 解决方案一:关闭 SELinux

简单粗暴,直接关闭 SELinux ,就没有这么多乱七八糟的限制了

# 以 CentOS 7 为例
# 临时关闭
[root@localhost ~]# setenforce 0#永久关闭,将 SELINUX=enforcing 改为 SELINUX=disabled,然后保存退出
[root@localhost ~]# sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
  • 解决方案二(失败了):修改 check.sh 的安全上下文与 keepalived 一致

我想把 check.sh 的安全上下文改成与 keepalived 一致,可是失败了,有小伙伴知道原因吗

[root@localhost ~]# chcon -t keepalived_t  /etc/keepalived/check.sh
chcon: 改变"/etc/keepalived/check.sh" 的环境到"system_u:object_r:keepalived_t:s0" 失败: 权限不够
  • 解决方案三:修改 check.sh 的安全上下文

依旧是修改 check.sh 的安全上下文,不过这次参考了资料

[root@localhost ~]# chcon -t keepalived_unconfined_script_exec_t  /etc/keepalived/check.sh

keepalived_unconfined_script_exec_t 是一个在 SELinux 中用于标识 Keepalived 执行未限制脚本的上下文,这个上下文允许 Keepalived 进程在执行脚本时绕过一些 SELinux 限制,从而可以在需要的情况下执行脚本

  • 解决方案四:将脚本转移到 /usr/libexec/keepalived 目录中
# keepalived 配置
vrrp_script nginx_check {script "/usr/libexec/keepalived/check.sh"interval 2fall 2rise 1
}

这个目录的安全上下文是 keepalived_unconfined_script_exec_t,与解决方案三同理

[root@localhost ~]# ll -Z /usr/libexec/keepalived/ -d
drwxr-xr-x. root root system_u:object_r:keepalived_unconfined_script_exec_t:s0 /usr/libexec/keepalived/
  • 解决方案五: keepalived 全局配置添加 enable_script_security 字段

加了这个字段意味着如果脚本路径的任一部分对于非 root 用户来说,都具有可写权限,则不会以 root 身份运行脚本

以非 root 身份运行的脚本就能够通过 SELinux 的审查吗?这一块我不太懂,有懂的小伙伴可以告诉我

global_defs {...enable_script_security...
}

参考资料:

https://github.com/acassen/keepalived/issues/1322

https://serverfault.com/questions/709428/track-script-doesnt-work-after-keepalived-update

https://www.mankier.com/8/keepalived_selinux

https://linux.vbird.org/linux_basic/centos7/0440processcontrol.php#selinux

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/39704.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《安富莱嵌入式周报》第320期:键盘敲击声解码, 军工级boot设计,开源CNC运动控制器,C语言设计笔记,开源GPS车辆跟踪器,一键生成RTOS任务链表

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版&#xff1a; https://www.bilibili.com/video/BV1Cr4y1d7Mp/ 《安富莱嵌入式周报》第320期&#xff1a;键盘敲击…

【智慧工地源码】:人工智能、BIM技术、机器学习在智慧工地的应用

智慧工地云平台是专为建筑施工领域所打造的一体化信息管理平台。通过大数据、云计算、人工智能、BIM、物联网和移动互联网等高科技技术手段&#xff0c;将施工区域各系统数据汇总&#xff0c;建立可视化数字工地。同时&#xff0c;围绕人、机、料、法、环等各方面关键因素&…

理解持续测试,才算理解DevOps

软件产品的成功与否&#xff0c;在很大程度上取决于对市场需求的及时把控&#xff0c;采用DevOps可以加快产品交付速度&#xff0c;改善用户体验&#xff0c;从而有助于保持领先于竞争对手的优势。 作为敏捷开发方法论的一种扩展&#xff0c;DevOps强调开发、测试和运维不同团…

Go 安装配置

介绍Ubuntu20.04 安装和配置Go 1.安装Go 去这个地方下载Go https://go.dev/doc/install 如果之前安装过&#xff0c;可以参考这个&#xff08;没有可以忽略&#xff09; 下载完成后执行 sudo tar -C /usr/local -xzf go1.21.0.linux-amd64.tar.gz 然后修改环境变量 sudo ge…

css3-grid:grid 布局 / 基础使用

一、理解 grid 二、理解 css grid 布局 CSS Grid布局是一个二维的布局系统&#xff0c;它允许我们通过定义网格和网格中每个元素的位置和尺寸来进行页面布局。CSS Grid是一个非常强大的布局系统&#xff0c;它不仅可以用于构建网格布局&#xff0c;还可以用于定位元素&#xf…

代码审计-ASP.NET项目-未授权访问漏洞

代码审计必备知识点&#xff1a; 1、代码审计开始前准备&#xff1a; 环境搭建使用&#xff0c;工具插件安装使用&#xff0c;掌握各种漏洞原理及利用,代码开发类知识点。 2、代码审计前信息收集&#xff1a; 审计目标的程序名&#xff0c;版本&#xff0c;当前环境(系统,中间件…

Web framework-Gin

一、Gin Go Web--Go Module 软件框架&#xff08;software framework&#xff09;&#xff0c;通常指的是为了实现某个业界标准或完成特定基本任务的软件组件规范&#xff0c;也指为了实现某个软件组件规范时&#xff0c;提供规范所要求之基础功能的软件产品。 框架就是&#…

机器学习|Softmax 回归的数学理解及代码解析

机器学习&#xff5c;Softmax 回归的数学理解及代码解析 Softmax 回归是一种常用的多类别分类算法&#xff0c;适用于将输入向量映射到多个类别的概率分布。在本文中&#xff0c;我们将深入探讨 Softmax 回归的数学原理&#xff0c;并提供 Python 示例代码帮助读者更好地理解和…

HarmonyOS NEXT新能力,一站式高效开发HarmonyOS应用

2023年8月6日华为开发者大会2023&#xff08;HDC.Together&#xff09;圆满收官&#xff0c;伴随着HarmonyOS 4的发布&#xff0c;华为向开发者发布了汇聚所有最新开发能力的HarmonyOS NEXT开发者预览版&#xff0c;并分享了围绕“一次开发&#xff0c;多端部署” “可分可合&a…

代码随想录算法训练营第60天|动态规划part17| 647. 回文子串、516.最长回文子序列、动态规划总结篇

代码随想录算法训练营第60天&#xff5c;动态规划part17&#xff5c; 647. 回文子串、516.最长回文子序列、动态规划总结篇 647. 回文子串 647. 回文子串 思路&#xff1a; 暴力解法 两层for循环&#xff0c;遍历区间起始位置和终止位置&#xff0c;然后还需要一层遍历判断…

【mysql】—— 表的增删改查

目录 序言 &#xff08;一&#xff09;Create操作 1、单行数据 全列插入 2、多行数据 指定列插入 3、插入否则更新 4、直接替换 &#xff08;二&#xff09;Retrieve操作 1、SELECT 列 1️⃣全列查询 2️⃣指定列查询 3️⃣查询字段为表达式 4️⃣为查询结果指定…

数据结构——堆

数据结构——堆 堆堆简介堆的分类 二叉堆过程插入操作 删除操作向下调整&#xff1a; 增加某个点的权值实现参考代码&#xff1a;建堆方法一&#xff1a;使用 decreasekey&#xff08;即&#xff0c;向上调整&#xff09;方法二&#xff1a;使用向下调整 应用对顶堆 其他&#…

Python Flask+Echarts+sklearn+MySQL(评论情感分析、用户推荐、BI报表)项目分享

Python FlaskEchartssklearnMySQL(评论情感分析、用户推荐、BI报表)项目分享 项目背景&#xff1a; 随着互联网的快速发展和智能手机的普及&#xff0c;人们越来越倾向于在网上查找餐厅、购物中心、酒店和旅游景点等商户的点评和评分信息&#xff0c;以便做出更好的消费决策。…

YOLOv8 : 网络结构

一. YOLOv8网络结构 1. Backbone YOLOv8的Backbone同样参考了CSPDarkNet-53网络&#xff0c;我们可以称之为CSPDarkNet结构吧&#xff0c;与YOLOv5不同的是&#xff0c;YOLOv8使用C2f(CSPLayer_2Conv)代替了C3模块(如果你比较熟悉YOLOv5的网络结构&#xff0c;那YOLOv8的网络…

【GitHub】Pycharm本地项目打包上传到Github仓库的操作步骤

文章目录 1、Pycharm端的设置操作2、Github端的设置操作3、Pycharm上配置Github4、Git本地项目至GitHub仓库5、前往Github中查看确认6、常见报错 1、Pycharm端的设置操作 通过CtrlAltS快捷组合键的方式&#xff0c;打开设置&#xff0c;导航到版本控制一栏中的Git&#xff0c;…

Gin安装解决国内go 与 热加载

get 方式安装超时问题&#xff0c;国内直接用官网推荐的下面这个命令大概率是安装不成功的 go get -u github.com/gin-gonic/gin 可以在你的项目目录下执行下面几个命令&#xff1a; 比如我的项目在E:\Oproject\zl cmd E:\Oproject\zl>就在目录下执行 go env -w GO111…

回归预测 | MATLAB实现GRU门控循环单元多输入多输出

回归预测 | MATLAB实现GRU门控循环单元多输入多输出 目录 回归预测 | MATLAB实现GRU门控循环单元多输入多输出预测效果基本介绍程序设计往期精彩参考资料 预测效果 基本介绍 MATLAB实现GRU门控循环单元多输入多输出&#xff0c;数据为多输入多输出预测数据&#xff0c;输入10个…

pytorch安装VAE项目详解

安装VAE项目 一、 基本环境二、代码来源三、搭建conda环境四、下载数据集五、启动项目六、其他相关问题 一、 基本环境 工具版本号OSwin 11pycharm2020.1GPU3050 二、代码来源 github地址为&#xff1a; https://github.com/AntixK/PyTorch-VAE/blob/8700d245a9735640dda458d…

ZooKeeper的应用场景(集群管理、Master选举)

5 集群管理 随着分布式系统规模的日益扩大&#xff0c;集群中的机器规模也随之变大&#xff0c;因此&#xff0c;如何更好地进行集群管理也显得越来越重要了。 所谓集群管理&#xff0c;包括集群监控与集群控制两大块&#xff0c;前者侧重对集群运行时状态的收集&#xff0c;后…

08 - 追加commit和修改最新的commit message

查看所有文章链接&#xff1a;&#xff08;更新中&#xff09;GIT常用场景- 目录 文章目录 1. 追加提交2. 修改最新的commit message 1. 追加提交 将改动追加到上一次的commit 现在我已经修改了Readme文件并且已经add、commit操作&#xff0c;但是还没有push到远程仓库&#x…