我该如何告诉SELinux在没有audit2allow的情况下允许nginx访问unix套接字?


10

我有Nginx通过位于的unix套接字将请求转发给gunicorn /run/gunicorn/socket。默认情况下,SELinux不允许这种行为:

grep nginx /var/log/audit/audit.log
type=SERVICE_START msg=audit(1454358912.455:5390): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=nginx comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
type=AVC msg=audit(1454360194.623:7324): avc:  denied  { write } for  pid=9128 comm="nginx" name="socket" dev="tmpfs" ino=76151 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:httpd_sys_content_t:s0 tclass=sock_file
type=SYSCALL msg=audit(1454360194.623:7324): arch=c000003e syscall=42 success=no exit=-13 a0=c a1=1f6fe58 a2=6e a3=7ffee1da5710 items=0 ppid=9127 pid=9128 auid=4294967295 uid=995 gid=993 euid=995 suid=995 fsuid=995 egid=993 sgid=993 fsgid=993 tty=(none) ses=4294967295 comm="nginx" exe="/usr/sbin/nginx" subj=system_u:system_r:httpd_t:s0 key=(null)
type=AVC msg=audit(1454361591.701:13343): avc:  denied  { connectto } for  pid=9128 comm="nginx" path="/run/gunicorn/socket" scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:system_r:initrc_t:s0 tclass=unix_stream_socket
type=SYSCALL msg=audit(1454361591.701:13343): arch=c000003e syscall=42 success=no exit=-13 a0=c a1=1f6fe58 a2=6e a3=7ffee1da5950 items=0 ppid=9127 pid=9128 auid=4294967295 uid=995 gid=993 euid=995 suid=995 fsuid=995 egid=993 sgid=993 fsgid=993 tty=(none) ses=4294967295 comm="nginx" exe="/usr/sbin/nginx" subj=system_u:system_r:httpd_t:s0 key=(null)

我所到之处(例如,在这里这里),都可以使用此指令来向nginx发出请求,使该请求被SELinux拒绝,然后运行audit2allow以允许将来的请求。我想不出任何chconsemanage明确允许这种行为的命令。

这是唯一的方法吗?似乎荒谬的是,您无法设置一个允许nginx写入套接字而不首先尝试被拒绝,然后运行一个启用被拒绝的工具的策略。您如何确切知道正在启用什么?如果您在自动化下设置机器,这应该如何工作?

我正在使用CentOS 7。


您需要向我们展示AVC拒绝消息,并且最好也知道您正在运行哪个OS和版本。
user9517 '16

@lain好点。
Drs

Answers:


23

似乎荒谬的是,您无法设置一个允许nginx写入套接字而不首先尝试被拒绝,然后运行一个启用被拒绝的工具的策略。

嗯,不,SELinux是强制性访问控制,默认情况下拒绝所有操作,您必须明确允许某些操作。如果策略作者没有考虑特定的(弗兰肯)堆栈,或者守护程序的作者尚未使其成为SELinux感知的书面策略,那么您就该靠自己了。您必须分析您的服务在做什么以及它们如何与SELinux交互,并提出自己的策略来允许它。有可用的工具来帮助您audit2whyaudit2allow等。

...这是唯一的方法吗?

不,但是要取决于解决方案是什么,这取决于您要尝试做的事情以及如何尝试做。例如,您可能想将nginx(httpd_t)绑定到端口8010(unreserved_port_t)。当您启动nginx时,它将失败

Starting nginx: nginx: [emerg] bind() to 0.0.0.0:8010 failed (13: Permission denied)

然后您(最终)查看审核日志并找到

type=AVC msg=audit(1457904756.503:41673): avc:  denied  { name_bind } for
pid=30483 comm="nginx" src=8010 scontext=unconfined_u:system_r:httpd_t:s0
tcontext=system_u:object_r:port_t:s0 tclass=tcp_socket

您可以通过audit2alllow进行操作,并天真地接受它的发现

allow httpd_t port_t:tcp_socket name_bind;

然后允许httpd_t连接到任何tcp端口。这可能不是您想要的。

