Docker 安全加固措施

# 我们运行一个容器
[root@server1 ~]# docker run -it --rm --memory 256MB --memory-swap 256MB ubuntu
root@3f308cdd0b55:/# free -m			# 查看内存
             total       used       free     shared    buffers     cached
Mem:           991        433        557         12          2        249
-/+ buffers/cache:        181        809
Swap:         2047          0       2047
root@3f308cdd0b55:/# exit
[root@server1 ~]# free -m			# 容器外查看内存
              total        used        free      shared  buff/cache   available
Mem:            991         125         579          12         286         704
Swap:          2047    
  • 发现我们开启容器时虽然已经限制了内存为256M,但是看到的总内存和容器外一样,没有做到完全的隔离,这是一个不安全的点,需要进行安全加固。

lxcfs 文件系统

首先我们可以通过 lxcfs 文件系统增强 docker 容器的隔离性和资源可见性.

[root@server1 ~]# docker run -it --name vm1 -m 256M ubuntu		# 运行一个容器
root@6718c6a02544:/# free  -m
             total       used       free     shared    buffers     cached
Mem:           991        434        556         12          2        251
-/+ buffers/cache:        180        810
Swap:         2047          0       2047
# 内存大小和外界相同。

root@6718c6a02544:/# cat /proc/cpuinfo 
processor	: 0
vendor_id	: GenuineIntel
cpu family	: 6
model		: 61
model name	: Intel Core Processor (Broadwell)
stepping	: 2
microcode	: 0x1
cpu MHz		: 2495.998
cache size	: 4096 KB
physical id	: 0
siblings	: 1
core id		: 0
cpu cores	: 1
apicid		: 0
initial apicid	: 0
fpu		: yes
fpu_exception	: yes
# 这里和我们在外面看到的时一样的,因为它的信息都是共享宿主机的。

我们安装 lxcfs 文件系统:

[root@server1 lxcfs]# yum install lxcfs-2.0.5-3.el7.centos.x86_64.rpm  -y
[root@server1 ~]# lxcfs /var/lib/lxcfs/ &	# 后台运行启动,/var/lib/lxcfs 是 lxcfs 默认数据目录
[1] 3876
[root@server1 ~]# hierarchies:
  0: fd:   5: freezer
  1: fd:   6: devices
  2: fd:   7: memory
  3: fd:   8: cpuacct,cpu
  4: fd:   9: hugetlb
  5: fd:  10: pids
  6: fd:  11: net_prio,net_cls
  7: fd:  12: blkio
  8: fd:  13: cpuset
  9: fd:  14: perf_event
 10: fd:  15: name=systemd

[root@server1 ~]# cd /var/lib/lxcfs/		
[root@server1 lxcfs]# ls
cgroup  proc		# ccgroup 是资源限制,proc 是系统信息

[root@server1 proc]# ls
cpuinfo  diskstats  meminfo  stat  swaps  uptime
# 所以我们可以把这个目录挂载到容器里面,就可以看到我们想要的信息了,我们只需要在这里限制就行了

设置特权级运行的容器:

加 --privileged=true 参数。

有时候我们需要容器具备更多权限,比如操作内核模块,控制 swap 分区,修改 MAC 地址等。

root@9b2f8448999b:/# id			# 当前是root用户
uid=0(root) gid=0(root) groups=0(root)
root@9b2f8448999b:/# ip addr add 172.17.0.3/24 dev eth0
RTNETLINK answers: Operation not permitted			# 加一个ip地址却不被允许,因为没有实际权限

[root@server1 ~]# docker run --help | grep priv 	# 查看权限参数
--privileged			Give extended privileges to this container	# 给额外的权限
#默认这个权限是被禁掉的

[root@server1 proc]# docker run -it --name vm3 --privileged=true ubuntu		# 运行成功
root@c685225f26f0:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
12: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0		
       valid_lft forever preferred_lft forever
root@c685225f26f0:/# ip addr add 172.17.0.10 dev eth0		# 添加一个ip地址
root@c685225f26f0:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
12: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 172.17.0.10/32 scope global eth0		# 添加成功。
       valid_lft forever preferred_lft forever
       
[root@server1 proc]# docker inspect vm3 | grep Pri
            "Privileged": true,		# 当前只有vm3 开启了这个权限
