前言
上周的时候,作者在生产环境上部署正式系统的时候,遇到了万恶的nginx 403 问题,于是各种查找资料。关于nginx 403的文章到是非常多,但是涉及到SELinux的时候,大多都是将SELinux关闭直接解决问题,但生产环境能这么简单粗暴地解决问题吗?显然这样的操作是不太安全的, 那该如何解决呢?本文作者在查询各种资料后,终于解决了开启SELinux的情况下nginx 403的问题,将解决地过程进行了梳理和总结,分享出来,希望能对大家有所帮助 。
403原因分析
知己知彼,方能百战不殆,我们先来简单认识一下SELinux。
Security-Enhanced Linux(安全增强型 Linux)简称 SELinux,它是一个 Linux 内核模块,也是 Linux 的一个安全子系统。SELinux 主要由美国国家安全局开发,2.6 及以上版本的 Linux 内核都已经集成了该模块。SELinux 主要作用就是最大限度地减小系统中服务进程可访问的资源(最小权限原则)。
安全上下文是 SELinux 的核心。安全上下文分为「进程安全上下文」和「文件安全上下文」。只有两者的安全上下文对应上了,进程才能访问文件。它们的对应关系由政策中的规则决定。
安全上下文有四个字段,分别用冒号隔开,形如:system_u:object_r:admin_home_t:s0
。
开启SELinux的情况下 nginx 403的原因非常有可能是nginx的线程上下文和文件安全上下文 不一致导致nginx没有权限访问相关的文件。下面我们来验证一下,是否是这个原因。
分析验证
在相关命令参数中加上-Z 即可查看SELinux相关信息。
ps -efZ | grep nginx 查看nginx进程SELinux信息,结果如下:
[root@localhost ~]# ps -efZ | grep nginx
system_u:system_r:httpd_t:s0 root 1423 1 0 22:02 ? 00:00:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
system_u:system_r:httpd_t:s0 nginx 1578 1423 0 22:25 ? 00:00:00 nginx: worker process
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 root 1664 1297 0 22:29 pts/0 00:00:00 grep --color=auto nginx
ls -Z <文件或目录> 查看文件或目录SELinux信息,结果如下:
[root@localhost home]# ls -Z
drwxr-xr-x. root root unconfined_u:object_r:home_root_t:s0 www
[root@localhost home]# cd www
[root@localhost www]# ls -Z
-rw-r--r--. root root unconfined_u:object_r:home_root_t:s0 50x.html
-rw-r--r--. root root unconfined_u:object_r:home_root_t:s0 index.html
我们再来看一下nginx的默认目录/usr/share/nginx/html的SELinux信息
[root@localhost nginx]# ls -Z
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 html
[root@localhost nginx]# cd html/
[root@localhost html]# ls -Z
-rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0 50x.html
-rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0 index.html
从上面的信息中可以看出nginx 的SELinux 信息为system_u:system_r:httpd_t:s0
,其中线程上下文为httpd_t
。
www目录以及文件的SELinux 信息为unconfined_u:object_r:home_root_t:s0
,其中文件上下文为home_root_t
。
/usr/share/nginx/html目录以及文件的SELinux 信息为system_u:object_r:httpd_sys_content_t:s0
,其中文件上下文为httpd_sys_content_t
。
httpd_t
和home_root_t
不一致,导致nginx线程无法访问www目录以及相应的文件。
解决方案
httpd
可以读取标记为httpd_sys_content_t
类型的文件,但是不能进行写入操作,我们只需要将www及子目录和文件的SELinux信息修改为httpd_sys_content_t
即可
- 安装policycoreutils-python工具
[root@localhost home]yum -y install policycoreutils-python
- 执行semanage命令
[root@localhost home]# semanage fcontext -a -t httpd_sys_content_t '/home/www(/.*)?'
[root@localhost home]# ls -Z
drwxr-xr-x. root root unconfined_u:object_r:home_root_t:s0 www
发现此时文件上下文信息没有修改过来,不要着急,我们还有非常关键的一步要操作。
- 递归还原,刷新文件上下文信息
[root@localhost home]# restorecon -R /home/www
[root@localhost home]# ls -Z
drwxr-xr-x. root root unconfined_u:object_r:httpd_sys_content_t:s0 www
[root@localhost home]# cd www/
[root@localhost www]# ls -Z
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 50x.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 index.html
此时文件上下文信息已经修改过来,可以去验收成果了。
结果验证
此时,nginx和SELinux就能友好愉快地相处了,辛苦了半天,效果图如下:
如果文章能帮助到你,欢迎点个赞!
作者:gogole,聊一聊工作感悟,剖析下技术源码,让知识不再傲娇,乘舟破浪,扬帆启航,一起畅游知识的海洋。微信公众号【沧海一扁舟】,文章均首发于公众号。