Docker安全

Docker容器安全机制

2018-04-26  本文已影响260人  peerless_1024

来源:Docker容器安全监控系统设计与实现_简智强

         Docker安全是Docker团队和广大使用者都极为关注的话题,Docker能否在生产环境和公有云环境中普及,在于Docker能否提供安全可靠的运行环境。目前,官方已经在安全方面做了一定工作,包括Docker Daemon以TCP为基础提供服务的同时使用传输层安全协议,在构建和使用镜像时验证镜像的签名证书,通过Namespaces和Cgroup隔离和限制容器资源,通过定义的Seccomp限制容器内进程使用的系统调用,提供自定义容器权能(Capability)的接口。根据容器服务的要求合理定制相关安全方案可极大提高安全性。

镜像安全

镜像校验

        镜像校验和用来保证镜像完整性,以防镜像被篡改破坏。Docker镜像仓库里的每个镜像都对应一个manifest文件,内容包括镜像标签、所属命名空间、校验方法、校验和、镜像运行信息及其文件签名信息。用户在pull镜像时自动进行多次哈希验证,如果通过镜像的digest来pull镜像,则验证manifest的digest与传入的digest是否一致。根据manifest中镜像ID获得镜像配置文件,然后根据配置文件内容生成digest,并验证是否与镜像ID一致。在下载manifest中引用的镜像层后,会根据镜像文件内容计算出校验和“diff ID”,并与镜像配置文件中的diff ID比较验证。每一步传输过后都会本地计算校验和与前一步保存的可靠结果验证,如果验证失败则输出相关警告信息,说明镜像下载的过程中出现了文件损坏,或者镜像被人为篡改,使用时需要特别注意。这些验证过程保证了镜像内容的完整性和可靠性。

Docker Registry(仓库)访问控制

        目前,Docker使用一个中心验证服务器来完成Docker镜像仓库的访问权限控制,每一个Docker客户端对Registry进行push/pull操作,获取一个官方提供的授权文件official.json,其包含针对特定registry目录的授权信息和次授权文件的签名信息,在Docker Daemon启动时加载到Memory Graph(用于存储公钥及命名空间之间的授权信息)。每次pull镜像时会去Memory Graph验证授权信息是否过期以及权限是否符合,默认的每个授权节点在各自的授权空间上都具有读写权限。

Docker Daemon安全

        Docker向外界提供服务主要通过四种形式,默认以Unix域套接字方式来与客户端通信,该方式相对于TCP形式比较安全,只有进入Docker Daemon所在宿主机并且有权访问Daemon的域套接字才能和其建立通信。如果以TCP形式向外界提供服务,可访问到Daemon宿主机的用户都可能成为潜在的攻击者。同时,由于数据需要通过网络传输,传输过程可能被截获或修改,为了提高通信的安全性,Docker提供了TLS(Transport Layer Security)传输层安全协议。启动容器时可通过增添--tlsverify选项进行安全传输校验,通过--tlscacert(信任的证书)、--tlscert(证书位置)和--tlskey(密钥)选项来配置。安全认证在服务器端实现,客户端可以对服务端进行验证。客户端访问Docker Daemon时只需提供签署的证书就可使用Docker Daemon服务,最终通过HTTPS安全传输数据。

内核安全

        Linux内核通过Namespace和Cgroup机制为容器提供支撑。分别实现对容器资源隔离和资源限制的功能,从而实现虚拟化,使容器犹如一台独立主机环境。

1. Namespace

        Namespace(名字空间)是Linux系统的底层机制,由一些类型不同的Namespace选项组成,如下表所示。

Namespace选项说明

        Linux内核引入Namespace机制的主要目的就是实现容器技术。只有处于同一个Namespace下的进程才能互相可见,相互联系。为了在分布式环境下进行定位和通信,容器必然需要独立的IP、端口、路由等网络资源来隔离网络,Network Namespace提供了包括网络设备、IPv4、IPv6协议栈、/proc/net目录等网络资源的隔离。容器中进程间通信的方式有信号量、消息队列、和共享内存,与虚拟机不同的是,容器之间的进程间通信相当于是宿主机的相同IPC Namespace中的进程间通信。Mount Namespace通过隔离文件系统的功能,通过挂载点对文件系统进行隔离,用户可以通过“/proc/$pid/mounts”文件查看所有挂载在当前Namespace中的文件系统,还可以通过“/proc/$pid/mountstats”文件看到相关文件设备的统计信息,包括挂载文件名、挂载位置、文件系统类型等。同时,通过UTS Namespace在容器内部实现主机名和系统版本号的独立标识,而权限隔离和进程号的隔离保证容器内的用户和进程的独立。Docker利用Linux Namespace机制来实现UTS,IPC,PID,Network,Mount,User的隔离,如上表所示为各个Namespace在内核源码中的标志和功能。并且每个进程的Namespace都对应有自己的ns编号,可以通过“ls -l /proc/$pid/ns”命令来查询进程所属Namespace的标识号。

