云计算时代容器安全综述-增强容器隔离性(上)

咱们在前边的多篇文章中详细介绍过容器提供的所谓“隔离”具体含义,相信读过文章的同学应该能够脱口而出:这是一种逻辑上的隔离,因为底层的硬件和操作系统内核会在运行在同一台机器上的多个容器实例之间共享。没错,虽然说这种隔离提升了硬件资源的使用度,但是这种逻辑隔离也有本身的问题,比如恶意用户逃逸攻击,权限提升,默认情况下容器实例以root权限运行等,因此使用Kubernetes这样的容器部署平台之前,笔者建议大家还是需要掌握一些加固容器隔离性手段,而本篇文章的目的正是如此,希望大家通过这篇文章能够重温容器提供的这种逻辑隔离性存在的安全风险,进而对降级这种风险的机制,工具有个全面的学习。

应用之间隔离部署这样的需求并不是容器化应用特有的,两个应用程序之间维持某种程度的隔离性是应用部署的基本要求,特别是从安全的角度来看。在容器化部署模式之前,我们通常可以通过两台物理机器或者一台物理机器上的两台虚拟机来实现。容器化本质上也给应用提供了逻辑上的边界,因此如果配置得当,部署在两个容器实例中的应用程序,相互之间并不知道对方的存在。

当然解决隔离性并不只有物理机,虚拟机和容器化这三种方式,我们还可以通过约束应用的行为来实现,这样当一个应用程序被黑客攻破,由于约束机制的存在,即便是应用A知道应用B和自己运行在同一台物理机器上并且持有敏感数据,也无法通过常规手段来窃取敏感数据,或者影响应用B的正常运行,我们通常情况下把这种通过约束机制来隔离应用程序的机制称作“沙箱”(Sandboxing)。

理解了沙箱机制后,回过头来看容器实例,是不是觉得容器实例就是一个沙箱,后者稍微扩大一下概念,就是一个安全沙箱机制。每次我们启动一个容器实例的时候,结合镜像的immutable机制,我们可以非常确定容器实例中运行的应用程序,并且如果应用程序被攻破,恶意攻击者可能会试图通过这个被攻破的容器来提升权限,或者逃逸到物理机上来造成更大的破坏。因此我们需要针对容器实例来增强这个沙箱的安全机制,如我们可以约束容器实例可以执行的系统调用,来缩减容器实例被攻破可能造成的攻击面,接下来咱们来详细介绍一下增强容器沙箱安全性的手段。

我们从seccomp机制开始说起。现代操作系统都有非常清晰的优秀的系统架构,而操作系统是我们访问计算资源的入口,操作系统了系统调用(SYSCALL)来将系统资源的访问进行抽象并提供出来,而我们编写的应用程序,比如访问阿里云的数据库服务器,或者从阿里云提供的ACR服务拉取进镜像,以及将图片上传到OSS上来进行全球加速,本质上都需要系统调用的帮助来使用网络接口资源。为了约束部署在容器实例中应用程序的行为,特别是哪些变节后的应用不至于对整个集群或者应用造成毁灭性的损害,我们需要seccomp提供的这种约束应用程序系统调用的安全机制。

seccomp的全称是secure computing mode,第一次被引入Linux内核可以追溯到2005年,具体来说,当一个进程进入secomp模式后,能够进行的系统调用就会受到约束(反过来说如果运行在容器实例中的进程没有任何约束,那么可以进行的系统调用就不会受到约束,比如修改操作系统内核的时间,卸载或者挂在操作系统内核模块这样的高风险操作),在seccomp进程可以执行的系统操作如下:

- sigreturn,从signal handler返回

- 结束进程(exit操作)

- 对进入seccomp安全模式之前的文件描述符(file descriptor)的数据的读写操作

进程进入seccomp安全模式后,我们仍然可以执行应用代码,前提是这些代码只使用了被允许的系统调用。不过读者应该可以体会到,这种模式下本质上没有办法执行太多正常的业务操作,因为约束太强了,因此这种机制很快就被证明无法广泛的被应用在应用程序开发部署中。

科技行业的最基本的演进方式就是现有问题,然后有很多厂商跟进给出解决方案,然后市场验证方案的可行性,不断迭代。2012年一种称作是seccomp-bpf的机制被引入Linux内核,了解操作系统的同学看到BPF是不是觉得很亲切,全程是伯克利数据包过滤器,也是很多网络调优工具,抓包工具的基础,我们熟悉的tcpdump就基于BPF来实现对2层数据包的抓取和分析。

