运维实战 容器部分 Docker安全

Posted 洛冰音

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了运维实战 容器部分 Docker安全相关的知识,希望对你有一定的参考价值。

理解Docker安全

由于Docker与传统虚拟化不同, 并不是完全隔离, 因此其安全性也是常被诟病的一点.

要做到相对安全的隔离就应该先了解Docker安全相关的知识.

Docker容器的安全性, 很大程度上依赖于Linux系统自身, 评估Docker的安全性时, 主要考虑以下几个方面:

  • Linux内核的命名空间机制提供的容器隔离安全
  • Linux控制组机制对容器资源的控制能力安全
  • Linux内核的能力机制所带来的操作权限安全
  • Docker程序(特别是服务端)本身的抗攻击性
  • 其他安全增强机制对容器安全性的影响

命名空间隔离的安全

  • 当启动一个容器时, Docker将在后台为容器创建一个独立的命名空间. 命名空间提供了最基础也最直接的隔离.

  • 与虚拟机方式相比, 通过Linux namespace来实现的隔离不是那么彻底.

  • 容器只是运行在宿主机上的一种特殊的进程, 那么多个容器之间使用的就还是同一个宿主机的操作系统内核.

  • Docker目前能够Namespace化的资源只有6种. 在 Linux 内核中, 仍旧有许多资源不能被Namespace化, 比如系统时间, 内存信息等等.

控制组资源控制的安全

  • 当启动一个容器时, Docker会在后台为容器创建一个独立的控制组策略集合.
  • LinuxCgroups特性提供了很多有用的特性支持, 这确保各容器可以公平地分享主机的内存、CPU、磁盘IO等资源.
  • 在考虑Docker安全性时, “确保容器内发生的资源压力不会影响到本地物理主机系统和其他容器” 这一思想是必不可少的.这在防止拒绝服务攻击 (DDoS) 方面能起到一定作用.

考虑内核能力机制

  • 能力机制 (Capability) 是Linux内核一个强大的特性, 可以提供细粒度的权限访问控制.

  • 大部分情况下, 容器并不需要"真正的"root权限, 容器只需要少数的能力即可.实际上, 默认设置下在容器中看到的root权限也并不完全具有我们一般意义上认为的操作系统root权限.

  • 默认情况下, Docker采用"白名单"机制, 禁用"必需功能"之外的其他权限.

Docker服务端防护

  • 既然Docker的安全性很大程度上依托于宿主机的安全性, 尽可能控制其对宿主机的影响以及宿主机本身的访问控制就是很重要一环了.
  • 保证只有可信用户可以访问Docker服务, 这一操作可以从源头降低出现安全风险的问题.
  • Docker分配专门的非root用户, 并将容器的root用户映射到专用用户上, 采用对该用户的权限控制降低容器和主机间因权限可能导致的安全问题出现的概率.
  • 允许Docker服务在非root权限下运行, 采用安全可靠的子进程来代理执行那些需要特权权限的操作.

其他安全特性

  • 采用具有安全特性的模板进行容器构建.
  • 可以自定义更加严格的访问控制机制来提升安全性.
  • 当需要挂载文件系统到容器内部时, 限制其权限为只读来避免容器内的应用或其他难以预料的操作通过挂接进入的文件破坏宿主机的外部环境.
  • 在内核中启用GRSECPAX, 这将增加更多的编译和运行时的安全检查; 并且通过地址随机化机制来避免恶意探测等. 因为这是内核本身的功能, 因此启用该特性并不需要Docker进行额外配置.

容器资源控制

Cgroups

Linux Cgroups 的全称是 Linux Control Group.

  • Linux Cgroups能够限制一个进程组所能使用的资源上限, 包括但不限于CPU/内存/磁盘/网络带宽等等.

  • Linux Cgroups能做到设置进程优先级, 审计/挂起/恢复进程等操作.

  • Linux Cgroups通过文件系统的方式让用户来进行操作, 文件系统也是其暴露给用户的操作接口.

  • Linux Cgroups以文件和目录的方式组织在操作系统的/sys/fs/cgroup 路径下.

  • 可以通过执行mount -t cgroup查看相关情况.

可能用到的信息

  • /sys/fs/cgroup存在形如cpuset cpu. memory这样的子目录, 分门别类地对各种资源进行控制, 一般也叫做子系统.

  • 每个子系统目录下, 还可以为每个容器创建一个控制组 (即创建一个新目录), 通过这一控制组中的配置信息管理容器的资源.

  • 控制组下面的资源文件里填的值, 靠用户启动容器时的参数指定.

CPU限额

docker run -it --name Test --cpu-period=100000 --cpu-quota=20000 ubuntu 

可以看到出现了2个参数, 其含义不太相同但是通常组合使用.

--cpu-period=100000指定单位总时间长度为100000

--cpu-quota=20000则指定在单位总时间长度中能够分配给容器用的时间

结合起来看就是每100000中有20000分配给容器, 即20%CPU时间.

内存限制

容器可用内存包括两个部分 物理内存和swap交换分区.

对应的参数也有两个

--memory					内存使用限额
--memory-swap				swap交换分区限额

docker run -it --name Test --memory 200M --memory-swap=200M ubuntu

Block IO限制

首先需要提及的是,Block IO虽然可以限制写设备的上限, 但只对直接读写 (direct io) 起效果, 如果采用文件缓存则会无效, 因此测试时需要附加参数

