Linux 中实现沙箱隔离运行的多种方法

Linux 中实现沙箱隔离运行的多种方法

无论您是系统管理员还是软件开发人员,保护系统都是每个生产环境的重中之重。保护操作系统免受可疑程序或进程侵害的最佳方法是沙箱(也称为监禁jailing)。

沙盒包括为程序或软件提供一个安全的环境,以便您可以在不损害系统的情况下使用它。通过使用 Linux 内核中可用的任何一种不同方法,它实际上使您的程序与系统的其余部分隔离。

如果系统管理员想要在没有任何损害的情况下测试他们的应用,那么沙盒对他们很有用。沙箱可以帮助您创建与基本操作系统不同的环境。由于 PaaS 和 SaaS 提供商的广泛使用,它已成为一种时尚。那么在linux下有几种方式方法可以实现沙箱沙盒隔离运行软件呢?有6种方式。

一、命名空间namespace

命名空间是 Linux 中可用的功能,用于隔离不同系统资源方面的进程。在内核 4.0 之前有六种类型的命名空间可用。将来还会添加更多。这些是:

mnt(挂载点,文件系统)

pid(进程)

net(网络堆栈)

IPC(系统 V IPC)

uts(主机名)

用户(UID)

Linux 命名空间并不新鲜。第一个是在 2008 年添加到 Linux 中的(Linux 内核 2.6),但它们只在 Linux 内核 3.6 中得到了更广泛的使用,当工作在其中最复杂的时候??用户命名空间 ?? 完成了。Linux 内核使用clone()、unshare()和setns()系统调用来创建和控制命名空间。

新命名空间的创建由clone()系统调用完成,它也用于启动进程。该setns()系统调用增加了一个正在运行的进程,以现有的命名空间。在unshare()调用工作在命名空间中的过程,使主叫方的命名空间中的一员。它的主要目的是隔离命名空间而不必创建新的进程或线程(就像clone()). 你可以直接使用一些服务来获取这些命名空间的特性。CLONE_NEW* 标识符与这些系统调用一起使用来标识命名空间的类型。这三个系统调用使用 CLONE_NEW* 作为 CLONE_NEWIPC、CLONE_NEWNS、CLONE_NEWNET、CLONE_NEWPID、CLONE_NEWUSER 和 CLONE_NEWUTS。命名空间中的进程可能因创建时的唯一 inode 编号而不同。

#ls -al /proc/<pid>/ns
lrwxrwxrwx 1 root root 0 Feb 7 13:52 ipc -> ipc:[4026532253]
lrwxrwxrwx 1 root root 0 Feb 7 15:39 mnt -> mnt:[4026532251]
lrwxrwxrwx 1 root root 0 Feb 7 13:52 net -> net:[4026531957]
lrwxrwxrwx 1 root root 0 Feb 7 13:52 pid -> pid:[4026532254]
lrwxrwxrwx 1 root root 0 Feb 7 13:52 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Feb 7 15:39 uts -> uts:[4026532252]

挂载命名空间

进程查看原始系统挂载点以外的不同挂载点。它创建一个与不同进程相关联的单独文件系统树,从而限制它们对根文件系统进行更改。

PID命名空间

PID 命名空间将进程 ID 与主 PID 层次结构隔离开来。PID 命名空间内的进程可以与它外部的进程具有相同的 PID,即使在命名空间内,您也可以使用不同的 init 和 PID 1。

UTS 命名空间

在 UTS(UNIX 分时系统)命名空间中,一个进程可以拥有与主系统不同的一组域名和主机名。它使用 sethostname() 和 setdomainname() 来做到这一点。

IPC 命名空间

这用于进程间通信资源隔离和 POSIX 消息队列。

用户命名空间

这隔离了命名空间内的用户和组 ID,允许在命名空间中具有与主机中相同的 UID 或 GID。在您的系统中,非特权进程可以创建他们拥有完全特权的用户命名空间。

网络命名空间

在这个命名空间内,进程可以有不同的网络堆栈,即不同的网络设备、IP 地址、路由表等。

