使用 udica 为容器构建 SELinux 策略

[ad_1]

虽然现代 IT 环境转向 Linux 容器,但保护这些环境的需求与以往一样重要。 容器是一种进程隔离技术。 虽然容器可以作为一种防御机制,但它们只有在与 SELinux 结合时才会表现出色。

Fedora SELinux 工程构建了一个新的独立工具, , 通过自动检查容器为容器生成 SELinux 策略配置文件。 本文重点介绍容器世界中为什么需要 udica,以及它如何使 SELinux 和容器更好地协同工作。 您会找到容器的 SELinux 分离示例,这些示例可让您避免因为通用 SELinux 类型 container_t 太紧而关闭保护。 使用 udica,您可以使用有限的 SELinux 策略编写技巧轻松自定义策略。

SELinux技术

SELinux 是一种安全技术,可为 Linux 系统带来主动安全性。 它是一个标签系统,为所有主体(进程和用户)和对象(文件、目录、套接字等)分配一个标签。 这些标签随后用于控制整个系统访问的安全策略。 值得一提的是,默认情况下拒绝 SELinux 安全策略中不允许的内容。 策略规则由内核强制执行。 该安全技术已用于 Fedora 几年来。 这种规则的一个真实例子是:

allow httpd_t httpd_log_t: file { append create getattr ioctl lock open read setattr };

该规则允许任何标记为 httpd_t 的进程 创建、附加、读取和锁定标记为 httpd_log_t 的文件。 使用 ps 命令,您可以列出所有带有标签的进程:

$ ps -efZ | grep httpd
system_u:system_r:httpd_t:s0 root 13911 1 0 Apr14 ? 00:05:14 /usr/sbin/httpd -DFOREGROUND
...

要查看哪些对象被标记为 httpd_log_t,请使用 semanage:

# semanage fcontext -l | grep httpd_log_t
/var/log/httpd(/.)? all files system_u:object_r:httpd_log_t:s0
/var/log/nginx(/.)? all files system_u:object_r:httpd_log_t:s0
...

SELinux 安全策略 Fedora 在 selinux-policyRPM 包中提供。

SELinux 与容器

在 Fedora,container-selinux RPM 包为所有由 podman 或 docker 等引擎启动的容器提供通用的 SELinux 策略。 它的主要目的是保护主机系统免受容器进程的影响,并将容器彼此分开。 例如,SELinux 限制的进程类型为 container_t 的容器只能读取/执行 /usr 中的文件并写入 container_file_t 主机文件系统上的文件类型。 为了防止容器相互攻击,使用了多类别安全(MCS)。

由于容器使用的种类繁多,因此仅对容器使用一种通用策略是有问题的。 一方面,默认容器类型 (container_t) 通常过于严格。 例如:

  • Fedora 银蓝 需要容器来读/写用户的主目录
  • 流利的 项目需要容器才能读取 /var/log 目录中的日志

另一方面,对于某些用例,默认容器类型可能过于宽松:

  • 它没有 SELinux 网络控制——所有容器进程都可以绑定到任何网络端口
  • 它没有 SELinux 控制 Linux 功能 — 所有容器进程都可以使用所有功能

有一种解决方案可以处理这两种用例:为容器编写自定义 SELinux 安全策略。 这可能很棘手,因为需要 SELinux 专业知识。 为此,创建了 udica 工具。

介绍 udica

Udica 为容器生成 SELinux 安全配置文件。 它的概念是基于内部的“块继承”特性。 通用中间语言 (CIL) 由 SELinux 用户空间支持。 该工具创建的策略结合了:

  • 从指定的 CIL 块(模板)继承的规则,以及
  • 通过检查包含挂载点和端口定义的容器 JSON 文件发现的规则

您可以立即加载最终策略,或将其移动到另一个系统以加载到内核中。 这是一个使用容器的示例:

  • 将 /home 挂载为只读
  • 将 /var/spool 挂载为读/写
  • 暴露端口 tcp/21

