一.docker与虚拟机的差别
隔离与共享
- 每个虚拟机都有自己的系统内核
- docker容器则是通过隔离的方式让容器之间相互影响,但是容器无法影响宿主机
性能与损耗
- 与虚拟机相比,容器的资源损耗要小的多
- 同样在宿主机之下,能够建立的容器数量要比虚拟机多
- 但是虚拟机的安全性要好于容器
二.docker的安全问题以及架构缺陷
安全问题
- docker自身漏洞:CVE官方记录docker历史版本共有超过20项漏洞
- docker的源码问题:黑客上传恶意镜像、镜像使用有漏洞的软件、中间人攻击篡改镜像
架构缺陷
- 容器之间的局域网攻击
- DDos攻击耗尽资源
- 有漏洞的系统调用
- 共享root用户权限
三.docker的安全基线标准
- docker的安全基线标准包括:内核、主机、网络、镜像、容器、其他
内核级别
- 及时更新内核
- User Namespace(容器内的root权限在容器之外处于非高权限的状态)
- Cgroups(对资源的配额和度量)
- SElinux/AppArmor/GRSEC(控制文件访问权限)
- Capability(权限划分)
- Seccomp(限定系统调用)
- 禁止将容器的命名空间与宿主机进程命名空间共享
主机级别
- 为容器创建独立分区
- 仅运行必要的服务
- 禁止将宿主机上的敏感目录映射到容器
- 对docker守护进程、相关文件和目录进行审计
- 设置适当的默认文件描述符数。(问价描述符:内核(kernel)利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或者新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待镀锡的文件)
- 用户权限为root的docker相关文件的访问权限应该为644或者更低权限
- 周期性检查每个主机的容器清单,并且清理不必要的容器
网络级别
- 通过iptables设定规则实现禁止或者允许容器之间网络流量
- 允许docker修改iptables
- 禁止docker绑定到其他IP/port或者unix socket
- 禁止在容器上映射特权端口。
- 容器上只开放所需要的端口
- 禁止在容器上使用主机网络模式
- 若宿主机上有多个网卡,将容器进入流量绑定到特定的主机网卡上
镜像级别
- 创建本地镜像仓库服务器
- 镜像中软件都为最新版本
- 使用可信镜像文件,并且通过安全通道下载
- 重新构建镜像而非对容器和镜像打补丁
- 合理管理镜像标签,及时移除不再使用的镜像。
- 使用镜像扫描
- 使用镜像签名
容器级别
- 容器最小化,操作系统镜像最小集
- 容器以单一主进程的方式运行
- 禁止privileged标记使用特权容器
- 禁止在容器上运行ssh服务
- 以只读的方式挂载容器的根目录系统
- 明确定义属于容器的数据盘符
- 通过设置on-failure限制容器尝试重启的次数,容器反复重启容易丢失数据
- 限制在容器中可用的进程树,以防止fork bomb。(fork炸弹,迅速增长子进程,耗尽系统进程数量)
其他设置
- 定期对宿主机系统以及容器进行安全审计
- 使用最少的资源和最低权限运行容器
- 避免在同一宿主机上部署大量的容器,维持一个能够管理的数量
- 监控docker容器的使用,性能以及其他各项指标
- 增加实时威胁检测和事件响应功能
- 使用中心和远程日志收集服务
四.docker安全通信的措施
容器最小化
- 如果仅在容器与运行必要的服务,那么像ssh、telnet等服务就不能轻易开启连接容器,通常使用以下方式进入容器
docker exec -it 容器ID bash
docker remote api访问控制
- 对于docker的远程调用API接口存在未授权访问的漏洞,至少应该限制外网的访问,可以使用socket的方式访问,监听内网ip,docker daemon 启动方式如下:
1.使用命令配置socket的访问方式
//客户端连接docker服务时,通过对应IP地址和端口进行连接,这个端口可以选择
docker -d -H uninx:///var/run/docker.sock -H tcp://192.168.43.101:2375
2.修改docker的配置文件,实现socket访问
vi /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H 192.168.43.101:2375
#重启docker服务
systemctl deamon-reload
systemctl restart docker
[root@192 ~]# netstat -natp | grep dockerd
tcp 0 0 192.168.43.101:2375 0.0.0.0:* LISTEN 37179/dockerd
[root@192 ~]#
#在宿主机上配置firewalld的访问控制策略
[root@192 ~]# firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.43.101" port protocol="tcp" port="2379" accept"
success
[root@192 ~]# firewall-cmd --reload
success
[root@192 ~]#
限制流量流向(向外的数据)
- 使用防火墙限制docker容器的源IP地址范围与外界通讯
[root@192 ~]# firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.43.0/24" reject"
success
[root@192 ~]#
#permanent永久设置
#add-rich-rule添加规则
#reject拒绝
#source address源地址为容器地址,出去的数据
- 大量的问题是因为docker容器端口外放引起的漏洞,除了操作系统账户权限控制上的问题,更在于对docker daemon进程管理上存在隐患
- 目前常用的docker版本都支持docker daemon管理宿主机的iptables,而且一旦启动进程加上 -p host_port:guset_port的端口映射,Docker Daemon会直接增加对应的FORWARD chain并且-j ACCEPT,而默认的DROP规则是在INPUT链上做的,对docker没办法限制,这就留下了很严重的安全隐患
建议如下:
①不在有外网的机器上使用docker服务
②使用k8s等docker编排系统管理docker容器
③宿主机上的Docker Daemon启动命令上加一个 --iptables=false,然后把常用的iptables写进入文件里,再用iptables-restore
镜像安全
- docker镜像安全扫描,在镜像仓库客户端使用证书认证,对下载的镜像进行检查,通过与CVE数据库同步扫描镜像,一旦发生漏洞则通知用户处理,或者直接阻止继续构建
- 如果公司使用的是自己的镜像源,可以跳过此步骤;否则至少需要验证basetime的md5等特征值,确定一致后在基于basetime进一步构建,一般情况下,要确保只从受信任的库中获取镜像,并且不建议使用 --insecure-registry=[ ] 参数。