资源耗尽型攻击
同为虚拟化技术,容器与虚拟机既存在相似之处,也有显著不同。在资源限制方面,无论使用 VMware、Virtual Box 还是 QEMU,我们都需要为即将创建的虚拟机设定明确的CPU、内存及硬盘资源阈值。在虚拟机内部进程看来,他真的处于一台被设定好的独立计算机之中,然而,容器运行时默认情况下并未对容器内部进程在资源使用上做任何限制,以Pod 为基本单位的容器编排管理系统在默认情况下同样未对用户创建的Pod做任何CPU、内存使用限制
缺乏限制使得云原生环境面临资源耗尽型攻击的风险。攻击者可能通过在一个容器内发起拒绝式服务攻击来大量占用宿主机的资源,从而影响到宿主机自身或宿主机上其他容器的正常运行。注意,这里我们讨论的是默认配置下资源限制缺失,从而导致容器的隔离性在一定程度上失效(影响到容器外系统或服务的正常运行),而非针对容器本身的拒绝式服务攻击
常见容易受影响的资源如下:
1)计算资源:CPU、内存等
2)存储资源:本地硬盘等
3)软件资源:内核维护的数据结构等
4)通信资源:网络带宽等
CPU 资源耗尽
毫无疑问,CPU资源大量消耗会对计算机的正常运行产生影响,在限制缺少的情况下一个容器几乎能够使用宿主机上几乎所有的算力
下面,我们借助压力测试工具 stress 测试一下,同时使用 htop 工具 来监测宿主机CPU的使用情况
首先,我们在宿主机上开启 htop 监控,然后再宿主机上运行一个容器,接着在测量一个容器并执行 uname -a 命令所需的时间,可见从执行命令到结束的时间约为0.81s
time docker run -it --rm ubuntu uname -a
现在,我们模拟大量占用CPU算力的场景,执行如下的命令,拉取压力测试工具 stress的 docker 镜像:
docker pull joedval/stress
随机生成一个以“joedval/stress”镜像为基础的容器,设定权级为512,进行压力测试
time docker run -it --rm -c 512 joedval/stress --cpu 1
我们通过 htop 显示此时宿主机上的一个CPU核心使用率均为 100%,并且所花费的时间达到了31S
由此可见,在没有限制的情况下,恶意容器能够通过 CPU 算力耗尽的方式影响宿主机及其他容器的正常运行
内存资源耗尽
内存耗尽的表现也非常明显:应用交互及时性降低,服务响应时间或延长,在缺少限制的情况下,一个容器几乎能够占用宿主机上的所有内存
下面,我们借助压力测试工具stress测试一下,同时使用htop工具来检测一下宿主机内存的使用量
首先,我们在宿主机上打开 htop 监控,然后在宿主机上运行一个容器,接着再测量创建一个容器并执行uname -a 命令所需要的时间,可以见到从执行命令到结束花费了大约0.91S
现在我们模拟资源耗尽的场景,再第一次创建的容器中使用 stress 工具申请大量的存储空间,执行如下的命令:
stress --vm-bytes 800m --vm-keep -m 3
htop 显示此时宿主机上内存占用已经接近容量约为 1.77G,这时候我们在此测量创建一个容器并执行 uname -a 命令所需的时间已经变为 4.28S
由此可见,在没有限制的情况下,一个容器能够通过内存耗尽的方式影响宿主机及其其他容器的运行
进程表耗尽
事实上,除了硬件资源外,操作系统给还会提供很多软件资源,进程表就是其中之一,我们用经典的进程表耗尽案列——Fork炸弹——来分析这类软件资源无限制可能导致的问题。操作系统中一切行为都是以进程方式执行的。为了管理这些进程,操作系统内核维护了一张进程表,表的空间是有限的,一旦饱和,系统就无法再运行任何新程序,除非表中有进程终止
Fork炸弹,顾名思义,就是借助 fork 系统调用不断创建新进程,使进程表饱和,最终系统就无法正常运行,其中最经典的版本还是 bash 版本:
: () { : | : & } ; :
上面的代码的原理就是以无限递归的形式不断创建新进程。尽管只有一行代码,在Bash执行后,如果没有其他限制,操作系统就会慢慢失去响应
图中,我们展示了三个终端,在左上的终端中,我们在虚拟机中创建了一个容器,然后执行 Fork 炸弹代码,下方的终端给出当前虚拟机的IP地址,右上的终端则在Fork炸弹执行几分钟后,尝试使用 SSH 远程登陆到虚拟机,可以发现,此时虚拟机已经失去响应了
由此,我们可以看出,在没有相关限制的情况下,容器内的Fork炸弹能够影响宿主机正常运行
存储资源耗尽
除了运行时的资源外,相对静态的存储资源也可能被耗尽。所有虚拟化的技术都必须依托实体,容器也不列外。归根结底,容器内存储的数据、文件的实际存储位置还是在实体机上。如果容器内新增加了一个1GB的文件,不考虑 NFS的情况下,那么宿主机上的磁盘理应会减少 1GB。如果容器没有存储空间限制,容器内的攻击者理论上能够耗尽宿主机的存储资源
首先,我们使用 df 命令 查看 一下宿主机可用的存储空间,执行如下的命令,可以看到可用空间还有60G
df -h | grep /dev/sda1
然后我们在容器内使用fallocate命令创建一个 5 GB 的文件
fallocate -l 5.0G ./bomb
然后我们通过两次df 命令的对比发现,创建后的可用空间比创建前少了 5.0GB
由此,我们可以推理出,在没有限制存储资源的情况下,我们在容器中大量使用磁盘的存储空间,可占用大量宿主机的磁盘存储空间,从而影响宿主机及其其他容器的运行