一个开发人员与我联系,他想为fluentd构建一个作为日志聚合器运行的容器。这个容器需要是一个超级权限容器,可以管理主机系统的一些部分,也就是目录/var/logs里面的日志文件。
作为一个认真负责的开发人员,他想尽可能安全地运行他的应用程序。他想避免使用—priviledged 选项来运行容器,那样容器就丧失了所有的安全性。这样,当他运行应用的时候,SELinux就抱怨容器进程试图读取日志文件。
问题:一个日志超级权限容器
他问我是否有一个运行容器的办法,让SELinux允许这个访问,但容器进程仍是被限制的(confined)。我建议他可以只对这个容器禁用SELinux保护,而让SELinux在其它容器和主机环境强制执行:
docker run -d --security-opt label:disable -v /var/log:/var/log fluentd
我们不喜欢这个方案。我相信SELinux是容器当前可用的最好的安全隔离。
我们讨论的另一个选项是将/var/log目录里的内容重新打标签:
docker run -d -v /var/log:/var/log:Z fluentd
这个方法的问题是/var/log目录下所有的文件现在被标记为一个专用于容器的标签(svirt_sandbox_file_t)。主机系统的其它部分,例如Logrotate和log扫描器等,现在将无法访问日志文件了。
我们想到的最好的方案是生成一个新的type在运行容器的时候使用。
这样首先需要我们写一点儿policy。我是这么写的:
cat container_logger.te policy_module(container_logger, 1.0) virt_sandbox_domain_template(container_logger) ############################## # virt_sandbox_net_domain(container_logger_t) gen_require(` attribute sandbox_net_domain; ') typeattribute container_logger_t sandbox_net_domain; ############################## logging_manage_all_logs(container_logger_t)
编译安装这个policy:
make -f /usr/selinux/devel/Makefile container_login.pp semodule -i container_login.pp
使用这个新的policy来运行容器:
docker run -d -v /var/log:/var/log --security-opt label:type:container_logger_t -n logger fluentd
到容器中执行来确认你可以读/写日志文件:
docker exec -ti logger cat /var/log/messages docker exec -ti logger touch /var/log/foobar docker exec -ti logger rm /var/log/foobar
一切OK!
Policy的详细讲解
policy_module(container_logger, 1.0)
policy_module
命名了这个Policy,同时引入了policy的所有标准定义。所有的类型强制文件都以此开头。
virt_sandbox_domain_template(container_logger)
virt_sandbox_domain_template
是一个模板宏,它创建了 container_logger_t
类型,并且设置了策略以允许可以由docker进程 (docker_t
)变迁到它。它也定义了规则来允许它管理svirt_sandbox_file_t
文件,并将其设为MCS隔离。这意味着它只能使用自己的内容,而不能使用其它容器的内容,不管它是以缺省的svirt_lxc_net_t
类型运行还是以定制的类型运行。
############################## # virt_sandbox_net_domain(container_logger_t) gen_require(` attribute sandbox_net_domain; ') typeattribute container_logger_t sandbox_net_domain; ##############################
这部分最终将变成一个接口 virt_sandbox_net_domain
。(我给上面的selinux-policy 包打了一个补丁来加入这个接口)。这个新的接口只是给container_logger_t
增加了一个属性。属性引入了很多的policy规则,基本上这个属性给 container_logger_t
进程赋予了完全的网络访问权限。如果你的容器不需要访问网络,或者你想限制container_logger_t
可以监听或者链接的端口,那就不需要使用这个接口。
logging_manage_all_logs(container_logger_t)
最后的logging_manage_all_logs
接口给了 container_logger_t
管理所有日志文件的能力。SELinux 接口被定义和安装在/usr/share/selinux/devel目录中。
结论
只需增加一个相当简单的策略模块,我们就可以尽可能安全地运行容器,又不影响任务的完成。
原文链接:
https://www.projectatomic.io/blog/2016/03/selinux-and-docker-part-2/