您可以使用sesearch调查策略,并查看httpd_t可以将name_bind绑定到哪些端口类型

sesearch --allow -s httpd_t | grep name_bind
...
allow httpd_t http_port_t : tcp_socket name_bind ;
allow httpd_t http_port_t : udp_socket name_bind ;
...

在其他类型中,http_t可以绑定到http_port_t。现在,您可以使用管理功能进行更深入的研究。

semanage port -l | grep http_port_t
http_port_t                    tcp      80, 81, 443, 488, 8008, 8009, 8443, 9000
...

未列出端口8010。由于我们希望nginx绑定到端口8010,因此将其添加到http_port_t列表中并非没有道理。

semanage port -a -t http_port_t -p tcp 8010

现在,nginx将被允许name_bind绑定到端口8010,而不是如上所述的每个tcp端口。

您如何确切知道正在启用什么?

策略更改非常易于阅读,可以通过audit2在上方运行您的消息,

allow httpd_t httpd_sys_content_t:sock_file write;
allow httpd_t initrc_t:unix_stream_socket connectto;

这似乎很自我解释。

其中第一个引用的文件具有inum76151。您可以使用find获得其名称(find / -inum 76151),然后用于semanage fcontext -a -t ...更改策略和restorecon来修复上下文。

第二个问题/run/gunicorn/socket又与上下文有关。使用sesearch我们可以看到http_t可以连接到http_t类型的unix_stream_sockets。因此我们可以例如相应地更改上下文

semanage fcontext -a -t httpd_t "/run/gunicorn(/.*)?"
restorecon -r /run

这将设置/ run / gunicorn和tree |的上下文。文件下面的文件到httpd_t。

如果您在自动化下设置机器,这应该如何工作?

您需要分析系统并在测试中进行适当的更改。然后,您可以使用自动化工具来部署更改,puppet和ansible为此提供支持。

当然,只要将SElinux设置为宽松,就可以在生产中完成所有操作。收集所有消息,分析它们以决定您的更改并部署它们。

关于SELinux,还有很多要了解的东西,但这是我的技能极限,迈克尔·汉普顿(Michael Hampton)更好,而马修·艾夫(Mathew Ife)再次更好,他们可能还有更多补充。


1
您的建议很周到,使我自己更接近解决这些问题,尽管仍然有些不足。 allow httpd_t httpd_sys_content_t:sock_file write;对我来说,并不像您希望的那样自明。这是什么话对文件的需求政策,改为(即后所发生-tsemanage命令?
DRS

另外,我在semanage直接使用您的命令时会得到用法说明。我需要添加一个--add参数。
drs

实际上,我还要说的是,将套接字文件的类型更改httpd_var_run_t为下面的迈克尔·汉普顿(Michael Hampton)后,audit2allow消息是:allow httpd_t var_run_t:sock_file write;
drs

好像您将其设置为var_run_tnot httpd_var_run_t
user9517 '16

@lain,嗯..没有骰子。现在audit2allowallow httpd_t var_run_t:sock_file write;
drs

2

您要使用的类型不是httpd_sys_content_t。这是针对Web服务器要提供给用户代理的静态文件的。

对于用于进程间通信的套接字,您要查找的类型是httpd_var_run_t

不过,请注意,由于您是不受限制地奔跑的,所以可能会有其他问题。


3
谢谢!看来这解决了SELinux问题之一。关于如何设置Gunicorn(或任何其他服务)的任何限制?
drs

1

我尝试了前面的答案,但没有成功,在我的情况下,我使用nginx服务器作为uixgi应用程序的前端,该应用程序使用unix套接字与它们进行通信,我的操作系统是Fedora服务器26。

Unix套接字在目录中创建/var/local/myapp

/var/local/myapp/server.sock    
/var/local/myapp/stats.sock

要配置SELinux,我必须添加上下文类型: httpd_sys_rw_content_t

semanage fcontext -at httpd_sys_rw_content_t "/var/local/myapp(/.*)?"
restorecon -R -v '/var/local/myapp' 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.