1 宿主机安全

1.1 避免生产环境使用实验功能

docker自1.13.0版本引入--experimental参数用以启用实验功能。使用实验性功能应该非常谨慎,因为相关功能是未被充分测试,可能存在bug甚至安全问题

测试步骤:查看配置文件是否开启实验性功能

1
$ vi /etc/default/docker
2
DOCKER_OPTS="--experimental=true" # 追加此行代码
3
$ sudo service docker restart # 重启 docker daemon
1
$ vi /etc/docker/daemon.json
2
{
3
        "experimental": true
4
}

1.2 确认Docker软件关键文件安全性

  • 1.2.1 确认docker.service文件所有权为root:root
  • 1.2.2 确认docker.service文件权限为644或更严格
  • 1.2.3 确认docker.socket文件所有权为root:root
  • 1.2.4 确认docker.socket文件权限为644或更严格
  • 1.2.5 确认/etc/docker目录所有权为root:root
  • 1.2.6 确认/etc/docker目录权限为755或更严格
  • 1.2.7 确认镜像仓库证书文件所有权为root:root
  • 1.2.8 确认镜像仓库证书文件权限为444或更严格
  • 1.2.9 确认TLS CA证书文件所有权为root:root
  • 1.2.10 确认TLS CA证书文件权限为444或更严格
  • 1.2.11 确认docker服务端证书文件所有权为root:root
  • 1.2.12 确认docker服务端证书文件权限为444或更严格
  • 1.2.13 确认docker服务端证书密钥文件所有权为root:root
  • 1.2.14 确认docker服务端证书密钥文件权限为400或更严格
  • 1.2.15 确认docker.sock文件所有权为root:docker
  • 1.2.16 确认docker.sock文件权限为660或更严格
  • 1.2.17 确认daemon.json文件所有权为root:root
  • 1.2.18 确认daemon.json文件权限为644或更严格
  • 1.2.19 确认/etc/default/docker文件所有权为root:root
  • 1.2.20 确认/etc/default/docker文件权限为644或更严格
  • 1.2.21 确认/etc/sysconfig/docker文件所有权为root:root

测试步骤:使用linux命令查看这些文件对应的权限是否满足安全规范要求

2 容器安全

2.1 容器生命周期

  • 2.1.1 确保Docker软件更新到最新版本

  • 2.1.2 检查容器内软件生命周期

  • 2.1.3 避免镜像闲置冗余

  • 2.1.4 避免容器闲置冗余

  • 2.1.5 确保镜像仓库是最新版本

  • 2.1.6 确保镜像仓库是最新版本

测试步骤:这几项基本就是判断软件是否是最新版的检测删除未使用或旧的镜像。

1
# 查看所有实例化image
2
sudo docker images --quiet | xargs docker inspect --format '{{ .Id }}: Image={{ .Config.Image }}'
3
# 查看系统中存在的所有image
4
docker images
5
# 删除none镜像
6
sudo docker rmi $(docker images -f dangling=true -q)

2.2 容器启动安全

  • 2.2.1 不要以读写形式挂载相同目录到多个容器

    1
    docker ps -a --quiet | xargs docker inspect -f "{{ .Name }} {{ .Mounts }}"
  • 2.2.2 不要使用特权/用户选项的docker exec命令

    1
    # 查看是否使用特权 docker exec
    2
    ausearch -k docker | grep exec | grep privileged
    3
    4
    # 查看是否使用用户选项 docker exec
    5
    ausearch -k docker | grep exec | grep user
  • 2.2.3 使用PIDS cgroup限制

    1
    docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: PidsLimit={{ .HostConfig.PidsLimit }}'

    确保PidLimit不为0或-1

  • 2.2.4 不要在容器上挂载敏感的主机系统目录

    1
    docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: Volumes={{ .Mounts }}'
  • 2.2.5 限定容器重启次数上限(推荐5次)

    1
    docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: RestartPolicyName={{ .HostConfig.RestartPolicy.Name }} MaximumRetryCount={{ .HostConfig.RestartPolicy.MaximumRetryCount }}'
  • 2.2.6 不要直接将主机设备暴露给容器

    1
    docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: Devices={{ .HostConfig.Devices }}'
  • 2.2.7 禁止以共享模式挂载卷

    1
    docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: Propagation={{range $mnt := .Mounts}} {{json $mnt.Propagation}} {{end}}'
  • 2.2.8 不要将Docker socket挂载到任何容器内

    1
    docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: Volumes={{ .Mounts }}' | grep docker.sock
  • 2.2.9 不要使用特权容器

    1
    docker ps --quiet -a | xargs docker inspect --format='{{.Id}} {{.Name}} {{.HostConfig.Privileged}}'
  • 2.2.10 创建容器的用户

    1
    # 为空则使用root
    2
    docker ps --quiet | xargs docker inspect --format '{{ .Id }}: User={{.Config.User}}
  • 2.2.11 容器使用可信的基础镜像

    1
    docker history <imageName>
  • 2.2.12 容器内不安装非必要软件包

    1
    docker exec $INSTANCE_ID rpm –qa
    2
    # 或者 
    3
    docker exec $ INSTANCE_ID dpkg –l
  • 2.2.13 启用docker内容信任

    1
    echo $DOCKER_CONTENT_TRUST
  • 2.2.14 不在dockerfile中单独使用更新命令

  • 2.2.15 镜像中删除setuid和setgid权限

    1
    docker run <Image_ID> find / -perm +6000-type f -exec ls -ld {} \; 2> /dev/null
  • 2.2.16 在dockerfile中使用copy而不是add

    1
    # add指令可能从远程URL下载文件并执行解包等操作
    2
    3
    docker history <Image_ID> 
    4
    # 或者访问dockerfile
  • 2.2.17 涉密信息不存储在dockerfile上

    1
    docker history <Image_ID> 
    2
    # 或者访问dockerfile
  • 2.2.18 仅安装已经验证的软件包

    1
    docker history <Image_ID> 
    2
    # 或者访问dockerfile

