Docker安全是Docker团队和广大使用者都极为关注的话题,Docker能否在生产环境和公有云环境中普及,在于Docker能否提供安全可靠的运行环境。目前,官方已经在安全方面做了一定工作,包括Docker Daemon以TCP为基础提供服务的同时使用传输层安全协议,在构建和使用镜像时验证镜像的签名证书,通过Namespaces和Cgroup隔离和限制容器资源,通过定义的Seccomp限制容器内进程使用的系统调用,提供自定义容器权能(Capability)的接口。根据容器服务的要求合理定制相关安全方案可极大提高安全性。
-
内核安全
Linux内核通过Namespace和Cgroup机制为容器提供支撑。分别实现对容器资源隔离和资源限制的功能,从而实现虚拟化,使容器犹如一台独立主机环境。
1. Namespace
Namespace(名字空间)是Linux系统的底层机制,由一些类型不同的Namespace选项组成,如下表所示。
Linux内核引入Namespace机制的主要目的就是实现容器技术。只有处于同一个Namespace下的进程才能互相可见,相互联系。为了在分布式环境下进行定位和通信,容器必然需要独立的IP、端口、路由等网络资源来隔离网络,Network Namespace提供了包括网络设备、IPv4、IPv6协议栈、/proc/net目录等网络资源的隔离。容器中进程间通信的方式有信号量、消息队列、和共享内存,与虚拟机不同的是,容器之间的进程间通信相当于是宿主机的相同IPC Namespace中的进程间通信。Mount Namespace通过隔离文件系统的功能,通过挂载点对文件系统进行隔离,用户可以通过“/proc/$pid/mounts”文件查看所有挂载在当前Namespace中的文件系统,还可以通过“/proc/$pid/mountstats”文件看到相关文件设备的统计信息,包括挂载文件名、挂载位置、文件系统类型等。同时,通过UTS Namespace在容器内部实现主机名和系统版本号的独立标识,而权限隔离和进程号的隔离保证容器内的用户和进程的独立。Docker利用Linux Namespace机制来实现UTS,IPC,PID,Network,Mount,User的隔离,如上表所示为各个Namespace在内核源码中的标志和功能。并且每个进程的Namespace都对应有自己的ns编号,可以通过“ls -l /proc/$pid/ns”命令来查询进程所属Namespace的标识号。
1.查看容器的命名空间
容器vm1虽然是root用户,但被限制不能管理网络。
2.Cgroup
Cgroup(Control Group)作为一个强大的内核工具,可以限制被Namespace隔离起来的资源,通过对任务使用资源总额进行限制,如设定容器启动后运行时内存的上限,一旦超过这个上限就发出OOM(out of memory)警告。也可以通过分配CPU时间片数量和磁盘IO带宽大小来控制任务运行的优先级。还可以为CPU使用时长、内存使用状态信息、IO占用情况等计算物理资源,操控任务启停,对任务执行挂起、恢复等操作,为Linux环境下实现虚拟化和容器技术提供了基础支撑,是构建虚拟化管理工具的基石。Cgroup的实现本质上是给任务挂上钩子,当任务运行过程中涉及某种资源时就会触发钩子上所附带的子系统进行检测,根据不同的资源类别使用相应的技术进行资源限制和优先级分配。
组控制器:
blkio: 这个subsystem可以为块设备设定输入/输出限制,比如物理驱动设备(包括磁盘、固态硬盘、USB等)。
cpu: 这个subsystem使用调度程序控制task对CPU的使用。
cpuacct: 这个subsystem自动生成cgroup中task对CPU资源使用情况的报告。
cpuset: 这个subsystem可以为cgroup中的task分配独立的CPU(此处针对多处理器系统)和内存。
devices: 这个subsystem可以开启或关闭cgroup中task对设备的访问。
freezer: 这个subsystem可以挂起或恢复cgroup中的task。
memory: 这个subsystem可以设定cgroup中task对内存使用量的限定,并且自动生成这些task对内存资源使用情况的报告。
perf_event: 这个subsystem使用后使得cgroup中的task可以进行统一的性能测试。
net_cls: 这个subsystem Docker没有直接使用,它通过使用等级识别符(classid)标记网络数据包,从而允许 Linux 流量。
cgroup对容器memory的控制目录
cgroup对容器cpu的控制目录
删除容器后,cgroup中清除对该容器的控制文件
运行容器时可以控制cpu memory的参数
针对cpu的限制
(1)针对系统某一进程
[root@server1 cpu]# mkdir x1
[root@server1 cpu]# cd x1/
[root@server1 x2]# echo 20000 > cpu.cfs_quota_us #占用"20000/100000=20%"的CPU [root@server1 x2]# cat cpu.cfs_quota_us
20000
[
值的注意的是:/sys/fs/cgroup/cpu目录中的文件,不能用vim进行编辑,利用vim进行编辑,无法进行保存退出(即使使用"wq!",也不能保存退出。)
(2)测试
[root@server1 x1]# dd if=/dev/zero of=/dev/null &
[1] 1314
[root@server1 x1]# top #看到dd命令占用的cpu比例将近为100%,这是因为还没有在tasks文件中写入要限制的进程号
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1314 root 20 0 107940 604 516 R 93.0 0.0 0:43.84 dd
[root@server1 x1]# echo 1314 > tasks #写入dd命令的进程号,对该进程进行限制
[root@server1 x1]# cat tasks
1314
[root@server1 x1]# top #看到dd命令占用的cpu比例在20%左右。
[root@server1 x1]# kill -9 1314
[root@server1 x1]# cat tasks
如果不对cpu进行限制,即不修改/sys/fs/cgroup/cpu/cpu.cfs_quota_us(文件内容默认是-1,表示不限制)文件中的内容。那么执行命令"dd if=/dev/zero of=/dev/null &"时,会占用100%的cpu。
cpu.cfs_period_us:cpu分配的周期(微秒),默认为100000。
cpu.cfs_quota_us:表示该control group限制占用的时间(微秒),默认为-1,表示不限制。如果设为50000,表示占用50000/100000=50%的CPU。