Docker-docker安全
1. 理解Docker安全
1.1 Docker容器的安全性,很大程度上依赖于Linux系统自身,评估Docker的安全性时,主要考虑以下几个方面:
• Linux内核的命名空间机制提供的容器隔离安全
• Linux控制组机制对容器资源的控制能力安全。
• Linux内核的能力机制所带来的操作权限安全
• Docker程序(特别是服务端)本身的抗攻击性。
• 其他安全增强机制对容器安全性的影响。
1.2 命名空间隔离的安全
• 当docker run启动一个容器时,Docker将在后台为容器创建一个独立的命名空间。命名空间提 供了最基础也最直接的隔离。
• 与虚拟机方式相比,通过Linux namespace来实现的隔离不是那么彻底。
• 容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作系统内核。
• 在 Linux 内核中,有很多资源和对象是不能被 Namespace 化的, 比如:时间。
1.3 • 控制组资源控制的安全
• 当docker run启动一个容器时,Docker将在后台为容器创建一个独立的控制组策略集合。
• Linux Cgroups提供了很多有用的特性,确保各容器可以公平地分享主机的内存、CPU、磁盘IO等资源。
• 确保当发生在容器内的资源压力不会影响到本地主机系统和其他容器,它在防止拒绝服务攻击(DDoS)方面必不可少。
1.4 内核能力机制
• 能力机制(Capability)是Linux内核一个强大的特性,可以提供细粒度的权限访问控制。
• 大部分情况下,容器并不需要“真正的”root权限,容器只需要少数的能力即可。
• 默认情况下,Docker采用“白名单”机制,禁用“必需功能”之外的其他权限。
1. 5 Docker服务端防护
• 使用Docker容器的核心是Docker服务端,确保只有可信的用户才能访问到Docker服务。
• 将容器的root用户映射到本地主机上的非root用户,减轻容器和主机之间因权限提升而引起的安全问题。
• 允许Docker 服务端在非root权限下运行,利用安全可靠的子进程来代理执行需要特权权限的操作。这些子进程只允许在特定范围内进行操作。
1.6 其他安全特性
• 在内核中启用GRSEC和PAX,这将增加更多的编译和运行时的安全检查;并且通过地址随机化机制来避免恶意探测等。启用该特性不需要Docker进行任何配置。
• 使用一些有增强安全特性的容器模板。
• 用户可以自定义更加严格的访问控制机制来定制安全策略。
• 在文件系统挂载到容器内部时,可以通过配置只读模式来避免容器内的应用通过文件系统破坏外部环境,特别是一些系统运行状态相关的目录
2. 容器资源控制
2. 1 Linux Cgroups 的全称是 Linux Control Group。
• 是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。
• 对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。
2.2 Linux Cgroups 给用户暴露出来的操作接口是文件系统。
• 它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。
• 执行此命令查看:mount -t cgroup
[root@lnmp0 ~]# mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_prio,net_cls)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
• 在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。
[root@lnmp0 ~]# cd /sys/fs/cgroup/
[root@lnmp0 cgroup]# ls
blkio cpu cpuacct cpu,cpuacct cpuset devices freezer hugetlb memory net_cls net_cls,net_prio net_prio perf_event pids systemd
• 在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录)。
• 控制组下面的资源文件里填上什么值,就靠用户执行 docker run 时的参数指定。
2.3 CPU限额
• docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu
• cpu_period 和 cpu_quota 这两个参数需要组合使用,用来限制进程在长度为 cpu_period 的一段时间内,只能被分配到总量为cpu_quota 的 CPU 时间,以上设置表示20%的cpu时间。
2.3.1 没限额之前
运行容器
[root@lnmp0 docker]# docker run -it ubuntu
root@b7c9b9120961:/# dd if=/dev/zero of=/dev/null & ##拉取一个无限零设备,一个无限空设备,不耗磁盘,只消耗cpu
[1] 9
root@b7c9b9120961:/#
CTRL+pq退出
查看cpu使用情况,可以看到在不做限制的情况下,cpu使用率为100%
[root@lnmp0 docker]# top
top - 06:26:59 up 21:17, 2 users, load average: 1.80, 0.69, 0.60
Tasks: 213 total, 2 running, 211 sleeping, 0 stopped, 0 zombie
%Cpu(s): 19.3 us, 80.7 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1863220 total, 142432 free, 669968 used, 1050820 buff/cache
KiB Swap: 2097148 total, 2080424 free, 16724 used. 827160 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
114170 root 20 0 2544 384 320 R 100.0 0.0 0:52.88 dd
在 /sys/fs/cgroup/cpu/docker/中会自动创建一个子目录,子目录名称和运行的容器id是一样的,在子目录的文件中会更加清楚的记录cpu,磁盘等等的使用情况
[root@lnmp0 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b7c9b9120961 ubuntu "bash" 16 minutes ago Up 16 minutes flamboyant_lumiere
[root@lnmp0 ~]# cd /sys/fs/cgroup/cpu/docker/
[root@lnmp0 docker]# ls
cpuacct.usage cpuacct.usage_percpu cpu.cfs_period_us cpu.cfs_quota_us cpu.rt_period_us
cpu.rt_runtime_us cpu.shares cpu.stat
b7c9b912096164b695eee628b443197134e00e5e2bab35509eafba6267d0ac6f cgroup.clone_children
cgroup.event_control notify_on_release cgroup.procs tasks cpuacct.stat
[root@lnmp0 docker]# cd b7c9b912096164b695eee628b443197134e00e5e2bab35509eafba6267d0ac6f ##自动创建一个子目录,子目录名称和运行的容器id是一样的,只不过docker ps看到的是缩短版的
[root@lnmp0 b7c9b912096164b695eee628b443197134e00e5e2bab35509eafba6267d0ac6f]# ls
cgroup.clone_children cgroup.procs cpuacct.usage cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release
cgroup.event_control cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks
[root@lnmp0 b7c9b912096164b695eee628b443197134e00e5e2bab35509eafba6267d0ac6f]# cat cpu.cfs_period_us
100000
[root@lnmp0 b7c9b912096164b695eee628b443197134e00e5e2bab35509eafba6267d0ac6f]# cat cpu.cfs_quota_us
-1 ##配额-1代表不做限制,百分比使用
2.3.2 限额之后
运行容器的时候,限制配额
[root@lnmp0 ~]# docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu ##cpu_period 和 cpu_quota 这两个参数需要组合使用,用来限制进程在长度为 cpu_period 的一段时间内,只能被分配到总量为cpu_quota 的 CPU 时间,以上设置表示20%的cpu时间。
root@90e714081e0b:/# dd if=/dev/zero of=/dev/null &
[1] 9
查看cpu使用情况,可以看到在做限制之后的情况下,cpu使用率为20%
[root@lnmp0 ~]# top
top - 07:03:24 up 21:54, 2 users, load average: 1.75, 2.06, 2.03
Tasks: 213 total, 3 running, 210 sleeping, 0 stopped, 0 zombie
%Cpu(s): 20.9 us, 79.1 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1863220 total, 151928 free, 658268 used, 1053024 buff/cache
KiB Swap: 2097148 total, 2080424 free, 16724 used. 839492 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7206 root 20 0 2544 384 320 R 20.0 0.0 0:37.99 dd
在 /sys/fs/cgroup/cpu/docker/子目录中查看限制配额后的情况
[root@lnmp0 ~]# cd /sys/fs/cgroup/cpu/docker/
[root@lnmp0 docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
90e714081e0b ubuntu "bash" 8 minutes ago Up 8 minutes blissful_hamilton
[root@lnmp0 docker]# ls
90e714081e0b21a703e497f42292eb8965de4e6f5e1ffa164f1a11c79a8dcb38
cpuacct.usage cpuacct.usage_percpu cpu.cfs_period_us cpu.cfs_quota_us cpu.rt_period_us
cpu.rt_runtime_us cpu.shares cpu.stat group.clone_children
cgroup.event_control notify_on_release cgroup.procs tasks cpuacct.stat
[root@lnmp0 docker]# cd 90e714081e0b21a703e497f42292eb8965de4e6f5e1ffa164f1a11c79a8dcb38/
[root@lnmp0 90e714081e0b21a703e497f42292eb8965de4e6f5e1ffa164f1a11c79a8dcb38]# ls
cgroup.clone_children cgroup.procs cpuacct.usage cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release
cgroup.event_control cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks
[root@lnmp0 90e714081e0b21a703e497f42292eb8965de4e6f5e1ffa164f1a11c79a8dcb38]# cat cpu.cfs_period_us
100000
[root@lnmp0 90e714081e0b21a703e497f42292eb8965de4e6f5e1ffa164f1a11c79a8dcb38]# cat cpu.cfs_quota_us
20000 ##和运行容器时做的配额限制一样
[root@lnmp0 90e714081e0b21a703e497f42292eb8965de4e6f5e1ffa164f1a11c79a8dcb38]# cat tasks
7206 ##控制哪些进程受限,7206是刚做的用top查看配额限制的id
2.4 内存限制
• 容器可用内存包括两个部分:物理内存和swap交换分区。
• docker run -it --memory 200M --memory-swap=200M ubuntu
• --memory设置内存使用限额
• --memory-swap设置swap交换分区限额
2.4.1 没做限制之前
运行容器
[root@lnmp0 ~]# docker run -d --name demo1 nginx
630ae768c5032966ab13638adde977ab4486b66143f79bee2f7a934c0fed519e
[root@lnmp0 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
630ae768c503 nginx "/docker-entrypoint.…" About a minute ago Up About a minute 80/tcp demo1
在/sys/fs/cgroup/memory/docker/中会自动创建一个子目录,子目录名称和运行的容器id是一样的,在子目录的文件中会更加清楚的记录内存的使用情况
[root@lnmp0 ~]# cd /sys/fs/cgroup/memory/docker/
[root@lnmp0 docker]# ls
memory.kmem.tcp.failcnt memory.kmem.tcp.limit_in_bytes
memory.kmem.tcp.max_usage_in_bytes memory.kmem.tcp.usage_in_bytes
memory.kmem.usage_in_bytes memory.limit_in_bytes
630ae768c5032966ab13638adde977ab4486b66143f79bee2f7a934c0fed519e memory.max_usage_in_bytes memory.memsw.failcnt
memory.memsw.limit_in_bytes memory.memsw.max_usage_in_bytes
cgroup.clone_children memory.memsw.usage_in_bytes
cgroup.event_control memory.move_charge_at_immigrate
cgroup.procs memory.numa_stat
memory.oom_control memory.pressure_level
memory.soft_limit_in_bytes memory.failcnt
memory.stat memory.force_empty
memory.swappiness memory.kmem.failcnt
memory.usage_in_bytes memory.kmem.limit_in_bytes memory.use_hierarchy memory.kmem.max_usage_in_bytes notify_on_release memory.kmem.slabinfo tasks
[root@lnmp0 docker]# cd 630ae768c5032966ab13638adde977ab4486b66143f79bee2f7a934c0fed519e/
[root@lnmp0 630ae768c5032966ab13638adde977ab4486b66143f79bee2f7a934c0fed519e]# ls
cgroup.clone_children memory.kmem.max_usage_in_bytes memory.limit_in_bytes memory.numa_stat memory.use_hierarchy
cgroup.event_control memory.kmem.slabinfo memory.max_usage_in_bytes memory.oom_control notify_on_release
cgroup.procs memory.kmem.tcp.failcnt memory.memsw.failcnt memory.pressure_level tasks
memory.failcnt memory.kmem.tcp.limit_in_bytes memory.memsw.limit_in_bytes memory.soft_limit_in_bytes
memory.force_empty memory.kmem.tcp.max_usage_in_bytes memory.memsw.max_usage_in_bytes memory.stat
memory.kmem.failcnt memory.kmem.tcp.usage_in_bytes memory.memsw.usage_in_bytes memory.swappiness
memory.kmem.limit_in_bytes memory.kmem.usage_in_bytes memory.move_charge_at_immigrate memory.usage_in_bytes
[root@lnmp0 630ae768c5032966ab13638adde977ab4486b66143f79bee2f7a934c0fed519e]# cat memory.limit_in_bytes
9223372036854771712 ##不做限制的物理内存
[root@lnmp0 630ae768c5032966ab13638adde977ab4486b66143f79bee2f7a934c0fed519e]# cat memory.memsw.limit_in_bytes
9223372036854771712 ##不做限制的swapp分区
2.4.2 做限制之后
运行容器时对内存加以限制
[root@lnmp0 docker]# docker run -d --name demo --memory 200M --memory-swap=200M nginx
3e397b10b8f4ac8711554a356add331e37d9ae87e3ea97f954f53c06853a82b6
[root@lnmp0 docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3e397b10b8f4 nginx "/docker-entrypoint.…" 7 seconds ago Up 6 seconds 80/tcp demo
在自动建立的子目录的文件中查看记录内存的使用情况
[root@lnmp0 ~]# cd /sys/fs/cgroup/memory/docker/
[root@lnmp0 docker]# ls
memory.failcnt memory.memsw.max_usage_in_bytes
memory.force_empty memory.memsw.usage_in_bytes
memory.kmem.failcnt memory.move_charge_at_immigrate
3e397b10b8f4ac8711554a356add331e37d9ae87e3ea97f954f53c06853a82b6 memory.kmem.limit_in_bytes memory.numa_stat
memory.kmem.max_usage_in_bytes memory.oom_control
memory.kmem.slabinfo memory.pressure_level
memory.kmem.tcp.failcnt memory.soft_limit_in_bytes
memory.kmem.tcp.limit_in_bytes memory.stat
memory.kmem.tcp.max_usage_in_bytes memory.swappiness
cgroup.clone_children memory.kmem.tcp.usage_in_bytes memory.usage_in_bytes
cgroup.event_control memory.kmem.usage_in_bytes memory.use_hierarchy
cgroup.procs memory.limit_in_bytes notify_on_release
memory.max_usage_in_bytes tasks
memory.memsw.failcnt
memory.memsw.limit_in_bytes
[root@lnmp0 docker]# cd 3e397b10b8f4ac8711554a356add331e37d9ae87e3ea97f954f53c06853a82b6/
[root@lnmp0 3e397b10b8f4ac8711554a356add331e37d9ae87e3ea97f954f53c06853a82b6]# ls
cgroup.clone_children memory.kmem.max_usage_in_bytes memory.limit_in_bytes memory.numa_stat memory.use_hierarchy
cgroup.event_control memory.kmem.slabinfo memory.max_usage_in_bytes memory.oom_control notify_on_release
cgroup.procs memory.kmem.tcp.failcnt memory.memsw.failcnt memory.pressure_level tasks
memory.failcnt memory.kmem.tcp.limit_in_bytes memory.memsw.limit_in_bytes memory.soft_limit_in_bytes
memory.force_empty memory.kmem.tcp.max_usage_in_bytes memory.memsw.max_usage_in_bytes memory.stat
memory.kmem.failcnt memory.kmem.tcp.usage_in_bytes memory.memsw.usage_in_bytes memory.swappiness
memory.kmem.limit_in_bytes memory.kmem.usage_in_bytes memory.move_charge_at_immigrate memory.usage_in_bytes
[root@lnmp0 3e397b10b8f4ac8711554a356add331e37d9ae87e3ea97f954f53c06853a82b6]# cat memory.limit_in_bytes
209715200 ##限制的是物理内存,这里出现的是字节数,换算过来和之前限制的内存使用量是一样的
[root@lnmp0 3e397b10b8f4ac8711554a356add331e37d9ae87e3ea97f954f53c06853a82b6]# cat memory.memsw.limit_in_bytes
209715200 ##这里限制的是swapp分区的使用量
2.5 Block IO限制
• docker run -it --device-write-bps /dev/sda:30MB ubuntu
• --device-write-bps限制写设备的bps,磁盘的IO速率
• 目前的block IO限制只对direct IO有效。(不使用文件缓存)
没做block IO限制之前
[root@lnmp0 docker]# docker run -it ubuntu
root@8287ed187198:/# dd if=/dev/zero of=bigfile bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.104512 s, 1.0 GB/s ##没做限制之前拉取文件时间只需要0.104512
做block IO限制之后
[root@lnmp0 ~]# docker run -it --device-write-bps /dev/sda:30MB ubuntu ##每秒30M的写入量
root@77aee0846918:/# dd if=/dev/zero of=bigfile bs=1M count=100 oflag=direct ##正常设备数据会先写入到缓存,30s后刷新,再持久化到磁盘上,加上oflag=direct会直接写入到磁盘,不使用文件缓存,以达到限制写入速率的目的
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 3.34532 s, 31.3 MB/s ##限制之后需要的时间达到了3.34532
[root@lnmp0 docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
77aee0846918 ubuntu "bash" 3 minutes ago Up 3 minutes confident_jennings
进入自动创建的目录中查看block IO限制情况,block IO限制自动创建的目在 /sys/fs/cgroup/blkio/
[root@lnmp0 ~]# cd /sys/fs/cgroup/blkio/docker/
[root@lnmp0 docker]# cd 77aee084691805b2cc88522a92e2acce9a2e1d052e1ab54c88b2642c32382aa6/
[root@lnmp0 77aee084691805b2cc88522a92e2acce9a2e1d052e1ab54c88b2642c32382aa6]# ls
blkio.io_merged blkio.io_serviced_recursive blkio.reset_stats blkio.throttle.write_bps_device cgroup.event_control
blkio.io_merged_recursive blkio.io_service_time blkio.sectors blkio.throttle.write_iops_device cgroup.procs
blkio.io_queued blkio.io_service_time_recursive blkio.sectors_recursive blkio.time notify_on_release
blkio.io_queued_recursive blkio.io_wait_time blkio.throttle.io_service_bytes blkio.time_recursive tasks
blkio.io_service_bytes blkio.io_wait_time_recursive blkio.throttle.io_serviced blkio.weight
blkio.io_service_bytes_recursive blkio.leaf_weight blkio.throttle.read_bps_device blkio.weight_device
blkio.io_serviced blkio.leaf_weight_device blkio.throttle.read_iops_device cgroup.clone_children
[root@lnmp0 77aee084691805b2cc88522a92e2acce9a2e1d052e1ab54c88b2642c32382aa6]# cat blkio.throttle.write_bps_device
8:0 31457280 ##此文件显示block IO限制情况,8:0代表/dev/sda的设备标识
[root@lnmp0 77aee084691805b2cc88522a92e2acce9a2e1d052e1ab54c88b2642c32382aa6]# ll -d /dev/sda
brw-rw---- 1 root disk 8, 0 Jun 29 23:18 /dev/sda
3. docker安全加固
3.1 利用LXCFS增强docker容器隔离性和资源可见性
• yum install -y lxcfs-2.0.5-3.el7.centos.x86_64.rpm
• lxcfs /var/lib/lxcfs &
• docker run -it --rm --memory 200M --memory-swap 200M
-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
3.1.1 不做容器隔离的情况下
[root@lnmp0 ~]# docker run -it --rm --memory 200M --memory-swap=200M ubuntu
root@af636009f58b:/# free -m
total used free shared buff/cache available
Mem: 1819 693 134 257 991 690
Swap: 2047 139 1908
root@af636009f58b:/# exit
[root@lnmp0 ~]# free -m
total used free shared buff/cache available
Mem: 1819 557 154 257 1107 711
Swap: 2047 139 1908
##可以看到在容器中显示的是我们主机的磁盘使用情况,但是运行容器的时候实际上是做了磁盘使用限制的,而且容器的磁盘使用量实际也只有我们做了限制的200M, 这样就出现了容器磁盘实际使用量与磁盘可见性不符的问题
3.1.2 容器隔离后,磁盘使用量的可见性
首先先下载容器隔离所用到的工具
[root@lnmp0 ~]# yum install -y lxcfs-2.0.5-3.el7.centos.x86_64.rpm
Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager
This system is not registered with an entitlement server. You can use subscription-manager to register.
.....
Installed:
lxcfs.x86_64 0:2.0.5-3.el7.centos
Complete!
[root@lnmp0 ~]# lxcfs /var/lib/lxcfs & ##启动lxcfs,打入后台
[1] 89507
[root@lnmp0 ~]# hierarchies:
0: fd: 5: devices
1: fd: 6: freezer
2: fd: 7: hugetlb
3: fd: 8: perf_event
4: fd: 9: cpuset
5: fd: 10: cpuacct,cpu
6: fd: 11: memory
7: fd: 12: net_prio,net_cls
8: fd: 13: blkio
9: fd: 14: pids
10: fd: 15: name=systemd
PID file '/run/lxcfs.pid' is already locked.
[2]+ Exit 1 lxcfs /var/lib/lxcfs/
运行容器做磁盘限制时将lxcfs下的文件挂载到容器中
[root@lnmp0 ~]# docker run -it --rm --memory 200M --memory-swap 200M -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@03e6178df1d6:/# free -m
total used free shared buff/cache available
Mem: 200 0 199 257 0 199
Swap: 0 0 0
root@03e6178df1d6:/#
##做完隔离后,运行容器时限制的磁盘是多少,进入容器查看到的就是多少
3.2 设置特权级运行的容器:--privileged=true
• 有的时候我们需要容器具备更多的权限,比如操作内核模块,控制swap交换分区,挂载USB磁盘,修改MAC地址等。
3.2.1 不加特权进入容器
[root@lnmp0 ~]# docker run -it --rm busybox
ip: SIOCSIFFLAGS: Operation not permitted
/ # id
uid=0(root) gid=0(root) groups=10(wheel)
/ #
##可以发现,我们进入容器所持的身份虽然是root,但依然会受限制
3.2.2 设置特权级运行的容器
[root@lnmp0 ~]# docker run -it --rm --privileged=true busybox ##设置特权运行容器
/ # ip link set down eth0
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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
332: eth0@if333: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
/ # ip link set up eth0
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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
332: eth0@if333: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
/ #
设置特权后,进入容器虽然权限会比较高,但使用一定要注意,不然可能你在容器中所做的一些操作会直接影响你的主机,三思而后行。
3.3 设置容器白名单:--cap-add
• --privileged=true 的权限非常大,接近于宿主机的权限,为了防止用户的滥用,需要增加限制,只提供给容器必须的权限。此时Docker 提供了权限白名单的机制,使用--cap-add添加必要的权限。
• capabilities手册地址:http://man7.org/linux/man-pages/man7/capabilities.7.html
• # docker run -it --cap-add=NET_ADMIN busybox
还有更多的能力机制建议参考官方文档
[root@lnmp0 ~]# docker run -it --rm --cap-add=NET_ADMIN busybox
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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
334: eth0@if335: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
/ # ip addr add 10.0.0.1/24 dev eth0
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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
334: eth0@if335: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet 10.0.0.1/24 scope global eth0
valid_lft forever preferred_lft forever
/ # ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1): 56 data bytes
64 bytes from 10.0.0.1: seq=0 ttl=64 time=0.068 ms
64 bytes from 10.0.0.1: seq=1 ttl=64 time=0.043 ms
^C
--- 10.0.0.1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.043/0.055/0.068 ms
3.4 安全加固的思路
• 保证镜像的安全
• 使用安全的基础镜像
• 删除镜像中的setuid和setgid权限
• 启用Docker的内容信任
• 最小安装原则
• 对镜像进行安全漏洞扫描,镜像安全扫描器:Clair
• 容器使用非root用户运行
3.5 docker安全的遗留问题
• 主要的内核子系统都没有命名空间,如:
• SELinux
• cgroup
• 在 /sys 下的文件系统
• / proc/sys , /proc/sysrq-trigger, /proc/irq , /proc/bus
• 设备没有命名空间:
• /dev/mem
• /dev/sd* 文件系统设备
• 内核模块
如果你能沟通或攻击的其中之一作为特权的过程中,你可以拥有自己的系统。
4 . Docker安全的顶尖开源工具:
• Docker Bench for Security 对照安全基准审计 Docker 容器的脚本
• Clair API 驱动的静态容器安全分析工具,拥有庞大的 CVE 数据库
• Cilium 内核层可感知 API 的网络和安全工具
• Anchore 使用 CVE 数据和用户定义的策略检查容器安全的工具
• OpenSCAP Workbench 用于为各种平台创建和维护安全策略的环境
• Dagda 用于在 Docker 容器中扫描漏洞、特洛伊木马、病毒和恶意软件的工具
• Notary 使用服务器加强容器安全的框架,用于以加密方式委派责任
•Sysdig Falco 提供了行为活动监控,可深入了解容器