2.3 容器编排安全

2.3.1 docker swarm安全

  • 2.3.1.1 确认swarm模式下overlay驱动开启加密功能

    1
    # 确认是否有使用overlay类型的网络驱动。如果没有返回结果,说明没有使用overlay驱动,无问题。
    2
    docker network ls|grep overlay
    3
    4
    # 确认返回结果中是否每一个overlay驱动都使用了encrypted选项
    5
    docker network ls --quiet |xargs docker network inspect --format '{{.Name}} {{.Driver}} {{.Options}}' |grep overlay
  • 2.3.1.2 非必要不要启用Swarm集群模式

    1
    # 如果输出包括Swarm:active,则表明集群模式在Docker引擎上激活
    2
    docker info | grep Swarm
  • 2.3.1.3 控制群中的管理器节点数

    1
    docker node ls | grep 'Leader'
    2
    # 或者
    3
    docker info --format'{{.Swarm.Manager}}'
  • 2.3.1.4 将集群服务绑定到特定网卡

    1
    netstat -lt | grep -i 2377
  • 2.3.1.5 使用Docker的secret管理命令来管理集群中的secret

    1
    docker secret ls
  • 2.3.1.6 在自动锁定模式下运行集群管理器

    1
    # 若返回 no unlock key is set,说明没有开启 autolock
    2
    docker swarm unlock-key
  • 2.3.1.7 定期修改集群管理器自动锁定密钥

    1
    # 可运行以下命令更换
    2
    Docker swarm unlock-key --rotate

2.3.2 docker compose安全

2.3.3 kubernetes安全

2.4 容器存储安全

  • 2.4.1 为容器创建一个独立分区

    docker根目是/var/lib/docker的情况:

    1
    # 存储驱动非devicemapper
    2
    docker info |grep "Storage Driver"
    3
    4
    # 查看docker根目录是否挂载在独立分区
    5
    mountpoint -- $(docker info | grep "Docker Root Dir" | awk '{print $4}')

    devicemapper的情况: devicemapper不需要单独配置挂载

    1
    # 查看是否是否devicemapper
    2
    docker info |grep "Storage Driver"
  • 2.4.2 禁止使用aufs存储驱动

    1
    # 查看是否使用aufs驱动
    2
    docker info | grep -e "^Storage Driver:\s*aufs\s*$"
  • 2.4.3 备份容器数据

  • 2.4.4 避免容器闲置冗余

    1
    # 步骤 1 通过执行以下命令列出当前实例化的所有镜像 ID:
    2
    docker images --quiet | xargs docker inspect --format '{{.Id}}: Image = {{.Config.Image}}'
    3
    4
    # 步骤 2:通过执行以下命令列出系统中存在的所有镜像: 
    5
    docker images
    6
    7
    # 步骤 3:比较步骤 1 和步骤 2 中的镜像 ID 列表, 找出当前未实例化的镜像。 如果发现未使用或旧镜像,请与系统管理员讨论是否需要在系统上保留这些镜像。

