CI/CD是DevOps的主要工程实践,其环境、流程和系统是任何现代软件组织的核心。它们将代码从工程师的开发环境交付到生产环境。随着DevOps学科和微服务架构的兴起,CI/CD系统和流程重塑了整个软件工程生态系统,软件交付更加快捷、灵活和多元,然而与此同时,攻击面也被重塑,即为攻击者提供了大量新的方法和机会。因此,OWASP发布了“OWASP Top 10 CI/CD Security Risks”,以帮助软件开发组织确定其CI/CD生态中所需重点保护的领域。本文首先对“OWASP Top 10 CI/CD Security Risks”做简要介绍,然后基于这些风险提出CI/CD的若干安全实践,以期对软件开发组织构建安全的CI/CD生态有所帮助。
OWASP Top 10 CI/CD Security Risks
“OWASP Top 10 CI/CD Security Risks”是OWASP正在孵化中的一个项目,虽然项目仍在不断充实、想法仍在不断被证实中,其对于我们进行CI/CD安全建设具有很好的参考价值。十大风险如下表:
排名 | 风险名称 | 风险描述 |
---|---|---|
1 | Insufficient Flow Control Mechanisms 不充分的CI/CD流控制机 | 不充分的CI/CD流控制机制指的是攻击者在CI/CD流程中获得了访问系统(SCM、CI、Artifact repository等)的权限,而由于缺乏额外强制的审批或评审机制,攻击者能够单方面地将恶意代码或工件植入CI/CD流水线。 |
2 | Inadequate Identity and Access Management 不充分的身份和访问管理 | 不充分的身份和访问管理风险源于管理软件工程生态中大量的账户的困难,这些账户分布于从源代码控制到部署等不同的系统中。账户(包括人员和程序账户)管理不善,增加了其被破坏的可能性和遭受损害程度。 |
3 | Dependency Chain Abuse 依赖链滥用 | 依赖链滥用风险是指攻击者滥用一种缺陷的能力,该缺陷有关于软件工程工作站和构建环境如何获取代码依赖项。依赖链滥用会导致恶意程序包在拉取时无意中被提取并在本地执行。 |
4 | Poisoned Pipeline Execution “毒化”管道的执行 | “毒化管道的执行”风险是指攻击者能够访问源代码控制系统,但无法访问构建环境,通过将恶意代码/命令注入构建管道配置来操纵构建过程,本质上是通过“毒化”的管道使得运行恶意代码成为构建过程的一部分。 |
5 | Insufficient PBAC 不充分的PBAC(Pipeline-Based Access Controls) | 管道执行节点可以访问执行环境内外的众多资源和系统。在管道中运行恶意代码时,攻击者利用不充分的PBAC风险滥用授予管道的权限,以便在 CI/CD 系统内部或外部横向移动。 |
6 | Insufficient Credential Hygiene 凭据安全管理不当 | 由于凭据周围的访问控制、不安全的机密管理和过于宽松的凭据相关的缺陷,凭据安全管理不当风险会导致攻击者有能力获取和使用遍布整个管道的各种机密和令牌。 |
7 | Insecure System Configuration 不安全的系统配置 | 不安全的系统配置风险来自于整个管道中不同系统(如SCM、CI、工件库)的安全设置、配置和加固方面的缺陷,往往导致攻击者希望在环境中扩大其立足点的”低垂果实”。 |
8 | Ungoverned Usage of 3rd Party Services 第三方服务使用缺乏管控 | CI/CD攻击面包括一个组织的有机资产,如SCM或CI,以及被授予访问这些有机资产的第三方服务。第三方服务使用缺乏管控的风险源于第三方服务被授予访问CI/CD系统中的资源的极端便利性,显著地扩大了组织的攻击面。 |
9 | Improper Artifact Integrity Validation 组件完整性验证不当 | 由于代码和工件合法性校验机制不充分,组件完整性验证不当风险,使得攻击者在具备CI/CD流程中系统的访问权限的情况下,能够将恶意(尽管看起来是良性的)代码或工件推送到管道上。 |
10 | Insufficient Logging and Visibility 日志记录和可视性不足 | 日志记录和可视性不足风险允许攻击者在CI/CD环境中执行恶意活动,而不会在攻击杀伤链的任何阶段被发现,攻击者的TTP(技术、策略和程序)也无法被识别以用于事后调查。 |
CI/CD十大风险涉及到整个CI/CD生态,而CI/CD生态大都包括CI/CD平台(例如:Jenkins),SCM系统(例如Gitlab、Github),第三方组件管理系统(例如:JFrog),Pipeline节点工具(即各种构建、测试和部署工具),本文安全实践的分享将围绕这些系统展开。
SCM系统安全管理
软件交付过程由多个相互连接系统组成,目标是将代码和工件从开发环境转移到生产环境。SCM系统作为代码、文件和脚本等的版本控制工具,其安全关系到整个CI/CD流水线。然而,在多数软件开发组织当中,SCM的普通用户账户是高度宽松的,因为这些系统传统上并不是安全团队的主要关注领域。这些账户主要由工程师使用,以便在代码和基础架构创建重大变更。因此,SCM的安全也面临一些主要问题和挑战,包括账户过度授权、账户过期未清理、外部账户以及共享账户等。针对这些问题,我们可以采取以下安全措施:
- 对软件工程生态中所有系统的所有账户进行持续的分析和映射。对于每个账户,建立其提供者、授权级别以及实际权限级别三者之间的对应关系。确保所有通过编程方法的访问在分析范围内。
- 对于环境中不同系统的每一个账户,删除其进行中工作所不需要的权限。
- 确定一个禁用/删除过期账户的可接受期限,并禁用/删除任何超过该期限的不活跃账户。
- 持续了解所有外部合作者的信息,确保他们的账户符合最小特权原则。在可能的情况下,为个人账户和程序账户授予具有预定失效日期的权限,并在工作完成后将其禁用。
- 对于SCM、CI或任何其他CI/CD平台,防止员工使用个人电子邮件或不为组织拥有和管理的域的任何地址。持续监控不同系统中的非域地址并删除不合规用户。
- 不允许用户自行注册到系统,并根据需要授予权限。
- 避免将系统中的基本权限授予所有用户以及自动分配用户账户的大型组。
- 避免使用共享账户。为每个特定上下文创建专用账户,并授予该上下文所需的确切权限集。
下面以Gitlab为例来说明账户及权限管理。Gitlab用户在组中有五种权限:Guest、Reporter、Developer、Master、Owner,其角色权限说明以及适用项目角色如下表:
Gitlab角色 | 权限说明 | 赋予角色 |
Guest(访客) | 可以创建issue、发表评论,不能读写版本库 | 项目外成员 |
Reporter(报告者) | 可以克隆代码,不能提交 | QA、PM、编程账号 |
Developer(开发人员) | 可以克隆代码、开发、提交、push | 开发工程师 |
Master(主程序员) | 可以创建项目、添加tag、保护分支、添加项目成员、编辑项目 | 核心开发工程师 技术经理 |
Owner(所有人) | 可以设置项目访问权限 – Visibility Level、删除项目、迁移项目、管理组成员 | 研发负责人 团队Leader |
Gitlab中的组和项目有三种访问权限:Private(只有组成员才能访问)、Internal(登录用户即可访问)、Public(所有人都可访问),对于内部项目需将权限设置为Private,对于开源项目可将权限设置为Internal
第三方组件安全管理
考虑到软件开发组织中所有开发环境中涉及的系统总数,管理自编写代码使用的依赖项和第三方组件变得越来越复杂。通常使用每种编程语言的专用客户端获取包,通常来自自我管理的包存储库(例如 Jfrog Artifactory)和特定语言的 SaaS 存储库(例如 – Node.js与npm,Python与pip, Ruby与gems)。由此可见,第三方组件的安全管理对于CI/CD至关重要,管理不当可能使得软件开发组织面临:依赖混淆、依赖劫持、Typosquatting以及Brandjacking等类型的攻击。因此,我们建议采取以下安全措施:
- 禁止任何拉取代码包的客户端直接从Internet或不受信任的来源获取包。
- 对于拉取的包,启用校验和检查和签名验证。
- 避免将客户端配置为拉取最新版本的软件包。推荐配置经预审的版本或版本范围。使用框架特定的技术将组织所需的包版本,持续“锁定”到稳定且安全的版本。
- 当安装脚本作为包安装的一部分执行时,确保这些脚本存在单独的上下文,该上下文无权访问构建过程中其他阶段可用的机密和其他敏感资源。
- 确保内部项目始终在其的代码存储库中包含包管理器的配置文件(例如NPM中的.npmrc),以覆盖获取包的客户端可能存在的任何不安全配置。
Pipeline节点的安全管理
Pipeline是CI/CD的核心。Pipeline中的节点执行管道配置中指定的命令,并以此来执行许多敏感活动:访问源代码,构建和测试它;从不同位置获取机密信息(环境变量、保管库、基于云的专用身份服务);创建、修改和部署工件。另一方面,Pipeline节点的命令一般由各类构建、测试和部署工具来完成,如果对于节点工具的授权与访问控制不当或者节点工具本身存在漏洞,都有可能导致恶意代码在Pipeline节点的上下文中运行,进而访问机密信息、访问底层主机并连接到该Pipeline有权访问的任何系统。这可能导致机密数据的暴露、非法访问CI环境之外的服务器和系统,以及将恶意工件部署到Pipeline中甚至包括生产。因此,对于Pipeline节点的安全管理,我们建议采取以下安全措施:
- 对于敏感级别或者资源访问权限不同的Pipeline,不应该共享节点。
- 确保CI/CD系统中使用的机密信息的访问域得到管控,即仅能被需要这些机密信息的Pipeline访问。
- 每次Pipeline执行结束后,将执行节点恢复到其原始状态。
- 确保作业运行环境中的网络分段得到了合理的配置,即仅允许执行节点访问其在网络中所需的资源。在可能的情况下,不要授予对互联网的自由访问以构建节点。
- 当安装脚本作为包安装的一部分执行时,确保这些脚本存在单独的上下文,该上下文无权访问构建过程中其他阶段可用的机密和其他敏感资源。
- 确保每一个Pipeline节点工具的版本是稳定安全的,并且已打上正确的补丁。
工件完整性校验
CI/CD流程由多个步骤组成,最终负责将代码从工程师的工作站一直带到生产。每个步骤都有多种输入资源,——包括内部资源和工件以及从远程获取的第三方软件包和工件。最终的资源依赖于多个贡献者在各个不同步骤提供的资源。这就创造了多个资源入口,而通过这些入口,最终的资源可能被篡改。如果一个被篡改的资源能够成功地渗透到交付过程中,而且不引起任何怀疑或遇到任何安全门,则它很可以合法资源的幌子,能继续通过管道一直到生产。因此,从开发到生产的整个过程,通过流程和技术来验证资源的完整性。当一个资源被生成时,应使用签名基础设施对其进行签名。管道在后续步骤消费该资源前,应根据签署机构验证该资源的完整性。在这种情况下,需要考虑一些普遍的安全措施:
- 代码签名——SCM解决方案提供了使用每个贡献者的唯一密钥来签署提交的能力。这一措施可以用来防止未签名的提交在Pipeline中流动。
- 工件验证软件——使用工具对代码和工件进行签名和验证,提是一种防止未经验证的软件在管道中交付的方法。这种项目的一个例子是由Linux基金会创建的Sigstore。
- 配置漂移检测——检测配置漂移的措施(例如,云环境中的资源没有使用签名的IAC模板进行管理),可以检测资源是否由一个不受信任的来源或进程部署。
- 从构建/部署管道获取的第三方资源(如构建过程中的导入和执行的脚本)应遵循类似的逻辑——在使用第三方资源之前,应计算资源的哈希值并与资源提供者的官方公布的哈希值进行交叉对比。
日志可视性建设
攻击者逐渐将他们的注意力转移到CI/CD工程环境,并以此作为实现其目标的一种手段。软件开发组织如果不对这些环境建立适当的日志记录和可视性控制,就可能无法发现漏洞,并由于调查能力低下而在缓解风险/修复漏洞时面临巨大困难。对于日志可视性建设,可以采取以下措施:
- 绘制环境图——如果对涉及潜在威胁的所有不同系统不熟悉,就无法实现强大的可见性能力。潜在漏洞可能涉及参与CI/CD流程的任何系统,包括 SCM、CI、工件库、软件包管理软件、容器注册、CD和协调引擎(如 K8s)。识别并建立一个组织内使用的所有系统的清单,包含这些系统的每个实例(特别是与自我管理的系统如Jenkins有关)。
- 识别和启用适当的日志源——一旦确定了所有相关的系统,下一步就是确保所有相关的日志被启用,因为这不是系统的默认状态。应围绕人员和程序被授权的各种行为来优化可视性。重要的是,对于识别所有相关的审计日志源,以及应用性日志源,应给与同样的重视。
- 将日志发送到集中位置(例如SIEM),以支持不同系统之间的日志聚合与关联,以便于检测和调查。
- 创建警报来检测异常情况和潜在的恶意活动,既包括每个系统本身的异常情况,也包括代码运输过程中的异常情况,这涉及多个系统,需要对内部构建和部署过程有更深入的了解。
写在最后
不充分的CI/CD流控制、身份认证和访问控制不足、依赖链滥用、“毒化”管道、PBAC不足、不安全的系统配置、三方服务的使用缺乏管控、组件完整性校验不当以及日志可视性不足等风险的发生,归根结底就是整个CI/CD生态中各系统的安全需求存在缺陷,包括由外而内的访问以及内部系统的互访,即在身份认证、授权、访问控制、数据加密和日志记录与审计等安全功能的实现方面存在缺失或者缺陷,才使得不怀好意的攻击者有机可乘。牢记CIANIAAA并以此为基础来建设和优化整个CI/CD生态,将对组织的软件安全大有裨益。