好的安全性是基于分层隔离的,Docker 有很多分层。Docker 支持所有主流 Linux 安全机制,同时 Docker 自身还提供了很多简单的并且易于配置的安全技术。

Docker安全 - 图1

  • Linux Docker 利用了大部分 Linux 通用的安全技术,Docker都设置了适度安全性的默认值,可以通过修改值来自定义安全性。包括:
    • 命名空间(Namespace)
    • 控制组(CGroup)
    • 系统权限(Capability)
    • 强制访问控制(MAC)系统
    • 安全计算(Seccomp)
  • Docker 平台本身也提供了一些原生安全技术。包括:
    • Docker Swarm 模式

默认是开启安全功能的。无须任何配置,就可以获得加密节点 ID、双向认证、自动化 CA 配置、自动证书更新、加密集群存储、加密网络等安全功能。

  • Docker 内容信任(Docker Content Trust, DCT)

允许用户对镜像签名,并且对拉取的镜像的完整度和发布者进行验证。

  • Docker 安全扫描(Docker Security Scanning)

分析 Docker 镜像,检查已知缺陷,并提供对应的详细报告。

  • Docker 密钥

使安全成为 Docker 生态系统中重要的一环。Docker 密钥存储在加密集群存储中,在容器传输过程中实时解密,使用时保存在内存文件系统,并运行了一个最小权限模型。

1. Linux安全技术

Docker集成了Linux部分安全技术。

Docker安全 - 图2

1.1 Namespace

  • Docker 的虚拟化是基于OS层虚拟出来一个看起来是操作系统的容器,能做许多操作系统的事情,又能共享OS资源,用到的就是Linux命名空间的功能。Docker 容器本质是由各种命名空间有机组合而成的

1.1.1 Linux Docker利用的内核命名空间

  • 进程ID(PID)
  • 网络(NET)
  • 文件系统/挂载(MNT)
  • 进程内通信(IPC)
  • 用户(USER)
  • UTS

Docker安全 - 图3

  1. 进程 ID 命名空间

Docker 使用 PID 命名空间为每个容器提供互相独立的容器树。每个容器都拥有自己的进程树,故每个容器都有自己的 PID 为 1 的进程。PID 命名空间也意味着容器不能看到其他容器的进程树,或者其所在主机的进程树。

  1. 网络命名空间

Docker 使用 NET 命名空间为每个容器提供互相隔离的网络栈。网络栈中包括接口、ID 地址、端口地址以及路由表。(例如,每个容器都有自己的 eth0 网络接口,并且有自己独立的 IP 和端口地址)

  1. 挂载点命名空间

每个容器都有互相隔离的根目录 /。这意味着每个容器都有自己的 /etc、/var、/dev 等目录。容器内的进程不能访问 Linux 主机上的目录,或者其他容器的目录,只能访问自己容器的独立挂载命名空间。

  1. 进程内通信命名空间

Docker 使用 IPC 命名空间在容器内提供共享内存。IPC 提供的共享内存在不同容器间也是互相独立的。

  1. 用户命名空间

Docker 允许用户使用 USER 命名空间将容器内用户映射到 Linux 主机不同的用户上。常见的例子就是将容器内的 root 用户映射到 Linux 主机的非 root 用户上。(用户命名空间对于 Docker 来说还属于新生事物且非必选项。该部分内容在未来可能出现改变)

  1. UTS 命名空间

Docker 使用 UTS 命名空间为每个容器提供自己的主机名称。

1.2 Control Group

  • CGroup 允许用户设置一些限制来保证不会存在单一容器占用全部的公共资源。在 Docker 的世界中,容器之间是互相隔离的,但却共享 OS 资源,比如 CPU、RAM 以及硬盘 I/O。CGroup 允许用户设置限制,这样单个容器就不能占用主机全部的 CPU、RAM 或者存储 I/O 资源了。

    1.3 Capability

    以 root 身份运行容器很危险(有所有权限),但如果以非 root 身份在后台运行容器的话,非 root 用户缺少权限,处处受限。所以需要能选择容器运行所需的 root 用户权限的功能。Capability!

  • 在底层,Linux root 用户是由许多能力组成的,其中包括但不限于以下几点:

    • CAP_CHOWN:允许用户修改文件所有权。
    • CAP_NET_BIND_SERVICE:允许用户将socket绑定到系统端口号。
    • CAP_SETUID:允许用户提升进程优先级。
    • CAP_SYS_BOOT:允许用户重启系统。
  • Docker 采用 Capability 机制来实现用户在以 root 身份运行容器的同时,还能移除非必须的 root 能力(若容器运行只需要 root 的绑定系统网络端口号的能力,则用户可以在启动容器的同时移除全部 root 能力,然后再将 CAP_NET_BIND_SERVICE 能力添加回来)。

    1.4 MAC

  • Docker 采用主流 Linux MAC(强制访问控制) 技术(例如 AppArmor 以及 SELinux),对应用进行权限配置。

    1.5 Seccomp

  • Docker 使用过滤模式下的 Seccomp 来限制容器对宿主机内核发起的系统调用。

    2. Docker平台安全技术

    2.1 Swarm 模式

  • Swarm 模式包括很多开箱即用的安全特性,同时还设置了合理的默认值。这些安全特性包括以下:

    • 加密节点 ID。
    • 基于 TLS 的认证机制。
    • 安全准入令牌。
    • 支持周期性证书自动更新的 CA 配置。
    • 加密集群存储(配置 DB)。
    • 加密网络。

      2.1.1 构建安全的 Swarm示例

      3 个 Docker 主机,每个都运行 1.13 或者更高版本的 Docker。示例中 3 个 Docker 主机分别叫作“mgr1”“mgr2”“wrk1”。每台主机上都安装 Ubuntu 16.04,其上运行了 Docker 18.01.0-ce。同时还有一个网络负责联通 3 台主机,并且主机之间可以通过名称互相 ping 通。

