作为主机安全类产品的核心组件,Agent部署在需要保护的业务服务器内部,与管理中心通信,实现数据采集、安全监控、任务推送等功能,任何像HIDS、CWPP、EDR、EPP产品都离不开这根定海神“针”。
主机安全产品最基础的部署架构
关于如何做好主机安全,业内前辈做过无数的梳理,本文不再一一考古,从主机安全产品 Agent 架构的三个技术细节出发,旨在分享长亭科技在牧云(CloudWalker)主机安全管理平台产品开发过程中遇过的坑与部分解决问题的心得。
作为主机安全产品最核心的部分,Agent面临的风险和挑战也最大;Agent自身的任何异常都有可能影响到操作系统稳定性,甚至产生严重的安全风险。因此Agent的运行权限是大部分使用者最关心的问题之一。
我们分析了一些开源的主机安全项目,确实发现部分项目的 Agent 存在安全问题可以通过漏洞直接获取系统的 root权限。
Agent作为复杂的程序难免会出bug,一旦行为不可控,会直接影响操作系统的正常使用。
Linux本身也不是100%完美,基本上每个版本都有不少 bug。应用程序的正常行为一旦触发 Linux的bug,带来的可能是 kernel panic。
安全是为了辅助业务健康成长,任何不考虑业务连续性的安全方案都是耍流氓。牧云团队组建初期就立下了一条铁律: Agent所有的操作均使用纯旁路、无污染的方式实现,侵入性强的技术方案永远不是我们的选择。
牧云Agent以非root方式运行,一方面可以避免意外导致系统稳定性受到挑战,另一方面也是对于安全性的有效保证。Linux内核在2.1版本以后引入了 capability机制,他打破了原有超级用户与普通用户严格区分的限制,使普通用户也可以完成部分特权操作。牧云Agent使用 capability在探针安装阶段对Agent进行授权,使Agent具有完整的对操作系统监控的能力。同时确保Agent在运行阶段即使发生异常,也不会做超出能力范围之外的事情,从而保证了业务负载的稳定性和 Agent 自身的安全性。
Agent 作为长期运行在服务器上的后台程序,对稳定性的要求极高,代码足够精简、尽可能减少改动是必选项(别问,眼泪ing)。考虑到这一前提,我们将 Agent 从架构上划分了两部分:Agent 内核和业务应用。
内核是对一些与操作系统相关,与硬件平台相关的实现进一步抽象。牧云团队提取了资产采集、风险感知、入侵检测等业务功能所需的公共部分,组成 Agent内核。Agent 内核作为常驻程序持续运行,不实现实际的业务功能,只为上层提供调用接口。(注意,Agent 内核运行在操作系统用户态,与操作系统内核无关)。在Agent内核之上是业务应用,使用golang和lua开发,通过主动或被动的方式向Agent内核发起调用,最终实现与操作系统进行交互,为产品直接提供相关的功能实现。
Agent 内核提供的主要硬核功能如下
业务应用无法直接访问操作系统,所有对操作系统的读写操作均需经过Agent内核,如:进程访问能力,文件访问能力,网络访问能力,用户访问能力,容器访问能力等。
事件监控是主机安全产品的核心能力,所有对入侵行为的审计都离不开事件监控。Agent 内核提供了一种叫做 “事件源”的接口,支持业务应用注册异步回调来实现对于操作系统关键事件的监控,这些事件包括:执行命令、创建用户、用户登录、用户被修改、创建进程、进程被修改、进程退出、创建文件、文件被修改、监听端口、发起网络连接、发起 DNS 请求、加载内核模块等。
Agent 内核作为底层抽象,帮业务应用屏蔽所有平台相关的特性,使业务应用可以实现跨平台运行的可能,而不用考虑 Windows、Linux、x86、x64、ARM 等不同平台带来的实际差异。
抽象多种容器的底层机制,使业务应用的工作逻辑可以对容器生效。
Agent内核负责所有上层业务应用的运行调度,根据服务器状态与业务需求选择加载卸载业务应用;合理分配资源,适当调整不同业务应用的优先级,使业务应用有序运行。
Agent内核提供了业务应用在运行阶段对于CPU、内存、网络、磁盘等硬件资源的限制能力。得益于此机制,牧云产品可以向用户提供行业内独家的CPU与内存限制功能,可完全由使用者自定义牧云探针的资源使用阈值。
不同的业务应用运行在不同的沙箱内,相互隔离,互不干扰,任何业务应用运行发生异常都不影响Agent整体的运行。
优秀的产品离不开高手如云的专业团队。牧云技术团队近 40 人,根据工作内容的不同,分为 3 个小团队,分别是研发、安全对抗、安全开发。
纵观整个安全行业,大部分优秀的安全工程师都是 fullstack,搞渗透、搞逆向、写脚本样样精通。但作为 fullstack 的安全工程师普遍缺乏工程化的研发经验,虽然能随手写一个 100 行的脚本,但是很少有人能维护 100 万行代码的大型项目。因此,组建一个安全水平较高的工程化研发团队极其困难,我们依然需要 fullstack 小伙伴与我们一同实现梦想;并必须拥有一定的规范,确保代码质量。(别细问,哭更凶ing)
业务应用是体现产品安全价值的重要模块,业务复杂,代码量大。在立项初期,随着不断有新同事的加入,业务应用的代码质量下降很快,模块划分不明确,代码逻辑结构混乱,开始出现一些实现层面的低级错误,比如写错变量名,比如不检查错误等等。经过一段时间的思考和纠结,我们认为问题的根源在于 lua。lua 是一门很好的嵌入式脚本语言,有非常广泛的应用,尤其是它的灵活性,是脚本语言很大的优势。但是过于灵活却会导致其很难组织大项目,举几个典型的问题:
这些是很多脚本语言都会面临的问题,这种现象如果任由其发展,最终势必会对项目的整体质量造成严重影响。为了解决这些问题,javascript有了typescript,python有了 python3,lua也需要类似的东西,我们遇到的问题需要从编程语言入手去解决。经过调研我们锁定了开源的 Teal-Lang,可以实现对lua代码的类型标注和语法检查,但任然无法满足我们的所有需求,考虑再三,我们还是开发了ctlua。
ctlua 是什么?
他是长亭 lua;也是 lua with class & type。
伴随着 ctlua 的诞生,安全开发团队还做了 3 件小事:
避免大家反复造轮子,避免在不了解实现的情况下引入风险较高的第三方模块。
如果写出来的代码或者设计的架构让人很难理解,那一定是存在问题的,优秀的设计必然清晰简单,要拒绝黑魔法,绝不引入过渡的抽象。
模块的接口需要足够友好,为其他开发者和测试工程师在调用和自动化测试的过程中提供便利性。
然后就是迁移的过程,迁移原有的业务应用是一个渐进的过程,从我们写下第一个ctlua 的函数开始,团队的小伙伴很快就接受了 ctlua,代码质量在短时间内有了一个质的飞跃。截止目前,除了已经被废弃的模块,牧云所有的业务应用均使用 ctlua 开发,之前遇到的问题很少有再发生。
足够精简的代码和尽可能减少改动,确保Agent内核&业务应用架构下的Agent稳如磐石,为主机安全高效服务提供坚实基础。
主机安全作为内网安全的最后一道防线,是一线安全工程师一致认可的重要安全业务。长亭主机安全团队从 2018年写下第一行代码,到 2020年正式发布商业化版本牧云(CloudWalker)主机安全管理平台,已经有了足够的技术积累(血泪),感谢在过去不到一年的时间内数十家付费客户对牧云的认可。开发安全产品是一条艰辛且漫长的道路,持续优化迭代,将长亭的安全能力为甲方赋能是对客户最好的回馈。
大型工程的建设必然会遇到不断的技术挑战,上文只是在牧云 Agent 开发过程中遇到的零光片羽,长亭始终会以开放的态度朝着最优方案的方向努力,同时诚邀各路大佬与我们在这趟奇旅之中,共筑安全梦想(这是其实一条招聘广告)。