2.Cgroup

        Cgroup(Control Group)作为一个强大的内核工具,可以限制被Namespace隔离起来的资源,通过对任务使用资源总额进行限制,如设定容器启动后运行时内存的上限,一旦超过这个上限就发出OOM(out of memory)警告。也可以通过分配CPU时间片数量和磁盘IO带宽大小来控制任务运行的优先级。还可以为CPU使用时长、内存使用状态信息、IO占用情况等计算物理资源,操控任务启停,对任务执行挂起、恢复等操作,为Linux环境下实现虚拟化和容器技术提供了基础支撑,是构建虚拟化管理工具的基石。Cgroup的实现本质上是给任务挂上钩子,当任务运行过程中涉及某种资源时就会触发钩子上所附带的子系统进行检测,根据不同的资源类别使用相应的技术进行资源限制和优先级分配。

附加安全机制

1.Capability(权能)

        Linux将用户权限划分为若干组,每一组代表用户所能执行的系统调用范围,以此分割超级用户权限。传统的UNIX将进程分为两类来执行权限检查:特权进程(有效用户UID为0,称为根用户),和非特权进程(eUID为零)。特权进程绕过所有的内核权限检查,而非特权进程受到进程凭证的权限检查。Linux支持将部分root的特权操作权限细分成Capability,如果将某个权限赋给某进程,即使不是root用户也可以执行该权限对应的特权操作。该机制可加强容器内部的权限管控,使容器内外的root权限隔离。启动容器时可通过增添--cap-add、--cap-drop选项选择容器拥有或禁止的权能,如下启动容器的操作可禁止容器内进程使用SETUID,SETGID的能力:docker run --cap-drop SETUID --cap-drop SETGID -it ubuntu /bin/sh

2.Seccomp(安全计算模式)

        Seccomp是一个Linux内核特性,可以用它来限制容器中的系统调用范围以限制进程的内核操作,从而减少内核攻击面,被广泛用于构建沙箱。从Docker1.10版本起,增加了对Seccomp的支持,通过Docker默认Seccomp策略限制内核系统调用,可降低容器内执行内核漏洞利用程序的风险,目前默认过滤的系统调用包括open_by_handle_at、bpf、mount、keyctl、ptrace等40多个,可有效防御针对CVE-2014-3519、CVE-2015-8660、CVE-2016-0728等漏洞利用的攻击。对于某些默认Secommp过滤范围之外的系统调用,存在被恶意利用的风险,在不影响容器应用功能的前提下可指定过滤这些系统调用。通过为每个容器编写json格式的Seccomp配置文件实现,以下为容器内过滤splice系统调用的json文件内容,通过在启动容器时增添“--security-opt seccomp:splice.json”选项来启用splice系统调用过滤功能。

splice.json

3.SeLinux

        SeLinux是由内核实现的强制访问控制的一种机制,为每一个进程设置一个标签,称为进程的域,也为文件设置标签称为类型,每一标签由User、Type、Role和Level四部分组成。SeLinux中用户是由权限集构成而非Linux用户。用户登录时会被分配一个SeLinux用户,并与对应的系统用户形成映射。Type是SeLinux访问控制的基础,描述进程所能访问的资源类型。Role是一些类型的组合,是用户和类型的过度,一个用户可拥有多个角色,一个角色可使用不同类型。Level定义具体的权限,分为MLS(多层级安全)和MCS(多级分类安全)。SeLinux提供了三种工作模式:Enforcing(强制执行SeLinux);Permissive(不执行SeLinux但记录相关操作);Disabled(关闭SeLinux),可通过setenforce命令进行设置。通过在Docker容器中引入SeLinux策略,控制容器如何访问资源。SeLinux策略全局性地强制整个系统遵循,使攻击者难以突破。如果一个进程被攻陷,攻击者只能访问该进程能访问到的权限,降低了威胁范围。宿主机安装SeLinux并设置为enforcing模式后,启动Docker容器时 通过增添--selinux-enabled=true来启用SeLinux,结合--security-opt选项设置容器的User、Type、Role和Level。

4.User Namespace

        User Namespace属于Docker1.10版本后引入的新特性,只要用户在启动Docker Daemon时指定了--userna-remap选项,则容器运行时其内部的root用户并不等于宿主机内的root用户,而是映射到宿主机的普通用户。这样进程在容器里执行特权操作局限于该容器内所具有的特权。User Namespace的引入显著增强了容器安全性,恶意程序通过容器入侵主机或其他容器的风险也随之降低,但这并不意味着容器就绝对安全了。另外,User Namespace弥补了内核层在容器隔离性方面的不足,限制了容器内的特权操作对外部的影响。

上一篇下一篇

猜你喜欢

热点阅读