##限制对/dev/sda的写入速率为30MB
docker run -it --name Test --device-write-bps /dev/sda:30MB ubuntu

测试方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NrMZxYCQ-1620223427269)(C:\\Users\\NeuWings\\AppData\\Roaming\\Typora\\typora-user-images\\image-20210505220156830.png)]

dd if=/dev/zero of=bigfile bs=1M count=100 oflag=direct

100+0 records in
100+0 records out
104657600 bytes (105M) copied, 3.31933 s, 31.6MB/s

##可以看出速度得到了限制

Docker安全加固

利用LXCFS增强Docker容器隔离性和资源可见性

之前我们提过了, Docker容器的Namespace并不能完全隔离系统信息.

比如默认情况下即使你分配给容器定量的内存资源, 通过free- m时看到的实际上也会是宿主机的内存情况.

但这显然不符合业务需求, 用户应该看到的就是真实的情况.

LXCFS是一个开源的用户态文件系统, 常被用来对LXC容器提供支持. 它在容器中提供下列procfs文件

/proc/cpuinfo					CPU信息
/proc/diskstats					硬盘状态
/proc/meminfo					内存信息
/proc/stat						系统状态
/proc/swaps						swap分区
/proc/uptime					系统时间

不难看出其对Docker本身的Namespace进行了扩充.

##安装LXCFS
yum install -y lxcfs-2.0.5-3.el7.centos.x86_64.rpm

#安装完成后会生成/var/lib/lxcfs空目录

##后台静默运行
lxcfs /var/lib/lxcfs &

##自定义内存信息挂接进入容器
docker run  -it --name Test -m 256m \\
      -v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo:rw \\
      -v /var/lib/lxcfs/proc/diskstats:/proc/diskstats:rw \\
      -v /var/lib/lxcfs/proc/meminfo:/proc/meminfo:rw \\
      -v /var/lib/lxcfs/proc/stat:/proc/stat:rw \\
      -v /var/lib/lxcfs/proc/swaps:/proc/swaps:rw \\
      -v /var/lib/lxcfs/proc/uptime:/proc/uptime:rw \\
      ubuntu

##容器内查看情况
root@8457f705365:/# free -m
             total       used       free     shared    buffers     cached
Mem:           256          1        254          6          0          0
-/+ buffers/cache:          1        254
Swap:          256          0        256

##不难发现,内存的显示被隔离了
##对其他资源也适用

设置特权级运行的容器

虽然大部分时候容器内的root权限所具有的权限都已经足够使用.

但不免有的时候我们想要具有更多的权限: 如操作内核模块/挂载磁盘/修改硬件MAC地址/控制交换分区等等.

默认情况下你这么做是会被拒绝的, 并提示权限不足.

这时就需要在启动容器时附加--privileged=true参数, 他代表以特权级运行容器.

##以特权级驱动容器并进入bash
docker run -it --privileged=true --name Test ubuntu bash

设置容器白名单

但如果略加思考就会发现, 附加特权级****这一操作在安全逻辑上与我们所提倡的是相悖**的

  • 特权级具有几乎等同于宿主机管理权限的操作权限
  • 那他自然也就会引出对于宿主机的安全风险
  • 显然, 按需赋予权限更为安全, 只赋予容器其需要具有的额外权限, 尽可能避免可能出现的安全风险

通过附加--cap-add来赋予额外权限的方式我们就可以做到这一点.

##启动容器并赋予其网络管理的权限白名单
docker run -it  --name Test --cap-add=NET_ADMIN ubuntu  

##通过inspect命令查询容器情况
##可以看到并未服务特权
docker inspect -f {{.HostConfig.Privileged}} vm1
false
##但仍具有NET_ADMIN能力机制
docker inspect -f {{.HostConfig.CapAdd}} vm1
{[NET_ADMIN]}

可以附加的权限参数及其所包含的功能可以去如下网址查询.

Docker安全的遗留问题

  • 主要的内核子系统都没有命名空间, 如
SELinux

cgroup

位于/sys下的文件系统

/proc/sys  /proc/sysrq-trigger  /proc/irq  /proc/bus
  • 设备没有命名空间
/dev/mem

/dev/sd* 文件系统设备

内核模块

一些涉及Docker安全的开源工具

Docker Bench for Security			对照安全基准审计Docker容器的脚本
Clair								API驱动的静态容器安全分析工具, 拥有庞大的CVE数据库
Cilium								内核层可感知API的网络和安全工具
Anchore								使用CVE数据和用户定义的策略检查容器安全的工具
OpenSCAP Workbench					用于为各种平台创建和维护安全策略的环境
Dagda								用于在Docker容器中扫描漏洞 特洛伊木马 病毒和恶意软件的工具
Notary								使用服务器加强容器安全的框架, 用于以加密方式委派责任
Sysdig Falco						提供了行为活动监控, 可深入了解容器

以上是关于运维实战 容器部分 Docker安全的主要内容,如果未能解决你的问题,请参考以下文章

运维实战 容器部分 Docker网络

运维实战 容器部分 Docker入门简介

运维实战 容器部分 Docker数据卷

运维实战 容器部分 Docker仓库

运维实战 容器部分 Docker Swarm

运维实战 容器部分 Docker Machine