# 我們運行一個容器
[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安全加固思路
-
保證鏡像安全:
使用安全的基礎鏡像(比如看不到構建歷史的不用);刪除鏡像中的 setuid 和 setgid 權限(suid、sgid);;啓用 docker 內容信任(證書認證);最小安裝原則;對鏡像進行安全漏洞掃描,鏡像安全掃描 器(Clair);容器使用非 root 運行 -
保證容器安全:
對 docker 主機進行安全加固;限制容器之間的網絡流量(某個容器流量升高,會對其他容器或主機有影響);配置 docker 守護程序的 TLS 身份驗證;啓用用戶命名空間支持(userns-remap 參數,在容器第一次啓動前就要加上,寫在 /etc/docker/daemon.json 文件裏,還需要對 docker 數據目錄做權限配置 /var/lib/docker);限制容器內存使用量;適當設置容器 CPU 優先級,/sys/fs/cgroup/cpu/cpu.shares 這個文件裏 -
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*文件系統設備,內核模
塊等,都還需要進一步的改進。