Docker安全 - 图4

  1. 初始化swarm
    1. mgr1$ docker swarm init
  • “mgr1”被配置为 Swarm 集群中的第一个管理节点,也是根 CA 节点。Swarm 集群已经被赋予了加密 Swarm ID。
  • 证书的更新周期默认设置为 90 天,集群配置数据库也已经配置完成并且处于加密状态。安全令牌也已经成功创建,允许新的管理者和工作者节点加入到 Swarm 集群中。
  1. 将“mgr2”节点加入到集群 ```bash

    1. 提取加入管理者到集群中所需的令牌

    mgr1$ docker swarm join-token manager To add a manager to this swarm, run the following command:

docker swarm join —token \ SWMTKN-1-1dmtwu…r17stb-2axi5…8p7glz \ 172.31.5.251:2377

2. 在“mgr2”节点上执行 docker swarm join 命令

mgr2$ docker swarm join —token SWMTKN-1-1dmtwu…r17stb-2axi5…8p7glz 172.31.5.251:2377 This node joined a swarm as a manager.

  1. ![](https://cdn.nlark.com/yuque/0/2020/gif/1204927/1590110427243-d5db9e87-54f3-47bc-975b-0a688d258bec.gif#align=left&display=inline&height=211&margin=%5Bobject%20Object%5D&originHeight=281&originWidth=500&size=0&status=done&style=shadow&width=375)
  2. 3. 将“wrk1”节点加入到集群
  3. ```bash
  4. # 1. 在任意管理者节点上运行下面的命令,获取工作者准入令牌
  5. $ docker swarm join-token worker
  6. To add a worker to this swarm, run the following command:
  7. docker swarm join --token \
  8. SWMTKN-1-1dmtw...17stb-ehp8g...w738q \
  9. 172.31.5.251:2377
  10. # 2. 在“wrk1”节点上执行 docker swarm join 命令
  11. $ docker swarm join --token SWMTKN-1-1dmtw...17stb-ehp8g...w738q 172.31.5.251:2377
  12. This node joined a swarm as a worker.
  • 目前已经拥有包含两个管理者和一个工作者的 Swarm 集群。管理者配置为高可用(HA),并且复用集群存储。

Docker安全 - 图5

2.1.2 Swarm 安全背后的原理

  1. Swarm 准入令牌

向某个现存的 Swarm 中加入管理者和工作者所需的唯一凭证就是准入令牌。每个 Swarm 都包含两种不同准入令牌。管理者所需准入令牌和工作者所需准入令牌。准入令牌都由 4 个不同的字段构成,中间采用虚线(-)连接。

  1. PREFIX - VERSION - SWARM ID - TOKEN

PREFIX 永远是“SWMTKN”,这样允许工作者通过表达式匹配到该令牌,以避免意外将其发布到公共环境当中;VERSION 这一列则展示了 Swarm 的版本信息;SWARM ID 列是 Swarm 认证信息的一个哈希值;TOKEN 这一列的内容决定了该令牌是管理者还是工作者的准入令牌。对于指定 Swarm 的管理者和工作者准入令牌,除了最后 TOKEN 字段的内容之外没有任何区别。
如果当前准入令牌存在风险,可以取消该准入令牌授权,同时发布新的准入令牌。

  1. $ docker swarm join-token --rotate manager
  2. Successfully rotated manager join token.
  3. To add a manager to this swarm, run the following command:
  4. docker swarm join --token \
  5. SWMTKN-1-1dmtwu...r17stb-1i7txlh6k3hb921z3yjtcjrc7 \
  6. 172.31.5.251:2377