[root@server1 proc]# docker inspect vm2 | grep Pri
            "Privileged": false,
[root@server1 proc]# docker inspect vm1 | grep Pri
            "Privileged": false,
  • 默认情况下这个权限比较大,基本上接近宿主机的权限,为了防止用户的权限滥用, 需要增加机制,只提供给容器必要的权限’ 相当于做 sudo的用户权力下放

我们通过设置容器白名单实现。

容器白名单

http://man7.org/linux/man-pages/man7/capabilities.7.html
可以在这个网址进行capability 权限查询
在这里插入图片描述

[root@server1 proc]# docker run -it --name vm4 --cap-add=NET_ADMIN ubuntu	# 这个参数代表只可以控制网络,但其他不行
root@c8a9b1998cfb:/# ip addr add 172.17.0.5/24 dev eth0
root@c8a9b1998cfb:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 172.17.0.5/24 scope global eth0
       valid_lft forever preferred_lft forever
root@c8a9b1998cfb:/# 
[root@server1 proc]# docker inspect vm4 |grep Pri
            "Privileged": false,			# 但是此时的 privileged 是关闭的
[root@server1 proc]# docker inspect vm4 | less
            "CapAdd": [
                "NET_ADMIN"		# 可以看到我们加的参数
            ],

# 我们还可以用这种方式查看:
[root@server1 proc]# docker inspect -f {{.HostConfig.Privileged}} vm4
false
[root@server1 proc]# docker inspect -f {{.HostConfig.CapAdd}} vm4
[NET_ADMIN]

Docker安全加固思路

  1. 保证镜像安全:
    使用安全的基础镜像(比如看不到构建历史的不用);删除镜像中的 setuid 和 setgid 权限(suid、sgid);;启用 docker 内容信任(证书认证);最小安装原则;对镜像进行安全漏洞扫描,镜像安全扫描 器(Clair);容器使用非 root 运行

  2. 保证容器安全:
    对 docker 主机进行安全加固;限制容器之间的网络流量(某个容器流量升高,会对其他容器或主机有影响);配置 docker 守护程序的 TLS 身份验证;启用用户命名空间支持(userns-remap 参数,在容器第一次启动前就要加上,写在 /etc/docker/daemon.json 文件里,还需要对 docker 数据目录做权限配置 /var/lib/docker);限制容器内存使用量;适当设置容器 CPU 优先级,/sys/fs/cgroup/cpu/cpu.shares 这个文件里

  3. docker 安全遗留问题:
    默认情况下只有 6 个 namespace,很多主要的内核子系统是没有命名空间的,如 SELinux,Cgroup,
    /sys 下的文件系统,/proc/sys,/proc/sysrq-trigger 等

[root@server1 ns]# ls /sys
block  bus  class  dev  devices  firmware  fs  hypervisor  kernel  module  power
[root@server1 ns]# ls /proc/sys
abi  crypto  debug  dev  fs  kernel  net  sunrpc  user  vm
[root@server1 ns]# ls /proc/sysrq-trigger 
/proc/sysrq-trigger
[root@server1 ~]# docker inspect vm4| grep Pid
            "Pid": 4204,			# 进程为4024
            "PidMode": "",
            "PidsLimit": 0,
[root@server1 ~]# cd /proc/4204/ns
[root@server1 ns]# ls
ipc  mnt  net  pid  user  uts			# 可以看到只有六个命名空间
命名空间 功能 系统调用参数 内核版本
MNT Namespace(mount) 提供磁盘挂载点和文件系统的隔离能力 CLONE_NEWNS Linux 2.4.19
IPC Namespace(Inter-Process Communication) 提供进程间通信的隔离能力 CLONE_NEWIPC Linux 2.6.19
UTS Namespace(UNIX Timesharing System) 提供主机名隔离能力 CLONE_NEWUTS Linux 2.6.19
PID Namespace(Process Identification) 提供进程隔离能力 CLONE_NEWPID Linux 2.6.24
Net Namespace(network) 提供网络隔离能力 CLONE_NEWNET Linux 2.6.29
User Namespace(user) 提供用户隔离能力 CLONE_NEWUSER Linux 3.8

比如我们的设备就没有命名空间:/dev/mem(进程和物理地址的映射),/dev/sd*文件系统设备,内核模
块等,都还需要进一步的改进。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章