Linux 中可用的沙盒工具使用此命名空间功能来隔离进程或创建新的虚拟环境。一个更安全的工具将是使用最大命名空间进行隔离的工具。现在,让我们谈谈沙盒的不同方法,从软隔离到硬隔离。

二、chroot

chroot是 Linux 中最古老的沙箱工具。它的工作与 mount 命名空间相同,但它实现得更早。chroot将进程的根目录更改为任何chroot目录(如 / chroot)。由于根目录是文件系统层次结构的顶部,应用程序无法访问高于根目录的目录,因此与系统的其余部分隔离。这可以防止chroot内的应用程序以免干扰计算机上其他地方的文件。要在旧的基于 SystemV 的操作系统中创建隔离环境,您首先需要将所有必需的包和库复制到该目录。出于演示目的,我正在运行 ??ls?? 在 chroot 目录中。

首先,创建一个目录以将进程的文件系统设置为 root:

<em>#mkdir /chroot</em>

接下来,在其中创建所需的目录。

<em>#mkdir /chroot/{lib,lib64,bin,etc}</em>

现在,最重要的步骤是复制可执行文件和库。要在chroot 中获取 shell ,您还需要/bin/bash。

#cp -v /bin/{bash,ls} /chroot/bin

要查看此脚本所需的库,请运行以下命令:

#ldd /bin/bash
linux-vdso.so.1 (0x00007fff70deb000)
libncurses.so.5 => /lib/x86_64-linux-gnu/libncurses.so.5 (0x00007f25e33a9000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f25e317f000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f25e2f7a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f25e2bd6000)
/lib64/ld-linux-x86-64.so.2 (0x00007f25e360d000)

#ldd /bin/ls
linux-vdso.so.1 (0x00007fff4f8e6000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f9f00aec000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9f00748000)
libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f9f004d7000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9f002d3000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9f00d4f000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9f000b6000)

现在,这些文件复制到LIB或lib64目录的/ chroot的要求。

一旦您复制了所有必要的文件,就可以进入chroot 了。

#sudo chroot /chroot/ /bin/bash

系统将提示您在虚拟环境中运行一个 shell。在这里,除了 ls 之外,您没有什么可以运行的,但是它已经将这个进程的根文件系统更改为/chroot。

要获得功能更全面的环境,您可以使用debootstrap实用程序来引导基本的 Debian 系统:

#debootstrap --arch=amd64 unstable my_deb/

它将下载一个最小系统以在chroot下运行。您甚至可以使用它在 64 位系统上测试 32 位应用程序或在安装前测试您的程序。要获得进程管理,将proc挂载到chroot,并使home的内容在退出时丢失,将tmpfs挂载到/home//:

#sudo mount -o bind /proc my_deb/proc
#mount -t tmpfs -o size=100m tmpfs /home/user

要在内部获得 Internet 连接,请使用以下命令:

#sudo cp /etc/resolv.conf /var/chroot/etc/resolv.conf

之后,您就可以进入您的环境了。

#chroot my_deb/ /bin/bash

在这里,您在chroot 中获得了一个完整的基本操作系统。但它与您的主系统的挂载点不同,因为它仅使用挂载属性作为隔离器。它具有与主系统中相同的主机名、IP 地址和运行的进程。这就是为什么它的安全性要低得多(甚至在 chroot 的手册页中也提到了这一点),并且任何正在运行的进程仍然可以通过终止您的任务或影响基于网络的服务来损害您的计算机。

注意:要在 chroot 中运行图形应用程序,请通过在主系统上运行以下命令来打开 x 服务器:

#xhost +
and on chroot system
#export DISPLAY=:0.0

在基于systemd的系统上,chrooting 非常简单。它只需要在进程单元文件上定义根目录。

[Unit]
Description=my_chroot_Service
[Service]
RootDirectory=/chroot/foobar
ExecStartPre=/usr/local/bin/pre.sh
ExecStart=/bin/my_program
RootDirectoryStartOnly=yes

这里RootDirectory显示了 foobar 进程的根目录在哪里。