容器以以下命令启动:

# podman run -v /home:/home:ro -v /var/spool:/var/spool:rw -p 21:21 -it fedora bash

默认容器类型 (container_t) 不允许这三个操作中的任何一个。 为了证明这一点,您可以使用 sesearch 工具查询系统上是否存在允许规则:

# sesearch -A -s container_t -t home_root_t -c dir -p read 

不存在允许标记为 container_t 的进程访问标记为 home_root_t 的目录(如 /home 目录)的允许规则。 同样的情况发生在 /var/spool 上,它被标记为 var_spool_t:

# sesearch -A -s container_t -t var_spool_t -c dir -p read

另一方面,默认策略完全允许网络访问。

# sesearch -A -s container_t -t port_type -c tcp_socket
allow container_net_domain port_type:tcp_socket { name_bind name_connect recv_msg send_msg };
allow sandbox_net_domain port_type:tcp_socket { name_bind name_connect recv_msg send_msg };

保护容器

限制这种访问并允许容器仅绑定到 TCP 端口 21 或使用相同的标签会很棒。 假设您使用 podman ps 找到一个示例容器,其 ID 为 37a3635afb8f:

# podman ps -q
37a3635afb8f

您现在可以检查容器并将检查文件传递给 udica 工具。 新策略的名称是 my_container。

# podman inspect 37a3635afb8f > container.json
# udica -j container.json my_container
Policy my_container with container id 37a3635afb8f created!

Please load these modules using:
# semodule -i my_container.cil /usr/share/udica/templates/{base_container.cil,net_container.cil,home_container.cil}

Restart the container with: "--security-opt label=type:my_container.process" parameter

而已! 您刚刚为示例容器创建了自定义 SELinux 安全策略。 现在您可以将此策略加载到内核中并使其处于活动状态。 上面的 udica 输出甚至告诉您要使用的命令:

# semodule -i my_container.cil /usr/share/udica/templates/{base_container.cil,net_container.cil,home_container.cil}

现在您必须重新启动容器以允许容器引擎使用新的自定义策略:

# podman run --security-opt label=type:my_container.process -v /home:/home:ro -v /var/spool:/var/spool:rw -p 21:21 -it fedora bash

示例容器现在正在新创建的 my_container.process SELinux 进程类型中运行:

# ps -efZ | grep my_container.process
unconfined_u:system_r:container_runtime_t:s0-s0:c0.c1023 root 2275 434 1 13:49 pts/1 00:00:00 podman run --security-opt label=type:my_container.process -v /home:/home:ro -v /var/spool:/var/spool:rw -p 21:21 -it fedora bash
system_u:system_r:my_container.process:s0:c270,c963 root 2317 2305 0 13:49 pts/0 00:00:00 bash

看到结果

命令 sesearch 现在显示允许访问 /home 和 /var/spool 的规则:

# sesearch -A -s my_container.process -t home_root_t -c dir -p read
allow my_container.process home_root_t:dir { getattr ioctl lock open read search };
# sesearch -A -s my_container.process -t var_spool_t -c dir -p read
allow my_container.process var_spool_t:dir { add_name getattr ioctl lock open read remove_name search write }

新的自定义 SELinux 策略还允许 my_container.process 仅绑定到标记为与 TCP 端口 21 相同的 TCP/UDP 端口:

# semanage port -l | grep 21 | grep ftp
ftp_port_t tcp 21, 989, 990
# sesearch -A -s my_container.process -c tcp_socket -p name_bind
allow my_container.process ftp_port_t:tcp_socket name_bind;

结论

udica 工具可帮助您根据检查文件为容器创建 SELinux 策略,而无需任何 SELinux 专业知识。 现在,您可以提高容器化环境的安全性。 来源可在 GitHub, 并且 RPM 包在 Fedora 存储库 Fedora 28 及以后。

拍摄者 塞缪尔·泽勒不飞溅。

[ad_2]

Related Posts