前言
企业中使用容器承载业务,除了考虑到容器的优势之外,容器的安全更是很多客户关心的话题。本篇文章就此进行讨论。本文在书写过程中,参考了一些文档,文后给出了链接。
一、企业级容器安全的九个方面
要全面保证生产上容器云的安全,就应该考虑到和容器云相关的各个层面。
企业级容器云安全,需要考虑的九个方面有:
容器云宿主机与多租户、容器内容、容器仓库、容器构建、部署容器、容器平台、容器网络隔离、容器持久存储、API管理。
接下来,我们针对这九个方面展开讨论。
二、宿主机与多租户
红帽的企业级容器云解决方案Openshift,可以运行在物理机、虚拟化、私有云、公有云上。但无论运行在哪,其宿主机的操作系统都是RHEL。
所以,我们先看一下RHEL是如何针对容器实现安全的。
RHEL针对容器有四个安全的技术:内核命名空间、SELinux、Cgroups、Seccomp(安全计算模式)。
1. 内核命名空间
Linux命名空间提供了容器隔离的基础。Linux命名空间是资源隔离的,让命名空间内的进程看起来具有自己的全局资源实例。
从容器的角度来看,最重要的命名空间是PID命名空间和Network命名空间。
PID命名空间仅允许容器查看容器内的进程,而不能查看宿主机上其他容器上的进程。
网络命名空间是保护容器不与同一主机上的其他容器通信的重要部分。
所以说,OpenShift利用PID和网络两个命名空间,为容器从进程和网络级别提供一个本地安全层,是同一个宿主机上可以有多个容器共存。
Mount命名空间的作用是提供文件系统挂载的隔离。使用Mount命名空间,mount()和umount()系统调用将停止对全局挂载点集(对所有进程可见)进行操作,而是执行仅影响与容器进程关联的挂载名称空间的操作。例如,每个容器可以有自己的/ tmp或/ var目录,甚至可以有完全不同的用户空间。
UTS命名空间隔离由uname()系统调用返回的两个系统标识符 - nodename和domainname实现。UTS命名空间允许每个容器都有自己的主机名和NIS域名。
IPC命名空间隔离了某些进程间通信(IPC)资源,例如System V IPC对象和POSIX消息队列。这意味着两个容器可以创建具有相同名称的共享内存段和信号量,但不能与其他容器内存段或共享内存进行交互。
2. SELinux
SELinux最初是由NSA构建的,以在传统的Linux安全模型之上增加额外的安全性。 Selinux是一个标签系统。 运行在启用了selinux的红帽企业Linux系统上的每个进程都有一个标签。 每个由安装创建的文件,目录或系统对象,或者如果您添加新文件/包都会得到一个标签。
SELinux 是透过 MAC(Mandatory Access Control) 的方式来控管程序,他控制的主体是程序, 而目标则是该程序能否读取的文件
资源主体 (Subject):
SELinux 主要想要管理的就是程序,因此你可以将『主体』跟本章谈到的 process 划上等号;
目标 (Object):
主体程序能否存取的『目标资源』一般就是文件系统。因此这个目标项目可以等文件系统划上等号;
政策 (Policy):
由于程序与文件数量庞大,因此 SELinux 会依据某些服务来制订基本的存取安全性政策。这些政策内还会有详细的守则 (rule) 来指定不同的服务开放某些资源的存取与否。分别是:
建议使用默认的 targeted 政策即可。
targeted:针对网络服务限制较多,针对本机限制较少,是默认的政策;
strict:完整的 SELinux 限制,限制方面较为严格。
我们来看看我们如何标注容器。
对于容器进程,selinux定义允许容器执行哪些系统调用。 例如,它允许容器:
chown kill fowner fsetid mknod net_admin net_bind_service net_raw setfcap sys_resource for its own process。
如果进程想要做超出权限范围之内的事,selinux会对此进行阻止。
从Docker 1.11开始,Docker容器运行已经不是简单的通过Docker daemon来启动,而是集成了containerd、runC等多个组件。
containerd向上为Docker Daemon提供了gRPC接口,使得Docker Daemon屏蔽下面的结构变化,确保原有接口向下兼容。向下通过containerd-shim结合runC,使得引擎可以独立升级,避免之前Docker Daemon升级会导致所有容器不可用的问题。
接下来,我回通过实验进行展现。
Openshift要求宿主机的RHEL启动SELinux:
接下来,我们看看在我的实验环境中,SELinux如何对容器相关进行进行安全管控:
docker engine:
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 root 20125 12896 0 19:12 pts/0 00:00:00 grep --color=auto -i docker-engine
查看containerd-shim进程:
system_u:system_r:container_runtime_t:s0 root 1902 1784 0 18:57 ? 00:00:01 /usr/bin/docker-containerd-current -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --shim docker-containerd-shim --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --runtime docker-runc --runtime-args --systemd-cgroup=true
在上面的进程中,system_u:system_r:container_runtime_t:s0就是SElnux的安全策略,它管理的是该进程对/var/run/docker/libcontainerd/containerd文件的访问权限,级别是s0。
让我们来看看SElinux如何管理容器访问目录/var/lib/docker下的文件
system_u:object_r:container_var_lib_t:s0就是SELinux设置的权限,这四个字段的含义:
身份:角色:类型:级别
-
身份:
主要的有三种类型:root:表示 root 的帐号身份,
system_u:指程序本身
-
user_u:代表的是一般使用者帐号相关的身份。
-
角色 (Role):
角色有两种:object_r:代表的是文件或目录等文件资源
-
system_r:代表程序
-
类型 (Type) :
有两种:type:在文件资源 (Object) 上面称为类型 (Type);
-
domain:在主体程序 (Subject) 则称为领域 (domain)
对于容器,如果文件或目录上的标签不是container_var_lib_t或svirt_sandbox_file_t,则内核将拒绝进程访问这些文件。
级别level:
MLS(多级安全 )和MCS(多类安全)级别的属性。
关于MCS:
我们可以在配置文件:/etc/selinux/targeted/setrans.conf中查看级别的描述和设置:
3. Cgroups
使用cgroups来确保容器不会被同一主机上的另一个容器越权访问。
4.Seccomp
从docker 1.10版本,安全计算模式配置文件从Docker容器中删除了上图列出的权限。
也就是说在Openshift里,即使容器里的root用户,也没有以上的权限。
5. Read Only Mounts
容器在挂载宿主机文件系统的时候,对以上关键目录是只读权限,以避免容器可以写入sysfs虚拟文件系统并更改影响整个系统的内核参数。
sysfs文件系统是一个基于RAM的文件系统。 它提供了一种手段来导出内核数据结构及其属性以及它们与用户空间之间的关联。
三、容器内容
在关注容器内容安全的时候,我们首先需要明确容器里有什么内容。
目前我们使用的很多容器基础镜像,在社区和红帽官网都有,不必再自行构建。
但我们知道,既然操作系统可能会有漏洞,容器镜像就有可能存在着漏洞。
因此,我们需要使用容器镜像扫描工具,利用不断更新的漏洞数据库,以确保始终具有有关容器内容已知漏洞的最新信息。
1. 手工扫描容器镜像
在Openshift中,我们使用容器健康指数,来识别红帽容器目录提供的容器的安全风险。通常情况下,新版本的容器镜像会修复已知漏洞。关于镜像健康评级,请见链接:https://access.redhat.com/articles/2803031。
在Openshift中,红帽提供了atomic scan容器镜像安全扫描工具:
执行完毕后,生成安全扫描文件:
我们也可以单独扫描某一个容器镜像:
查看扫描结果,漏洞已经被扫描出来了(CVE):
扫描报告存到这个目录下:
Files associated with this scan are in /var/lib/atomic/openscap/2018-02-28-18-18-35-900492.
2. 自动扫描容器镜像
我们也可以通过红帽的CloudForms自动扫描容器镜像。
如果有容器镜像不合规,会被自动标注。
3.禁止镜像运行
在OpenShift中,防止用户在环境中启动新的易受***的容器,我们可以通过CloudForms的配置,让容器镜像不能直接被docker run运行。
方法是将使用字符串deny-execution来注释容器镜像。
三、容器仓库
根据统计数字,在社区里的容器镜像中,大概有1/3左右的容器镜像是有安全漏洞的。
并且,在生产中,需要保证镜像仓库实时高可用。
红帽提供了一个官方容器镜像下载地址(https://access.redhat.com/search/#/container-images),这里面有几百种红帽做过安全加固的容器镜像。
OpenShift中有个集成的镜像仓库,用于存放S2I过程中的进行。它是基于角色的访问控制,允许您管理谁可以推送和推送哪些容器图像。 OpenShift还支持与您可能已经使用的其他镜像仓库的集成,例如JFrog的Artifactory和Docker Trusted Registry。
OpenShift中可以配置外部镜像仓库的地址,比如可以定义开发人员可以从哪里拉或推图像。
在上图中,定义允许用户从docker.io下载图像并在容器平台上启动它。 设置策略时要小心,因为您将matchIntergratedRegistry设置为true的话,将无法通过这个镜像进行S2I。
四、容器构建
我们要实现整个容器云平台的安全,就必须要保证构建过程的安全。比如,是否允许开发人员在自己笔记本上构建应用镜像,然后push到生产上进行deploy?
OpenShift的S2I可以保证不同应用从源码到镜像的成功部署的并发执行,在这个过程中,所有构建都是相互隔离的。
此外,OpenShift还支持使用Jenkins进行持续集成(CI),可以将自己的CI环境与OpenShift集成(使用IDE工具)。构建完成后,应将图像推送到注册表中。
通常,我们会建议客户指定容器镜像管理的规范,如:
运营团队管理基本映像。
架构师管理中间件。
开发人员专注于应用程序层并只编写代码。
在上图中,是全发开发流程所需要的软件集。所有这些组件(git,nexus,jenkins,sonar)都在OpenShift中作为容器运行。 它们能够标准化通过S2I构建的容器,也可以使用Jenkins方式进行构建。
正是由于Openshift将全发开发流程所需要的软件集全都容器化,并对容器镜像进行权限管理,保证了在整个开发过程中的安全。
四、容器部署
如果在构建过程中出现任何问题,或者在部署映像后发现漏洞的情况下,Openshfit可以使用触发器来重建并替换为自动更新。
OpenShift带有内置的安全上下文约束(SCC),这也提升了容器的安全。
安全上下文是一组应用于容器的约束,以实现以下目标:
确保容器与其运行的底层主机之间有明确的隔离
限制容器对基础设施或其他容器造成负面影响的能力
默认情况下,SCC将添加到Openshift集群,并且具有特权和限制。
它们允许管理员控制以下内容:
运行特权容器;一个关键的安全概念是应该尽可能少的权限运行进程 - 容器也是如此。除非绝对必要,否则不希望容器以root身份运行。
容器可以请求添加的功能。
使用主机目录作为卷。
容器的SELinux上下文。
用户标识。
总之,通过利用CI / CD和OpenShift,我们可以实现如下步骤100%自动化:重建应用程序以整合最新修复程序、测试并确保其部署在环境中。
六、容器PaaS平台
对于企业来说,在面临大规模容器部署的时候,需要考虑:使用什么工具在同一主机上部署多个容器,或者如何分布在多个主机或节点上,具体而言:
哪些容器应该部署到哪些主机?
哪些容器需要彼此访问?
如何控制对共享资源(如网络和存储)的访问和管理?
如何监测容器的健康状况?
如何自动扩展应用程序容量以满足需求?
我们来看看Openshift节点如何隔离。
OpenShift具有Regions的概念。 这个概念也可以用来隔离在相同节点上运行的Pod。
例如,可以创建一个项目,并且可以在节点选择器上设置一个selector,只允许在特定区域运行pod。
容器平台的关键价值之一是能够支持开发人员的自助服务,使开发团队能够更轻松、更快速地交付构建在批准层上的应用程序。
因此,容器云平台多租户安全性是平台本身的必要条件,以确保团队在未经授权的情况下不会访问彼此的环境。 大多数客户需要一个自助服务门户,为团队提供足够的控制,以促进协作,同时提供安全性。
在K8S基础上,Openshift针对安全做了如下的工作:
所有对Master的访问都通过TLS
访问API服务器是基于X.509证书或令牌
项目的资源限制和配额避免一个程序占用过多的宿主机资源
Etcd不直接暴露给集群,而必须通过master API。
让我们看看Openshift登录过程。
当用户登录Openshift时,它执行标准的OAth令牌请求。
1. 首先,OAth服务器识别用户。如果无法识别用户,则OAth服务器可以将用户重定向到登录页面、或将身份验证质询发送到命令行客户端或委托给外部身份验证提供程序。
2.一旦请求令牌的人员已被识别,OpenShift会将该身份映射到用户。
3.一旦在OAuth访问令牌上确定OpenShift用户被创建并返回给用户。此时登录流程已完成。该令牌在ETCD数据存储中保存,并在用户注销时删除。
在OpenShift中有一个基于角色的授权组件。 RoleBindings和ClusterRolebindings定义了用户登录后的权限。
OCP的对外路由是容器化的HAProxy,我们可以针对Router配置安全策略。其步骤如下:
1.Create a Root CA and generate a server certificate, private key, client certificate,and client key.
2.In the real world, the certificate issuance process will vary from oneorganization to another; I this example we use OpenSSL to generate and signcertificates.
3.Build a docker image from RHEL 7’s latest base operating system to install and configure Nginx and Apache for two-way SSL.
4.Tag and push the docker image to the registry that Openshift is using.
七、容器网络
在容器云平台中,网络的安全是非常重要的。
Openshift默认使用OVS的SDN。目前支持三种模式:subnet、多租户、network policy。
在OVS-Subnet模式下,所有项目之间的pod是互通的。
ovs-multitenant插件实现网络隔离。
在配置了ovs-multitenant以后,不同项目之间的pod是不能互通的,除非手工将两个项目join。
目前,Openshift的OVS也支持network policy的模式。它支持白名单的模式,如将一个项目的所有pod的端口的入栈流量都封掉,只允许80端口的访问。
OpenShift X509证书也可用于保护与IPSEC的通信。 每个主机需要三个文件
群集CA文件
主机客户端文件
主机私钥
八、容器存储
目前,Openshift支持多种存储:包括AWS Elastic Block Stores(EBS),GCE持久磁盘,GlusterFS,iSCSI,Ceph和Cinder。
我们保证存储隔离方面,主要是通过PV和PVC的权限设置实现。
例如,用户可以请求一个PersistentVolume,它可以通过资源提供者支持的任何方式安装在主机上,例如ReadWriteOnce,ReadOnlyMany和ReadWriteMany。
ReadWriteOnce - 可以将卷挂载为单个节点的读写
ReadOnlyMany - 卷可以由多个节点以只读方式挂载
ReadWriteMany - 卷可以作为许多节点的读写装入
OpenShift使用SELinux功能来保护卷的根目录,使卷仅由与其关联的容器可访问。
访问共享存储(NFS,Ceph,Gluster等)可以通过将PV的组标识(gid)添加到pod的补充组来进行管理,从而使该pod可以访问共享存储的内容。
九、API管理
API网关是由微服务组成的应用程序的关键。微服务中,应用程序有多个独立的API服务,导致产生大量endpoint,因此需要额外的治理工具。Red Hat的3scale可以做这方面的工作。
3scale提供了API认证和安全的各种标准选项,可以单独使用或组合使用,以发布凭证和控制访问。
3scale的访问控制功能不仅仅是基本的安全和认证。它可以限制对特定端点,方法和服务的访问,并为用户组应用访问策略。
九、总结
Openshift作为企业级PaaS平台,除了保证其功能和性能以外,安全性是其重点的关注内容。
Openshift通过本文所述的9个方面,可以保证整个PaaS平台在各个方面的安全性。