最近在群里看到有人问:"为什么我的服务启动不了?"然后下面一堆人回复:“setenforce 0试试”、“直接关掉SELinux”。每次看到这种回复我都想说,兄弟们,这就像是因为门锁太复杂就把门拆了一样啊。
说实话,我刚开始接触Linux的时候也是这样,遇到权限问题第一反应就是关SELinux。但是工作这么多年下来,我发现SELinux其实是个好东西,只是大家对它的误解太深了。今天就来聊聊这个让无数运维人员又爱又恨的安全机制。
SELinux到底是个什么玩意儿
SELinux全称是Security-Enhanced Linux,翻译过来就是安全增强型Linux。这东西最初是美国国家安全局(NSA)开发的,听起来就很厉害对不对?
简单来说,SELinux就是在传统的Linux权限控制基础上,又加了一层更细粒度的访问控制。传统的Linux权限只有读、写、执行三种,而且是基于用户和组的。但SELinux不一样,它可以控制到进程能访问哪些文件、能调用哪些系统调用、能绑定哪些端口等等。
我记得有一次,公司的一个Web应用突然访问不了数据库了,开发那边说代码没改过,数据库也正常。最后发现是SELinux策略更新后,httpd进程被禁止连接数据库端口了。当时如果直接关掉SELinux确实能解决问题,但这样做就失去了一层重要的安全保护。
SELinux的工作模式
SELinux有三种工作模式,这个必须要搞清楚:
Enforcing模式:这是严格模式,SELinux会强制执行所有的安全策略。如果有违反策略的操作,直接拒绝,不给你商量的余地。
Permissive模式:这是宽松模式,SELinux会记录所有违反策略的操作,但不会阻止它们执行。这个模式特别适合调试,你可以看到哪些操作被SELinux认为是有问题的。
Disabled模式:这就是完全关闭SELinux,相当于没有这层保护。
查看当前模式很简单,用getenforce
命令就行:
[root@server ~]# getenforce
Enforcing
如果想临时切换模式,可以用setenforce
:
# 切换到宽松模式
setenforce 0
# 切换到严格模式
setenforce 1
不过这种切换只是临时的,重启后会恢复到配置文件中设置的模式。要永久修改的话,需要编辑/etc/selinux/config
文件。
安全上下文:SELinux的核心概念
SELinux最重要的概念就是安全上下文(Security Context)。每个文件、进程、端口都有一个安全上下文,SELinux就是根据这些上下文来决定是否允许某个操作。
安全上下文的格式是这样的:user:role:type:level
用ls -Z
可以查看文件的安全上下文:
[root@server ~]# ls -Z /var/www/html/
-rw-r--r--. root root unconfined_u:object_r:httpd_exec_t:s0 index.html
这里的httpd_exec_t
就是类型(type),这是SELinux策略中最重要的部分。Apache进程只能访问标记为httpd_exec_t
、httpd_config_t
等特定类型的文件。
我之前遇到过一个情况,开发把网站文件直接放在了/root
目录下,然后发现Apache访问不了。用ls -Z
一看,文件的类型是admin_home_t
,Apache当然访问不了。解决办法就是把文件移到正确的位置,或者修改文件的安全上下文。
常见的SELinux问题和解决方法
说到这里,我想分享几个工作中经常遇到的SELinux问题。
问题一:Web服务无法访问自定义目录
有时候我们需要把网站文件放在非标准目录,比如/data/www
。这时候Apache可能无法访问,因为这个目录的安全上下文不对。
解决办法是修改目录的安全上下文:
# 递归修改目录的安全上下文
chcon -R -t httpd_exec_t /data/www/
# 或者使用restorecon命令
restorecon -R /data/www/
更好的做法是设置SELinux策略,让系统自动为这个目录分配正确的上下文:
semanage fcontext -a -t httpd_exec_t "/data/www(/.*)?"
restorecon -R /data/www/
问题二:服务无法绑定非标准端口
比如你想让Apache监听8080端口,但是SELinux默认只允许Apache绑定80、443等标准端口。
这时候需要添加端口到SELinux策略:
# 查看当前允许的端口
semanage port -l | grep http_port_t
# 添加新端口
semanage port -a -t http_port_t -p tcp 8080
问题三:应用无法连接数据库
这个问题我遇到过好几次。Web应用突然连不上数据库了,检查网络、防火墙都没问题,最后发现是SELinux阻止了httpd进程连接数据库。
解决办法是启用相应的布尔值:
# 允许httpd连接数据库
setsebool -P httpd_can_network_connect_db on
# 允许httpd进行网络连接
setsebool -P httpd_can_network_connect on
SELinux的日志和调试
当SELinux阻止某个操作时,它会把详细信息记录到日志中。这些日志通常在/var/log/audit/audit.log
或者/var/log/messages
中。
不过原始的审计日志看起来比较费劲,我推荐安装setroubleshoot-server
包:
yum install setroubleshoot-server
安装后,SELinux的拒绝信息会以更友好的方式显示在/var/log/messages
中,而且还会给出解决建议。
另外,audit2allow
工具也很有用,它可以根据审计日志生成SELinux策略:
# 查看被拒绝的操作
audit2allow -w -a
# 生成允许这些操作的策略
audit2allow -a -M mypolicy
# 安装策略
semodule -i mypolicy.pp
实际工作中的SELinux最佳实践
不要一上来就关闭SELinux。我知道这样做很简单,但是你失去的安全保护可能比你想象的更重要。特别是在生产环境中,SELinux能够有效防止很多攻击。
善用Permissive模式进行调试。当你不确定某个问题是否由SELinux引起时,可以临时切换到Permissive模式。这样既不会影响服务运行,又能看到SELinux的日志。
学会看日志。SELinux的日志信息很详细,包含了被拒绝操作的所有相关信息。学会分析这些日志,能帮你快速定位问题。
使用标准的目录结构。尽量把文件放在系统预期的位置,比如网站文件放在/var/www/html
,这样可以避免很多SELinux问题。
定期备份SELinux策略。如果你对系统的SELinux策略做了很多自定义修改,记得备份这些策略,以免系统重装后丢失。
我记得有一次系统升级后,之前自定义的SELinux策略都没了,结果好几个服务都启动不了。从那以后我就养成了定期备份策略的习惯。
一些实用的SELinux命令
这里整理一些工作中经常用到的SELinux命令,建议收藏:
# 查看SELinux状态
sestatus
# 查看文件的安全上下文
ls -Z filename
# 查看进程的安全上下文
ps -eZ
# 修改文件的安全上下文
chcon -t type_t filename
# 恢复文件的默认安全上下文
restorecon filename
# 查看SELinux布尔值
getsebool -a
# 设置SELinux布尔值
setsebool boolean_name on/off
# 查看端口的SELinux标签
semanage port -l
# 添加端口到SELinux策略
semanage port -a -t port_type_t -p tcp port_number
写在最后
SELinux确实有一定的学习成本,刚开始接触时可能会觉得很复杂。但是一旦你理解了它的工作原理,就会发现它其实是一个很强大的安全工具。
在当前网络安全形势越来越严峻的情况下,多一层保护总是好的。与其因为不熟悉就关闭SELinux,不如花点时间学习如何正确使用它。
当然,我也不是说SELinux就是万能的,它只是整个安全体系中的一环。但是作为运维人员,我们应该尽可能地利用系统提供的各种安全机制,而不是为了图省事就把它们关掉。
希望这篇文章能帮助大家对SELinux有一个更全面的认识。如果你在使用SELinux的过程中遇到了问题,欢迎在评论区讨论,我们一起交流学习。
如果这篇文章对你有帮助,别忘了点赞转发支持一下!想了解更多运维实战经验和技术干货,记得关注微信公众号@运维躬行录,领取学习大礼包!!!我会持续分享更多接地气的运维知识和踩坑经验。让我们一起在运维这条路上互相学习,共同进步!
公众号:运维躬行录
个人博客:躬行笔记