Docker之安全问题
1. 容器在使用中面临哪些威胁
1. 镜像污染
目前,Docker Hub上面有着数量众多的第三方上传镜像,这些镜像质量参差不齐。在这其中,不排除有黑客故意上传包含了恶意程序的镜像,并伪装成业务镜像供用户下载使用。当用户误用此类镜像启动容器时,无疑会导致容器被入侵。因此,用户必须保证容器所使用的镜像是可受信任的,尽可能不使用非信任的第三方镜像。
2. 网络攻击
Docker默认使用bridge网络,该网络会创建一个虚拟网桥,连接在同一个网桥之间的容器可以互相访问。当某个容器被入侵时,黑客有可能顺着网络访问到宿主机中的其他容器。同时 ,攻击者也可以通过DDos等方式,攻击容器的服务来耗尽主机的资源,从而引起整个宿主机的崩溃。
3. 内核攻击
当黑客获取到容器权限时,由于共享内核的缘故,理论上可通过对内核的攻击来达到控制或影响主机的地步 。
4. 操作不当
1. 在启动容器时将主机的根目录映射到容器中
2. 在启用容器时使用特权模式--privileged,此时Docker容器允许可以访问主机上的所有设备,并可以获取大量设备文件的访问权限。
5. 针对Docker Daemon的攻击
Docker使用的是C/S架构,作为服务端的Docker Daemon会接收客户端通过CLI或者REST API发送的命令,并执行对容器的相应操作。但请求不一定都是由可信任的用户发起的,攻击者可能通过伪造请求的方式,来达到欺骗Daemon端执行危险的操作。
6. Docker漏洞攻击
Docker本身属于应用程序,不可避免地会有出现代码的漏洞,这可能导致程序受到攻击。
2. Docker的安全防护
1. namespace
目前Namespace支持多种资源的隔离,包括文件系统挂载 、主机名和域名、进程间通信 、进程访问、网络隔离、用户和组隔离等。
2. Cgroup
Cgroup则是限制容器对于资源的占用,如CPU、内存、磁盘/IO等。这个特性非常有用,它避免了某个容器因为被Ddos攻击或者自身程序的问题导致对资源的不断占用,并最终影响到宿主机及上面运行的其他容器,出现“雪崩”的灾难 。
3. Capability
Capability是Linux内核具有的一个强大特性,可以提供颗粒化的权限访问控制。默认情况下,Docker启动的容器对能力有严格限制,只允许使用内核的一部分能力,包括chown、net_bind_service、fowner、kill、setgid等。
3. 容器安全的最佳实践
1. 容器配置
1. 禁止使用特权容器
使用--privileged启动容器时,会将所有内核功能赋予容器,从而覆盖Capability的能力限制。在这种情况下,容器可执行主机层面能做的大部分事情,从而给系统带来较大的安全隐患,所以应该被禁止。
docker run -d --privileged nginx
2. 限制容器的资源使用
1. 默认docker没有任何限制,可以占用宿主机的所有资源,容器可能会被linux系统杀掉。
                CFS schedule:每个进程都有优先级,非实时进程的优先级从100-139,CSF schedule是用来调度这些非实时进程的调度器,优先级高的进程会先被cpu执行
                realtime schedule:实时进程调度器,进程的优先级从0-99,realtime schedule是专门调度实时进程的调度器 
2. 限制内存
-m 为容器指定最多可以使用多少内存,如果超过了限制,那么可能会被kill掉
--memory-swap 依赖于第一个选项,为容器指定最多可以使用多少swap空间,此选项必须选了-m才能使用。
                
                -- memory-swappiness:设置容器使用swap的倾向性有多大,0-100。
                -- memory-reservation:容器使用内存的软限制,这个指一定要设置的比--memory小,当系统内存紧张时,会回收掉此容器的memory值-reservation值的内存,让容器的内存使用降到reservation的标准
--oom-kill-disable 禁止被oom杀掉,值为true
3. 限制CPU
                --cpus=:指定一个容器可以使用多少可用cpu资源,如果是4核cpu,可以设置为1.5,那么该容器最多只能使用1.5核的cpu资源,如果没有设置--cpuset-cpus,那么可以使用的1.5核可以是任意一个核心的资源。此选项只能在docker1.3以上版本中使用
                --cpu-shares:为容器按比例分配cpu资源,如果其他容器的cpu资源是空闲,那么容器1如果需要,将会使用所有cpu的资源,且将任务分配到任意核心处理
                --cpuset-cpus:为容器指定可以使用的cpu核心是哪个,如果cpu是4和,那么按照编号0-3区分每一个核心,此参数设置为0,1即表示可以使用cpu的第一个和第二个核心
