一. 容器配置
1、禁止使用特权容器
使用--privileged启动容器时,会将所有内核功能赋予容器,从而覆盖Capability的能力限制。在这种情况下,容器可执行主机层面能做的大部分事情,从而给系统带来较大的安全隐患,所以应该被禁止。
$ docker run -d --privileged nginx
2、限制容器的资源使用
默认情况下,主机上的容器对于资源的访问并没有受到限制。此时,当某个容器被攻击或者程序出错时,将可能因为过多占用资源而影响到主机和其他容器的运行。
因此,可以通过Cgroup的特性来设置容器的资源使用限制,这样得以最大程度减少因此类问题而产生的影响 。
示例1:限制CPU可以使用的最大核数为1 。
$ docker run -d --cpus 1 nginx
示例2:限制容器可以使用特定的CPU,如宿主机有4个CPU,我们只允许容器使用第一个CPU,可以设置如下 :
$ docker run -d --cpuset-cpus 0 nginx
示例3:限制容器最大内存使用量为512M。
$ docker run -d -m 512m nginx
3、 隔离容器网络
Docker默认使用bridge网络,该网络会创建一个虚拟网桥,连接在同一个网桥之间的容器可以互相访问。为了提升网络安全性,建议不要依赖默认的docker0网络,而是通过自定义网络方式进行容器网络的划分,这样可保证对宿主机中的容器之间做到访问隔离。
另外,在主机层面也应尽可能进行网络划分,不同的主机运行不同安全性要求的容器,如开发环境、测试环境和生产环境的宿主机应该彼此隔离。
4、禁止挂载主机系统目录
主机中与系统相关的目录,包含 /boot、/dev、/etc、/proc、/sys、/usr等,应该明令禁止被挂载到容器中。尤其是在读写模式下,这种情况会导致容器具有对主机系统进行修改的能力,从而给主机系统带来极大的安全隐患。
遗憾的是,目前在Docker层面并没有相关的技术方案来限制此类行为,只能通过审计等手段进行发现。
5、 将容器的根文件系统挂载为只读
将容器的根文件系统挂载为只读模式,这种模式可以避免对根文件系统带来任何的修改,从而保证了容器的安全性。当然,只读的模式也会带来不便 ,需要结合挂载存储来使用,将输出的内容写到持久化存储中。
配置只读的方式很简单,在启动容器时添加 --read only 选项,如下:
$ docker run -it --read-only nginx sh
# echo 'test' > /root/1.txt
sh: 2: cannot create /root/1.txt: Read-only file system
6、禁止共享主机的网络栈
在启动容器时,使用--network host 可以让容器与主机共享网络栈,此时,容器会使用主机的IP及其他的网络配置,并自动将容器的端口映射到主机。
这种方法虽然带来了一定的便利性,但也给容器带来了风险。在这种模式下,容器内可对主机的网络栈进行操作,所以并不建议使用。
$ docker run -d --network host nginx
二、镜像管理
1、禁止在镜像中存储机密信息
容器中程序在正常运行的过程中,通常需要使用到一些机密信息,如数据库账号密码、access token等。诸如此类的敏感信息,不应被保存到镜像中,不然会造成机密信息泄露风险。
可以使用配置中心等方案,将这些信息移到外部进行管理。
2、选用最小化的基础镜像
在使用Dockerfile构建应用镜像时,需要选择一个镜像来作为基础镜像。对于该镜像的选择,应避免使用功能大而全的镜像,而采用最小化满足的模式。
这样可以带来两个好处:
最大程度减少安全漏洞。
减少对于资源的占用。
3、扫描并验证镜像
在 2019 年时,作为安全公司的Snyk 发现,10大最流行的 Docker 镜像中,每个镜像至少有 30 个安全漏洞。这足以引起我们对于镜像安全的警觉。
通过对Docker镜像进行漏洞扫描,可以让开发和运维人员清楚镜像的安全状态,并采取措施修复发现的问题,从而实现更安全的部署。
目前支持镜像扫描的开源方案有Docker scan、Clair、Anchore等,其中Docker Scan已集成到最新的Docker版本中,可以开箱即用。
4、使用多阶段构建
在旧的版本中,构建镜像的操作通常在一个Dockerfile流程中完成,在这种模式下构建的镜像会包含很多冗余的文件,如源码文件、下载的依赖包、打包产生的临时文件等。
为了解决这个问题,Docker在17.05 版本开始支持使用多阶段构建(Multi-stage builds)。使用这种模式构建镜像时,我们可以第一阶段完成代码的打包等工作流程,然后在第二阶段选择合适的运行镜像,并将上个阶段生成的包拷贝到镜像中配置运行。
多阶段构建具有速度快、镜像体积更小、安全性更高等特点,建议采用此种方式来进行镜像的构建 。
示例:
#阶段一:编译打包
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"]
三、管理规范
1、限制用户对容器主机的访问
运行容器的主机应该存放在安全、可靠的环境中,如IDC机房,这可以在物理上保证机器的安全性。同时 ,做好系统登录权限的管控,只允许可信任的用户登录访问主机,这样能够减少由于人为影响而出现的故障。
2、定期更新Docker版本
过时的版本由于已发现的漏洞,容易受到安全攻击。新版本通常会修复旧版本出现的Bug和程序错误,有利于更好地保证容器安全。作为容器的管理员,需要定期进行Docker版本的更新,并维持着较新的版本。
3、完善容器监控
如何合理有效的利用好监控是容器管理员的重要工作,一套完善的监控系统有利于帮助我们及时发现容器的问题,例如资源负载高、容器退出等。
关于容器的监控,目前比较常用的方案有cAdvisor+Prometheus+Grafana+Alertmanager组合,该方案集成监控、展示和告警等系列功能,可以有效发现容器问题。