笔者不打算在这里详细的聊BPF,后续关于容器和Kubenrnets网络的文章会详细介绍。具体来说,seccomp-bfp这种机制使用BPF来判断某个系统调用是否被允许,而规则写在进程专属的被称作是seccomp profile配置文件中。具体原理其实很简单,BPF会截获所有的系统调用,然后读取系统调用方法名称和参数,基于profile配置的规则来判断系统调用是否被允许。事实上profile提供的能力远比上边描述的复杂,当系统调用命中某个规则(filter)之后,我们还可以配置命中后的规则,包括:返回错误,终止调用或者调用tracer(可以理解为某个接口功能)。

不过对于容器化部署的应用程序实例来说,只用到了返回错误和允许系统调用这两个功能,这其实和我们熟知的黑名单和白名单机制非常类似,白名单放行,黑名单拒绝。seccomp-bpf这种机制提升了seccomp机制的灵活性,特别是对容器化部署的应用程序具有极大的现实意义,因为对于大部分的业务系统来说,其实很多系统调用我们都不会用到,除非是极端情况。咱么来举几个例子说明一下:

- 我们一般情况下不会在运行在容器应用程序中修改宿主机内核的时间,因此我们一般情况下根本不需要使用clock_adjtime和clock_settime这两个系统调用

- 容器的最主要目的是运行其中的应用程序,因此我们一般情况下也不需要在应用代码中加载,初始化或者卸载操作系统内核模块,因此我们也不需要create_module,delete_module和init_module系统调用

- Linux内核的秘钥保留服务keyring机制,一般我们也用不着,因此系统调用request_key和keyctl也应该被拒绝

对于Docker来说,默认的seccomp profile已经包含了40+系统调用服务黑名单,因此我们一般情况下不太需要对这个默认profile进行调整。不幸的是Kubernetes上并没有默认的seccomp profile,即便是我们选择的容器运行时为Docker(这句话可能有些同学无法理解,笔者稍微做一些解释,大家都知道最新版本的K8S上默认容器运行时已经不是Docker,这说明一个道理,Docker这样的容器运行时本质上就是个插件,我们可以基于自己的需求来替换。回到profle的问题,也就是K8S平台上Docker运行时,并没有默认的seccomp profile)。

不过大家不需要担心,Kubernets社区当然知道这个安全问题,已经在着手解决这个问题,支持seccomp的功能已经进入Alpha版本,相信很快就会和大家见面,到时我们就可以通过PodSecruityPolicy对象的annotation来实现实现profile机制,感兴趣的同学可以关注一下。

注:Jess Frazelle通过容器+seccomp展示了一套非常坚固的安全方案,到目前为止还没有被攻破,大家可以访问:https://contained.af/ 来获取更新的信息。

作为架构师的我们,肯定会问:那么有没有什么机制能够让这个限制系统调用的粒度更细,比如在应用程序级别来限制应用程序可以进行哪些系统调用?这句话翻译成安全需求就是我们是否可以有应用程序级别的prole来准确的控制应用程序可以进行哪些系统调用,背后的原因也非常直白,应用程序的功能千差万别,细粒度的控制安全性更好,业界的确有如下罗列的方案供大家选择:

- 我们可以借助于strace工具来追踪和收集应用程序全部功能需要的系统调用,然后通过这个清单来调整Docker的seccomp profile

- 咱们前边介绍过seccomp-bpf机制,大家应该对bpf这个工具可以用来控制系统调用是否被允许印象深刻,我们也可以用这个工具包来获取应用程序使用的系统调用清单

- 我们可以使用falco2seccomp和Tracee工具来产生容器实例使用到的系统调用清单

- 如果你觉得自己来管理profile太麻烦,不用担心,阿里云的容器服务ACK提供了整套的安全手段,包括笔者这里提到的seccomp机制,大家可以访问阿里云ACK网站获取更多详细的信息。

介绍完seccomp之后,接着咱们来了解另外一个叫AppArmor的Linux安全模块,全程是Application Armor。AppArmor机制为Linux操作系统上的每个可执行文件都提供了一个profile,我们可以在profile中配置可执行文件被允许的能力(capabilities)和文件访问权限。