4. 限制I/O
--blkio-weight 容器权重,值在10~1000之间
docker run -it --rm --blkio-weight 100 ubuntu bash
--device-read-bps
--device-write-bps
--device-read-iops
--device-write-iops
用于限制容器的读写速度
docker run -it --rm --device-write-bps /dev/sda:1mb ubuntu bash
4. 压力测试
1. 拉取压测工具
[root@bogon ~]# docker pull lorel/docker-stress-ng Using default tag: latest latest: Pulling from lorel/docker-stress-ng c52e3ed763ff: Pull complete a3ed95caeb02: Pull complete 7f831269c70e: Pull complete Digest: sha256:c8776b750869e274b340f8e8eb9a7d8fb2472edd5b25ff5b7d55728bca681322 Status: Downloaded newer image for lorel/docker-stress-ng:latest
2. 启动容器,8颗 CPU
docker container run --name stress -it --rm lorel/docker-stress-ng:latest --cpu 8
root@bogon ~]# docker stats
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
92b0b8d916c1        stress              101.54%             15.81MiB / 983.3MiB   1.61%               648B / 0B           0B / 0B             9
[root@bogon ~]# top
top - 19:15:49 up 2 days,  2:38,  2 users,  load average: 7.02, 3.00, 1.15
Tasks: 131 total,  10 running, 121 sleeping,   0 stopped,   0 zombie
%Cpu(s): 99.7 us,  0.3 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  1006892 total,   100680 free,   320704 used,   585508 buff/cache
KiB Swap:  2097148 total,  2096628 free,      520 used.   422732 avail Mem
  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                     
40035 root      20   0    6908   4180    252 R 12.6  0.4   0:12.79 stress-ng-cpu                                                               
40037 root      20   0    6908   4180    252 R 12.6  0.4   0:12.78 stress-ng-cpu                                                               
40038 root      20   0    6908   2136    252 R 12.6  0.2   0:12.78 stress-ng-cpu  
0040 root      20   0    6908   2136    252 R 12.6  0.2   0:12.78 stress-ng-cpu                                                               
40036 root      20   0    6908   2136    252 R 12.3  0.2   0:12.77 stress-ng-cpu                                                               
40039 root      20   0    6908   2136    252 R 12.3  0.2   0:12.78 stress-ng-cpu                                                               
40041 root      20   0    6908   4180    252 R 12.3  0.4   0:12.77 stress-ng-cpu                                                               
40042 root      20   0    6908   2136    252 R 12.3  0.2   0:12.77 stress-ng-cpu                                                               
    1 root      20   0  128484   7208   4196 S  0.0  0.7   0:10.12 systemd 
看到CPU使用率已经满了。
3. 启动一个限制CPU的容器
docker container run --name stress --cpus=0.5 -it --rm lorel/docker-stress-ng:latest --cpu 8
[root@bogon ~]# docker stats CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 845220ef9982 stress 51.57% 20.05MiB / 983.3MiB 2.04% 648B / 0B 0B / 0B 9 设置的参数生效
4. 测试内存
1、不限制内存使用,压测指定了2个内存,每个128m [root@bogon ~]# docker container run --name stress -it --rm lorel/docker-stress-ng:latest --vm 2 --vm-bytes 128m stress-ng: info: [1] defaulting to a 86400 second run per stressor stress-ng: info: [1] dispatching hogs: 2 vm [root@bogon ~]# docker stats CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS beb3cfa10748 stress 99.29% 256.2MiB / 983.3MiB 26.05% 648B / 0B 0B / 0B 5 而实际使用了256M内存 2、重新启动容器,加入内存限制 --memory限制容器只能使用128m内存 [root@bogon ~]# docker container run --name stress -it --memory=128m --rm lorel/docker-stress-ng:latest --vm 2 --vm-bytes 128m stress-ng: info: [1] defaulting to a 86400 second run per stressor stress-ng: info: [1] dispatching hogs: 2 vm [root@bogon ~]# docker stats CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS decee18cb471 stress 99.47% 126.4MiB / 128MiB 98.77% 648B / 0B 3.19MB / 461MB 5
3. 隔离容器网络
默认都是用docker0,建议使用自定义网桥
4. 禁止挂载主机系统目录
主机中与系统相关的目录,包含 /boot、/dev、/etc、/proc、/sys、/usr等,应该明令禁止被挂载到容器中。尤其是在读写模式下,这种情况会导致容器具有对主机系统进行修改的能力,从而给主机系统带来极大的安全隐患。
5. 将容器的根文件系统挂载为只读
将容器的根文件系统挂载为只读模式,这种模式可以避免对根文件系统带来任何的修改,从而保证了容器的安全性。当然,只读的模式也会带来不便 ,需要结合挂载存储来使用,将输出的内容写到持久化存储中。配置只读的方式很简单,在启动容器时添加 --read only 选项
6. 禁止使用网络模式host
在启动容器时,使用--network host 可以让容器与主机共享网络栈,此时,容器会使用主机的IP及其他的网络配置,并自动将容器的端口映射到主机。
2. 镜像配置
1. 禁止在镜像中存储机密信息
2. 选择最小化的基础镜像
3. 扫描并验证镜像
4. 使用多阶段构建镜像
#阶段一:编译打包 FROM maven:3.5.0-jdk-8-alpine AS builder ADD ./pom.xml pom.xml ADD ./src src/ RUN mvn clean package # 阶段二:配置运行 From openjdk:8-jre-alpine COPY --from=builder target/my-app-1.0-SNAPSHOT.jar my-app-1.0-SNAPSHOT.jar EXPOSE 8080 CMD ["java", "-jar", "my-app-1.0-SNAPSHOT.jar"]
3. 管理规范
1. 限制用户对容器宿主机的访问
2. 定期更新Docker版本
3. 完善容器监控
4. 使用TLS证书
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号