执行摘要
目的
云原生的开发和部署模式已经成为业界趋势,技术、产品、标准和解决方案的生态系统也在同步的扩张之中,决策者面临着跟进复杂设计的挑战。CISO 要在这个动荡的战场中实践业务价值,这个角色显得尤为重要。云原生模式鼓励消费模式的变化,和采用需要集成安全实践的现代工作流程(如敏捷方法和 DevOps)。
问题分析
面对快速开发和部署的迫切需要,基于边界的传统安全保障显得力不从心。传统安全方法偏重于对边界进行保护,而更复杂的云原生应用则倾向于识别动态工作负载中的属性和元数据来进行保护,这样才能为应用的模式转换保驾护航。这种方式能对工作负载进行识别和保护,以此适应云原生应用的规模扩展以及快速变化的需要。模式的转变要求使用面向安全的架构设计(例如零信任),并且在应用安全生命周期中采用更多的自动化方法。作为云原生环境的典型特征,容器化也需要最新的最佳实践。安全措施的变更会触及组织内的多个利益方,并且会对开发和运维人员的生产力造成影响,因此其权衡过程会持续存在。云原生应用并没有跳出开发、发布、部署和运维的圈子,但是新的模式需要新的安全机制,从而保障(新方式下)能够保障这些环节目标的达成。云原生应用的生命周期可以建模为开发、发布、部署和运行时这样几个不同的阶段。和传统安全方法相比,云原生安全有机会在不同的阶段注入各自的安全保障,而不是用独立的安全措施来干预应用的生命周期。需要指出的是,需要针对这些概念的使用和整合、相关工具和流程的教育和培训,云原生的落地和应用可能难以为继,甚至被打回原形。
生命周期
开发
对云原生应用来说,建议在应用生命周期的早期就引入安全保障。尽早地使用安全测试来识别合规和配置的相关问题,从而为持续改进提供快速、可操作的反馈流程。这种方式能够使用同样的工作流程来处理安全问题和 Pipeline 中的其它常规问题(例如 Bug 修复或者 CI 失败)。这种模型中使用的现代的安全方法符合设计模式(例如 12 要素)要求,并且能保障交付过程的完整性。云原生的概念和 IaC(基础设施即代码)的实践密不可分,以此确保能够在早期进行安全检查后,按照预期执行。这样的过程能够识别错误配置,并可以尽早在 IaC 和编排清单中实施最佳实践,从而降低长期成本并提高安全价值。
发布
软件供应链安全在快速的软件迭代过程中尤其重要。云原生应用的完整性保障不仅针对工作负载自身,还需保证其创建和运维过程的完整性。对于开源软件和第三方应用的强依赖加剧了这方面的要求。Pipeline 生产的制品(例如容器镜像)需要持续地进行自动扫描和更新,从而避免遭受漏洞、恶意软件、危险代码以及其它不当行为的侵害。完成这些检查之后,应该对制品进行签名来保障其完整性和不可否认性。
部署
在开发和发布过程中集成的安全性能够对候选工作负载的属性进行实时的持续的验证(例如制品签名的验证、容器镜像和运行时的安全策略等)。随安全的工作负载同时部署的可观察性支持,提供了对日志和指标的支持,进一步完善了安全保障的覆盖面积。
运行时
云原生运行环境应提供策略和资源限制功能。对工作负载进行运行时资源限制(例如 Linux 的 cgroup 隔离)就是一个在云原生环境中进行限制和可观察性的原语的例子。可以把云原生运行时环境分解为具备不同安全问题的关联的组件层(例如硬件、主机、容器镜像运行时和编排)。
在云原生环境中,普遍采用了微服务架构。应用通常会由独立且目标单一的微服务组成,这些微服务需要通过服务层进行通信,容器编排层完成了这一任务。这种相互纠缠的组件架构下,安全方面的最佳实践包括只有被许可的进程才能在容器的命名空间内运行、预防和告知未经授权的资源访问、以及能够感知恶意行为的网络监控。服务网格是另一个常见的抽象,它在避免对工作负载进行变更的情况下,为被编排的服务提供了加固和补充的功能(例如 API 流量日志、传输加密、认证、授权以及可观察性等)。
建议
相对传统安全模型,云原生安全同样要对尽职性、完整性、信任关系以及威胁防范提供支持,在此基础之上还加入了临时性、分布式和不可变设施的现代概念。在这种快速变化的环境中,要在迭代中实现与开发 Pipeline 自动同步的安全保障才能防止迭代失败。组织必须对这些核心安全概念进行学习分析和应用,避免在应用加固和环境管理方面的落后;需要对相关的第三方执行同样的标准;并对其云功能和安全支持方面的员工进行持续的教育和培训。因为复杂性的增加和组件的复杂关系,必须通过在整个生命周期和运行环境中整合安全保障能力来制止未授权访问。强烈建议组织根据攻击框架[^2]来确认安全堆栈的覆盖面。另外组织还可以采用安全左移[^3]的方式,扩大 DevOps 的能力,在 Pipeline 执行之前、之中和之后进行持续、适用的检查,对进入生命周期的任何新东西进行校验。
结论
如果一个组织以战略的高度重视云原生安全的落地工作,能够在大规模情况下提供高可用、可信、韧性和冗余的应用能力,保证客户和开发者能够以他们期望的效率,安全地访问所需资源。安全是一个跨学科领域,并不能独立于开发之外,也不仅仅局限在技术范畴。开发、运维和安全人员都必须紧密交流和协作,推动该领域的持续进步。与任何技术创新一样,真正使社区和云原生安全成为可能的是人。
简介
本文尝试让组织及其技术领导者能够清晰地理解云原生,从而能够将其纳入原有生命周期,并确定其应用方式。云原生安全是一个覆盖多个专业技术和实践领域的多目标、多约束的问题空间。在初期运维过程中有很多工作都和安全领域重叠,例如身份管理和存储方案。然而云原生安全的覆盖面远不止于此,它还是一个关系到人本身的问题空间,其中包含了个人、团队以及组织。它是一种机制和流程,人类和系统借此进行交互,对云原生应用和技术造成深远影响。
目标读者
我们的目标读者是希望交付安全云原生技术生态的企业、政府机构以及非营利组织的首席安全观(CSO)、首席信息安全观 (CISO) 或者 首席技术官 (CTO) 。其它的组织利益相关方,包括负责设计实现安全云原生产品和服务的项目经理、产品经理和架构师。当然其他对云原生安全有兴趣的人也都可以参考本文。
云原生的目标
包括容器和微服务架构在内的新技术的采用和创新带来了新的挑战。现代组织中,安全需求的优先级已经大幅提升。围绕云原生技术的加速创新,威胁范围也在扩大。安全领导者要负责保护人力[^4]和非人力的资产,要在满足严格合规性要求的同时,采取措施来预防、检测和对应安全问题。一个老生常谈的埋怨就是,安全措施降低了 DevOps 团队的速度和敏捷性。因此安全领导层必须(和 DevOps 团队)进行更紧密的合作并增进双方的理解,让 DevOps 团队也能同样共享网络风险方面的所有权。
企业需要采用的安全云原生模式和架构必须进行分享,确保业界能够用更高优先级来实施安全实践,并将其集成到现代应用生命周期之中。强调安全架构和安全行业领导者的协同作用,并在漏洞管理、零信任、云安全和 DevSecOps 等方面调整组织的架构目标,这是当务之急。
本文中的概念是具备普遍性的,并不偏向于特定的组件或者服务。
但是这里并不会对安全和云原生方面的基本概念进行扫盲,也不会推荐特定的技术和工具,当然,叙述过程中可能会使用一些相关工具被列举在相关专题中,或者进行示例。
除了本文中的建议之外,与数据和隐私保护(例如 GDPR、PCI DSS)的相关内容需要额外的监管相关的方面进行考虑。建议读者另行寻找相关咨询资源对这方面的技术控制和合规风险提供支持。
假设
CNCF 在 CNCF 技术监督委员会(TOC)的 GitHub 仓库中提供了云原生的定义。本文不会改变这一定义或对其进行扩展。
云原生的落地和现代软件开发方法论都在持续演进之中。构成云原生技术栈的技术也会随着时间的推移不断变化。云原生 Landscape 中会持续支持这个不断变化的技术栈。
本文中出现的工作负载这个词,代表已经或者将要开发、运维、发布以及部署到基于云的运行时环境的任何产品、项目、应用或者系统。
云原生的层次
图 1
云原生技术栈由基础、环境和生命周期构成。云原生技术栈可能用不同的模型(例如 IaaS、PaaS、CaaS 或者 FaaS)进行部署。每一种模型都提供了各自的抽象,以此来简化云原生环境的管理和运维。这些模型中有一些是已经广为人知并被广泛采用,我们会聚焦在云原生特有的模型上。
CaaS(容器即服务)模型让用户通过基于容器的虚拟化平台及其 API 或者 Web 管理界面对容器、应用和集群进行编排和其它管理工作。CaaS 帮助用户构建容器化应用,其中内置以代码方式表达的安全策略,这些应用能运行在私有云、自建数据中心和公有云上。CaaS 有助于简化容器的构建过程。有了微服务的编排和部署,CaaS 帮助企业更快地发布软件,并且具备在混合云、多云环境下的移植性,同时还降低了基础设施和运维成本。CaaS 模型之所以能节约成本,是因为它能够帮助企业简化容器管理,并给企业仅为实际的 CaaS 需求买单的选择。CaaS 以容器为基础资源,而 IaaS 环境中的基础资源则是虚拟机和裸金属。
FaaS(功能即服务)是另一种云原生部署模型,它是一种云原生服务的形态,让企业用户能够根据事件来触发代码的执行,避免了构建运行微服务的复杂的基础设施管理工作。在云上运行应用通常提供虚拟环境,管理操作系统和 Web 组件等。有了 FaaS 之后,物理硬件、主机操作系统以及 Web 服务器软件管理都由云服务提供商自动支持。这样一来,用户就能专注于单独的微服务功能代码,并且只需要向云服务商用弹性的方式支付资源的实际使用费用。
生命周期
云原生语境下的生命周期指的是在云环境下,帮助实现有韧性、可管理、可观测的工作负载的技术和实践。如图一所示,生命周期由四个持续阶段构成:开发、发布、部署和运行时。每个阶段都是前一个阶段的扩展和放大,同时要放行安全工作负载的运行,并提供相应支持。
生命周期过程
对于安全实现来说,供应链的管理和合适的安全基线是非常重要的。
供应链
组织有责任确保它们开发的工作负载的供应链能够接受可操作的安全分析。供应链安全可以分为两个部分:为创建工作负载供应支撑环境的服务和工具(开发工具)的安全,以及组成工作负载的组件(例如库、依赖和镜像)的安全。供应链必须以能够接受检查的方式来构建,软件供应链输出的制品也应该能够使用签署的方式确认来源。为保障依赖项的正常运行并阻止可能的破坏行为,对第三方包的真实性和完整性进行校验非常必要。
云原生应用的一个显著特征就是软件复用,这些软件可能以软件包或容器镜像的方式,通过开源仓库进行构建和分发。正因如此,对于开发、运维和安全人员来说,确保应用中的制品和依赖不包含已知的恶意软件和缺陷是个必要工作。容器镜像可能包含的恶意软件,很明显会威胁到运行时环境[^5]。在持续集成过程中和容器仓库中进行周期性扫描和按需扫描能够有效防范这些问题。
使用这些手段实现可检测的、安全的软件发布和运维操作。在工作负载的产生过程中进行威胁检测让组织能够快速向开发团队进行反馈,并阻止不安全的或有漏洞的更新被发布和部署。对现存软件进行周期性的扫描,能够发现新公布的问题,从而避免其造成危害。
安全基准
安全基准(例如 NIST Application Security Container Guide、 Center for Internet Security (CIS), NIST Security Strategies for microservices 以及 OpenSCAP)为开发团队和组织提供了创建“缺省即安全”的工作负载的指引。采纳并实现这些安全标准,让团队能够基于加固的基线进行测试。然而这些基准无法深入数据流,也无法干涉平台的用法。因此这些内容应该作为一个指南,而非检查表。
接下来的几节将详细分析在整个应用程序生命周期中集成安全的意义、工具、机制和最佳实践。
开发
图 2
云原生应用的安全需要体现在应用的整个生命周期之中。开发环境是这个周期的第一个环节,这个环节输出的是制品,例如 IaaS、应用和容器清单等,这些制品会被用于云原生应用的部署和配置。经验表明,这些制品会是多种攻击的来源。接下来的内容会介绍这个阶段里需要介绍多种工具、流程和检查过程,以此减少运行时应用程序的攻击面。
开发过程中的安全检查
在应用开发过程中的安全加固是一个重要环节。安全需求也是需求的一部分,应该尽早在软件开发过程中进行引入。安全需求通常是围绕业务的风险和合规性进行的。这些需求如果不在早期进行处理,而是在生命周期的后续才开始进行的话,就会拖慢 DevOps 过程,提高总体成本。DevOps 团队还需要使用专门工具在这些应用的部署之前对危险配置和漏洞进行检测。这些工具应该无缝集成到 DevOps 团队现有的熟悉的工作链之中,在不阻碍敏捷性的同时,提高安全性。例如可以在开发 IDE 中或者创建 PR 的时候对 IaaS 模板以及应用清单文件进行扫描,并生成丰富的上下文相关的安全信息,开发团队就能够尽早、迅速、轻松地采取行动。加入这些步骤后能够避免已知漏洞和高危配置。云原生组件应该是 API 驱动的,被编排的业务应用能够和复杂的调试工具进行交付。
团队应该部署独立的开发、测试和生产环境,从而为应用开发者提供隔离的设施,对基础镜像、容器、应用、虚拟机镜像以及进行开发、测试和部署。有些组织可能已经在尝试金丝雀部署和蓝绿部署。以及其他部署模型在现场进行动态和交互测试,以此进一步提高效率。
测试方案的开发
开发、运维和安全人员应该为关键业务、有高危特征、变化频繁或具有历史问题的代码和基础设施建立测试方案。威胁建模可以识别高风险和高影响的代码热点,提高开发测试的投资回报率(ROI)。测试对象可以包括部署、操作系统、基础设施和数据库加固、应用测试(静态和动态源码测试、容器配置)、集成或系统测试(应用程序和基础设施组件及其交互的验收)和冒烟测试(针对实时系统的部署后检查)。测试作者应该能够全面地访问开发和测试环境,从而能够快速地开发测试方案,同时减少持续集成(CI)反馈循环次数。作者应该能在本地和共享测试环境中运行系统测试套件。
代码评审
对工作负载或基础设施的细微变更可能引发意料之外的安全问题。为减少风险,建议合并 PR 之前应用四眼原则进行评审。
发布
图 3
这个阶段会使用镜像定义和规范来构建后续步骤的制品,例如容器镜像、虚拟机镜像等。在现代 CI/CD 语境下,发布阶段中包含了系统性的应用测试,以此识别软件中的 Bug 和故障。然而对开源软件和包的复用,有可能会把安全威胁引入到制品之中。为了防止这种情况,需要对制品进行扫描,并验证其完整性,防止发生篡改。后续内容会为开发和运维人员介绍识别和保护容器镜像、CI/CD 流水线的工具、技术以及基础设施。还可以对制品进行加密来满足额外的保密需求。
如果遭遇泄密等问题导致制品不可信,应对密钥进行更换并重新签署。
构建流水线
不同安全级别和敏感性的项目,应对 CI 服务器应进行分别的隔离和保护。需要提权的基础设施构建应在专用的持续构建服务上运行。编排器应该为流水线创建和执行构建策略。
供应链工具可以对流水线的元数据进行搜集和签名。后续步骤能够对签名进行检查,并借此确信前面的步骤已经完成。
读者要确保 CI/CD 设施的安全。例如及时进行安全更新,并通过硬件安全模块或者凭据管理器对密钥进行保护,防止泄露。
镜像扫描
镜像扫描是应用镜像生命周期中的重要步骤。在把镜像部署到生产环境之前对其进行扫描是非常必要的。具备了这一能力之后,开发、运维和安全人员就能够获知已知问题的详细信息例如严重性、CVSS 评级以及对应的补救和修复措施。将容器漏洞扫描和流水线的合规规则结合在一起,能够确保仅有打过合适补丁的应用能够部署到生产环境,从而降低攻击风险。容器扫描还能帮助识别开源软件包和基础镜像中可能存在的恶意软件。镜像扫描仅是对现状的识别而非预防措施。组织需要谨慎选择扫描工具、在合理的环节中进行调用,在合乎规则的情况下,提供可操作的输出信息。
镜像加固
容器镜像是构建管道的第一次输出。因此必须对其进行安全加固,加固过程不仅需要考虑降低威胁,还要为整体环境下的应用运行提供可配置的能力。
需要在安全保障目标中评估以下几个问题:
执行环境应该限制到特定用户么?
资源访问应该受限么?
需要在内核级对进程执行做限制么?
容易应用清单扫描
应用清单描述了部署容器化应用所需的配置。正如在安全基准部分介绍的那样,NIST 800-190 之类的材料中推荐了容器化应用的最佳安全实践和配置。可以在 CI/CD 中对清单进行必要的扫描。
容器化应用清单的加固
和容器镜像类似,容器应用清单的加密也可以在构建和运行时进行。
需要在安全保障目标中评估以下几个问题:
满足环境运行目标的最小化限制是什么样的?
测试
云原生应用应该适用于传统应用相同的测试套件和质量标准——例如代码清洁、测试金字塔,为开发人员提供测试所需完整的基础设施,通过静态安全扫描(SAST)、依赖分析和扫描、动态应用安全测试(DAST)(例如 Mocking)等,为安全和合规提供实时的保障能力。
确定了安全问题之后(例如错误的防火墙或路由规则),进行根本原因分析之后,如果认为它有可能重复发生的话,开发人员就应该编写一个自动化测试,防止问题卷土重来。在测试失败时,团队应该收到反馈,改正 bug,试图在下一次合并中通过测试。(有效的测试)能够防范对同一段代