准入令牌保存在集群配置的数据库中,默认是加密的。

  1. TLS 和双向认证

每个加入 Swarm 的管理者和工作者节点,都需要发布自己的客户端证书。这个证书用于双向认证。证书中定义了节点相关信息,包括从属的 Swarm 集群以及该节点在集群中的身份(管理者还是工作者)。使用下面的命令查看指定节点的客户端证书。

  1. $ sudo openssl x509 \
  2. -in /var/lib/docker/swarm/certificates/swarm-node.crt \
  3. -text
  4. Certificate:
  5. Data:
  6. Version: 3 (0x2)
  7. Serial Number:
  8. 80:2c:a7:b1:28...a8:af:89:a1:2a:51:89
  9. Signature Algorithm: ecdsa-with-SHA256
  10. Issuer: CN=swarm-ca
  11. Validity
  12. Not Before: Jul 19 07:56:00 2017 GMT
  13. Not After : Oct 17 08:56:00 2017 GMT
  14. Subject: O=mfbkgjm2tlametbnfqt2zid8x, OU=swarm-manager,
  15. CN=7xamk8w3hz9q5kgr7xyge662z
  16. Subject Public Key Info:
  17. <SNIP>
  • Subject 中的字段:
    • 组织字段O:Swarm ID
    • 组织单元字段OU:节点角色
    • 规范名称字段CN:节点 ID 信息。
  • Validity 可以看到证书的更新周期。

可以在 docker system info 的输出内容中得到验证。

  1. 配置一些 CA 信息

通过 docker swarm update 命令可以配置 Swarm 证书的更新周期。Swarm 允许节点在证书过期前重新创建证书,这样可以保证 Swarm 中全部节点不会在同一时间尝试更新自己的证书信息。可以在创建 Swarm 的时候,通过在 docker swarm init 命令中增加 --external-ca 参数来指定外部的 CA。 docker swarm ca 命令可以用于管理 CA 相关配置。

  1. $ docker swarm update --cert-expiry 720h
  1. 集群存储

集群存储是 Swarm 的大脑,保存了集群配置和状态数据。存储目前是基于 etcd 的某种实现,并且会在 Swarm 内所有管理者之间自动复制。存储默认也是加密的。Docker 平台的很多部分都已经用到了集群存储(如:Docker 网络和 Docker 密钥都用到了集群存储)。未来对集群存储的利用会更多。
集群存储的日常维护由 Docker 自动完成。但是,在生产环境中,需要为集群存储提供完整的备份和恢复方案。

2.2 Docker 安全扫描

Docker 安全扫描功能可以对检测 Docker 镜像的已知缺陷。

Docker 安全扫描已经用于 Docker Hub 上私有仓库的镜像,扫描报告在其仓库中可以查阅。也可以作为 Docker 可信服务本地化部署解决方案的一部分。
Docker 可信镜像仓库服务(Docker Trusted Registry, DTR),属于 Docker 企业版中本地化镜像仓库服务的一部分内容,提供了相同的 Capability,同时还允许用户自行控制其镜像扫描时机以及扫描方式。

2.3 Docker 内容信任

Dockr 内容信任(Docker Content Trust,DCT)使得用户很容易就能确认所下载镜像的完整性以及其发布者。在不可信任的网络环境中下载镜像时,这一点很重要。
DCT 允许开发者对发布到 Docker Hub 或者 Docker 可信服务的镜像进行签名。当这些镜像被拉取的时候,会自动确认签名状态。在 Docker 主机上启用 DCT 功能,所要做的只是在环境中将 DOCKER_CONTENT_TRUST 变量设置为 1。(DCT 开启会阻止 Docker 客户端拉取一个被篡改的镜像的,阻止客户端拉取旧镜像)

  1. $ export DOCKER_CONTENT_TRUST=1

DCT 还可以提供关键上下文,如镜像是否已被签名从而可用于生产环境,镜像是否被新版本取代而过时等。DCT 提供的上下文还在初期,配置起来相当复杂。

2.4 Docker 密钥

在后台,密钥在创建后以及传输中都是加密的,使用时被挂载到内存文件系统,并且只对那些已经被授权了的服务开放访问。
Docker安全 - 图6
上图所示工作流的过程:
1) 密钥被创建,并且发送到 Swarm。
2) 密钥存放在集群存储当中,并且是加密的(每个管理者节点都能访问集群存储)。
3) B 服务被创建,并且使用了该密钥。
4) 密钥传输到 B 服务的任务节点(容器)的过程是加密的。
5) B 服务的容器将密钥解密并挂载到路径 /run/secrets 下。这是一个临时的内存文件系统。
6) 一旦容器(服务任务)完成,内存文件系统关闭,密钥也随之删除。
7) A 服务中的容器不能访问该密钥。