注:读者可以查看文件/sys/module/apparmor/parameters/enabled来了解自己的Linux操作系统上是否开启了AppArmor安全模块,如果返回值是y,那么就说明已经开启。

AppArmor采用一种称作强制访问控制的机制,具体来说访问规则被集中管理,一旦访问规则被配置,用户就没有任何办法来修改或者绕过访问规则。与这种模式相对应的是被称作discrectionary access control自主访问控制的方式,通常用在文件权限访问控制。用户可以按自己的意愿,有选择的与其他用户共享他的文件。

使用这种mandatory access control强制访问控制机制让我们对系统调用有更强的控制,并且所有使用系统的用户(客体)无法对默认的规则进行重写和修改,安全性得到的极大的提升。

在AppArmor模式下,我们首先要准备好profile文件,有了这个文件后,我们就可以讲profile安装到目录/etc/apparmor,然后在通过工具apparmor_parser来加载安全规则,我们可以通过目录/sys/kernel/security/apparmor/profiles来查看系统加载的所有profiles。

另外我们也可以通过docker run --security-opt="apparmor:<profile name>" ...来显示的在启动Docker容器实例的时候来加载profile,结果是容器实例的行为将受到profile中定义的安全规则约束。另外大家需要注意的是,Containerd和CRI-O也支持AppArmor机制。

同Seccomp类似,Docker也为AppArmor提供了默认的profile,但是Kubenretes默认情况下不使用AppArmor机制,我们需要使用annotation来显示的在POD上声明AppArmor profile来开启这个安全机制。

接下来我们讨论的这个功能由红帽公司开发,可能很多同学都有所耳闻:SELinux,全称是Security-Enhanced Linux,这也是整个Linux内核中一系列安全机制的一种(LSM,Linux Security module)。在写这些文字的时候,红帽公司刚刚发布了最新版本Linux8.5,其中包含了很多对于跨云场景以及容器化部署场景的支持,特别是PODMAN这种运行时方式的优化,感兴趣的读者可以查看官方的release note:https://www.redhat.com/en/about/press-releases/red-hat-extends-foundation-multicloud-transformation-and-hybrid-innovation-latest-version-red-hat-enterprise-linux。

如果读者的应用运行在Centos或者RHEL版本的操作系统上,那么有很大的概率SELinux功能已经被打开。具体来说,SELinux约束进程能够对文件和其他进程进行的操作,每个进程都运行在SELinux领域中,不幸的是领域这个词有出现了,这和我们说的领域驱动设计中的领域在某种程度类似,描述的是进程运行的上下文环境。

咱们前边介绍过DAC(自主访问控制)机制,而Linux操作系统中的文件权限就是典型的DAC机制。和DAC比起来,SELinux机制中的权限最大的不同就是和用户Identity无关性,SELinux的权限通过标签来工作,这两种机制原理上可以同时工作,因此同一种操作可以被DAC和SELinux同时允许。

注:大家可以在自己的Linux操作系统上通过命令ls -lZ或者ps -Z来查看lable的情况,以下是笔者机器上Ubuntu虚拟上的输出结果:

$ ps -Z

LABEL                              PID TTY          TIME CMD

kernel                            8059 pts/0    00:00:00 bash

kernel                            9386 pts/0    00:00:00 ps

为了让操作系统上的文件被SELinux安全机制识别和管理,我们就必须为所有文件打标(labeled),这样我们就可以通过策略(policies)来约束进程可以访问的文件类型和文件。比如我们可以限制进程只能访问自己所属的文件,这样当进程变节后,由于SELinux机制的存在,因此变节的进程对系统的安全影响只限于这个进程内,这是一种典型的控制爆炸半径的机制。

本篇文章到目前为止介绍的三个机制:seccomp,apparmor以及selinux都是相对比较底层的安全机制,能否使用到自己的应用程序中取决于是否有完整的profile配置文件,并且这个profile并不是静态不变的,会随着应用的功能开发变化需要不断的更新,因此会对运维造成巨大的负担,很容易出现问题,造成结果是这些安全机制都是掩耳盗铃式存在,甚至很多场合功能直接被关闭。

由于这些原因,我们只能寄希望于K8S提供对这些功能的默认支持,比如默认的seccomp profile等。好了, 这篇文章的内容就这么多了,咱们在(下)篇中会介绍稍微没有那么底层的安全沙箱技术,敬请期待!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容