注意:程序脚本路径必须在 chroot 内,这使得该进程脚本的完整路径为 /chroot/bin/my_program。

在守护进程启动之前,会调用一个shell 脚本pre.sh,其目的是根据需要设置chroot 环境,即将/proc和类似的文件系统挂载到其中,这取决于服务可能需要什么。您可以使用以下命令启动您的服务:

#systemctl start my_chroot_Service.service

三、ip-netns

Ip-netns 实用程序是少数直接使用网络命名空间来创建虚拟接口的实用程序之一。要创建新的网络命名空间,请使用以下命令:

#ip netns add netns1

要检查内部接口,请使用如下所示的命令:

#ip netns exec netns ip addr

您甚至可以在其中获取外壳,如下所示:

#ip netns exec netns /bin/bash

这将带您进入网络命名空间,它只有一个没有 IP 的网络接口。所以,你没有连接外网,也无法ping通。

#ip netns exec netns ip link set dev lo up

这将打开循环界面。但是要连接到外部网络,您需要创建一个虚拟以太网并将其添加到netns 中,如下所示:

# ip link add veth0 type veth peer name veth1
# ip link set veth1 netns netns1

现在,是时候为这些设备设置 IP,如下所示:

# ip netns exec netns1 ifconfig veth1 10.1.1.1/24 up
# ifconfig veth0 10.1.1.2/24 up

四、unshare

unshare 实用程序用于创建任何命名空间隔离环境并在其中运行程序或 shell。

要获取网络命名空间并在其中运行 shell,请使用如下所示的命令:

#unshare --net /bin/bash

您返回的 shell 将带有不同的网络堆栈。您可以使用#ip addr进行检查,如下所示:

1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

要创建用户命名空间环境,请使用以下命令:

#unshare --user /bin/bash

您可以使用以下命令在 shell 内检查您的用户:

#whoami
nobody

要获取 PID 命名空间,请使用以下命令:

#unshare --pid --fork /bin/bash

在这个命名空间中,您可以看到所有进程,但不能杀死任何进程。

#ps -aux |grep firefox
root 1110 42.6 11.0 1209424 436756 tty1 Sl 23:36 0:15 .firefox1/./firefox
root 1208 0.0 0.0 12660 1648 pts/2 S+ 23:37 0:00 grep firefox
#kill 1110
bash: kill: (1110) - No such process

要获得完全不同程度的进程树隔离,您需要为命名空间挂载另一个 proc,如下所示:

unshare --pid --fork --mount-proc /bin/bash

这样,您可以使用 unshare 来创建单个命名空间。可以在 unshare 的手册页上找到有关它的更多信息。

注意: 使用 unshare 创建的命名空间也可以组合起来创建使用不同命名空间的单个 shell。例如:

#unshare --pid --fork --user /bin/bash

这将使用 PID 和用户命名空间创建一个隔离的环境。

五、Firejail 


Firejail 是一个 SUID 沙盒程序,用于隔离程序以用于测试或安全目的。它是用 C 编写的,可以配置为使用大多数命名空间。要在 firejail 中启动服务,请使用以下命令:

#firejail firefox

它将在沙箱中启动 Firefox,并将根文件系统挂载为只读。要仅通过~/Downloads和~/.mozilla挂载来启动 Firefox ,请使用以下命令:

#firejail --whitelist=~/.mozilla --whitelist=~/Download firefox
默认情况下,Firejail 使用用户命名空间并在私有模式下在用户主目录顶部安装空的临时文件系统 ( tmpfs )。要以私有模式启动程序,请使用以下命令:

#firejail --private firefox

要在新的网络堆栈中启动 firejail,请使用以下命令:

#firejail --net=eth0 --whitelist=~/.mozilla --whitelist=~/Download firefox

要为沙箱分配 IP 地址,请使用以下命令:

#firejail --net=eth0 --ip=192.168.1.155 firefox
注意:要沙盒用户运行的所有程序,您可以将该用户的默认 shell 更改为 /usr/bin/firejail。