2.5 容器网络安全

  • 2.5.1 限制容器间的网络通信

    1
    # 确认返回结果com.docker.network.bridge.enable_icc对应值是否为false
    2
    docker network ls --quiet | xargs docker network inspect --format '{{ .Name }}: {{ .Options }}' | grep "default_bridge"
  • 2.5.2 避免docker daemon暴露于外网网络

    1
    # 确认是否以端口形式对外开放docker api
    2
    ps -o user,args -e | grep docker | grep "tcp:" 2>/dev/null | sort
  • 2.5.3 禁止userland端口转发

    1
    # 启动参数中是否配置
    2
    ps -o user,args -e | grep dockerd | grep '\-\-userland-proxy'
    3
    # 配置文件中是否配置
    4
    ps -ef | grep docker |grep "\-\-config-file"
    5
    "userland-proxy":false
  • 2.5.4 开启iptables选项

    1
    # 启动参数中是否配置
    2
    ps -ef |grep docker |grep iptables
    3
    # 配置文件中是否配置
    4
    ps -ef | grep docker |grep "\-\-config-file"
    5
    "iptables": true
  • 2.5.5 不要使用Docker的默认网桥docker0

    1
    # 易受到 ARP 欺骗以及 MAC 洪泛攻击
    2
    # 运行以下命令,确保没有使用 docker0 bridge
    3
    docker network ls --quiet | xargs docker network inspect --format '{{ .Name }}: {{ .Options }}'
  • 2.5.6 不要在容器中映射特权端口

    1
    docker ps --quiet | xargs docker inspect --format '{{ .Id }}: Ports={{ .NetworkSettings.Ports }}'
  • 2.5.7 不用共享host’s network命令空间

    1
    # 若返回 'NetworkMode=host',就说明启动时加入了 '--net=host' 参数,命名空间被共享
    2
    # 应放返回 bridge 或 none 或 container:$Container_Instance
    3
    docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: NetworkMode={{ .HostConfig.NetworkMode }}'
  • 2.5.8 在容器中开放需要的端口

    1
    docker ps --quiet | xargs docker inspect --format '{{ .Id }}: Ports={{ .NetworkSettings.Ports }}'
  • 2.5.9 禁止将容器端口绑定到宿主机所有网卡

    1
    docker ps --quiet | xargs docker inspect --format '{{ .Id }}: Ports={{ .NetworkSettings.Ports }}'

3 运行安全

3.1 安全机制配置

  • 3.1.1 启用live restore

    1
    默认情况下,当daemon进程结束时,所有容器会被停止。自docker engine 1.12起,可以配置live-restore, 以支持当daemon不可用时,容器仍然正常运行。该功能在daemon崩溃、断电、升级时,能有效保证容器正常运行。该功能默认不会开启,需要手动配置。
  • 3.1.2 确保cgroup参数正确配置

    1
    # 如果为空,则表示容器在默认的docker cgroup 下运行,可以认为是安全的
    2
    docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}:CgroupParent={{ .HostConfig.CgroupParent }}'
  • 3.1.3 确认默认seccomp规则正确配置

    1
    # 返回default使用默认配置,无问题
    2
    docker info --format='{{.SecurityOptions}}'
  • 3.1.4 不要禁用AppArmor文件

    1
    docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: AppArmorProfile={{ .AppArmorProfile }}'
  • 3.1.5 限制容器内的Linux Capabilities

    1
    docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: CapAdd={{ .HostConfig.CapAdd }} CapDrop={{ .HostConfig.CapDrop }}'
  • 3.1.6 设置SELinux选项(可选)

    1
    docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: SecurityOpt={{ .HostConfig.SecurityOpt }}'
  • 3.1.7不要共享宿主机process namespace

    1
    #PID
    2
    docker ps --quiet | xargs docker inspect --format '{{ .Id }}: PidMode={{ .HostConfig.PidMode }}'
  • 3.1.8 不要共享宿主机 IPC namespace

    1
    #IPC
    2
    docker ps --quiet | xargs docker inspect --format '{{ .Id }}: IpcMode={{ .HostConfig.IpcMode }}'
  • 3.1.9 不要共享宿主机 UTS namespace

    1
    #UTS
    2
    docker ps --quiet | xargs docker inspect --format '{{ .Id }}: UTSMode={{ .HostConfig.UTSMode }}'

3.2 资源消耗

  • 3.2.1 设置默认的ulimit配置(可选)

    1
    # 返回 <no value> 表示使用默认配置,没问题
    2
    docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: Ulimits={{ .HostConfig.Ulimits }}'
  • 3.2.2 检测是否限制容器CPU使用

    1
    # 如果命令返回0或1024,说明未限制CPU共享;如果返回一个非零值(非1024)表示已限制CPU共享。
    2
    docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: CpuShares={{ .HostConfig.CpuShares }}'
  • 3.2.3 检测是否限制容器内存使用

    1
    # 如果命令返回0,说明未限制容器内存使用;如果返回一个非零值,表示已限制容内存使用
    2
    docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: Memory={{ .HostConfig.Memory }}'
  • 3.2.4 检测是否已限制容器存储使用

  • 3.2.5 使用PIDs_cgroup_limit防止fork炸弹

    1
    # 执行如下命令,确保PidsLimit的值不为0或-1。PidsLimit为0或-1意味着可以在容器内并发地创建任意数量的进程。
    2
    docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}: PidsLimit={{ .HostConfig.PidsLimit }}'