#chsh –shell /usr/bin/firejail

六、虚拟容器container

在学习虚拟化技术时,最吸引我的是容器,因为它们易于部署。容器(也称为轻量级虚拟化)是用于隔离的工具,它为此目的使用命名空间。它们是一种更好的沙箱实用程序,因为它们通常使用多个命名空间,并且更专注于创建整个虚拟系统实例而不是隔离单个进程。

容器并不是一项新技术。它们已经在 UNIX 和 Linux 中使用了几十年,但由于它们在 SaaS 和 PaaS 中的使用越来越多,它们已经成为一个热门话题,因为它们提供了最安全的环境来交付和使用这些服务。它们被称为轻量级虚拟化,因为它们提供进程级隔离,这意味着它们依赖于 Linux 内核。因此,只能创建使用相同基本内核的那些实例。有许多可用于 Linux 的容器在过去几年中越来越受欢迎。

Systemd-nspawn

这是 systemd 默认可用的实用程序,它创建单独的容器以进行隔离。它默认使用 mount 和 PID 命名空间,但也可以配置另一个命名空间。要创建容器或隔离外壳,您需要使用 debootstrap 下载我们已经完成的基本发行版。要进入此容器,请使用以下代码:

#systemd-nspawn -D my_deb

这个容器比chroot更强大,因为它不仅有不同的挂载点,而且还有一个单独的进程树(通过ps -aux检查)。但是,主机名和 IP 接口仍然与主机系统相同。要添加您自己的网络堆栈,您需要连接到现有的网桥。

#systemd-nspawn -D my_deb --network-bridge=br0

这将使用一对veth设备启动具有网络命名空间的容器。您甚至可以通过-b选项启动实例,如下所示:

#systemd-nspawn -bD my_deb

注意: 启动容器时,需要输入root用户的密码;所以首先在里面运行 #passwd 来设置 root 密码。

整个nspawn项目比较年轻;因此还有很多需要开发。

Docker 

Docker 是 Linux 中运行应用程序环境的最智能、最突出的容器。在过去的几年中,它引起了最多的关注。Docker 容器使用 systemd 中存在的大部分命名空间和 cgroup 来提供强大的隔离环境。Docker 运行在 Docker 守护进程上,它启动一个像 systemd-nspawn 这样的独立实例,只需稍作调整就可以在其中部署任何服务。它可以用作沙盒工具来安全地运行应用程序或在其中部署一些软件服务。

要运行您的第一个 Docker 容器,您需要先启动 Docker 守护进程,然后从 Docker 在线存储库下载基础镜像,如下所示:

#service docker start
#docker pull kalilinux/kali-linux-docker
注意: 您还可以从 Docker Hub (https://hub.docker.com/) 下载其他 Docker 镜像。

它将下载基本的 Kali Linux 映像。您可以使用以下代码查看系统上的所有可用图像:

#docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
kalilinux/kali-linux-docker
latest 63ae5ac8df0f 1 minute ago 325 MB
centos centos6 b9aeeaeb5e17 9 months ago 202.6 MB
hello-world latest 91c95931e552 9 months ago 910 B
要在容器内运行程序,请使用以下命令:

#docker run -i -t kalilinux/kali-linux-docker ls
bin dev home lib64 mnt proc run selinux sys usr
boot etc lib media opt root sbin srv tmp var
这将启动(运行)您的容器,执行命令,然后关闭容器。要在容器内获取交互式 shell,请使用下面给出的命令:

#docker run -t -i kalilinux/kali-linux-docker /bin/bash
root@24a70cb3095a:/#
这将使您进入容器中,您可以在其中进行工作,与主机隔离。24a70cb3095a是您的容器?的 ID。您可以使用以下命令检查所有正在运行的容器:

#docker ps

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
24a70cb3095a kalilinux/kali-linux-docker “/bin/bash” About a minute ago Up About a minute angry_cori
在安装 Docker 镜像时,Docker 会自动为 Docker创建一个veth,这使得 Docker 镜像连接到主系统。您可以通过使用#ifconfig并ping 您的主系统来检查这一点。在任何情况下,您都可以使用以下代码将 Docker 状态保存为新容器:

#docker commit 24a70cb3095a new_image
#docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
new_image latest a87c73abca9d 6 seconds ago 325 MB
kalilinux/kali-linux-docker
latest 63ae5ac8df0f 1 hours ago 325 MB
centos centos6 b9aeeaeb5e17 9 months ago 202.6 MB
hello-world latest 91c95931e552 9 months ago 910 B
您可以使用#docker rmi new_image删除该图像。要停止容器,请使用docker stop ,然后删除该容器在主机节点上创建的文件。

#docker stop 24a70cb3095a
#docker rm 24a70cb3095a
为了在 Docker 实例上运行应用程序,您可能需要以某种方式将其附加到主机系统。因此,要将外部存储挂载到 Docker 映像,您可以使用 -v 标志,如下所示:

#docker run -it -v /temp/:/home/ kalilinux/kali-linux-docker /bin/bash
这会将/temp/从主系统挂载到主机系统的/home/。要将 Docker 端口附加到外部系统端口,请使用 -??p:

#docker run -it -v /temp/:/home/ -p 4567:80 kalilinux/kali-linux-docker /bin/bash
这会将外部端口 4567 附加到容器的 80 端口。这对于 SaaS 和 PaaS 非常有用,前提是部署的应用程序需要连接到外部网络。在 Docker 上运行 GUI 应用程序通常是另一个要求。Docker 没有定义 x 服务器,为此,您需要将 x 服务器文件挂载到 Docker 实例。

#docker run -it -v -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix \ kalilinux/kali-linux-docker /bin/bash
这会将 X11 套接字转发到 Docker 内的容器。要将 Docker 镜像发送到另一个系统,您需要将其推送到 Docker 在线存储库,如下所示:

#docker push new_image
您甚至可以将容器映像保存在 tar 存档中:

#docker export new_image
关于 Docker 有很多东西要学习,但深入研究这个主题并不是本文的目的。Docker 的优点在于其在线提供了许多教程和技巧,您可以从中轻松地更好地了解如何使用它来完成工作。自 2013 年首次发布以来,Docker 已经有了很大的改进,它可以部署在生产或测试环境中,因为它易于使用。

还有其他为 Docker 设计的解决方案,它们是为所有场景设计的。其中包括 Kubernetes(一个用于 Docker 编排的 Google 项目)、Swarm 和更多用于 Docker 迁移的服务,这些服务提供图形仪表板等。系统管理员(如 Puppet 和 Chef)的自动化工具也开始为 Docker 容器提供支持。甚至 systemd 也开始为 nspawn 和其他容器提供管理实用程序,其中包含许多工具,例如 machinectl 和 journalctl。

machinectl 

它预装了 systemd 初始化管理器。它用于管理和控制基于 systemd 的虚拟机的状态,容器在 systemd 服务下工作。要查看系统中运行的所有容器,请使用以下命令:

#machinectl -a

要获取任何正在运行的容器的状态,请使用下面给出的命令:

#machinectl status my_deb

注意:machinectl 不显示 Docker 容器,因为后者在 Docker 守护进程后面运行。

要登录到容器,请使用以下命令:

#machinectl login my_deb
关闭容器,如下所示:

#machinectl poweroff my_deb
要强制终止容器,请使用以下命令:

#machinectl -s kill my_deb
查看一个容器的日志,可以使用journalctl,如下:

#journalctl -M my_deb

七、总结

沙箱对每个 IT 专业人员都很重要,但不同的专业人员可能需要不同的解决方案。如果您是开发人员或应用程序测试人员,chroot可能不是一个好的解决方案,因为它允许攻击者逃离chroot监狱。systemd-nspawn 或 firejail 等弱容器可能是一个很好的解决方案,因为它们易于部署。使用类似 Docker的容器进行应用程序测试可能会让人有点头疼,因为让容器为流程顺利运行做好准备可能会有点痛苦。

{{collectdata}}

网友评论0