原文:zh.annas-archive.org/md5/8ee20dbda2ce1515f121225d872e820c
译者:飞龙
协议:CC BY-NC-SA 4.0
前言
Kubernetes 默认情况下并不安全。现有的企业和云安全方法受到 Kubernetes 动态特性的挑战,以及使用它通常带来的加强组织敏捷性的目标。乐成地在这种新环境中保护、观察和排错关键微服务须要全面理解一系列考虑因素。这些包括组织挑战、新的云原生方法怎样资助应对这些挑战,以及新的最佳实践以及怎样操作化它们。
尽管有大量关于 Kubernetes 的资源,但在此中导航并订定全面的安全和可观察性策略大概是一项艰巨的任务,在许多情况下,会导致显著侵害所需的安全姿态。
为了指导您朝向一个综合的安全和可观察性策略,覆盖这些考虑的广度,并为您提供在将应用步伐迁移到 Kubernetes 时资助您的最佳实践和工具,我们撰写了这本书。
在我们在 Tigera 工作并构建 Kubernetes 的网络和安全工具 Calico 多年后,我们近距离地见证了用户的路程。我们看到许多用户专注于在 Kubernetes 中摆设工作负载,而没有深图远虑他们的安全或可观察性策略,然后在尝试理解怎样保护和观察这样一个复杂的分布式系统时遇到困难。我们撰写本书的目标是通过与您分享我们所学到的知识,只管减少这种痛苦。我们在全书中提到了一些工具示例,此中包括 Calico。我们认为 Calico 是一个优秀且受欢迎的选项,但另有许多好的工具,如 Weave Net、VMware Tanzu、Aqua Security 和 Datadog,供您选择。终极,只有您可以决定哪个对您的需求最合适。
Kubernetes 采用的阶段
任何乐成的 Kubernetes 采用过程都遵循三个明确阶段:
学习阶段
作为新用户,您首先要学习 Kubernetes 的工作原理,设置一个沙盒环境,并开始考虑怎样在您的环境中使用 Kubernetes。在这个阶段,您渴望使用在线 Kubernetes 资源,并使用开源技能。
试点/预生产阶段
一旦你熟悉了 Kubernetes 并理解了它的工作原理,你会开始考虑采用 Kubernetes 的高级战略。在这个阶段,通常会进行试点项目来设置你的集群并引入几个应用步伐。随着你在这个阶段的进展,你将会对你将使用的平台有所相识,而且决定它们是在当地还是在云上。假如你选择云端,你将决定是自己托管集群还是使用云提供商提供的托管 Kubernetes 服务。你还须要考虑保护应用步伐的策略。此时,你会意识到 Kubernetes 由于其声明性子而与众不同。这意味着平台对于网络、基础设施、主机等方面抽象了许多细节,因此使得你非常容易为你的应用步伐使用该平台。由于这一点,你现在须要考虑与 Kubernetes 当地安全干系的安全性,因为你目前使用的保护应用步伐、基础设施和网络的方法根本行不通。
生产阶段
到此时,你已经完成了试点项目并乐成引入了几个应用步伐。你的重点是在生产中运行关键任务应用步伐,并考虑是否将大多数应用步伐迁移到 Kubernetes 上。在这个阶段,你须要具体计划安全性、合规性、故障清除和可观察性,以便安全有效地将应用步伐迁移到生产环境,并实现 Kubernetes 平台的全部好处。
注意
Kubernetes 作为基于容器的应用步伐平台的盛行和乐成使得许多人急于采用它。在已往几年中,托管 Kubernetes 服务提供商已经积极创新并使采用更加容易。新用户大概会被勾引直接跳过学习和试点阶段,以便快速进入生产阶段。我们警告不要因此而忽视尽职观察。在将关键任务应用步伐引入 Kubernetes 之前,你必须将安全性和可观察性视为关键的第一步;否则你的 Kubernetes 采用将是不完备的,而且大概存在安全隐患。
这本书得当谁
这本书得当广泛范围的 Kubernetes 实践者,他们处于采用试点/预生产阶段。你大概是平台工程师,或者是安全或 DevOps 团队的一部分。你们中的一些人是组织中首批采用 Kubernetes 的人,渴望从一开始就精确处理安全性和可观察性问题。其他人正在资助在已经采用 Kubernetes 但尚未解决其带来的安全性和可观察性挑战的组织中建立最佳实践。我们假设你具备 Kubernetes 的基础知识——知道它是什么以及怎样将其作为托管应用步伐的编排工具使用。我们还假设你相识应用步伐在 Kubernetes 集群中的摆设方式及其分布式特性。
在这个广泛的受众中,有许多不同的脚色。以下是一些资助设计和实施基于 Kubernetes 架构的团队的非细致列表,这些团队将在本书中找到代价。请注意,您的组织中大概使用不同的脚色名称,因此请查看每个脚色的职责,以确定在您的组织中对应的脚色。本书将使用这些名称资助您理解一个概念怎样影响每个脚色。
平台团队
平台工程团队负责设计和实施 Kubernetes 平台。许多企业选择实施容器即服务平台(CaaS)策略。这是一个跨企业使用的平台,用于实现基于容器的工作负载。平台工程团队负责平台组件,并将它们提供为应用团队的服务。本书将资助您相识安全平台的重要性,并提供资助保护平台层的最佳实践,以便为应用团队提供在安全 Kubernetes 平台上摆设应用步伐的方法。它还将资助您相识怎样管理新应用步伐对平台的安全风险。
网络团队
网络团队负责在企业网络中集成 Kubernetes 集群。我们看到这些团队在当地摆设 Kubernetes 和在云环境中使用自托管或托管 Kubernetes 服务时扮演不同脚色。您将相识网络安全的重要性以及怎样建立具有强大安全架构的网络。本书涵盖了将应用步伐暴露到 Kubernetes 平台外部以及应用步伐访问外部网络的最佳实践。您还将学习怎样与其他团队合作,实施保护 Kubernetes 内工作负载外元素的网络安全措施。
安全团队
企业安全团队在向云原生应用转型过程中受到的影响最大。云原生应用是专为云环境设计的应用步伐,与传统应用步伐有所不同。例如,这些应用步伐分布在网络基础设施中。本书将资助您相识怎样保护用于托管应用步伐的 Kubernetes 平台的具体信息。它将为您提供一个完备的视角,教您怎样保护关键工作负载。您将学习怎样与各种团队合作,在 Kubernetes 新天下中有效实施安全措施。
合规团队
企业的合规团队负责确保组织中的运营和流程符合组织采用的合规标准的要求。您将相识怎样在基于 Kubernetes 的平台中实施各种合规要求以及怎样监控持续的合规性。请注意,我们不会具体介绍各种合规要求和标准,但我们将为您提供策略、示例和工具,以资助您满意合规性要求。
运营团队
运营团队是负责构建和维护应用步伐的开发职员/工具/运维工程师团队。他们也被称为 DevOps 或站点可靠性工程师(SREs)。他们确保应用步伐被接入并符合所需的服务程度协议(SLAs)。在本书中,您将相识怎样在安全 Kubernetes 集群中扮演脚色以及与安全团队的合作。我们将介绍"左移安全"的概念,即安全须要在应用步伐开发生命周期的早期阶段发生。在 Kubernetes 平台中,可观察性意味着通过查看平台数据推断有关集群操作的具体信息的能力。这是监视分布式应用步伐的当代方式,您将学习怎样实施可观察性及其对安全性的重要性。
您将学到什么
在本书中,您将学习怎样在实施 Kubernetes 战略时考虑安全性,从构建应用步伐到构建基础设施再到托管应用步伐再到摆设应用步伐再到运行应用步伐。我们将为每个步骤提供安全最佳实践,并附有示例和工具,资助您保护您的 Kubernetes 平台。我们将介绍怎样实施审计、合规性以及像加密这样的其他企业安全控制。
您还将学习怎样使用工具和示例来实施可观察性,并展示其与安全性和故障清除的干系性。这种对您的 Kubernetes 平台加强的可见性将驱动与您独特情况干系的可操作见解。
在本书的结尾,您将能够为您的 Kubernetes 集群实施这些安全和可观察性最佳实践。
本书中使用的约定
本书中使用以下排版约定:
Italic
表示新术语、网址、电子邮件地址、文件名和文件扩展名。
Constant width
用于步伐清单,以及在段落中引用步伐元素,如变量或函数名、数据库、数据类型、环境变量、语句和关键字。
Constant width bold
显示用户应按照字面意思键入的命令或其他文本。
Constant width italic
显示应由用户提供的值或由上下文确定的值替换的文本。
注意
此元素表示一样平常解释。
使用代码示例
补充质料(代码示例、训练等)可在 https://github.com/tigera/k8s-security-observability-book 下载。
假如您有技能问题或在使用代码示例时遇到问题,请发送电子邮件至:bookquestions@oreilly.com。
这本书旨在资助您完成工作。一样平常情况下,假如本书提供了示例代码,您可以在步伐和文档中使用它。除非您复制了本书的大部分代码,否则无需征得我们的允许。例如,编写一个使用本书多个代码片段的步伐不须要允许。贩卖或分发 O’Reilly 书籍中的示例代码须要允许。引用本书回答问题并引用示例代码不须要允许。将本书中大量示例代码整合到产品文档中须要允许。
我们感谢您的支持,但通常不须要署名。署名通常包括标题、作者、出书社和 ISBN 号。例如:“Kubernetes Security and Observability 由 Brendan Creane 和 Amit Gupta(O’Reilly)编写。版权全部 2022 年 O’Reilly Media,978-1-098-10711-6。”
假如您觉得使用代码示例超出了合理使用范围或上述允许,欢迎随时与我们联系:permissions@oreilly.com。
O’Reilly Online Learning
注意
40 多年来,O’Reilly Media 一直为公司提供技能和贸易培训、知识和见解,资助它们取得乐成。
我们独特的专家和创新者网络通过书籍、文章以及我们的在线学习平台分享他们的知识和专长。O’Reilly 的在线学习平台为您提供按需访问的现场培训课程、深入学习路径、交互式编码环境,以及来自 O’Reilly 和其他 200 多家出书商的广泛的文本和视频内容。获取更多信息,请访问:http://oreilly.com。
怎样联系我们
请将有关本书的评论和问题寄给出书社:
- O’Reilly Media, Inc.
- 1005 Gravenstein Highway North
- CA 95472 Sebastopol
- 800-998-9938(美国或加拿大)
- 707-829-0515(国际或当地)
- 707-829-0104(传真)
我们为这本书制作了一个网页,上面列出了勘误、示例和任何额外信息。您可以访问这个页面:https://oreil.ly/KSO。
电子邮件 bookquestions@oreilly.com 以评论或扣问有关此书的技能问题。
获取关于我们的书籍和课程的消息和信息,请访问:http://oreilly.com。
在 Facebook 上找到我们:http://facebook.com/oreilly
关注我们的 Twitter:http://twitter.com/oreillymedia
在 YouTube 关注我们:http://youtube.com/oreillymedia
致谢
写作本书是一次很棒的履历,没有几位人士的资助、支持和指导是不大概的。首先,我们要感谢 Project Calico 的社区、开发职员和维护者,是你们的创新和对 Kubernetes 及其安全性和可观测性的贡献,使我们能够写出这本书。Tigera 令人惊叹的工程和安全研究团队已构建生产品来解决安全和可观测性的复杂挑战,这使我们能够清晰地理解用户面对的挑战。在我们撰写本书的过程中,这些都非常有资助,以引导用户找到全面的安全和可观测性解决方案。
我们还要感谢那些提供意见和专业知识的审视者。他们的评论和指导极大丰富了本书内容。特别感谢 Manish Sampat、Alex Pollitt、Virginia Wilson、Seth Vargo、Tim Mackey、Ian Lewis、Puja Absassi 和 Jose Ruiz——你们太棒了!
末了,我们要感谢全部为 Kubernetes 安全性和可观测性做出贡献的社区成员。看到这个领域的创新令人惊叹,我们很高兴能参与到 Kubernetes 安全性和可观测性中去。
第一章:安全性和可观察性策略
在本章中,我们将概述您怎样为 Kubernetes 实施构建安全性和可观察性策略。后续章节将更具体地涵盖这些概念。在您的 Kubernetes 之旅的试点/预生产阶段,您须要考虑安全策略,因此假如您是安全团队的一部分,本章非常重要。假如您是网络、平台或应用团队的一部分,本章展示了您怎样成为安全策略的一部分,并讨论了安全、平台和应用团队之间合作的重要性。
我们将涵盖以下概念,指导您订定安全性和可观察性策略:
- 怎样保护 Kubernetes 与传统安全方法有所不同
- 在 Kubernetes 集群中摆设应用步伐(工作负载)的生命周期以及每个阶段的最佳实践
- 您应该怎样实施可观察性以资助安全。
- 知名的安全框架以及怎样在安全策略中使用它们
Kubernetes 的安全性:一个新的不同天下
在本节中,我们将强调 Kubernetes 的不同之处以及为什么传统的安全方法在 Kubernetes 实施中不起作用。
随着工作负载转移到云端,Kubernetes 是最常见的编排器来管理它们。Kubernetes 受欢迎的缘故原由在于其声明性特质:它抽象了基础设施细节,并允许用户指定他们想要运行的工作负载和盼望的结果。应用团队不须要担心工作负载怎样摆设,工作负载在那里运行,或者像网络这样的其他细节;他们只须要在 Kubernetes 中设置设置来摆设他们的应用。
Kubernetes 通过管理工作负载的创建、关闭和重启来实现这种抽象。在典范的实现中,根据工作负载的要求,工作负载可以安排在网络中的任何可用资源(物理主机或捏造机)上。工作负载运行的一组资源被称为Kubernetes 集群。Kubernetes 监视工作负载的状态(在 Kubernetes 中摆设为 pod)并根据须要采取纠正措施(例如,重新启动无响应的节点)。它还管理全部须要的网络以便 pod 和主机之间进行通信。您可以通过从一组支持的网络插件中进行选择来决定网络技能。虽然有一些网络插件的设置选项,但您将无法直接控制网络行为(无论是用于 IP 地址分配还是在典范设置中节点被调度的情况)。
对于安全团队来说,Kubernetes 是一个全新的天下。他们传统的方法是构建一个“呆板网络”,然后启用工作负载(应用步伐)。在启用的过程中,须要分配 IP、根据须要更新网络设置,并定义和实施网络访问控制规则。完成这些步骤后,应用步伐就可以供用户使用了。这个过程确保安全团队有很大的控制权,而且可以轻松地启用和保护应用步伐。由于应用步伐的 IP 分配、摆设位置等方面都是静态的,因此应用步伐也更容易保护。
在 Kubernetes 环境中,工作负载作为容器镜像构建,并使用设置文件(yaml)在 Kubernetes 集群中摆设。这通常集成在开发过程中,大多数开发团队使用持续集成(CI)和持续交付(CD)来确保软件的快速可靠交付。这意味着安全团队对每个应用步伐变动对集群安全的影响具有有限的可见性。在此过程中添加安全审查步骤是不可取的,因为唯一合理的地方是在提交代码时进行。此后的开发过程是自动化的,打断它会与 CI/CD 模型冲突。那么在这种环境下怎样保护工作负载呢?
为了相识怎样在 Kubernetes 中保护工作负载,相识摆设工作负载的各个阶段黑白常重要的。
在 Kubernetes 中摆设工作负载:每个阶段的安全性
在前一节中,我们描述了使用 CI/CD 管道摆设应用步伐时面对的安全挑战。本节描述了 Kubernetes 集群中工作负载摆设的生命周期,并解释了怎样保护每个阶段。工作负载摆设的三个阶段是构建、摆设和运行时阶段。与传统的客户端-服务器应用步伐不同,在 Kubernetes 摆设中,应用步伐是分布式的,而且 Kubernetes 集群网络作为正常操作的一部分被应用步伐使用。由于这种设置,须要考虑以下几点:
- 在构建工作负载和基础设施时,须要考虑安全最佳实践。这一点非常重要,因为 Kubernetes 中的应用步伐是通过 CI/CD 管道摆设的。
- 在摆设 Kubernetes 集群和应用步伐时,须要考虑安全最佳实践。
- 末了,应用步伐使用基础设施和 Kubernetes 集群网络进行正常操作,须要考虑应用步伐运行时的安全最佳实践。
图 1-1 描述了在 Kubernetes 环境中保护工作负载时须要考虑的各个阶段和方面。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0101.png
图 1-1. 工作负载摆设阶段及每个阶段的安全性
每个阶段下方的框描述了您须要考虑该阶段的各个安全方面:
- 构建阶段是您为工作负载(应用步伐)创建(构建)软件并构建基础设施组件(主机或捏造机)以托管应用步伐的阶段。此阶段是开发周期的一部分,在大多数情况下由开发团队负责。在此阶段,您须要考虑 CI/CD 管道的安全性,实施镜像库的安全性,扫描镜像中的毛病,并加固主机操作系统。您须要确保实施最佳实践以保护镜像注册表,并避免影响镜像注册表中的镜像。通常通过保护对镜像注册表的访问来实现这一点,尽管许多用户拥有私有注册表,而且不允许来自公共注册表的镜像。末了,您须要考虑密钥管理的最佳实践;密钥类似于暗码,允许访问集群中的资源。我们将在第三章中具体讨论这些主题。我们建议,在考虑此阶段的安全性时,您应与安全团队合作,以使此阶段的安全性与您的整体安全策略保持同等。
- 接下来的阶段是摆设阶段,在此阶段您设置运行 Kubernetes 摆设的平台并摆设工作负载。在此阶段,您须要考虑设置 Kubernetes 集群的安全最佳实践,以及为在 Kubernetes 集群内运行的应用步伐提供外部访问的安全控制。您还须要考虑安全控制,例如限定对工作负载的访问(Pod 安全策略)、网络策略以控制应用步伐对平台组件的访问以及基于脚色的访问控制(RBAC)以访问资源(例如服务创建、命名空间创建和向 Pod 添加/更改标签)。在大多数企业中,平台团队负责此阶段。作为平台团队的一员,您须要与开发团队和安全团队合作,实施您的安全策略。
- 末了一个阶段是运行时阶段,在此阶段您已摆设了应用步伐而且它正在运行。在此阶段,您须要考虑网络安全,涉及使用网络策略进行控制、威胁防御(使用技能检测和防备集群中的恶意活动)以及企业安全控制,如合规性、审计和加密。安全团队负责此摆设阶段。作为安全团队的一员,在设计和实施运行时安全时,您须要与平台和开发团队合作。团队之间的协作(开发、平台和安全)对于建立有效的安全策略非常重要。我们建议您确保全部这些团队保持同等。
请注意,与传统的安全策略不同,传统安全策略在关键点(如边界)强制实行安全性,而在 Kubernetes 集群的情况下,您须要在每个阶段实施安全性。此外,全部参与的团队(应用步伐、平台和安全团队)在实施安全性方面都起着非常重要的作用,因此乐成实施策略的关键是团队之间的协作。记着,安满是一种共同责任。让我们探讨每个阶段及您可以使用的构建策略的技能。
构建时安全性:向左移动
本节将指导您通过示例相识构建时安全性的各个方面。
映像扫描
在这个阶段,您须要确保应用步伐没有任何已公开的主要未修补问题,这些问题在国家毛病数据库中被披露为常见的毛病枚举 (CVEs),而且须要扫描应用步伐代码和依赖项以查找使用步伐和易受攻击的代码段。然后对构建和交付为容器的映像进行扫描,以检测未修补的严重或主要毛病,这些毛病被披露为 CVEs。通常通过将基础映像及其全部软件包与跟踪易受攻击软件包的数据库进行对比来实行此操作。为了实施扫描,您可以使用几种开源和贸易工具。例如,Whitesource、Snyk、Trivy、Anchor,甚至像谷歌这样的云提供商都提供容器映像的扫描功能。我们建议您选择一个理解容器构建方式并不仅仅扫描主机操作系统,还扫描容器基础映像的扫描解决方案。考虑到 Kubernetes 摆设的动态性子,保障 CI/CD 管道的安全非常重要;代码和映像扫描必须成为管道的一部分,而且必须检查从映像注册表交付的映像是否受到妥协。您须要确保对注册表的访问受到控制,以避免妥协。这个阶段的盛行术语是“向左移动安全性”,也被称为“向左移动安全性”。
主机操作系统的加固
在这里,您必须确保被摆设的应用步伐仅限于在其摆设的主机上具有所需的权限。为此,您应该使用支持控制以仅允许限定应用步伐对系统调用和文件系统访问的须要权限的强化主机操作系统。这样可以有效地减轻与“特权升级”干系的攻击,即使用容器中摆设的软件中的毛病来访问主机操作系统。
减少攻击面:基础容器镜像
我们建议您审查容器镜像的组成,并最小化构成基础镜像的软件包,只包括您的应用步伐运行所绝对必需的软件包。在基于 Dockerfile 的容器镜像中,您可以从一个父镜像开始,然后将您的应用步伐添加到镜像中以创建一个容器镜像。例如,您可以使用 FROM scratch 指令在 Docker 中构建一个基础镜像,这将创建一个最小的镜像。然后,您可以添加您的应用步伐和必需的软件包,这将让您完全控制容器镜像的组成,而且有助于 CVE 管理,因为您无需担心在容器镜像中不须要的软件包中修补 CVE。假如构建一个 scratch 镜像不可行,您可以考虑从 distroless 镜像(一个精简的 Linux 发行版镜像)或 Alpine 最小镜像作为容器的基础镜像开始。
这些技能将资助您设计和实施构建时安全策略。作为开发团队的一部分,您将负责与平台和安全团队合作设计和实施构建时安全,以确保与整体安全策略同等。我们提醒不要信托“左移安全”可以成为您整个安全策略的全部。这是不精确的,是保护工作负载的一种幼稚方法。另有其他几个重要方面,如摆设和运行时安全,也须要作为安全策略的一部分考虑进去。
摆设时安全
保护工作负载的下一阶段是保护摆设。为了实现这一点,您须要加固您摆设工作负载的 Kubernetes 集群。您须要具体审查 Kubernetes 集群设置,以确保与安全最佳实践保持同等。首先,建立一个信托模型来评估集群的各个组件。信托模型是一个框架,您在此中审查威胁概况并定义响应机制。您应该使用诸如基于脚色的访问控制(RBAC)、标签分类法、标签管理和准入控制等工具来设计和实施信托模型。这些是控制资源访问、在资源创建时应用控制和验证的机制。这些主题在第三章、第四章和第七章中有具体覆盖。集群中的另一个关键组件是 Kubernetes 数据存储和 Kubernetes API 服务器,在设计这些组件的信托模型时,您须要特别注意访问控制和数据安全等细节。我们建议您使用强暗码、公钥基础设施(PKI)进行访问以及传输层安全(TLS)进行数据传输加密。有关怎样保护 Kubernetes API 和数据存储的具体信息,请参阅第二章。
您应该将摆设关键任务负载的 Kubernetes 集群视为一个实体,然后为该实体设计信托模型。这要求您审查边界的安全控制,由于 Kubernetes 摆设架构的复杂性,这将是一个具有挑战性的任务;我们将在下一节中具体介绍这一点。目前,让我们假设当前摆设在边界的产品,如 Web 访问控制网关和下一代防火墙,对 Kubernetes 架构并不相识。我们建议您通过与这些设备建立集成来解决这个问题,使它们相识 Kubernetes 集群的上下文,从而能够有效地在边界应用安全控制。这样一来,您可以创建一个非常有效的安全策略,此中边界安全设备与 Kubernetes 集群内实施的安全控制协同工作。例如,假设您须要使这些设备相识您的工作负载的身份(IP 地址、TCP/UDP 端口等)。这些设备可以有效地保护构成您 Kubernetes 集群的主机,但在大多数情况下,它们无法区分单个主机上运行的工作负载。假如您在云提供商环境中运行,您可以使用安全组,这些是允许对一组节点(例如 Amazon Web Services 中的 EC2 实例)进行访问控制的捏造防火墙,这些节点承载工作负载。安全组比传统防火墙和安全网关更符合 Kubernetes 架构;然而,纵然是安全组也不相识集群内运行工作负载的上下文。
总结一下,当您考虑摆设时间安全性时,您须要为 Kubernetes 集群实施信托模型,并与保护集群的边界安全设备建立有效的集成。
运行时安全性
现在您已经订定了保护构建和摆设阶段的策略,须要考虑运行时安全性。术语运行时安全性用于描述保护 Kubernetes 集群的各个方面,例如在运行软件的主机上,但任何保护主机和工作负载免受未经授权活动的设置(例如系统调用、文件访问)也被称为运行时安全性。第四章将具体介绍主机和工作负载的运行时安全性。在本节中,我们将专注于确保 Kubernetes 集群网络安全运行所需的安全最佳实践。Kubernetes 是一个编排器,可以在主机网络上摆设工作负载和应用步伐。您必须将网络安全性视为运行时安全性的一个非常重要的方面。
Kubernetes 承诺提升机动性和更有效地使用计算资源,相比于静态分区和服务器或捏造机的预配。它通过在集群中动态调度工作负载来实现这一点,考虑每个节点上的资源使用情况,并在平面网络上毗连工作负载。默认情况下,当摆设新工作负载时,相应的 Pod 可以被调度到集群中的任何节点,并使用 Pod IP 地址中的任何 IP 地址。假如稍后将 Pod 重新调度到其他地方,则通常会得到不同的 IP 地址。这意味着 Pod IP 地址须要视为暂时的。Pod IP 地址或其在网络中的位置没有恒久或特别的意义。
现在考虑传统的网络安全方法。在企业网络中,网络安全通常使用安全设备(或设备的捏造版本),如防火墙和路由器来实现。这些设备强制实行的规则通常基于网络的物理拓扑结构以及为不同种别的工作负载分配特定 IP 地址范围的组合。
由于 Kubernetes 基于平面网络,而且 Pod IP 地址没有任何特别含义,很少有传统设备能够提供有意义的工作负载感知的网络安全,而是不得不将整个集群视为单个实体。此外,在同一节点上托管的两个 Pod 之间的东西流量甚至不会经过底层网络。因此,这些设备根本看不到这些流量,基本上只能限定于北向安全,即保护从外部源进入集群的流量以及从集群内部源到外部源的流量。
鉴于这统统,很明显 Kubernetes 须要一种新的网络安全方法。这种新方法须要涵盖广泛的考虑因素,包括:
- 新方法来实行网络安全(允许哪些工作负载与哪些其他工作负载通信),不依赖于 IP 地址或网络拓扑的特别含义,而且纵然流量不经过底层网络也能工作;Kubernetes 网络策略旨在满意这些需求。
- 新工具资助管理支持新开发流程和微服务愿景的网络策略,以增加组织的机动性,例如策略保举、策略影响预览和策略分阶段。
- 新方法来监视和可视化网络流量,涵盖集群范围的整体视图(例如怎样轻松查看整体网络和集群的网络安全状态)以及针对微服务序列进行深入分析以资助清除故障或诊断应用步伐问题的有针对性拓扑视图。
- 实施入侵检测和威胁防御的新方法,包括违规策略警报、网络异常检测和集成威胁源。
- 新的修复工作流程,以便在法医观察期间可以快速安全地隔离潜在受损的工作负载。
- 审计设置和策略变动以符合合规要求的新机制。
- 审计设置和策略变动的新机制,以及 Kubernetes 感知的网络流日志以满意合规性要求(因为传统的网络流日志是基于 IP 的,在 Kubernetes 上下文中恒久意义不大)。
我们将审查一个典范的企业 Kubernetes 摆设示例,以相识这些挑战。 图 1-2 是多云环境中 Kubernetes 和微服务的常见摆设模型的表示。多云环境是指企业在多个云服务提供商(如亚马逊网络服务、谷歌云等)上摆设 Kubernetes 的情况。混淆云环境指企业在至少一个云服务提供商的环境中摆设 Kubernetes,而且在其数据中心内摆设 Kubernetes。大多数企业都有双云战略,并将在亚马逊网络服务(AWS)、微软 Azure 或谷歌云上运行集群;更多企业还在其数据中心运行一些传统应用步伐。数据中心的工作负载大概位于安全网关后,该网关通过过滤进入的流量来保护外围。在这些 Kubernetes 摆设中运行的微服务也大概对以下一种或多种依赖有所依赖:
- 其他云服务,如 AWS RDS 或 Azure DB
- Twilio 品级三方 API 终端
- SaaS 服务,如 Salesforce 或 Zuora
- 数据库或在数据中心内运行的传统应用步伐
数据中心的工作负载大概位于安全网关后,该网关通过过滤进入的流量来保护外围。
可观察性 在 Kubernetes 中是通过网络的度量标准获取有关 Kubernetes 状态的可行见解的能力(稍后详述)。虽然可观察性另有其他应用,比如监视和故障清除,但在网络安全的背景下也很重要。将应用于流日志的可观察性概念与其他 Kubernetes 元数据(Pod 标签、策略、命名空间等)干系联,用于监视(然后保护)Kubernetes 集群中的 Pod 之间的通信,通过比较 IP 地址与已知恶意 IP 地址来检测恶意活动,并使用基于呆板学习的技能来检测恶意活动。这些主题将在下一节中具体介绍。正如您在 图 1-2 中所见,Kubernetes 的摆设由于每个集群中的数据孤立以及将一个集群中的工作负载与另一个集群或外部服务的工作负载关联起来大概导致的可见性损失而面对挑战。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0102.png
图 1-2. 企业中 Kubernetes 摆设示例
如图 1-2 所示,微服务应用步伐的足迹通常延伸到捏造私有云(VPC)边界之外,保护这些应用步伐须要一种不同于传统周界安全方法的方法。它是网络安全控制、可观察性、威胁防御和企业安全控制的组合。接下来我们将具体介绍每一个。
网络安全控制
云提供商提供的当地安全控制(例如 AWS 安全组或 Azure 网络安全组)或位于 VPC 或数据中心周边的安全网关(例如下一代防火墙)并不理解 Kubernetes 集群内微服务的身份。例如,您不能使用安全组规则或防火墙策略来过滤与 Kubernetes pod 或服务之间的流量。此外,从 pod 发送的流量到达云提供商的网络或第三方防火墙时(根据云提供商的架构),流量会应用源网络地址转换(SNAT)。换句话说,从节点上全部工作负载的流量的源 IP 地址都设置为节点 IP,因此,最多只能具有节点级别(节点的 IP 地址)的允许/拒绝策略粒度。
Kubernetes 工作负载具有高度动态和短暂的特性。假设开发职员提交了一个特定工作负载的新检入。自动化的 CI/CD 工作流将启动,构建一个新版本的 pod(容器),并开始在 Kubernetes 集群中摆设这个新版本的工作负载。Kubernetes orchestrator 将进行滚动升级并摆设工作负载的新实例。全部这些都是自动化进行的,没有手动或带外工作流重新设置新摆设工作负载的空间。
你须要一种新的安全架构来保护在多云或混淆云基础设施中运行的工作负载。就像你在 Kubernetes 集群中摆设工作负载一样,工作负载的安全性必须以代码情势定义,采用声明性模型。安全控制必须能够跨 Kubernetes 发行版、云、基础设施和/或网络进行移植。这些安全控制必须随着工作负载一起移动,因此,假如工作负载的新版本在 Amazon Elastic Kubernetes Service(EKS)的 VPC 上摆设,而不是在当地集群上摆设,您可以放心,与服务干系的安全控制将无缝实行,而无需重新设计任何网络拓扑、超出带外设置的安全组或 VPC/周界防火墙。
网络安全控制通过使用 Kubernetes 原生的网络策略解决方案实施,提供精细的访问控制。有几种众所周知的网络策略实现(例如 Calico,Weave Net,Kube-router,Antrea)可供选择使用。除了在第 3/第 4 层(TCP/IP)应用策略外,我们建议您查看支持应用层策略(例如 HTTP/HTTPS)的解决方案。我们还建议选择基于盛行的代理 Envoy 的解决方案,因为它广泛用于应用层策略。Kubernetes 支持将应用步伐摆设为微服务(服务应用步伐功能的小组件),分布在节点网络上。微服务之间的通信依赖于应用步伐协议如 HTTP。因此,有须要实施可以通过应用层策略实现的精细应用步伐控制。例如,在三层应用步伐中,前端微服务大概只允许与后端数据库微服务使用基于 HTTP GET 的哀求(读访问),而不允许与后端数据库微服务使用 HTTP POST(写访问)。全部这些哀求终极可以使用相同的 TCP 毗连,因此必须添加支持所述应用层控制的策略引擎是至关重要的。
企业安全控制
现在您已经定义了网络访问控制和可观察性策略,应考虑其他重要且在企业中广泛存在的安全控制措施。在数据传输中加密是安全和合规的关键要求。有几种选择可以考虑使用传统方法进行加密,比如在您的工作负载中使用基于 TLS 的加密;双向 TLS,它是服务网格平台的一部分;或者基于 VPN 的方法,比如提供基于加密密钥的 VPN 的 Wireguard。
我们建议您使用观察策略的数据网络来天生所需的报告,以资助满意 PCI、HIPAA、GDPR 和 SOC 2 等标准的合规要求。您还应考虑确保持续合规性的能力,可以使用 Kubernetes 的声明性特性来协助设计和实施持续合规性。例如,您可以通过使用 Pod 的合规性状态来响应未通过合规性检查的 Pod,触发须要的操作以纠正情况(触发镜像更新)。
威胁防御
Kubernetes 集群中的威胁防御是查看集群中的恶意活动并防御其的能力。恶意活动允许对手未经授权访问并操纵或窃取 Kubernetes 集群中的数据。恶意活动可以采用多种情势,例如使用不安全的设置或使用应用步伐流量或应用步伐代码中的毛病。
在构建威胁防御策略时,您必须考虑入侵检测和防备两个方面。入侵检测的关键在于可观察性;您须要回顾网络的数据以扫描已知威胁。在 Kubernetes 摆设中,由于您须要检查的数据量很大,数据网络非常具有挑战性。我们常常听到这样的问题:“我须要一个 Kubernetes 集群来网络数据以保护 Kubernetes 集群吗?”答案是“不须要”。我们建议您将可观察性策略与入侵检测保持同等,并使用智能聚合来网络和检查数据。例如,您可以考虑使用一种工具,将数据聚合为“类似”pod 组,这些 pod 在给定目标端口和协议上相互通信,而不是使用传统的五元组(源 IP、源端口、目标 IP、目标端口、协议)聚合方法。这种方法将有助于显著减少网络的数据量,而不会牺牲效果。请记着,运行相同容器镜像并以相同方式摆设的多个 pod 将为交易天生相同的网络流量。您大概会问,“假如只有一个实例被感染怎么办?怎样检测到?”这是一个很好的问题。有几种方法可以解决。您可以选择一个支持基于各种指标(如毗连、字节和数据包)网络的呆板学习的工具来检测异常工作负载。另一种方法是使用工具,作为网络的一部分检测和匹配来自知名威胁源的已知恶意 IP 和域名,或记录未聚合的由策略拒绝的网络流量。这些都是资助您构建策略的简单技能。请注意,威胁防御技能在不断发展,您须要与安全研究团队合作,资助理解您的应用步伐并构建威胁模型,以实施您的威胁防御策略。
可观察性
可观察性对于监控和保障像 Kubernetes 这样的分布式系统非常有用。Kubernetes 抽象了许多细节,在监视这样的系统时,您不能单独网络和独立基线化和监视各个指标(如单个网络流,pod 创建/销毁变乱或一个节点上的 CPU 峰值)。须要的是一种在 Kubernetes 上下文中监视这些指标的方法。例如,一个与服务或摆设干系联的 pod 被重新启动,并作为其对等体的不同二进制运行,或者与摆设中的其他 pod 的活动(网络,文件系统,内核系统调用)不同。当考虑由多个服务(微服务)组成的应用时,情况变得更加复杂,这些服务又由多个 pod 支持。
可观察性在故障清除和监控 Kubernetes 工作负载的安全性方面非常有用。例如,在 Kubernetes 服务的上下文中,可观察性将允许您实行以下操作:
- 将您的 Kubernetes 集群可视化为服务图,显示 Pod 怎样与服务干系联及服务之间的通信流量。
- 在服务图上叠加应用步伐(第 7 层)和网络流量(第 3/第 4 层)作为独立层,这将使您能够轻松确定应用步伐和底层网络的流量模式和流量负载。
- 查看摆设有 Pod 的节点的元数据(例如 CPU、内存或主机操作系统详情)。
- 查看与 Pod 操作、流量负载、应用延迟(例如 HTTP 持续时间)、网络延迟(网络来回时间)或 Pod 操作(例如 RBAC 策略、服务账户或容器重启)干系的指标。
- 查看给定服务(支持该服务的 Pod)的 DNS 活动(DNS 响应代码、延迟、负载)。
- 追踪跨多个服务进行通信的用户事务;这也被称为分布式跟踪。
- 查看给定服务与外部实体的网络通信。
- 查看与给定服务干系的 Pod 和资源的 Kubernetes 活动日志(例如审计日志)。
我们将在后续章节具体介绍可观测性的细节及其怎样资助安全性。在本讨论中,我们将简要描述怎样将可观测性作为安全策略的一部分使用。
网络流量可见性
如前所述,须要一个解决方案,它提供以服务级别汇总的网络流量,并提供如命名空间、标签、服务账户或网络策略等上下文,以充实监视集群中应用的活动和应用的访问控制。例如,报告 IP1 与 IP2 在端口 8080 上通信与报告标记为“前端”和“后端”的 Pod 在 Kubernetes 集群中的特定端口或流量模式之间的通信有显著差异。此报告将允许您审查来自外部实体的通信,并应用基于 IP 地址的威胁源来检测来自已知恶意 IP 地址的活动,甚至来自意外地理位置的流量。我们将在第十一章中具体介绍这些概念。
DNS 活动日志
域名系统(DNS)是将域名转换为 IP 地址的系统。在您的 Kubernetes 集群中,审查 DNS 活动日志至关重要,以检测意外活动,例如查询已知恶意域的情况、DNS 响应代码如 NXDOMAIN,以及 DNS 查询中字节和数据包的意外增加。我们将在第十一章中具体介绍这些概念。
应用步伐流量可见性
我们建议您审查应用步伐流量,以寻找异常活动,快意外的响应代码和罕见或已知的恶意 HTTP 头部(用户代理,查询参数)。在 Kubernetes 摆设中,HTTP 是最常用的协议,因此重要的是与您的安全研究团队合作,监控 HTTP 流量以检测恶意流量。假如您使用其他应用步伐协议(例如 Kafka、MySQL),同样须要进行相同的操作。
Kubernetes 活动日志
除了网络活动日志外,您还必须监视 Kubernetes 活动日志以检测恶意活动。例如,审查资源访问拒绝日志以及服务账户创建/修改。审查命名空间创建/修改日志以寻找意外活动。并审查记录对 Kubernetes API 哀求的审计日志。
呆板学习/异常检测
呆板学习是一种技能,系统能够通过数据在一段时间内推导出模式。输出结果是一个呆板学习模型,然后可以用于预测和基于预测检测实际数据中的毛病。我们建议您考虑将基于呆板学习的异常检测应用于各种指标,以检测异常活动。一种简单有效的方法是对单独的指标应用称为基线设定的呆板学习技能。这样您就不须要担心为每个指标应用规则和阈值;系统会为您实行这些操作并将毛病报告为异常。将呆板学习技能应用于网络流量是一个相对新的领域,而且正在得到安全团队的关注。我们将在第六章具体讨论这个主题。
对于 Kubernetes 的可观测性策略,您可以选择许多解决方案(如 Datadog、Calico Enterprise、来自 Google、AWS、Azure 的基于云提供商的解决方案)。
安全框架
末了,我们渴望让您相识安全框架,这些框架为行业提供了安全最佳实践的共同方法和术语。安全框架是理解攻击技能和最佳实践以防御和减轻攻击的良好途径。您应该使用它们来构建和验证您的安全策略。请注意,这些框架大概不特定于 Kubernetes,但它们提供了有关对手在攻击中使用的技能的见解,安全研究职员须要审查并确定它们是否与 Kubernetes 干系。我们将回顾两个知名框架——MITRE 和 Kubernetes 威胁矩阵。
MITRE
MITRE 是基于对网络攻击的实际观察而建立的对手战术和技能知识库。企业版 MITRE ATT&CK® 矩阵非常有用,因为它为每个网络安全杀伤链的阶段提供了分类的战术和技能。杀伤链描述了网络攻击的各个阶段,对于构建有效的防御措施非常有用。MITRE 还提供了针对 AWS、Google Cloud 和 Microsoft Azure 等云环境的攻击矩阵。
图 1-3 描述了适用于 AWS 的 MITRE ATT&CK® 矩阵。我们建议您查看攻击矩阵中描述的每个阶段,以便构建您的威胁模型,保护您的 Kubernetes 集群。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0103.png
图 1-3. AWS 云环境攻击矩阵
Kubernetes 的威胁矩阵
另一个框架是一种威胁矩阵,它是对通用 MITRE 攻击矩阵的 Kubernetes 特定应用。这是微软团队基于安全研究和实际攻击发布的。这是另一个优秀的资源,用于构建和验证您的安全策略。
图 1-4 提供了与您的 Kubernetes 集群干系的各个阶段。它们映射到我们在本章讨论的各个阶段。例如,您应该考虑初始访问阶段中注册表中的受损镜像,特权升级阶段中的访问云资源,以及构建、摆设和运行时安全性的侧向移动阶段中的集群内部网络。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0104.png
图 1-4. Kubernetes 的威胁矩阵
安全性和可观察性
在像 Kubernetes 这样的动态环境中,通过同时考虑安全性和可观察性,可以实现应用步伐的安全摆设。例如,你须要“观察”你的集群,找到实施控制以保护集群的最佳方式。作为编排引擎,Kubernetes 具有强大的采用率,因为它具有声明性的特性,允许用户指定更高级别的结果。Kubernetes 还具有内置功能,以确保您的集群按照规范运行。它通过监视各种属性并采取行动(例如,重新启动 pod)来实现这一点,假如属性偏离指定值一段时间,就会采取行动。Kubernetes 的这些方面使得实施确保集群安全所需的可见性和控制变得困难。你实施的控制须要与 Kubernetes 运营保持同等。因此,在考虑向 Kubernetes 添加任何控制之前,相识上下文非常重要——例如,你不能通过应用不允许其与其他任何元素通信的策略来隔离一个 pod。Kubernetes 将检测到 pod 无法与其他元素(例如,API 服务器)通信,确定 pod 未按规定操作,然后重新启动并在集群的其他位置启动 pod。
你须要做的第一件事是先相识 pod 的运行方式,相识其预期操作是什么,然后应用控制或检测意外变乱。之后,你须要确定意外变乱是运营问题还是安全问题,然后应用所需的补救措施。为了做到这一点,可观察性和安全性须要并重:你观察以相识预期情况并应用控制以确保预期操作,然后观察以检测意外变乱并分析它们,然后添加须要的控制以补救由变乱引起的任何问题。因此,在考虑保护你的集群时,你须要一种全面的安全和可观察性方法。
结论
到目前为止,你应该对 Kubernetes 安全性和可观察性的高层概述有了相识。这些是支撑整本书的基本概念。简而言之:
- Kubernetes 的安全性与传统安全性非常不同,而且在工作负载摆设的全部阶段——构建、摆设和运行时都须要一种全面的安全性和可观察性方法。
- Kubernetes 是声明性的,并抽象了工作负载操作的细节,这意味着工作负载可以在节点网络的任何地方运行。此外,工作负载大概是短暂的,它们会在不同节点上被销毁并重新创建。保护这样的声明式分布式系统须要你在全部阶段考虑安全性。
- 我们渴望你理解在设计和实施全面安全方法时,应用步伐、平台和安全团队之间合作的重要性。
- MITRE和 Kubernetes 的威胁矩阵是广泛被安全团队采取的两个安全框架。
重要的是要将全部内容整合在一起,因为乐成的安全和可观察性策略是一体化的。在接下来的章节中,我们将涵盖基础设施安全。
第二章:基础设施安全
许多 Kubernetes 设置在默认情况下是不安全的。在本章中,我们将探讨怎样在基础设施级别保护 Kubernetes。通过加固主机使托管 Kubernetes 的服务器或捏造机更加安全,加固集群以保护 Kubernetes 控制平面组件,并进行网络安全设置以将集群与四周基础设施集成,可以使其更加安全。请注意,本章讨论的概念适用于自托管 Kubernetes 集群以及托管 Kubernetes 集群。
主机加固
这涵盖了操作系统的选择,避免在主机上运行非须要进程以及基于主机的防火墙设置。
集群加固
这涵盖了一系列设置和策略设置,用于加固控制平面,包括设置 TLS 证书,锁定 Kubernetes 数据存储,加密静态密钥,凭证轮换,以及用户认证和访问控制。
网络安全
这涵盖了安全地将集群与四周基础设施集成,特别是允许集群与四周基础设施之间的网络交互,用于控制平面、主机和工作负载流量。
让我们具体看看每个方面的细节,并探讨构建安全基础设施以保护您的 Kubernetes 集群所需的内容。
主机加固
安全的主机是安全 Kubernetes 集群的重要基石。当您考虑主机时,它是在构成 Kubernetes 集群的工作负载背景下。现在我们将探讨确保主机具有强大安全姿态的技能。
操作系统的选择
许多企业在其全部基础设施上标准化使用单一操作系统,这意味着大概已经为您做出了选择。但是,假如有选择操作系统的机动性,那么考虑专为容器设计的当代不可变 Linux 发行版是值得的。这些发行版有以下优势:
- 它们通常具有更新的内核,包括最新的毛病修复以及最新技能(如 eBPF)的实现,这些技能可以被 Kubernetes 网络和安全监控工具使用。
- 它们设计为不可变,这在安全方面带来了额外的好处。在此上下文中,不可变性意味着根文件系统被锁定,应用步伐无法更改。只能使用容器安装应用步伐。这将应用步伐与根文件系统隔离,并显著减少了恶意应用步伐破坏主机的能力。
- 它们通常包括自动更新到较新版本的能力,上游版本已预备好快速发布以解决安全毛病。
设计用于容器的当代不可变 Linux 发行版的两个盛行示例是 Flatcar Container Linux(最初基于 CoreOS Container Linux)和 Bottlerocket(最初由亚马逊创建和维护)。
无论您选择哪种操作系统,监视上游安全公告以便相识新发现的安全毛病,并确保您有适当的流程来更新您的集群到更新版本以解决关键的安全毛病,是一个良好的实践。根据您对这些毛病的评估,您将须要决定是否将集群升级到操作系统的新版本。在考虑操作系统选择时,您还必须考虑来自主机操作系统的共享库,并相识它们对将摆设在主机上的容器的影响。
另一个安全最佳实践是确保应用开发职员不依赖特定版本的操作系统或内核,因为这样将无法根据须要更新主机操作系统。
非须要进程
每个运行的主机进程都是黑客的潜在攻击向量。从安全的角度来看,最好是删除默认情况下大概正在运行的任何非须要进程。假如一个进程对于乐成运行 Kubernetes、管理您的主机或保护您的主机没有须要,则最好不要运行该进程。怎样禁用进程将取决于您的特定设置(例如,通过 systemd 设置更改或从 /etc/init.d/ 中删除初始化脚本)。
假如您正在使用针对容器优化的不可变 Linux 发行版,则已经消除了非须要进程,您只能作为容器运行额外的进程/应用步伐。
防火墙主机化
为了进一步锁定托管 Kubernetes 的服务器或捏造机,可以为主机本身设置当地防火墙规则,以限定允许与主机交互的 IP 地址范围和端口。
根据您的操作系统,可以使用传统的 Linux 管理工具,例如 iptables 规则或 firewalld 设置来实现这一点。重要的是确保这些规则与 Kubernetes 控制平面和您计划使用的 Kubernetes 网络插件兼容,以免壅闭 Kubernetes 控制平面、Pod 网络或 Pod 网络控制平面。精确设置这些规则并随时间保持其更新大概是一个耗时的过程。此外,假如使用不可变的 Linux 发行版,您大概无法直接使用这些工具。
幸运的是,一些 Kubernetes 网络插件可以资助解决这个问题。例如,几个 Kubernetes 网络插件,如 Weave Net、Kube-router 和 Calico,包括应用网络策略的能力。你应该审查这些插件,并选择一个也支持将网络策略应用于主机本身(而不仅仅是 Kubernetes Pod)。这样可以大大简化集群中主机的安全性,而且基本上与操作系统无关,包括与不可变 Linux 发行版一起使用。
始终研究最新的最佳实践
随着安全研究社区确定新的毛病或攻击向量,安全最佳实践随时间而演变。许多这些都有具体的在线文档,而且可以免费获取。
例如,互联网中心安全性维护了免费的 PDF 指南,具体说明了安全地设置许多常见操作系统所需的行动。称为 CIS 基准,它们是确保你覆盖了保护主机操作系统所需的许多重要行动的极好资源。你可以在他们的网站上找到 最新的 CIS 基准列表。请注意,另有针对 Kubernetes 的特定基准,我们将在本章后面讨论。
集群加固
Kubernetes 默认情况下是不安全的。因此除了加固组成集群的主机外,加固集群本身也非常重要。这可以通过 Kubernetes 组件和设置管理、身份验证和基于脚色的访问控制(RBAC),以及保持集群更新到最新的 Kubernetes 版本来实现,以确保集群具有最新的毛病修复。
保护 Kubernetes 数据存储
Kubernetes 使用 etcd 作为其主要数据存储。这是存储全部集群设置和盼望状态的地方。访问 etcd 数据存储与在全部节点上拥有 root 登录权限基本上是等效的。假如恶意用户获取了对 etcd 数据存储的访问权限,险些全部你在集群内实施的其他安全措施都将失效。他们将完全控制你的集群,包括在任何节点上以提升的权限运行任意容器的能力。
保护 etcd 的主要方法是使用 etcd 本身提供的安全功能。这些功能基于 x509 公钥基础设施(PKI),使用密钥和证书的组合。它们确保全部传输中的数据都使用 TLS 加密,而且全部访问都受到强暗码的限定。最好为不同 etcd 实例之间的对等通信设置一组根据(密钥对和证书),并为来自 Kubernetes API 的客户端通信设置另一组根据。作为此设置的一部分,etcd 还必须设置证书颁发机构(CA)的具体信息,用于天生客户端根据。
一旦精确设置了 etcd,只有拥有有效证书的客户端才能访问它。然后,您必须设置 Kubernetes API 服务器,使其能够使用客户端证书、密钥和证书颁发机构来访问 etcd。
您还可以使用网络级防火墙规则限定对 etcd 的访问,以便只能从 Kubernetes 控制节点(托管 Kubernetes API 服务器的节点)访问它。根据您的环境,可以使用传统防火墙、捏造云防火墙或在 etcd 主机上设置规则(例如支持主机端点保护的网络策略实施)来阻止流量。这最好是作为深度防御策略的一部分,与使用 etcd 的安全功能一起使用,因为仅通过防火墙规则限定访问并不能解决加密 Kubernetes 敏感数据在传输中的安全需求。
除了为 Kubernetes 安全地访问 etcd,建议不要将 Kubernetes etcd 数据存储用于除 Kubernetes 之外的任何其他用途。换句话说,不要在数据存储中存储非 Kubernetes 数据,也不要让其他组件访问 etcd 集群。假如正在运行使用 etcd 作为数据存储的应用步伐或基础架构(在集群内部或集群外部),最佳实践是为其设置单独的 etcd 集群。可以辩称的例外情况是,假如应用步伐或基础架构具有足够的特权,以至于其数据存储的妥协也会导致 Kubernetes 的完全妥协。还非常重要的是要保持 etcd 的备份,并确保备份的安全性,以便能够从失败(例如升级失败或安全变乱)中规复。
保护 Kubernetes API 服务器的安全性
在 etcd 数据存储之上的另一层,须要保护的下一个关键是 Kubernetes API 服务器。与 etcd 一样,可以使用 x509 PKI 和 TLS 来实现安全性。怎样以这种方式引导集群的具体步骤因您使用的 Kubernetes 安装方法而异,但大多数方法包括创建所需的密钥和证书并将其分发到其他 Kubernetes 集群组件的步骤。值得注意的是,某些安装方法大概为某些组件启用不安全的当地端口,因此重要的是熟悉每个组件的设置,以识别潜在的未安全流量,以便采取适当的安全措施。
在静止状态下加密 Kubernetes Secrets
Kubernetes 可以设置为加密存储在 etcd 中的敏感数据,例如 Kubernetes secrets。这样可以防止任何攻击者访问 etcd 或其离线副本(例如离线备份)时泄露这些秘密。
默认情况下,Kubernetes 不会对存储的秘密进行加密,当启用加密时,它仅在将秘密写入 etcd 时进行加密。因此,在启用静态加密时,重写全部秘密(通过标准 kubectl apply 或 update 命令)以触发其在 etcd 中的加密至关重要。
Kubernetes 支持各种加密提供步伐。根据加密最佳实践选择保举的加密方法非常重要。主推的选择是基于 AES-CBC 和 PKCS #7 的加密。这使用 32 字节密钥提供非常强大的加密,而且相对较快。有两种不同的提供步伐支持此加密:
- 完全在 Kubernetes 中运行并使用当地设置密钥的当地提供步伐。
- 使用外部密钥管理服务(KMS)的 KMS 提供步伐来管理密钥。
当地提供步伐将其密钥存储在 API 服务器的当地磁盘上。因此,假如 API 服务器主机受到攻击,则全部您的秘密都会受到威胁。根据您的安全立场,这大概是可以接受的。
KMS 提供步伐使用一种称为信封加密的技能。使用信封加密时,每个秘密都使用动态天生的数据加密密钥(DEK)进行加密。然后,DEK 使用由 KMS 提供的密钥加密密钥(KEK)进行加密,并将加密的 DEK 与 etcd 中加密的秘密一起存储。KEK 始终由 KMS 托管为中心的信托根,永久不会存储在集群中。大多数大型公共云提供商提供基于云的 KMS 服务,可用作 Kubernetes 中的 KMS 提供步伐。对于当地集群,可以使用第三方解决方案,如 HashiCorp 的 Vault,作为集群的 KMS 提供步伐。由于具体的实施方式有所不同,评估 KMS 怎样验证 API 服务器以及 API 服务器主机的妥协是否大概威胁到您的秘密,因此仅能提供有限的优势,相比当地加密提供步伐。
假如预计有异常高量的加密存储读/写操作,则使用 secretbox 加密提供步伐大概会更快。但是,secretbox 是一种较新的标准,在撰写时的审查较少。因此,在须要高程度审查的环境中,大概不被认为是可接受的。此外,KMS 提供步伐尚不支持 secretbox,必须使用当地提供步伐,将密钥存储在 API 服务器上。
加密 Kubernetes 秘密是最常见的必须在静态时加密要求,但请注意,假如须要,还可以设置 Kubernetes 以加密其他 Kubernetes 资源的存储。
值得注意的是,假如您有超出 Kubernetes secrets 能力范围的需求,可以使用第三方的秘密管理解决方案。此中一个这样的解决方案,已被提及作为 Kubernetes 中信封加密的潜在 KMS 提供者,是 HashiCorp 的 Vault。除了为 Kubernetes 提供安全的秘密管理外,Vault 还可以在企业范围内更广泛地管理秘密,假如须要的话。Vault 还是早期 Kubernetes 版本中弥补重要差距的非常受欢迎的选择,这些版本不支持加密处于静态状态的秘密。
频繁轮换根据
频繁地轮换根据使攻击者更难使用大概得到的任何被泄露的根据。因此,设置任何 TLS 证书或其他根据的短寿命并自动化其轮换是最佳实践。大多数身份验证提供步伐可以控制签发证书或服务令牌的有效期多长时间,尽大概使用短的生命周期是最佳的,例如每天轮换密钥或假如特别敏感则更频繁。这须要包括用于外部集成或作为集群引导过程的任何服务令牌。
完全自动化根据的轮换大概须要定制的 DevOps 开发工作,但通常与尝试定期手动轮换根据相比,代表了一个很好的投资。
在对存储在静态状态下的 Kubernetes secrets 进行密钥轮换时(如前一节讨论的),当地提供步伐支持多个密钥。第一个密钥始终用于加密任何新的秘密写入。对于解密,密钥按次序尝试,直到乐成解密秘密。由于密钥仅在写入时进行加密,因此重写全部秘密(通过标准的 kubectl apply 或更新命令)以触发使用最新密钥进行加密是很重要的。假如秘密的轮换是完全自动化的,则写入将作为此过程的一部分而发生,无需单独步骤。
当使用 KMS 提供者(而不是当地提供者)时,可以轻松地轮换 KEK 而无需重新加密全部秘密,这可以减少重新加密大量巨细适当的秘密时的性能影响。
认证和 RBAC
在前面的部分中,我们主要关注在集群内部保障步伐化/代码访问的安全性。同样重要的是要遵循最佳实践,以保障用户与集群的交互。这包括为每个用户创建单独的用户账户,并使用 Kubernetes RBAC 为用户授予他们实行脚色所需的最小访问权限,遵循最小特权访问原则。通常最好使用组和脚色来实现这一点,而不是为个别用户分配 RBAC 权限。这样做可以更轻松地随着时间调整不同用户组的权限,同时减少定期审查/考核集群中用户权限是否精确和最新的工作量。
Kubernetes 对于用户有限的内置认证能力,但可以与大多数外部企业认证提供者集成,如公共云提供商的 IAM 系统或当地认证服务,可以直接或通过第三方项目(如最初由 CoreOS 创建的 Dex)。通常建议与此中一个外部认证提供者集成,而不是使用 Kubernetes 基本认证或服务账户令牌,因为外部认证提供者通常具有更友爱的根据轮换支持,包括指定暗码强度和轮换频率时间段的能力。
限定云元数据 API 访问
大多数公共云提供了一个可从每个主机/VM 实例当地访问的元数据 API。这些 API 提供对实例的云根据、IAM 权限和实例大概具有的其他潜在敏感信息的访问。默认情况下,这些 API 可由运行在实例上的 Kubernetes Pod 访问。任何被攻击的 Pod 都可以使用这些根据提升其在集群内的预期特权级别,或者访问实例大概具有权限访问的其他云提供商托管服务。
解决这个安全问题的最佳实践是:
- 根据云提供商的保举机制提供任何须需的 Pod IAM 根据。例如,Amazon EKS 允许您为服务账户分配唯一的 IAM 脚色,Microsoft Azure 的 AKS 允许您为 Pod 分配托管标识,Google Cloud 的 GKE 允许您通过工作负载标识分配 IAM 权限。
- 限定每个实例的云权限至最低限度,以减少从实例访问元数据 API 的任何被攻击影响。
- Use network policies to block pod access to the metadata API. This can be done with per-namespace Kubernetes network policies, or preferably with extensions to Kubernetes network policies such as those offered by Calico, which enable a single network policy to apply across the whole of the cluster (without the need to create a new Kubernetes network policy each time a new namespace is added to the cluster). This topic is covered in more depth in the Default Deny and Default App Policy section of Chapter 7.
Enable Auditing
Kubernetes auditing provides a log of all actions within the cluster with configurable scope and levels of detail. Enabling Kubernetes audit logging and archiving audit logs on a secure service is recommended as an important source of forensic details in the event of needing to analyze a security breach.
The forensic review of the audit log can help answer questions such as:
- What happened, when, and where in the cluster?
- Who or what initiated it and from where?
In addition, Kubernetes audit logs can be actively monitored to alert on suspicious activity using your own custom tooling or third-party solutions. There are many enterprise products that you can use to monitor Kubernetes audit logs and generate alerts based on configurable match criteria.
The details of what events are captured in Kubernetes audit logs are controlled using policy. The policy determines which events are recorded, for which resources, and with what level of detail.
Each action being performed can generate a series of events, defined as stages:
RequestReceived
Generated as soon as the audit handler receives the request
ResponseStarted
Generated when the response headers are sent, but before the response body is sent (generated only for long-running requests such as watches)
ResponseComplete
Generated when the response body has been completed
Panic
Generated when a panic occurs
The level of detail recorded for each event can be one of the following:
None
Does not log the event at all
Metadata
Logs the request metadata (user, timestamp, resource, verb, etc.) but not the request details or response body
Request
Logs event metadata and the request body but not the response body
RequestResponse
Logs the full details of the event, including the metadata and request and response bodies
Kubernetes’ audit policy is very flexible and well documented in the main Kubernetes documentation. Included here are just a couple of simple examples to illustrate.
To log all requests at the metadata level:
- apiVersion: audit.k8s.io/v1
- kind: Policy
- rules:
- - level: Metadata
复制代码 To omit the RequestReceived stage and to log pod changes at the RequestResponse level and configmap and secrets changes at the metadata level:
- apiVersion: audit.k8s.io/v1 # This is required.
- kind: Policy
- omitStages:
- - "RequestReceived"
- rules:
- - level: RequestResponse
- resources:
- - group: ""
- resources: ["pods"]
- - level: Metadata
- resources:
- - group: "" # core API group
- resources: ["secrets", "configmaps"]
复制代码 第二个示例说明了审计日志中敏感数据的重要考虑因素。根据对审计日志访问安全性的要求,确保审计策略不记录秘密或其他敏感数据大概是至关重要的。就像对静止状态的加密暗码的做法一样,通常建议始终从审计日志中清除敏感细节。
限定对 alpha 或 beta 功能的访问
每个 Kubernetes 发布版本都包含 alpha 和 beta 功能。可以通过为各个 Kubernetes 组件指定功能门标志来控制它们的启用。由于这些功能正在开发中,它们大概存在限定或错误,从而导致安全毛病。因此,良好的做法是确保全部不打算使用的 alpha 和 beta 功能都被禁用。
Alpha 功能通常(但并非总是)默认禁用。它们大概存在错误,而且该功能的支持大概会在不向后兼容的情况下发生根本性变化,或在未来的版本中被删除。一样平常建议仅将其用于测试集群,而不是生产集群。
Beta 功能通常默认启用。它们在版本发布之间大概会以不向后兼容的方式更改,但通常被认为经过合理测试且安全可用。但与任何新功能一样,它们天生更有大概存在毛病,因为它们的使用较少且考核较少。
评估 alpha 或 beta 功能大概提供的代价,对比其带来的安全风险,以及在发布版本之间功能非向后兼容变动大概带来的操作风险黑白常重要的。
频繁升级 Kubernetes
在任何大型软件项目中,随着时间的推移,新的毛病是不可避免的。Kubernetes 开发者社区在及时响应新发现的毛病方面表现良好。严重毛病通常在封禁期间修复,这意味着毛病的知识不会在开发者有时间订定修复方案之前公开。随着时间的推移,较旧的 Kubernetes 版本中已公开已知毛病的数量增加,这大概会增加较旧集群的安全风险。
为减少集群被妥协的风险,定期升级集群非常重要,并确保能够告急升级以应对发现的严重毛病。
全部 Kubernetes 安全更新和毛病报告(一旦有任何封禁结束)通过公开且免费加入的 kubernetes-announce 邮件组。猛烈建议任何渴望跟踪已知毛病以最小化安全风险的人加入此组。
使用托管的 Kubernetes 服务
减少实行本章建议所需工作的一种方式是使用主要的公共云托管 Kubernetes 服务之一,例如 EKS、AKS、GKE 或 IKS。使用这些服务将安全性从完全由您自己负责减少到共享责任模型。共享责任意味着服务默认包含了许多安全元素,或者可以轻松设置以支持这些安全元素,但您仍然须要自己负责某些元素,以确保整体安全。
具体细节因您使用的公共云服务而异,但毫无疑问,全部这些服务都会做大量的重活,这降低了与自行安装和管理集群相比所需的安全工作量。此外,公共云提供商和第三方提供了大量资源,具体说明了作为共享责任模型的一部分,您须要采取哪些措施来全面确保您的集群安全。例如,此中一个资源就是 CIS 基准,接下来将讨论它。
CIS 基准
正如本章前面讨论的那样,CIS 维护了免费的 PDF 指南,提供了对许多常见操作系统进行安全设置指导。这些指南称为 CIS 基准,可资助您进行主机硬化,是一种无价的资源。
除了资助进行主机硬化外,另有针对 Kubernetes 本身的 CIS 基准,包括对许多盛行的托管 Kubernetes 服务的设置指导,这可以资助您实施本章指南中的大部分内容。例如,GKE CIS 基准包括指导怎样确保集群设置了节点的自动升级,而且使用 Google Groups 管理 Kubernetes 身份验证和 RBAC。这些指南是高度保举的资源,以获取关于怎样确保 Kubernetes 集群安全所需步骤的最新实用建议。
除了指南本身外,另有第三方工具可用来评估运行中的集群与许多这些基准的状态。一个盛行的工具是 kube-bench,这是一个开源项目,最初由 Aqua Security 团队创建。或者,假如您更喜欢一个更成熟的解决方案,那么许多企业产品在其集群管理仪表板中内置了 CIS 基准和其他安全合规工具和警报功能。在理想情况下,这些工具会定期自动运行,有助于验证集群的安全姿态,并确保在集群创建时大概采取的谨慎安全措施在管理和更新集群的过程中不会意外丢失或被破坏。
网络安全
当在集群与集群范围之外的四周基础设施安全地集成时,网络安满是主要考虑因素。有两个方面须要考虑:怎样保护集群免受集群外部的攻击,以及怎样保护集群内部任何受损元素对集群外部基础设施的影响。这适用于集群工作负载级别(即 Kubernetes pod)和集群基础设施级别(即 Kubernetes 控制平面以及运行 Kubernetes 集群的主机)。
首先要考虑的是集群是否须要从公共互联网访问,直接(例如,一个或多个节点具有公共 IP 地址)或间接(例如,通过可从互联网访问的负载均衡器或类似设备)。假如集群可以从互联网访问,那么黑客的攻击或探测活动数量将大幅增加。因此,假如集群不须要强制要求从互联网访问,猛烈建议在可路由级别上不允许任何访问(即确保互联网上的数据包无法到达集群)。在企业内部环境中,这大概涉及选择用于集群的 IP 地址范围及其在企业网络中的可路由性。假如使用公共云托管的 Kubernetes 服务,您大概会发现这些设置仅在集群创建时可以设置。例如,在 GKE 中,是否可以从互联网访问 Kubernetes 控制平面可以在集群创建时设置。
集群内的网络策略是下一道防线。网络策略可用于限定集群与集群外部基础设施之间的工作负载和主机通信。它具有两大优势:既能意识到工作负载(即限定构成单个微服务的一组 pod 的通信能力),又能在平台上不可知(即可以在任何环境中使用相同的技能和策略语言,无论是企业内部环境还是公共云中)。网络策略将在专门章节中深入讨论。
末了,猛烈建议使用周边防火墙,或其云等效物,如安全组,以限定流向/流出集群的流量。在大多数情况下,这些防火墙不相识 Kubernetes 工作负载,因此无法理解单个 pod,而且通常仅能以集群整体的方式进行粒度控制。尽管存在这些限定,它们作为防御策略的一部分仍然具有代价,但仅靠它们本身大概不敷以满意任何注重安全的企业需求。
假如须要更强的周边防御,有策略和第三方工具可以使周边防火墙或其云等效物更加有效:
- 一种方法是将集群中的少数特定节点指定为具有特定访问级别的节点,而这种访问级别不授予集群中的其他节点。然后可以使用 Kubernetes 的污点(taints),确保只有须要该特别访问级别的工作负载被调度到这些节点上。这样一来,可以基于特定节点的 IP 地址设置外围防火墙规则,允许所需的访问,而集群中的全部其他节点则被拒绝在集群外访问。
- 在当地环境中,一些 Kubernetes 网络插件允许您使用可路由的 Pod IP 地址(非覆盖网络),并控制支持特定微服务的一组 Pod 使用的 IP 地址范围。这使得外围防火墙可以根据 IP 地址范围实行类似于传统非 Kubernetes 工作负载的操作。例如,您须要选择一个在当地环境中支持可路由的非覆盖网络,并具有机动 IP 地址管理能力以促进此类方法的网络插件。
- 在不实际将 Pod IP 地址路由到集群外部不可行的任何环境中(例如使用覆盖网络时),前述方法的变体非常有用。在这种情况下,从 Pod 发出的网络流量似乎来自于节点的 IP 地址,因为它使用源网络地址转换(SNAT)。为相识决这个问题,可以使用支持出口 NAT 网关的 Kubernetes 网络插件。一些 Kubernetes 网络插件支持出口 NAT 网关功能,允许更改此行为,使一组 Pod 的出口流量通过集群内实行 SNAT 的特定网关路由,因此流量似乎来自于网关,而不是托管 Pod 的节点。根据使用的网络插件,网关可以分配给特定的 IP 地址范围或特定节点,从而允许外围防火墙规则比将整个集群视为单个实体更为选择性地实行。支持此功能的几个选项包括:Red Hat 的 OpenShift SDN、Nirmata 和 Calico 都支持出口网关功能。
- 终极,一些防火墙支持一些插件或第三方工具,使防火墙能够更加相识 Kubernetes 工作负载,例如通过自动添补防火墙中的 IP 地址列表,此中包括 pod 的 IP 地址(或者承载特定 pod 的节点的节点 IP 地址)。或者在云环境中,有自动编程规则允许安全组选择性地对进出 Kubernetes pod 的流量进行操作,而不仅仅是在节点级别操作。这种集成对于你的集群非常重要,可以资助补充防火墙提供的安全保障。市场上有几种工具可以实现这种类型的集成。选择一个支持与主要防火墙供应商的集成而且对 Kubernetes 当地化的工具非常重要。
在前面的部分,我们讨论了网络安全的重要性,以及怎样使用网络安全保护来自集群外部泉源的流量访问你的 Kubernetes 集群,以及怎样控制从集群内部源发往集群外部主机的访问。
结论
在本章中,我们讨论了以下关键概念,你应该使用这些概念来确保你的 Kubernetes 集群有一个安全的基础设施。
- 你须要确保主机运行的操作系统是安全的,没有关键性毛病。
- 你须要在主机上摆设访问控制以控制对主机操作系统的访问,并摆设用于进出主机的网络流量的控制。
- 你须要确保你的 Kubernetes 集群有一个安全的设置;保护数据存储和 API 服务器对于确保你拥有安全的集群设置至关重要。
- 末了,你须要摆设网络安全来控制源自集群内部 pod 而且要传输到集群内部 pod 的网络流量。
第三章:工作负载摆设控制
在 Manoj Ahuje 的贡献下,
Tigera 的高级威胁谍报研究工程师
一旦您决定了基础设施安全策略,下一个步骤是工作负载摆设控制。在本章中,我们将探讨镜像构建和扫描策略,CI/CD(将镜像扫描集成到构建中),以及 Kubernetes 基于脚色的访问控制(RBAC),这是一种广泛使用的授权系统,允许您根据用户脚色定义访问控制,以及应用步伐的密钥管理。
镜像构建和扫描
在本节中,我们将探讨镜像构建和扫描的最佳实践。这些包括选择基础映像以减少攻击面,使用 scratch 映像和镜像硬化最佳实践以防止对手入侵。镜像扫描涉及选择镜像扫描解决方案的细节,隐私问题,以及容器威胁分析解决方案的概述。
基础映像的选择
如在前一章节讨论的,您可以选择像 Bottlerocket 这样的当代 Linux 发行版作为容器的基础映像。传统 Linux 发行版的最小版本,如 Ubuntu、Red Hat 和 Alpine,也是可用的。
虽然使用最小映像作为出发点是个不错的开始,但是最小映像方法并不能阻止发现存在于操作系统中的 OS 包的毛病。在这种情况下,distroless 或 scratch 映像会是更好的选择。这些类型的映像仅包含应用步伐及其特定的运行时依赖项。
这里是 distroless 或 scratch 映像的好处:
- 这种策略显著减少了巨细、攻击面和毛病,从而进步了安全性。
- Distroless 映像已经可以用于生产环境。Kubernetes 本身就使用 distroless 映像来构建各种组件,如 kublet、scheduler 等。
- 假如您要为应用步伐选择一个基础映像,可以使用多阶段 Dockerfile 来构建一个基础映像。第一阶段涉及构建您的应用步伐。第二阶段涉及将运行时依赖和应用步伐移到基础映像。
distroless 映像项目标最受欢迎的例子是来自 Google 的 distroless,它为 Java、Python 或 C++ 等各种运行时提供映像。
一个空缺镜像从 Dockerfile 指令 FROM:scratch 开始,表示一个空文件系统。在 Dockerfile 中的下一条指令创建了容器镜像的第一个文件系统层。在这里,第一个文件系统层须要与应用步伐和依赖项一起编译。因为在容器外部构建应用步伐是不生产和不直观的,Docker 引入了多阶段构建。通过多阶段构建,Dockerfile 允许多个 FROM 指令。每个 FROM 指令创建一个独立的阶段,之前阶段的文件系统产物可以在后续阶段的构建中复制。这个机制使开发者能够在较早的阶段(构建器镜像)中构建和编译应用步伐,全部依赖项都可用,并终极仅复制运行生产应用步伐所需的文件系统产物到后续阶段。构建的末了阶段可以是一个空缺镜像,只须要在结果镜像中存在应用步伐二进制文件和依赖项。
下面是一个基于空缺镜像的 bash 脚本示例,目标是在容器内运行一个脚本。在这里,你可以创建一个两阶段 Dockerfile,此中第二阶段是一个仅包含脚本依赖项的空缺镜像。
你可以使用这个模板来容器化甚至是使用 Node.js、Python 和 Go 构建的复杂应用步伐。Go 还提供了一个选项,可以将全部的运行时库编译到二进制文件中。在下面的示例中,你可以使用 Alpine 作为基础镜像,为运行脚本的容器构建一个空缺镜像:
- # use alpine 3 as base image
- FROM alpine:3 as builder
- # upgrade all alpine packages
- RUN apk update && apk upgrade
- # add your script into container fs
- ADD your_init_script.sh your_init_script.sh
- RUN chmod u+x your_init_script.sh
- # stage 2
- FROM scratch
- # shell
- COPY --from=builder /bin/sh /bin/sh
- # dependent linux shared libraries
- COPY --from=builder /lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1
- ENV PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:
- /sbin:/bin
- ENTRYPOINT ["./your_init_script.sh"]
- In this example, only two files are copied into scratch images (second stage).
- Hence, the alpine base image containing more than five thousand files is minimized
- to two files, reducing the attack surface significantly.
复制代码 现在我们已经回顾了怎样为你的容器选择基础镜像,让我们探讨一下容器镜像的强化。
容器镜像强化
容器镜像强化是构建镜像以减少安全弱点和攻击面的过程。同时,它被用来为容器内的应用步伐添加防御层,以确保安全运行。
假如你使用一个未强化的容器镜像,大概会容易受到滥用、信息泄露或者更容易提升到容器主机的特权攻击。你应该使用以下工具和最佳实践来为你的应用步伐构建强化的容器镜像:
- 只使用来自受信托泉源的基础镜像,比如官方 Ubuntu 和 Red Hat 发行渠道,而且使用发布信息双重检查镜像哈希,因为很容易在镜像中嵌入恶意代码,比如加密货币挖矿步伐,并将这些镜像发布在像 Docker Hub 这样的仓库中。
- 将基础镜像最小化,仅包含应用步伐的运行时依赖项。
- 遵循最小权限访问原则,并以最低所需权限运行容器。例如,除非须要 root 权限,否则应将容器作为非 root 用户运行。这使得攻击者难以逃离容器,并提供了对毛病的保护,例如 CVE-2020-15257,此中 root 用户能够逃离容器。
- 不要使用 Docker 镜像的标签;而是在 Dockerfile 中固定基础镜像版本(例如,ubuntu:20.08)。可变的标签如 latest 或 master 不断更新以增加功能和修复问题,这大概导致在 CI/CD 流水线的镜像扫描中出现问题。此外,它们大概导致应用步伐稳固性问题(此中底层依赖库被更新/移除或更改)。
- 将 Docker 镜像层压缩为单个层。使用 Docker 或 buildah 等工具构建的容器镜像通常具有多个层。这些层显示了开发汗青,有时会泄露敏感信息。压缩现有层的最佳方法是使用多阶段构建;另有一个实验性的 Docker 功能(即 Docker API 1.25+ 中提供的选项 --squash)。
- 使用容器镜像签名来信托该镜像。原生的 Kubernetes 并不具备容器镜像验证功能。可以使用 Docker Notary 对镜像进行签名,并通过 Kubernetes 准入控制器验证镜像签名,以确定镜像是否被恶意行为者窜改(例如,在镜像位于注册表时对其进行更改)。
在接下来的部分,我们将审查容器镜像扫描。
容器镜像扫描解决方案
容器镜像扫描工具检查容器文件系统以获取元数据,相识镜像中是否存在易受攻击的组件。市场上有许多开源和贸易企业解决方案可供选择,用于此目标。它们具有 CI/CD 集成和丰富的扫描功能。您选择的解决方案应该能够回答一些基本问题:
- 镜像扫描器可否为您选择的基础镜像中的操作系统包进行扫描?
- 它可否扫描您的应用步伐依赖项(是否理解应用步伐使用的语言,如 Go、Python、Node.js)?
- 镜像扫描器可否检测文件系统中存在的敏感文件(如证书、暗码)?
- 误报率是多少?
- 它可以扫描二进制文件(.elf 或 .exe)吗?
- 扫描解决方案将网络哪些数据?扫描解决方案是否将您的镜像上传到其 SaaS 服务,还是仅网络包元数据?由于数据暴露风险,相识这一点非常重要。
- 网络的数据将存储在那里?在当地还是云端 SaaS?请查阅并选择符合安全/合规团队指南的选项。
- 镜像扫描器是否与您的 CI/CD 系统集成?
大多数扫描器从文件系统网络元数据,并尝试与从国家毛病数据库或私人谍报泉源网络的毛病信息匹配,以确定毛病的存在。请注意,扫描中大概会出现假阳性和假阴性。对于已确认存在毛病的镜像,应用步伐和安全团队须要共同分析 CVE 对运营的影响和风险。修复步骤涉及在更新可用时实施解决方法和修补镜像。
许多公共云提供商和容器注册服务提供商提供容器扫描服务。然而,它们支持的操作系统版本有限,而且大多数不扫描应用步伐依赖关系。在这方面,开源天下提供了更多选择。一些可以扫描应用步伐依赖关系的闻名开源工具包括Anchore,允许用户定义策略,以及Trivy,易于集成到 CI 中。
隐私问题
产品中的安全毛病及干系信息是高度秘密的数据,假如落入错误的手中,大概对组织构成重大责任。因此,在选择任何解决方案之前,最好验证扫描解决方案网络了哪些数据以及这些数据存储在那里(例如,在企业内部的当地或作为 SaaS 服务的一部分在云端)。假如购买贸易解决方案,请检查条约以相识在数据泄露情况下的侵害条款。通常,这些条款可以资助您相识组织对数据安全的严肃态度。假如使用开源解决方案,请阅读文档以相识数据泄露风险。
容器威胁分析
除了传统的镜像扫描,使用基于沙箱的解决方案进行容器威胁分析的领域正在日益盛行。这是一个相对较新的领域,我们建议您关注。这些基于沙箱的解决方案可以运行 Docker 镜像,并监视容器系统调用、进程、内存、网络流量(HTTP、DNS、SSL、TCP)以及容器的整体行为,使用呆板学习和其他技能来检测任何恶意活动。此外,它们还可以扫描容器文件系统以检查毛病和恶意二进制文件。这些技能可用于检测高级持续性威胁(APTs)和恶意软件。
CI/CD
在本节中,我们将讨论将镜像扫描解决方案集成到您的 CI/CD 流水线中的各种策略,保护 CI/CD 流水线的最佳实践,以及实施 CI/CD 和毛病扫描的组织政策技能。
一连集成(CI)是一种开发实践,每个开发者的检入都会通过自动化构建进行验证,使团队能够早期检测问题。而一连摆设(CD)是 CI 的延伸,一旦通过全部发布检查,变动就会发布给卑鄙消费者。
在 CI/CD 的目标中,将安全性集成到开发和发布过程的每个步骤中是关键,这是 DevOps 流程中左移策略的一个重要部分。通过将图像扫描集成到您的 CI/CD 流水线中(见图 3-1),开发团队可以在开发者提交到代码库后立即得到检查结果。这种方法的主要优势在于可以在构建时检测到新的安全毛病或威胁。一旦发现问题,全部利益干系者和 DevOps 团队通常会通过 CI 作业失败收到通知。然后各团队可以立即开始进行修复工作。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0301.png
Figure 3-1. 将图像扫描集成到 CI/CD 过程中
如图 3-1 所示,扫描应该在开发周期的每个步骤中进行集成,从开发者检入到持续交付到生产。本节的其余部分将专注于集成中的 CI 部分,以展示图像扫描过程的细粒度。可以将以下策略应用于图 3-1 中显示的每个步骤(即代码、构建[CI]和 CD 流水线)。
选择特定的 CI/CD 构建基础设施是次要的,可以根据更广泛的需求进行选择。盛行的 CI/CD 提供者包括但不限于Jenkins,Semaphore,和CircleCI。有四种主要方式将图像扫描集成到您的 CI/CD 流水线和构建基础设施中,如图 3-2 所示。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0302.png
Figure 3-2. 将图像扫描集成为图像注册表的一部分
通过注册表扫描服务扫描图像
如图 3-2 所示,在这种方法中,一旦开发者提交了检入,CI 即构建并将图像推送到注册表。然后图像会定期被注册表内集成的服务扫描。这种方法有许多缺点;注册表提供商通常仅限于扫描操作系统软件包层(例如 GCR 和 Quay)。由于它们显示的信息有限,使用毛病白名单、分类和跟踪时间表来解决各种问题大概非常贫苦。此外,大多数情况下没有选项可以编写符合您组织需求的策略。
当镜像扫描器发现问题时,大概已经使用 CD 消耗了镜像。注册表不会跟踪消耗了哪些镜像及其摆设者。使用这些镜像的用户大概面对妥协风险,却不知道注册表扫描服务识别出的毛病。毛病修复仅在通知后进行,可以是向开发团队和其他利益干系者发出的警报或电子邮件。修复大概是从上游提供商的简单更新到复杂的代码和设置修复。这种修复工作往往滞后于开发过程。
图 3-3 显示了镜像作为 CI 过程的一部分进行构建和扫描的方式,但无视扫描器的判定将镜像推送到内部注册表。假如您是一个敏捷的 DevOps 团队,您大概每天或每小时在多个分支上提交检查后立即构建和推送镜像至内部注册表。在这种情况下,假如镜像中存在毛病,您不渴望每个构建都作为 CI 的一部分失败。相反,您会收到有关毛病的通知,开发职员可以在 CD 启动之前修复该毛病。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0303.png
图 3-3. 镜像作为构建过程的一部分进行扫描
构建后扫描镜像
这种方法的缺点在于,纵然每个镜像在构建后立即进行扫描,也没有机制强制开发职员立即修复发现的问题。此外,纵然检测到毛病,镜像也可从注册表内提供给内部使用,因此大概成为组织中的单薄环节,大概导致妥协。
如图 3-4 所示,开发职员提交检查时会启动 CI 作业,构建并随后扫描镜像。扫描完成后,会评估镜像扫描器的判定。若通过,则将镜像推送至内部注册表以供使用。若未通过,则开发职员需立即修复问题,因为他们无法使用包含更改的最新构建。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0304.png
图 3-4. 镜像内联扫描作为 CI/CD 过程的一部分
内联镜像扫描
最初阶段,这种管道大概难以管理,这取决于您组织的规模和速度,但一旦掌握,组织就能更好地控制其安全姿态。同样的管道设计可以应用于您的 CD 作业,以确保在发布/摆设时您的应用步伐最为安全。
Kubernetes 准入控制器可以拦截来自 Kubernetes API 的 Pod 创建哀求(拜见图 3-5)。该机制可以作为末了一分钟的检查,通过触发 CI 作业来扫描正在摆设到集群上的镜像。根据扫描的结果,准入控制器可以允许或驳回该 Pod。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0305.png
图 3-5. 作为 Pod 创建的一部分的镜像扫描
Kubernetes 准入控制器
通常须要自定义或现成的准入控制器,它能够与准入服务器通信,并对实行的扫描给出判断。从容错的角度来看,值得注意的是,假如准入服务器因某些缘故原由失败,则大概影响整个集群中的 Pod 创建。在准入服务器失败的情况下,您渴望准入控制器“故障开放”(即继承进行 Pod 创建)还是“故障关闭”(即阻止全部 Pod 创建)是组织的决定;权衡安全风险与容错风险。
由于准入控制器是末了一分钟的检查,通常开发团队在查看正在扫描和拒绝的内容之前是不知道发现的安全毛病的。因此建议将此方法与早期方法联合使用,作为您防御策略的一部分。
保护 CI/CD 流水线
CI/CD 流水线的自主性子和最少人为干预使得 CI/CD 成为攻击者的一个吸引目标。此外,开发环境大概过于宽容,对安全关注不敷。以下是保护您的 CI/CD 流水线的最佳实践。
CI/CD 环境的零信托策略
全部与您的 CI/CD 流水线的毗连,无论是入站还是出站,都须要根据您的威胁模型进行零信托策略的严格审查。这将确保对 CI/CD 流水线的出站和入站访问通过安全策略进行管理。
安全的秘密管理
审查您的 CI/CD 流水线所需的每个秘密,并确保仅在须要时调用暗码、访问令牌和加密密钥。秘密管理的设计须要考虑对秘密的细粒度访问、秘密使用和更改日志功能、自动秘密轮换以及停用和废弃。我们将在本章的后续部分具体讨论秘密管理,以资助您选择合适的策略。
访问控制
对 CI/CD 资源的严格访问控制和用户责任的分离是确保安全的关键,无论是基于脚色、时间还是任务的方法。访问控制须要对流水线的访问进行分段,以便在受到威胁时大幅减少爆炸半径。此外,使用默认启用的两因素认证机制。
审计和监控
对 CI/CD 资源的访问须要持续考核和监控,以确定过分访问、用户脱离组织或更改工作脚色时的访问停用、滥用或可疑用户行为。
组织策略
解决 CI/CD 流水线和扫描带来的挑战,须要全局组织策略。该策略需指出对 CI/CD 资源的访问要求、用户职责的分离、秘密管理、日志记录和监控要求以及审计策略。
初始时,毛病扫描大概会使团队不堪重负。因此,开发、DevOps 和安全团队须要明确的指导方针,用于产品毛病发现和评估、风险、修复和根据组织的威胁模型关闭问题的时间表。
毛病扫描解决方案可以具有 codified 策略,根据扫描结果和组织的风险容忍度,可以接受或拒绝镜像。
构建有效策略的过程须要迭代,并基于持续反馈以实现量身定制的策略,根据您的行业、规模、工作流程和合规要求,均衡安全性和性能。
秘密管理
一个秘密可以是用于认证和授权用户、组或实体的任何内容。它可以是用户名/暗码、API 令牌或 TLS 证书。当应用步伐或微服务迁移到 Kubernetes 时,开发职员须要做出的早期设计选择是在那里存储这些秘密,以及怎样检索并在应用步伐中根据须要使其可用,而不会 compromis 安全性。以下是实现此目标的主要方法。
etcd 用于存储秘密
应用步伐迁移到 Kubernetes 的常见景象是将秘密以 Base64 编码格式存储在 etcd 中作为键值对。Etcd 是 Kubernetes 摆设中支持的数据存储。这些秘密可以作为卷挂载或来自 Kubernetes 摆设规范中的环境变量在容器内部提供。由于环境变量存储在内存中,与存储在容器文件系统上的卷挂载相比,提取秘密更加困难。对 etcd 的访问由 Kubernetes RBAC 支持,带来了所需的安全性和机动性。
Etcd 提供了强大的并发原语、可线性读取和用于规模化管理秘密的 API。这种方法的缺点是秘密以明文(Base64 编码)存储,而且在没有设置 etcd 使用 TLS 加密通信的情况下,检索和发送也是以明文进行的。在 第二章 中,您学习了在数据静止状态下加密数据的策略,此中秘密可以在存储在 etcd 中时进行加密。
此外,在 etcd 中存储的秘密既不是有版本控制的,也不能在删除后规复,而且 etcd 的访问没有经过审计,因此任何有权限访问 etcd 的人都可以访问全部的秘密。由于 etcd 是 Kubernetes 的数据存储,因此无法满意组织更广泛的秘密管理需求。
秘密管理服务
要解决组织的加密和秘密管理需求,可以使用云提供商的秘密管理服务。全部主要的公共云提供商都提供秘密管理服务。
最盛行的云提供商的秘密管理服务有AWS Secrets Manager、Google Secret Manager和Azure Key Vault。
一个显著的第三方示例是HashiCorp Vault,可以用作会集式秘密管理器。它提供了许多功能来满意组织的端到端秘密管理需求(密钥管理、加密、轮换、PKI、存储、复制、吊销、日志记录、监控、审计等)。例如,当 Vault 初始化时,初始密钥可以被加密并存储到 Cloud KMS 中,这样操作员就不必处理明文密钥。
Kubernetes 秘密存储 CSI 驱动步伐
容器存储接口(CSI)驱动步伐整合了外部秘密存储,如 Azure、GCP、AWS 和 HashiCorp Vault,通过 CSI 将它们集成到 Kubernetes 中,自版本 1.13 以来已广泛可用。
简而言之,CSI 驱动步伐使用卷属性与您的秘密存储服务进行身份验证,并无缝地将所需的秘密挂载到 Pod 中。这种方法避免了使用 Kubernetes etcd 数据存储,并允许您有效地扩展和管理组织的秘密。
秘密管理最佳实践
在管理 Kubernetes 中的秘密时,以下是须要考虑的最佳实践。
避免秘密扩散
秘密管理的主要目标是避免秘密扩散,即应用步伐的秘密分散在设置文件、YAML 和 Git 存储库等地方。这通常表明组织缺乏秘密管理工作流程。减少秘密扩散的唯一方法是建立一个会集式秘密管理策略,此中凭证可以安全地存储和检索,并由整个组织在适当的授权、日志记录和监控机制下使用。
使用反亲和性规则
理想情况下,秘密管理解决方案应该是少量专用捏造机或专用主机上的单一进程。由于大概须要在 Kubernetes 上作为微服务运行此解决方案,因此它将作为运行在专用 Pod 中的进程。但问题在于这些 Pod 应该在哪些节点上运行。在此,反亲和性有助于将 Pod 分布在所需节点上,这些节点被分类为运行秘密管理解决方案。
数据加密(传输和静态)
默认情况下,Kubernetes 不安全地存储和传输秘密。设置或使用能够在传输中使用端到端 TLS 加密的解决方案至关重要。同时,要有机制来以加密情势存储秘密。请参阅第二章相识怎样实现此目标的选项。
使用自动化秘密轮换
组织对于不同秘密的轮换采用不同的时间框架,但随着自动化秘密轮换的出现,您可以每天甚至每小时进行轮换。云秘密管理服务和外部第三方解决方案都可以资助实现自动化的秘密轮换和管理。
暂时或动态秘密
暂时或动态秘密是暂时天生的、按需天生的秘密,通常有短暂的生命周期,并在该时间间隔后被销毁。这些秘密可以根据应用步伐的种别或运维团队的须要提供。假如攻击者发现秘密(例如通过调试日志、应用步伐代码泄露或意外在 GitHub 上公开),这些秘密将在短时间窗口内被更改,从而保护应用步伐。此外,它们还可以资助追踪基础设施中的攻击者行踪,因为很容易确定攻击者发现秘密的时间范围。HashiCorp Vault 和 CyberArk Conjur 是一些提供此类功能的第三方秘密提供者。
启用审计日志
在你的秘密管理解决方案中具有审计日志,可以查看组织中秘密及其使用的可见性。审计日志对于确定意图或偶然中的妥协、攻击的影响范围以及干系的取证步骤至关重要。
将秘密存储在容器内存中
当容器化应用步伐接收到秘密时,不要将秘密存储在磁盘上(或在主机中可用的 volumeMount 中)。相反,将其存储在内存中,以便在妥协的情况下,这些秘密不易于攻击者获取。
零秘密问题
许多秘密管理解决方案采用信封加密,此中 DEK 受 KEK 保护。KEK 被视为零号秘密。假如攻击者破坏了 KEK,则可以解密 DEK,并随后解密 DEK 加密的数据。云提供商的 IAM 和 KMS 的组合可用于资助保护零号秘密。(当然,这些实际上也有自己的零号秘密链,必须视为高度敏感。)
使用您的证书颁发机构
作为深度防御的一部分,可以使用自定义证书颁发机构 (CA) 实施端到端的 TLS 实现。在这里,组织可以选择使用自己的 CA 签订其证书。在这种情况下,服务只能通过提交组织签订的证书进行访问。
身份验证
一旦您预备好强化您的镜像、CI/CD 管道和秘密管理策略,就是 Kubernetes 的认证和授权策略的时间了。Kubernetes 允许多种身份验证机制;在最简单的情势中,认证可以使用证书、令牌或基本身份验证(用户名和暗码)完成。此外,可以使用 Webhook 验证持有者令牌,并集成外部 OpenID 提供商。
让我们更具体地看看 Kubernetes 中可用的每种身份验证方法。身份验证方法的设置超出本书的范围。
X509 客户端证书
有两种签订客户端证书的方法,以便用于与 Kubernetes API 进行身份验证。首先是通过 Kubernetes API 内部签订证书。这涉及客户端创建证书签订哀求 (CSR)。管理员可以答应或拒绝 CSR。一旦答应,管理员可以提取并提供签订后的证书给哀求的客户端或用户。由于这种方法须要手动干预,无法为大型组织提供规模化支持。
第二种方法是使用企业 PKI,它可以签订客户端提交的 CSR。此外,签订授权机构可以将签订后的证书发送回客户端。这种方法要求外部解决方案管理私钥。
持有者令牌
Kubernetes 服务账户使用持有者令牌与 Kubernetes API 进行身份验证。使用持有者令牌的最简单方式是创建一个新的服务账户。Kubernetes API 自动分配与服务账户关联的随机令牌,可以检索并用于验证该账户。
可以使用 Webhook 验证持有者令牌,这涉及使用选项 --authentication-token-webhook-config-file 设置 API,并包含远程 Webhook 服务的具体信息。
Kubernetes 内部使用引导和节点认证令牌初始化集群。此外,还可以使用静态令牌文件的较不安全选项,在设置 Kubernetes API 时使用 --token-auth-file 选项提供。
OIDC 令牌
OpenID Connect 协议 是通过扩显现有的 OAuth2 协议构建的。Kubernetes 不提供 OpenID Connect 身份提供者。您可以使用 Google 或 Azure 等身份提供者,或者使用 dex、keycloak 或 UAA 运行自己的身份提供者。这些外部身份提供者可以根据须要轻松集成到您的认证工作流中,并支持原生身份提供者功能(例如,使用轻量目录访问协议的企业)。
认证代理
可以使用代理与 Kubernetes API 建立信托毗连。Kubernetes API 可以通过哀求头(如由认证代理设置的 X-Remote-User)识别用户,认证代剖析代表 Kubernetes API 对用户进行身份验证。认证代理可以根据工作流程须要进行用户身份验证。
匿名哀求
假如对 Kubernetes API 的哀求未被任何设置的认证方法拒绝,则将其视为匿名哀求(即没有承载令牌的哀求)。
对于 Kubernetes 版本 1.6 及以上,须要注意,默认情况下启用了匿名访问,但不包括 AlwaysAllow 授权模式。在设置 Kubernetes API 时,可以通过添加选项 --anonymous-auth=false 来禁用匿名访问。
用户假冒
这是一种微妙的认证机制,通过在哀求到 Kubernetes API 中设置额外的头部信息,具有对 Kubernetes 的某些访问权限的用户可以假冒另一个用户。
此机制允许 Kubernetes API 根据被假冒用户的权限和上下文处理哀求。此外,Kubernetes API 还可以记录谁假冒了谁以及来自哀求的其他干系细节,这在监控和审计过程中大概很有用。
授权
本节将涵盖可用的授权方法、Kubernetes 中的 RBAC、命名空间 RBAC 和注意事项。
Kubernetes 具有多种授权机制,如节点、ABAC、RBAC 和 AlwaysDeny/AlwaysAllow,此中 RBAC 是 Kubernetes 的行业标准。
节点
节点授权由 Kubernetes 在内部使用。它是一种专用授权模式,专门授权 kubelet 发出的 API 哀求。它使 kubelet 可以进行读取、写入和与认证干系的操作。为了乐成发出哀求,kubelet 必须使用标识其属于 system:nodes 组的根据。
ABAC
Kubernetes 将属性基于访问控制(ABAC)定义为“一种通过将属性组合在一起来授予用户访问权限的访问控制范式”。可以通过在 Kubernetes API 设置中提供 .json 文件,并使用 --authorization-policy-file 和 --authorization-mode=ABAC 选项来启用 ABAC。在调用 Kubernetes API 之前,须要存在 .json 文件。
AlwaysDeny/AlwaysAllow
AlwaysDeny 或 AlwaysAllow 授权模式通常用于开发环境,此中须要允许或拒绝对 Kubernetes API 的全部哀求。在设置 Kubernetes API 时,可以使用选项 --authorization-mode=AlwaysDeny/AlwaysAllow 启用 AlwaysDeny 或 AlwaysAllow 模式。这种模式被认为是不安全的,因此不建议在生产环境中使用。
RBAC
基于脚色的访问控制是 Kubernetes 中最安全和保举的授权机制。这是一种根据集群中用户脚色限定系统访问的方法。它允许组织强制实行最小权限原则。Kubernetes RBAC 遵循声明性的性子,具有明确的权限(操作)、API 对象(资源)和主体(用户、组或 ServiceAccounts)在授权哀求中声明。在 Kubernetes 中应用 RBAC 是一个两步过程。第一步是创建一个 Role 或 ClusterRole。后者是一个全局对象,而前者是一个命名空间对象。一个 Role 或 ClusterRole 由动词、资源和主体组成,提供了对资源的能力(动词),如 图 3-6 所示。第二步是创建一个 ClusterRoleBinding,将第一步中定义的权限分配给用户或组。
让我们举一个例子,假设一个 dev-admins 组须要对集群中的全部秘密进行读取访问。第一步是创建一个 ClusterRole secret-reader,允许通过各种操作(get、list)读取秘密,第二步是将其绑定到一个主体(即用户、组或 ServiceAccounts)以提供访问权限。在这种情况下,组 dev-admins 允许组用户全局读取秘密。
图 3-6 是一个示例,展示了怎样创建一个允许您定义对资源访问权限的 ClusterRole。右侧的示例展示了怎样将 ClusterRole 绑定到一组用户。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0306.png
图 3-6. Kubernetes 脚色和脚色绑定
图 3-7 显示了 RBAC 的概述;您可以根据须要使用任何操作、资源或主体的组合。
除了这些资源外,另有 Kubernetes 的非资源,如 /healths 或 /version API,假如须要的话也可以使用 RBAC 进行控制。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0307.png
图 3-7. Kubernetes 资源的 RBAC
命名空间 RBAC
在之前的示例中,您看到了一个在集群中全局应用的 RBAC。可以将类似的 RBAC 应用于资源地点的命名空间,使命名空间内的资源受到此 RBAC 策略的约束。应使用命名空间资源 Role 和 RoleBinding 来设置命名空间策略。
在使用命名空间 RBAC 时,有一些注意事项须要注意:
- 脚色和脚色绑定是唯一的命名空间资源。
- ClusterRoleBindings(全局资源)不能与 Role(命名空间资源)一起使用。
- 脚色绑定(命名空间资源)不能与全局资源集群脚色一起使用。
- 只有集群脚色可以进行聚合。
提权缓解
Kubernetes RBAC 减少了攻击者通过编辑脚色或脚色绑定来提升自己权限的能力。这种行为在 Kubernetes 的 API 级别上强制实行,纵然 RBAC 授权器未被使用时也适用:
- 假如用户 user-no-secret 没有能力在整个集群中列出秘密,他们将无法创建包含该权限的集群脚色或集群脚色绑定。
- 对于用户 user-no-secret 要获取秘密权限列表,他们将须要以下此中一种:
- 授予他们一个允许他们创建/更新脚色、集群脚色、脚色绑定或集群脚色绑定的脚色。
- 为他们在这些资源上提供显式的提权权限。
结论
在本章中,我们涵盖了以下关键概念,这些概念将资助您理解安全工具和构建摆设工作负载的最佳实践:
- 仅使用 Docker 提供的基础镜像是不够的,因为它们只是为您的容器提供。您必须花时间确保您的容器镜像经过硬化并考虑了安全性。就像在软件开发中一样,构建时发现毛病比摆设后发现毛病要便宜得多。
- 有几种方法可以将图像扫描添加到您的 CI/CD 过程中。我们探讨了像注册表扫描、构建时或内联扫描以及使用 Kubernetes 准入控制器等多种知名方法,资助您将图像扫描添加到您的 CI/CD 流水线中。我们还讨论了保护 CI/CD 流水线并添加组织策略,有效地为您的组织订定工作流程。
- 我们讨论了秘密管理的方法和最佳实践。
- 末了,我们涵盖了可用的 Kubernetes 认证和授权机制。我们建议您使用 RBAC 来减少提权风险。
第四章:工作负载运行时安全性
与 Manoj Ahuje 的贡献,
Tigera 的高级威胁谍报研究工程师
Kubernetes 的默认 Pod 提供机制存在广泛的攻击面,敌对方可以使用这一点来攻击集群或逃逸容器。本章将教您怎样实施 Pod 安全策略(PSP),以限定 Pod 的攻击面,并学习怎样监控进程(例如进程权限)、文件访问以及工作负载的运行时安全性。以下是我们将讨论的一些具体内容:
- 我们将覆盖 PSP 的实现细节,例如 Pod 安全上下文,并解释 PSP 的限定。请注意,自 Kubernetes v1.21 起,PSP 已被弃用;然而,由于我们知道 PSP 被广泛使用,本章节将继承讨论此主题。
- 我们将讨论过程监控,重点是须要 Kubernetes 当地监控来检测可疑活动。我们将覆盖使用内核安全特性如 seccomp、SELinux 和 AppArmor 来防止容器访问主机资源的运行时监控和强制实行。
- 我们将同时讨论毛病的检测和运行时防御、工作负载隔离以及爆炸半径的控制。
Pod 安全策略
Kubernetes 通过使用 PSP 提供了一种安全地引导 Pod 和容器的方法。它们是一个集群范围的资源,可以在将 Pod 允许并计划在集群中运行之前,检查一组条件。这通过一个 Kubernetes 准入控制器实现,该控制器会评估每个 Pod 创建哀求,以确保其符合分配给 Pod 的 PSP 的规定。
请注意,自 Kubernetes 1.21 版本起,PSP 已被弃用,并计划在 1.25 版本中移除。尽管如此,它们在生产集群中被广泛使用,因此本节将资助您相识它们的工作原理以及实施 PSP 的最佳实践。
PSP 允许您通过诸如 Pods 不应作为 root 运行 或 Pods 不应使用主机网络、主机命名空间或以特权模式运行 等控制来强制实行规则。这些策略在 Pod 创建时生效。通过使用 PSP,您可以确保 Pod 以操作所需的最低特权创建,从而减少应用步伐的攻击面。此外,该机制还资助您符合 PCI、SOC 2 或 HIPAA 等各种标准的要求,这些标准要求使用最少特权访问原则。正如其名称所示,该原则要求任何进程、用户或者在我们的情况下,工作负载都被授予其运行所需的最低权限。
使用 Pod 安全策略
Kubernetes PSP 被保举但通过可选的准入控制器实现。启用 PSP 的强制性可以通过启用一个准入控制器来实现。这意味着 Kubernetes API 服务器清单应在其–enable-admission-plugins 列表中具有一个 PodSecurityPolicy 插件。许多 Kubernetes 发行版不支持或默认禁用 PSP,因此在选择 Kubernetes 发行版时值得检查。
一旦启用了 PSP,将 PSP 应用到组而不是单个服务帐户是一个三步骤的过程,如图 4-1 所示。一个最佳实践是应用 PSP 到组。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0401.png
图 4-1. 应用 PSP 的过程
第 1 步是创建一个 PSP。第 2 步是创建具有use动词的 ClusterRole,授权 Pod 摆设控制器使用这些策略。然后第 3 步是创建 ClusterRoleBindings,用于对组(例如,system:authenticated 或 system:unauthenticated)或服务帐户强制实行策略。
一个良好的出发点是来自 Kubernetes 项目标 PSP 模板:
- apiVersion: policy/v1beta1
- kind: PodSecurityPolicy
- metadata:
- name: restricted
- annotations:
- seccomp.security.alpha.kubernetes.io/allowedProfileNames: |
- 'docker/default,runtime/default'
- apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
- seccomp.security.alpha.kubernetes.io/defaultProfileName: 'runtime/default'
- apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default'
- spec:
- privileged: false
- # Required to prevent escalations to root.
- allowPrivilegeEscalation: false
- # This is redundant with non-root + disallow privilege escalation,
- # but we can provide it for defense in depth.
- requiredDropCapabilities:
- - ALL
- # Allow core volume types.
- volumes:
- - 'configMap'
- - 'emptyDir'
- - 'projected'
- - 'secret'
- - 'downwardAPI'
- # Assume that persistentVolumes set up by the cluster admin are safe to use.
- - 'persistentVolumeClaim'
- hostNetwork: false
- hostIPC: false
- hostPID: false
- runAsUser:
- # Require the container to run without root privileges.
- rule: 'MustRunAsNonRoot'
- seLinux:
- # This policy assumes the nodes are using AppArmor rather than SELinux.
- rule: 'RunAsAny'
- supplementalGroups:
- rule: 'MustRunAs'
- ranges:
- # Forbid adding the root group.
- - min: 1
- max: 65535
- fsGroup:
- rule: 'MustRunAs'
- ranges:
- # Forbid adding the root group.
- - min: 1
- max: 65535
- readOnlyRootFilesystem: false
复制代码 在以下示例中,您可以使用 Kubernetes 基于脚色的访问控制将此策略应用于全部经过身份验证的用户:
- apiVersion: rbac.authorization.k8s.io/v1
- kind: ClusterRole Policy
- metadata:
- name: psp-restricted
- rules:
- - apiGroups:
- - policy
- resourceNames:
- - restricted
- resources:
- - podsecuritypolicies
- verbs:
- - use
- ---
- apiVersion: rbac.authorization.k8s.io/v1
- kind: ClusterRoleBinding
- metadata:
- name: psp-restricted-binding
- roleRef:
- apiGroup: rbac.authorization.k8s.io
- kind: ClusterRole
- name: psp-restricted
- subjects:
- - apiGroup: rbac.authorization.k8s.io
- kind : Group
- name: system:authenticated
复制代码 Pod 安全策略功能
让我们关注 PSP 提供的功能,您可以根据您的用例和内部威胁模型进行使用。您可以按照我们刚讨论过的示例 PSP 模板来构建您自己的 PSP。在此模板中,大部分 PSP 功能被使用来订定一种限定性策略。
要解释一项能力的影响,让我们看一个示例,在这个示例中,您可以看到为使用 privileged:true 和 privileged:false 创建的 Pod 授予的能力。Linux 实用步伐capsh可以用来评估容器化根用户的权限。正如您在图 4-2 中所见,特权 Pod 在其 Linux 命名空间中具有大量能力,这意味着攻击者可以更广泛地攻击您的容器逃逸面。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0402.png
图 4-2. 默认和特权 Pod 的 Pod 功能
表 4-1 总结了在Kubernetes PSP 文档中描述的 Pod 功能。
表 4-1. Pod 功能
FieldUsesprivileged允许容器得到访问主机挂载、文件系统以更改设置等功能。您可以使用命令capsh --print检查功能。hostPID, hostIPC允许容器访问主机命名空间,此中进程和以太网接口对其可见。hostNetwork, hostPorts允许容器访问主机网络和端口。volumes允许卷类型如 configMap、emtyDir 或 secret。allowedHostPaths允许列出可以被 hostPath 卷使用的主机路径的白名单(例如,/tmp)。allowedFlexVolumes允许特定的 FlexVolume 驱动步伐(例如 azure/kv)。fsGroup设置拥有 pod 卷的 GID 或 GID 范围。readOnlyRootFilesystem将容器的根文件系统设置为只读。runAsUser, runAsGroup, supplementalGroups定义容器的 UID 和 GID。在此处,您可以指定非 root 用户或组。allowPrivilegeEscalation, defaultAllowPrivilegeEscalation通过进程限定特权升级。defaultAddCapabilities, requiredDropCapabilities, allowedCapabilities根据须要添加或删除 Linux capabilities。SELinux定义容器的 SELinux 上下文。allowedProcMountTypes容器允许的 proc 挂载类型。forbiddenSysctls,allowedUnsafeSysctls设置容器使用的 sysctl 设置文件。annotations设置容器使用的 AppArmor 和 seccomp 设置文件。 在使用 PSP 解释时,可以使用 AppArmor 和 seccomp 设置文件,此中可以使用运行时(Docker、CRI)的默认设置文件或者您在主机上加载的自定义设置文件。您将在 “进程监控” 中相识更多关于这些防御措施的信息。
Pod 安全上下文
与定义为整个集群的 PSPs 不同,pod securityContext 可以在创建摆设或 pod 时定义运行时。以下是 pod securityContext 在操作中的简单示例,此中 pod 使用 root 用户 (uid=0) 创建,而且只允许四种功能:
- kind: Pod
- apiVersion: v1
- metadata:
- name: attacker-privileged-test
- namespace: default
- labels:
- app: normal-app
- spec:
- containers:
- - name: attacker-container
- image: alpine:latest
- args: ["sleep", "10000"]
- securityContext:
- runAsUser: 0
- capabilities:
- drop:
- - all
- add:
- - SYS_CHROOT
- - NET_BIND_SERVICE
- - SETGID
- - SETUID
复制代码 此代码片段展示了怎样通过指定安全上下文创建一个以 root 用户运行但只允许部分功能集的 pod。图 4-3 展示了可以运行的命令,以验证 pod 以 root 用户和受限功能集运行。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0403.png
图 4-3. 允许的四种 pod 功能
Pod 安全上下文,如 图 4-3 所示,可以在不启用 PSPs 的情况下使用,但一旦启用 PSPs,您须要定义 securityContext 以确保精确创建 pod。由于 securityContext 具有 PSP 构造,全部 PSP 的功能都适用于 securityContext。
PSPs 的限定
PSPs 的一些限定包括:
- PodSecurityPolicySpec 引用了 allowedCapabilities、privileged 或 hostNetwork。这些强制措施仅适用于基于 Linux 的运行时。
- 假如您正在使用控制器(例如复制控制器)创建 pod,则值得检查这些控制器是否被授权使用 PSPs。
- 一旦在整个集群启用了 PSPs 而且由于错误的 PSP 导致 pod 无法启动,那么清除问题将变得非常繁琐。此外,假如在生产集群中整个集群启用了 PSPs,您须要测试集群中的每个组件,包括像突变接入控制器和冲突判断这样的依赖项。
- Azure Kubernetes Service (AKS) 已弃用对 PSP 的支持,并优先使用 OPA Gatekeeper 进行策略实行,以支持使用 OPA 引擎实现更机动的策略。
- PSP 已被弃用,并计划在 Kubernetes v1.25 中移除。
- Kubernetes 大概存在 PSP 可被绕过的边缘情况(例如,TOB-K8S-038)。
现在您相识了 PSP、实施它们的最佳实践以及 PSP 的限定,让我们来看看进程监控。
进程监控
当您将工作负载容器化并在像 Kubernetes 这样的编排器上运行时,您须要考虑的层次许多,以监控容器内的进程。这些层次包括容器进程日志和工件、文件系统访问、网络毗连、所需的系统调用、内核权限(特别工作负载)、Kubernetes 工件和云基础设施工件。通常,您组织的安全姿态取决于您的解决方案在将这些各种日志上下文有机地联合起来方面的表现。这也是传统监控系统明显不敷之处,须要 Kubernetes 的当地监控和可观察性的缘故原由。传统解决方案,如终端点检测与响应(EDR)和终端点保护系统,在 Kubernetes 集群中使用时存在以下限定:
- 他们不知道容器。
- 他们不相识容器网络,通常从主机的角度看待活动,这大概导致对攻击者的侧向移动产生误判。
- 他们对容器之间的流量一无所知,也看不到像 IPIP 或 VXLAN 这样的底层协议。
- 他们不相识容器访问底层主机的进程权限和文件权限。
- 他们不相识 Kubernetes 容器运行时接口(CRI)或其复杂性和安全问题,这大概导致容器能够访问主机上的资源。这也被称为权限提升。
在接下来的几节中,我们将介绍您可以用于进程监控的各种技能。首先,我们将查看 Kubernetes 中可用的各种日志进行监控;然后,我们探讨 seccomp、SELinux 和 AppArmor 功能,这些功能允许您控制进程可以访问的内容(例如系统调用、文件系统等)。
Kubernetes 当地监控
如 图 4-4 所示,每一层到您的容器化应用步伐进程都引入了监控和日志记录要求,以及与传统 IT 安全从业职员监控网络和应用步伐不同的新攻击面。挑战在于减少这种监控开销,因为对于存储和计算资源来说这大概变得非常昂贵。有关度量网络及其高效实行的具体信息将在 第五章 中具体讨论。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0404.png
图 4-4. Kubernetes 当地监控
要在每个层面构建防御,你在选择解决方案时应该考虑以下几个选项:
- 能够阻止每个容器或 Kubernetes 编排创建容器天生的进程。
- 监控每个容器进程使用的内核系统调用,并能够过滤、阻止和警报可疑调用,以防止容器访问主机资源。
- 监控每个容器进程发起的每个网络毗连(套接字),并能够强制实行网络策略。
- 能够使用网络策略隔离容器(或运行该容器的节点),并将其停息以观察可疑活动并在 Kubernetes 中网络取证数据。基于 Docker 的容器的 pause 命令 停息容器中的进程以进行具体分析。请注意,停息容器将导致其制止正常操作,应作为对变乱(例如安全变乱)的响应而使用。
- 监控文件系统的读写操作,相识文件系统变动(二进制、软件包),并通过强制访问控制(MAC)进行额外隔离,以防止提权。
- 监控 Kubernetes 审计日志,相识客户端发出的 Kubernetes API 哀求及检测可疑活动。
- 启用云服务提供商的基础设施日志记录,并能够在云服务提供商的基础设施中检测可疑活动。
有许多企业和开源解决方案(例如,Falco),使用各种工具和机制(如 ebpf、kprobes、ptrace、tracepoints 等)来瞄准各层级,资助在各个层面构建防御。你应该查看它们的威胁模型,并选择满意其需求的解决方案。
在接下来的部分,你将看到 Kubernetes 提供的一些机制,通过将 Linux 防御措施与容器更精密地联合,资助你在各层面监控和减少攻击面。前一部分侧重于监控,以便检测意外(恶意)行为。以下机制允许你设置控件以防止意外(恶意)行为。
内核安全功能如 seccomp、AppArmor 和 SELinux 可以控制容器化应用步伐所需的系统调用,为每个容器提供捏造隔离和定制,以及使用 MAC 为访问资源(如卷或文件系统)提供访问,有效防止容器越界。仅使用默认设置的功能即可大幅减少集群中的攻击面。在接下来的部分中,你将深入相识每种防御措施及其在 Kubernetes 集群中的工作方式,以便选择得当你威胁模型的最佳选项。
Seccomp
Seccomp 是 Linux 内核的一个功能,可以在粒度基础上过滤容器实行的系统调用。Kubernetes 允许您通过像Docker、podman或CRI-O这样的运行时自动应用加载到节点上的 seccomp 设置文件。简单的 seccomp 设置文件包括一系列 syscalls 和在调用 syscalls 时要采取的适当操作。此操作将攻击面减少到仅允许的 syscalls,从而减少特权升级和容器逃逸的风险。
在下面的 seccomp 设置文件中,默认操作是SCMP_ACT_ERRNO,这会拒绝系统调用。但是对于 syscall chmod,默认的操作被覆盖为SCMP_ACT_ALLOW。通常,seccomp 设置文件由您的运行时加载到全部节点的/var/lib/kubelet/seccomp 目录中。您可以在同一位置添加自定义设置文件:
- {
- "defaultAction": "SCMP_ACT_ERRNO",
- "architectures": [
- "SCMP_ARCH_X86_64",
- "SCMP_ARCH_X86",
- "SCMP_ARCH_X32"
- ],
- "syscalls": [
- {
- "names": [
- "chmod",
- ],
- "action": "SCMP_ACT_ALLOW"
- }
- ]
- }
复制代码 要查找应用步伐使用的系统调用,可以使用strace,如下例所示。例如,您可以列出curl实用步伐使用的 syscalls 如下:
- $ strace -c -S name curl -sS google.com
- % time seconds usecs/call calls errors syscall
- ------ ----------- ----------- --------- --------- ----------------
- 4.56 0.000242 6 43 43 access
- 0.06 0.000003 3 1 arch_prctl
- 1.28 0.000068 10 7 brk
- 0.28 0.000015 15 1 clone
- 4.62 0.000245 5 48 close
- 1.38 0.000073 73 1 1 connect
- 0.00 0.000000 0 1 execve
- 0.36 0.000019 10 2 fcntl
- 4.20 0.000223 5 48 fstat
- 0.66 0.000035 3 11 futex
- 0.23 0.000012 12 1 getpeername
- 0.13 0.000007 7 1 getrandom
- 0.19 0.000010 10 1 getsockname
- 0.24 0.000013 13 1 getsockopt
- 0.15 0.000008 4 2 ioctl
- 13.96 0.000741 7 108 mmap
- 11.94 0.000634 7 85 mprotect
- 0.32 0.000017 17 1 munmap
- 11.02 0.000585 13 45 1 openat
- 0.11 0.000006 6 1 pipe
- 19.50 0.001035 115 9 poll
- 0.08 0.000004 4 1 prlimit64
- 5.43 0.000288 6 45 read
- 0.41 0.000022 22 1 recvfrom
- 11.47 0.000609 17 36 rt_sigaction
- 0.08 0.000004 4 1 rt_sigprocmask
- 1.00 0.000053 53 1 sendto
- 0.06 0.000003 3 1 set_robust_list
- 0.04 0.000002 2 1 set_tid_address
- 2.22 0.000118 30 4 setsockopt
- 1.60 0.000085 43 2 socket
- 0.08 0.000004 4 1 1 stat
- 2.35 0.000125 21 6 write
- ------ ----------- ----------- --------- --------- ----------------
- 100.00 0.005308 518 46 total
复制代码 Kubernetes 运行时提供的默认 seccomp 设置文件包含大多数应用步伐使用的常见 syscalls 列表。启用此功能可以禁止使用危险的系统调用,从而可以导致内核毛病使用和容器逃逸。您可以参考默认 Docker 运行时 seccomp 设置文件。
注
在撰写本文时,Docker/default 设置文件已弃用,建议您改用 runtime/default 作为 seccomp 设置文件。
表格 4-2 展示了通过 PSP 解释在 Kubernetes 中摆设 seccomp 设置文件的选项。
表格 4-2. Seccomp 选项
值描述runtime/default默认容器运行时设置文件未限定Kubernetes 中默认没有 seccomp 设置文件—此选项是默认的。localhost/ 您在节点上的自定义设置文件,通常位于/var/lib/kubelet/seccomp 目录中 SELinux
在最近的已往,每个容器运行时的突破(容器逃逸或特权升级)都是某种文件系统的突破(即 CVE-2019-5736、CVE-2016-9962、CVE-2015-3627 等)。通过提供控制谁可以访问文件系统以及资源之间的交互(例如用户、文件、目录、内存、套接字等),SELinux 可以减轻这些问题。在云计算环境中,应用 SELinux 设置文件对工作负载进行更好的隔离,通过限定主机内查对文件系统的访问来减少攻击面。
SELinux 最初由国家安全局在 2000 年代初开发,主要用于基于 Red Hat 和 centOS 的发行版。SELinux 之所以有效,是因为它提供了 MAC,极大加强了传统的 Linux 自主访问控制(DAC)系统。
在传统的 Linux DAC 中,用户可以更改文件、目录和自己拥有的进程的权限。根用户可以访问全部内容。但是使用 SELinux(MAC)时,每个操作系统资源都由内核分配一个标签,并存储为扩展文件属性。这些标签用于在内核内评估 SELinux 策略,以允许任何交互。启用 SELinux 后,纵然容器中的根用户也无法访问挂载卷中主机的文件,假如标签禁绝确的话。
SELinux 有三种模式:强制实行(Enforcing)、宽松(Permissive)和禁用(Disabled)。强制实行使 SELinux 策略生效,宽松提供警告,禁用则不使用 SELinux 策略。SELinux 策略本身可以进一步分为定向(Targeted)和严格(Strict),定向策略适用于特定进程,而严格策略适用于全部进程。
下面是主机上 Docker 二进制文件的 SELinux 标签,由 <user:role:type:level> 组成。在这里,您将看到类型,即 container_runtime_exec_t:
- $ ls -Z /usr/bin/docker*
- -rwxr-xr-x. root root system_u:object_r:container_runtime_exec_t:s0
- /usr/bin/docker
- -rwxr-xr-x. root root system_u:object_r:container_runtime_exec_t:s0
- /usr/bin/docker-current
- -rwxr-xr-x. root root system_u:object_r:container_runtime_exec_t:s0
- /usr/bin/docker-storage-setup
复制代码 为了进一步加强 SELinux,使用多种别安全(MCS)允许用户为资源打上种别标签。因此,标有种别标签的文件只能被该种别的用户或进程访问。
一旦启用 SELinux,像 Docker、podman 或 CRI-O 这样的容器运行时会选择一个随机的 MCS 标签来运行容器。这些 MCS 标签由两个在 1 到 1023 之间的随机数组成,并以字符“c”(种别)和一个敏感级别(即 s0)为前缀。因此,完备的 MCS 标签看起来像 “s0:c1,c2”。如 图 4-5 所示,除非精确标记,否则容器无法访问主机或 Kubernetes 卷上的文件。这在资源交互之间提供了重要的隔离,防止许多针对逃逸容器的安全毛病。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0405.png
图 4-5. SELinux 强制实行文件系统访问权限
接下来是一个摆设有 SELinux 设置文件的 pod 示例;除非在主机上标记为 so:c123,c456,否则此 pod 将无法访问任何主机卷挂载文件。纵然您可以看到整个主机,文件系统也是以 pod 的方式挂载的:
- apiVersion: v1
- metadata:
- name: pod-se-linux-label
- namespace: default
- labels:
- app: normal-app
- spec:
- containers:
- - name: app-container
- image: alpine:latest
- args: ["sleep", "10000"]
- securityContext:
- seLinuxOptions:
- level: "s0:c123,c456"
- volumes:
- - name: rootfs
- hostPath:
- path: /
复制代码 表 4-3 列出了关于容器逃逸的 CVE,通过在主机上启用 SELinux 可以防备。虽然 SELinux 策略大概难以维护,但它们对于深度防御策略至关重要。Openshift,一个 Kubernetes 分发版,在其默认设置中启用了 SELinux,并使用定向策略;对于其他发行版,检查状态值得一试。
表 4-3. 与容器逃逸干系的 CVE
CVE描述SELinux 阻止CVE-2019-5736允许攻击者覆盖主机的 runc 二进制文件,从而获取主机 root 访问权限是CVE-2016-9962RunC 实行毛病是CVE-2015-3627不安全的文件描述符使用是 Kubernetes 通过 PSP 提供以下选项来强制实行 SELinux:
Value描述MustRunAs须要像 图 4-5 中显示的那样设置 seLinuxOptions。RunAsAny在 PSP 中不提供默认设置(可以选择性地在 pod 和 deployments 上设置) AppArmor
与 SELinux 类似,AppArmor 是为 Debian 和 Ubuntu 操作系统开发的。AppArmor 的工作方式类似于 SELinux,此中一个 AppArmor 设置文件定义了进程可以访问的内容。让我们看一个 AppArmor 设置文件的示例:
- #include <tunables/global>
- /{usr/,}bin/ping flags=(complain) {
- #include <abstractions/base>
- #include <abstractions/consoles>
- #include <abstractions/nameservice>
- capability net_raw,
- capability setuid,
- network inet raw,
- /bin/ping mixr,
- /etc/modules.conf r,
- # Site-specific additions and overrides. See local/README for details.
- #include <local/bin.ping>
- }
复制代码 这里的 ping 实用工具仅具备三个能力(即 net_raw、setuid 和对 /etc/modules.conf 的 inet 原始和读取访问权限)。有了这些权限,ping 实用步伐无法修改或写入文件系统(密钥、二进制文件、设置、恒久性),也不能加载任何模块,这减少了 ping 实用步伐在受到威胁时实行任何恶意活动的攻击面。
默认情况下,像 Docker、podman 或 CRI-O 这样的 Kubernetes 运行时会提供一个 AppArmor 设置文件。Docker 的运行时设置文件可以参考 此处。
由于 AppArmor 更加机动且易于使用,我们建议为每个微服务单独创建一个策略。Kubernetes 通过 PSP 注解提供以下选项来强制实行这些策略:
Value描述runtime/default运行时的默认策略localhost/<profile_name>应用于主机上加载的设置文件,通常位于目录 /sys/kernel/security/apparmor/profilesunconfined不加载任何设置文件 Sysctl
Kubernetes sysctl 允许您使用 sysctl 接口在集群中使用和设置内核参数。使用 sysctl 的一个示例是管理须要处理大量并发毗连或须要特别参数设置(例如 IPv6 转发)以有效运行的资源密集型工作负载的容器。在这种情况下,sysctl 提供了一种仅对这些工作负载修改内核行为而不影响集群其余部分的方法。
sysctl 可以将 sysctl 分为两个桶:安全和不安全。安全的 sysctl 只影响容器,但不安全的 sysctl 影响容器和运行在其上的节点。管理员可以自行决定怎样设置这两个 sysctl 桶。
举例来说,假如一个容器化的 Web 服务器须要处理大量并发毗连,而且须要将 net.core.somaxconn 值设置为高于内核默认值,可以如下设置:
- apiVersion: v1
- kind: Pod
- metadata:
- name: sysctl-example
- spec:
- securityContext:
- sysctls:
- - name: net.core.somaxconn
- value: "1024"
复制代码 请注意,我们建议您使用节点亲和性来安排工作负载,以便在须要使用适用于节点的 sysctl 时使用。以下示例显示了 PSPs 怎样允许或禁止 sysctl:
- apiVersion: policy/v1beta1
- kind: PodSecurityPolicy
- metadata:
- name: sysctl-psp
- spec:
- allowedUnsafeSysctls:
- - kernel.msg*
- forbiddenSysctls:
- - kernel.shm_rmid_forced
复制代码 结论
在本章中,我们讨论了定义和实施工作负载运行时安全性的工具和最佳实践。最重要的要点是:
- Pod 安全策略是在工作负载创建时启用工作负载控制的一种绝佳方式。它们有一些限定,但可以有效使用。
- 您须要选择一个在 Kubernetes 中当地支持的监控进程的解决方案,并根据您的工作负载威胁模型实施控制。
- 我们建议您审查 Linux 内核中提供的各种安全选项,并根据您的用例使用适当的功能集。
第五章:观察性
在本章中,我们将讨论在 Kubernetes 摆设背景下监控和可观察性之间的区别。我们将解释在您的 Kubernetes 集群中实施可观察性的最佳实践和工具。在下一章中,我们将介绍怎样使用可观察性来保护您的集群。
可观察性最近在 Kubernetes 社区中成为讨论的话题,并引起了许多关注。我们首先要理解监控和可观察性之间的区别。然后,我们将看看为何在像 Kubernetes 这样的分布式应用中,可观察性对安全至关重要,并审查实现可观察性的工具和参考实现。虽然可观察性是一个广泛的话题,并适用于多个领域,但在本章中,我们将讨论重点放在 Kubernetes 上。让我们从监控和可观察性开始,并相识它们的区别。
监控
监控是系统中用于警示从正常范围偏离的已知一组丈量。以下是在 Kubernetes 中您可以监视的数据类型示例:
- Pod 日志
- 网络流日志
- 应用步伐流日志
- 审计日志
您可以监控的指标示例包括以下内容:
- 每秒毗连数
- 每秒数据包数,每秒字节数
- 应用步伐(API)每秒哀求数
- CPU 和内存使用率
这些日志和指标可以资助您识别已知故障,并提供有关症状的更多信息,以资助您解决问题。
为了监视您的 Kubernetes 集群,您使用诸如轮询和正常运行时间检查的技能,具体取决于您须要为其集群维护的 SLA。以下是您可以监视 SLA 的示例指标:
- 轮询应用步伐/API 端点
- 应用响应代码(例如 HTTP 或数据库错误代码)
- 应用步伐响应时间(例如 HTTP 持续时间,数据库事务时间)
- 用于扩展用例的节点可用性
- 节点上的内存/CPU/磁盘/IO 资源
监控的另一个重要部分是警报。您须要一个警报系统作为监控解决方案的一部分,为任何违反指定阈值的度量天生警报。像 Grafana、Prometheus、OpenMetrics、OpenTelemetry 和 Fluentd 这样的工具被用作监控工具,用于网络日志和指标,并为 Kubernetes 集群天生报告、仪表板和警报。Kubernetes 提供了与类似 Opsgenie、PagerDuty、Slack 和 JIRA 这样的工具集成的选项,用于警报转发和管理。
监控您的生产 Kubernetes 集群存在以下问题:
日志数据量
在类似 Kubernetes 的系统中,一个节点上有多个运行在主机上的 pod,每个 pod 都有其自己的日志、网络标识和资源。这意味着您须要网络来自应用步伐操作、网络流量日志、Kubernetes 活动(审计)日志以及每个 pod 的应用步伐流量日志。在非 Kubernetes 环境中,通常一个节点上运行一个应用步伐,因此日志集合只是单一的一组日志,而不是每个运行在节点上的 pod 的一组日志。这增加了须要网络/检查的日志数据量。除了每个 pod 的日志外,您还须要网络 Kubernetes 的集群日志。通常这些也称为审计日志,提供了对 Kubernetes 集群活动的可见性。系统中的日志数量将使监视变得非常泯灭资源且昂贵。您的日志网络集群不应该比运行应用步伐的集群更昂贵!
监视分布式应用步伐
在 Kubernetes 集群中,应用步伐分布在 Kubernetes 集群网络中。一个须要多个 pod 的应用步伐(例如,一个摆设集或一个服务)将会有每个 pod 的日志须要检查,除了须要考虑 pod 集合的上下文(例如,扩展,错误处理等)。在天生应用步伐警报之前,我们须要将多个 pod 视为一个组。请注意,目标是监视应用步伐并为其天生警报,独立为应用步伐的一部分天生警报并不会准确反映应用步伐的状态。另有微服务应用步伐的情况,此中单个应用步伐摆设为一组称为微服务的服务,每个微服务负责应用步伐功能的一部分。在这种情况下,您须要将每个微服务作为一个实体进行监视(请注意,一个微服务是一个或多个 pod 的集合),然后理解哪些微服务影响了任何给定的应用步伐事务。只有在这之后才能为应用步伐报告警报。
Kubernetes 的声明性子
正如我们所涵盖的,Kubernetes 是声明式的,允许您精确指定怎样在集群中创建和运行 pod。Kubernetes 允许您为内存、CPU、存储等指定资源限定,还可以创建自定义资源并为这些资源指定限定。调度器将查找具有所需资源的节点,并在节点上调度 pod。Kubernetes 还监视 pod 的使用情况,并将消耗超太过配资源的 pod 制止。此外,Kubernetes 提供具体的指标,可用于监控 pod 和集群状态。例如,您可以使用类似 Prometheus 的工具监控 pod 和集群状态,并使用这些指标,还可以使用所谓的 程度 Pod 自动伸缩器 自动扩展 pod 或其他集群资源。这意味着 Kubernetes 作为其操作的一部分正在监视并对集群进行更改,以维持根据设置的规范运行。在这种情况下,监控单个指标的警报大概是 Kubernetes 进行更改以适应集群负载的结果,也大概是一个真正的问题。您须要能够区分这两种情况,以准确监控您的应用步伐。
现在我们相识了监控及其怎样实施以及在使用监控时 Kubernetes 集群面对的挑战后,让我们来看看可观察性以及它怎样资助降服这些挑战。
可观察性
可观察性是指仅通过观察系统的外部输出就能理解系统内部状态的能力。可观察性工程,查理蒂·梅杰斯等人(O’Reilly) 是相识可观察性的绝佳资源。该书的第二章讨论了监控和可观察性,对本次讨论非常干系。
可观察性基于监控,并使您能够获取有关应用步伐内部状态的见解。例如,在 Kubernetes 集群中,意外的 pod 重新启动变乱大概对服务没有或只有很少的影响,因为在重新启动时,大概已经有足够的 pod 实例来处理负载。监控系统将天生警报,说明发生了意外的 pod 重新启动变乱;可观察性系统将天生一个中等优先级变乱,并说明发生了意外的 pod 重新启动变乱,但假如在 pod 重新启动时没有应用步伐错误等其他变乱,则对系统没有影响。另一个例子是在应用步伐层天生变乱时(例如,HTTP 哀求的持续时间大于正常值)。在这种情况下,可观察性系统将为应用步伐响应时间降落的缘故原由提供背景信息(例如,网络层问题、重传、由于资源或其他应用步伐问题导致的应用步伐 pod 重新启动、Kubernetes 基础设施问题,如 DNS 延迟或 API 服务器负载)。正如前面所解释的,可观察性系统可以查看影响应用步伐状态的多个变乱,并在考虑全部这些变乱后报告应用步伐状态。现在让我们看看怎样在 Kubernetes 系统中实现可观察性。
可观察性在 Kubernetes 中的工作原理
Kubernetes 的声明性特性在实施可观察性系统中非常有资助。我们建议您构建一个与 Kubernetes 当地化且能够理解集群操作的系统。例如,一个相识 Kubernetes 的系统将监视一个 pod(例如,重新启动、内存不敷、网络活动等),但还将相识一个 pod 是否是独立实例或摆设、副本集或服务的一部分。它还将知道 pod 对服务或摆设的关键性有多大(例如,服务设置为可扩展性和高可用性的方式)。因此,当它报告与 pod 干系的任何变乱时,它将提供全部这些上下文,并资助您轻松地做出关于怎样响应变乱的决定。
另一个须要记着的是,在 Kubernetes 中,您可以将应用步伐摆设为 pod,这些 pod 是高级结构的一部分,例如摆设或服务。为了理解为这些结构实施可观察性所带来的复杂性,我们将使用一个示例来解释它们。当您设置一个服务时,Kubernetes 管理与该服务关联的全部 pod,并确保将流量转达到服务的可用 pod。让我们来看一个来自 Kubernetes 文档的服务定义示例:
- `apiVersion`: v1
- `kind`: Service
- `metadata`:
- `name`: my-service
- `spec`:
- `selector`:
- `app`: MyApp
- `ports`:
- - `protocol`: TCP
- `port`: 80
- `targetPort`: 9376
复制代码 在这个例子中,全部标签为 MyApp 并监听 TCP 端口 9376 的 pod 都成为服务的一部分,全部发送到服务的流量都会被重定向到这些 pod 上。我们在第八章中具体讨论了这个概念。因此,在这种场景下,观测解决方案也应该能够提供服务级别的洞察力。仅仅监视一个 pod 是不够的。所需的是观测能够在服务中汇总全部 pod 的指标,并使用聚合信息进行更多的分析和警报。
现在让我们看一个在 Kubernetes 中的摆设的例子。摆设允许你管理 pod 和副本集(pod 的副本,通常用于扩展和高可用性)。以下是 Kubernetes 中摆设的一个示例设置:
- `apiVersion`: apps/v1
- `kind`: Deployment
- `metadata`:
- `name`: nginx-deployment
- `labels`:
- `app`: nginx
- `spec`:
- `replicas`: 3
- `selector`:
- `matchLabels`:
- `app`: nginx
- `template`:
- `metadata`:
- `labels`:
- `app`: nginx
- `spec`:
- `containers`:
- - `name`: nginx
- `image`: nginx:1.14.2
- `ports`:
- - `containerPort`: 80
复制代码 这个设置将创建一个 nginx 的摆设,此中有三个副本 pod,具有设置的元数据和规范。Kubernetes 拥有一个摆设控制器来确保摆设中全部的 pod 和副本都是可用的。使用摆设资源在 Kubernetes 中还可以实现滚动更新、自动扩展等多种其他好处。在这样的情况下,观测工具应该查看摆设中全部 pod(副本)的活动作为一个整体(例如,摆设中全部 pod 的流量、pod 的重新启动及其对摆设的影响等)。仅监视和警报每个 pod 并不敷以理解摆设的运行情况。
在这两个例子中都清楚地表明,指标的网络须要在 Kubernetes 的上下文中进行。我们不应该在 pod 级别粒度上网络全部数据和指标,而是在适用时应该在摆设或服务级别粒度上网络数据,以提供摆设或服务状态的准确表现。请记着,Kubernetes 抽象了 pod 级别的细节,因此我们须要在更高的级别上进行丈量和警报。在摆设和服务级别进行数据聚合将减少你须要一直网络的日志数量,并解决与大量日志干系的本钱问题。请注意,该工具须要在操作员须要分析问题时有能力深入相识并捕获 pod 级别的细节。我们将在本章后面讨论数据网络时具体介绍这一点。
现在我们已经相识了怎样使用 Kubernetes 的声明性特性来资助观测,并减少我们须要网络和天生干系警报的日志数据量,让我们来探讨 Kubernetes 的分布式特性及其对观测的影响。
在基于微服务的应用摆设中,单个应用由多个摆设在 Kubernetes 集群中的微服务组成。这意味着为了为用户服务一个单一事务,一个或多个服务须要相互交互,从而产生一个或多个子事务。一个典范的微服务应用示例是 Google 在线精品演示微服务应用。图 5-1 展示了该应用的架构。
图 5-1 展示了在线精品应用怎样作为 Kubernetes 中的微服务摆设。这里有 11 个微服务,每个负责应用的某个方面。我们鼓励您查看这个应用,因为我们将在本章后面使用它来演示怎样实现可观测性。假如您查看结帐交易,用户会向前端服务发出哀求,然后前端服务会向结帐服务发出哀求。结帐服务须要与多个服务进行交互(例如 PaymentService、Shipping Service、CurrencyService、EmailService、ProductCatalog Service、CartService)来完成交易。因此,在这种情况下,假如我们的 HTTP 应用日志显示结帐流程 API 响应时间大于预期,我们须要审查每个子事务,并查看是否存在问题以及问题是什么(应用问题、网络问题等)。另一个使情况复杂化的因素是每个子事务都是异步的,而每个微服务同时提供几个独立的事务。在这种情况下,您须要使用一种称为 分布式跟踪 的技能来跟踪单个事务在一组微服务中的流动。分布式跟踪可以通过对应用步伐或内核进行仪器化来实现。我们将在本章后面介绍分布式跟踪。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0501.png
图 5-1. 谷歌微服务演示应用架构
现在我们理解了可观测性以及在 Kubernetes 集群中怎样考虑它之后,让我们来看看 Kubernetes 可观测性工具的组件。图 5-2 展示了 Kubernetes 可观测性工具的各个组件的块图。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0502.png
图 5-2. Kubernetes 可观测性工具的组件
图 5-2 显示了实现可观测性所需的以下组件:
遥测数据网络
如前所述,您的可观测性解决方案须要从集群中的各种传感器网络遥测数据。它须要是分布式的且当地化于 Kubernetes。它必须支持从 L3 到 L7 的全部层的传感器。它还须要网络有关 Kubernetes 基础设施(例如 DNS 和 API 服务器日志)以及 Kubernetes 活动(这些称为审计日志)的信息。正如描述的那样,这些信息必须在摆设和服务的上下文中网络。
分析和可见性
在这一层面上,系统必须提供特定于 Kubernetes 操作的可视化(例如服务图、Kubernetes 平台视图、应用步伐视图)。我们将涵盖一些当地化于 Kubernetes 的常见可视化。我们建议您选择一个使用呆板学习技能进行基线化和报告异常的解决方案。末了,系统须要支持运营职员启用 pod 到 pod 的数据包捕获能力(请注意,这与在主机接口上启用数据包捕获不同,因为会丢失 pod 级别的可见性)。我们将在下一节中具体介绍这一点。
安全性和故障清除应用步伐
您实施的可观测性系统必须支持分布式跟踪,如前一节所述,以资助清除应用步伐问题。我们还建议使用先进的呆板学习技能来理解 Kubernetes 集群的行为并预测性能或安全问题。请注意,这是一个新领域,正在不断创新。
现在我们已经讨论了在 Kubernetes 集群中实施可观测性所需的内容,让我们具体审查每个组件。
实施 Kubernetes 的可观测性
在这一部分,我们将审查构建 Kubernetes 中有效观测系统所需的每个组件。
你应该将日志网络视为分布在你的集群中的一组传感器。您须要确保这些传感器是高效的,而且不会干扰系统操作(例如增加延迟)。我们将在本节后面涵盖网络方法,展示怎样有效地网络指标。您应该考虑在整个堆栈的全部层摆设传感器(或网络信息),如 图 5-2 所示。Kubernetes 审计日志是相识各种 Kubernetes 资源完备生命周期的重要信息源。除了审计日志外,Kubernetes 还提供了多种选项用于 监控。接下来,您须要关注流量流日志(Layer 3/Layer 4),以理解 Kubernetes 集群网络操作。考虑到 Kubernetes 的声明性特性,重要的是网络与应用步伐流(例如 HTTP 或 MySQL)干系的日志,这些日志可以展示用户看到的应用步伐行为可见性(例如响应时间、可用性等)。为了资助故障清除,您还应该网络与 Kubernetes 集群基础设施干系的日志(例如 API 服务器、DNS)。一些高级故障清除系统还会网络由 pod 活动引起的 Linux 内核信息(例如,由 pod 发起的流的进程信息、套接字统计信息),并提供一种启用 pod 之间流量的数据包捕获(原始数据包)的方式。以下描述了您应该每个流网络的内容:
Kubernetes 审计日志
Kubernetes 提供了网络和监控活动的能力。这是一个优秀的 指南,解释了怎样控制网络什么以及日志记录和警报机制。我们建议您细致审查您须要网络和设置审计策略 —— 我们建议不要仅仅网络全部内容。例如,您应该记录 API 哀求、用户名、RBAC、决定、哀求动词、发出哀求的客户端(用户代理)以及 API 哀求的响应代码。我们将在可视化部分展示一个样本 Kubernetes 活动仪表板。
网络流量日志
网络流量日志(Layer 3/Layer 4)是理解 Kubernetes 集群网络操作的关键。通常包括五元组(源和目标 IP 地址/端口和端口)。网络与 pods 干系的 Kubernetes 元数据(源和目标命名空间、pod 名称、与 pods 干系的标签、运行 pods 的主机)以及每个流的聚合字节/数据包黑白常重要的。请注意,这大概导致大量的流量数据,因为一个节点上大概有大量的 pods。在下一节关于集合时的聚合部分,我们将讨论怎样解决这个问题。
DNS 流量日志
除了 API 服务器,DNS 服务器是 Kubernetes 集群的关键部分,被应用步伐用于剖析域名以毗连其他服务/pod,作为正常运行的一部分。DNS 服务器的问题大概会影响集群中的多个应用步伐。从客户端的角度网络信息非常重要。应记录由 pod 发出的 DNS 哀求,包括哀求计数、延迟、用于剖析哀求的 DNS 服务器、DNS 响应代码和响应。这些信息应与 Kubernetes 元数据(例如,命名空间、pod 名称、标签等)一起网络,因为这将有助于将 DNS 问题与服务关联并进一步进行故障清除。
应用步伐日志
正如所解释的那样,在声明式系统如 Kubernetes 中,网络应用步伐日志(HTTP、MySQL)非常重要。这些日志提供了用户体验的视图(例如,响应时间或可用性)。日志将是特定于应用步伐的信息,但必须包括响应码(状态)、响应时间和其他特定于应用步伐的上下文。例如,对于 HTTP 哀求,应记录域(URL 的一部分)、用户代理、哀求次数、HTTP 响应代码,并在某些情况下完备的 URL 路径。再次强调,日志应包括 Kubernetes 元数据(例如,命名空间、服务、标签、pod 名称等)。
处理信息和套接字统计
如前所述,这些统计信息不属于典范的可观测性实现的一部分,但我们建议您考虑网络这些统计信息,因为它们提供了 Kubernetes 集群操作的更全面视图。例如,假如您可以获取进程信息(运行在 pod 中的进程),这可以很好地与应用步伐性能数据干系联(例如,将基于 Java 的应用步伐中的内存使用情况或垃圾网络变乱与响应时间和由进程发起的网络活动进行关联)。套接字统计是两个端点之间 TCP 流的具体信息(例如,网络来回时间、TCP 拥塞窗口、TCP 重传等)。当这些统计信息与 pod 关联时,可以查看底层网络对 pod 间通信的影响。
现在我们已经讨论了完备的可观测性解决方案所需网络的内容,让我们来看看可用于实施网络的工具和技能。图 5-3 是一个示例参考实现,展示了怎样在你的 Kubernetes 集群中的节点上实现网络。
图 5-3 展示了你的 Kubernetes 集群中的一个节点,该节点摆设了作为服务、摆设和命名空间中的 pod,这与典范的 Kubernetes 集群中看到的情况相同。为了方便网络,如可观测性组件部分所示,添加了一些组件,并展示了一些用于方便网络的 Linux 内核补丁。让我们探讨每个组件的功能。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0503.png
图 5-3. 节点上的参考实现网络
Linux 内核工具
Linux 内核提供了几个选项,可用于资助数据网络。非常重要的是,您使用的工具使用这些工具,而不是专注于处理其他工具天生的原始日志:
eBPF 步伐和 kprobes
eBPF 是扩展的伯克利数据包过滤器的缩写。它是一项令人高兴的技能,可用于网络和可观察性。它最初设计用于数据包过滤,但厥后扩展为允许将步伐添加到内核中各种挂钩点,用作跟踪点。假如您正在使用基于 eBPF 的数据平面,管理数据包路径的 eBPF 步伐还将提供数据包和流量信息。我们建议阅读 Brendan Gregg 的博客文章“Linux Extended BPF (eBPF) Tracing Tools” 以相识怎样使用 eBPF 进行性能和跟踪。在本讨论的背景下,您可以将 eBPF 步伐附加到内核探针(kprobe),这实质上是一个跟踪点,当注册了 kprobe 的函数实行时触发并实行步伐。有关 kprobes 的内核文档 提供了更多细节。这是从 Linux 内核获取可观察性信息的绝佳方式。
NFLOG 和 conntrack
假如您使用标准的 Linux 网络数据平面(基于 iptables),有可用工具来跟踪数据包和网络流量。我们建议使用 NFLOG,这是一个与 iptables 联合使用的机制,用于记录数据包。您可以在 iptables 文档中查看具体信息;在高层次上,NFLOG 可以被设置为 iptables 规则的目标,并通过 netlink 套接字在多播地址上记录数据包,用户空间进程可以订阅并网络数据包。Conntrack 是另一个模块,与 iptables 联合使用,用于查询数据包或流的毗连状态,并可用于更新流的统计信息。
我们建议您审查 Linux 内核提供的选项(例如 Net Filter),并在用于网络信息的传感器中使用它们。这非常重要,因为这将是一种高效的数据网络方式,由于 Linux 内核提供的这些选项都经过了高度优化。
可观察性组件
现在我们相识了怎样从 Linux 内核网络数据,让我们看看怎样在用户空间处理这些数据,以确保我们有一个有效的可观察性解决方案:
日志网络器
这是系统中非常重要的一个组件。该组件的目标是从 Kubernetes 集群中为从其他传感器网络的数据添加上下文,例如,将 Pod 元数据(名称、命名空间、标签等)添加到网络流的源和目标 IP 地址中。这是您可以将 Kubernetes 上下文添加到原始网络流日志的方式。同样,您网络的任何来自内核探测器的数据也可以通过添加干系的 Kubernetes 元数据来丰富。通过这种方式,您可以得到将内核中的活动与 Kubernetes 集群中的对象(例如 Pod、服务、摆设)关联起来的日志数据。您能够从中推断出有关 Kubernetes 集群操作的见解。请注意,这个组件是您须要实现的,或者必须确保您选择的可观察性工具具有此功能。这是您可观察性实施中的关键部分。
Envoy(代理)
我们讨论了拥有一个应用特定数据集的重要性,并为此保举您使用Envoy,这是一个广为人知的代理工具,用于分析应用协议并记录应用事务流(例如,在单个 HTTP 毗连上的 HTTP 事务)。请注意,Envoy 可以作为侧车模式使用,附加到每个 Pod,并跟踪与 Pod 的数据包进出。它还可以摆设为守护进程集(透明代理),您可以使用数据平面将流量重定向,通过运行在主机上的 Envoy 实例。我们猛烈建议您使用后一种设置的 Envoy,因为使用侧车模式存在安全问题,而且大概会对应用步伐造成干扰。在这次讨论的背景下,Envoy 守护进程集将是应用流日志的泉源,提供给日志网络器。现在,日志网络器可以使用 Pod 元数据(名称、命名空间、标签、摆设、服务、IP 地址)将这些数据与从内核接收的数据进行关联,并进一步丰富应用数据。
Fluentd
请注意,到目前为止讨论的数据网络是由集群中每个节点上的日志网络器处理的。您须要实现一种机制,将全部节点的数据发送到数据存储或安全信息和变乱管理(SIEM)中,在那里可以被分析和可视化工具获取。Fluentd是将网络的数据发送到您选择的数据存储的绝佳选择。它提供了出色的集成,是一个当地支持 Kubernetes 的工具。另有其他选择可用,但我们建议您使用 Fluentd 来将网络的日志数据发送到数据存储。
Prometheus
我们已经讨论了怎样网络流日志;现在我们须要一个组件来网络指标和警报。Prometheus,一个原生于 Kubernetes 的工具,是网络指标和警报的一个很好的选择。它摆设为端点,这些端点抓取指标并将其发送到 Prometheus 服务器中的时间序列数据库进行分析和查询。您还可以为发送到 Prometheus 服务器的数据定义警报。它是一个广泛使用的选项,而且具有与仪表板和警报工具的集成。我们建议您考虑它作为集群的一个选项。
渴望这次讨论使您相识怎样为您的 Kubernetes 集群实现数据网络。现在让我们来看一下聚合和干系性。
聚合和干系性
在前一节中,我们涵盖了数据网络并讨论了怎样从集群中的各种泉源(API 服务器、网络流量、内核探测器、应用步伐流量)网络数据。这非常有用,但假如我们将网络保持在 Pod 级别的粒度,我们仍然须要解决数据量的问题。另一个须要注意的是,假如我们保持来自不同泉源的数据分开,然后在查询时关联数据,数据量的问题会成倍增加。可以说,尽大概保存尽大概多的原始数据是更好的选择,而且在网络后有高效的工具来查询和聚合数据(离线),为什么不采用这种方法呢?是的,这是一个有效的观点,但有几件事须要考虑。大量数据意味着数据的聚合和查询时间的毗连将消耗大量资源(操作您的数据网络系统大概比操作您的 Kubernetes 集群更昂贵!)。此外,鉴于 Kubernetes 的暂时性子(Pod 生命周期大概非常短暂),离线分析数据的延迟阻止了对网络到的数据报告问题的任何合理响应。在某些情况下,假如在网络时未进行干系性,则无法关联两个不同的网络。例如,您无法网络策略列表和流量列表,然后在离线模式下重新运行策略评估而不将策略与流量关联。
我们还讨论了 Kubernetes 的声明性子,以及摆设(deployment)和服务(service)是比 Pod 更高级的构建。在这种情况下,我们建议您考虑在摆设或服务级别聚合数据。这意味着服务的全部 Pod 的数据被聚合;您将默认网络摆设之间和服务之间的数据。这将为您提供精确的粒度级别。您可以提供一个选项来减少聚合以网络 Pod 级别的数据,作为深入操作或响应变乱的一部分。这样,您可以解决关于网络大量日志数据及干系处理本钱的问题。此外,数据网络更符合 Kubernetes 本身,因为 Kubernetes 监控摆设/服务作为一个单位,并进行调整,以确保摆设/服务按照规范运行。
在数据网络部分,我们讨论了日志网络器组件,它从各种泉源接收数据。它可以用作网络时数据关联的源,因此您无需在数据网络后进行任何额外的关联,而且您还将受益于不必为每个泉源网络冗余数据。例如,假如内核中的 kprobe 网络五元组(IP 地址、端口、协议)的套接字数据,而且 NFLOG 为相同的五元组提供其他信息,如字节和数据包,日志网络器可以创建一个包含五元组、Kubernetes 元数据、网络流数据和套接字统计数据的单个日志。这将为网络和处理提供具有非常高上下文和低占用率的日志。
现在让我们回到 Google 在线精品示例,并看一看带有内核和网络流数据聚合和关联的日志样本。样本日志是使用前面描述的网络和聚合概念为应用步伐的前端服务和货币服务之间的交易天生的,这是基于 gRPC 的交易:
- {
- "_id": "YTBT5HkBf0waR4u9Z0U3",
- "_score": 3,
- "_type": "_doc",
- "start_time": 1623033303,
- "end_time": 1623033334,
- "source_ip": "10.57.209.32",
- "source_name": "frontend-6f794fbff7-58qrq",
- "source_name_aggr": "frontend-6f794fbff7-*",
- "source_namespace": "onlinebotique",
- "source_port": null,
- "source_type": "wep",
- "source_labels": [
- "app=frontend",
- "pod-template-hash=6f794fbff7"
- ],
- "dest_ip": "10.57.209.29",
- "dest_name": "currencyservice-7fd6c64-t2zvl",
- "dest_name_aggr": "currencyservice-7fd6c64-*",
- "dest_namespace": "onlinebotique",
- "dest_service_namespace": "onlinebotique",
- "dest_service_name": "currencyservice",
- "dest_service_port": "grpc",
- "dest_port": 7000,
- "dest_type": "wep",
- "dest_labels": [
- "app=currencyservice",
- "pod-template-hash=7fd6c64"
- ],
- "proto": "tcp",
- "action": "allow",
- "reporter": "src",
- "policies": [
- "1|platform|platform.allow-kube-dns|pass",
- "2|__PROFILE__|__PROFILE__.kns.hipstershop|allow",
- "0|security|security.pass|pass"
- ],
- "bytes_in": 68437,
- "bytes_out": 81760,
- "num_flows": 1,
- "num_flows_started": 0,
- "num_flows_completed": 0,
- "packets_in": 656,
- "packets_out": 861,
- "http_requests_allowed_in": 0,
- "http_requests_denied_in": 0,
- "process_name": "wrk:worker_0",
- "num_process_names": 1,
- "process_id": "26446",
- "num_process_ids": 1,
- "tcp_mean_send_congestion_window": 10,
- "tcp_min_send_congestion_window": 10,
- "tcp_mean_smooth_rtt": 9303,
- "tcp_max_smooth_rtt": 13537,
- "tcp_mean_min_rtt": 107,
- "tcp_max_min_rtt": 107,
- "tcp_mean_mss": 1408,
- "tcp_min_mss": 1408,
- "tcp_total_retransmissions": 0,
- "tcp_lost_packets": 0,
- "tcp_unrecovered_to": 0,
- "host": "gke-v2y0ly8k-logging-default-pool-e0c7499d-76z8",
- "@timestamp": 1623033334000
- }
复制代码 这是 Calico Enterprise 的流日志示例。有几点须要注意:它聚合了支持前端服务的全部 Pod(frontend-6f794fbff7-*)和属于 currencyservice 的全部 Pod(currencyservice-7fd6c64-*)的数据。来自 kprobe 和套接字统计的数据被聚合为每个指标的均匀值、最小值和最大值,用于服务之间的数据。来自内核的进程 ID 和进程名称与其他数据干系联,我们还看到网络策略操作和影响流的网络策略与其他数据干系联。这是您在 Kubernetes 集群中进行数据网络的目标示例!
现在我们已经讨论了怎样以 Kubernetes 当地方式网络、聚合和关联数据,让我们来探索数据的可视化。
可视化
有一些很棒的工具支持网络数据的可视化。例如,Prometheus 与 Grafana 的集成提供了非常好的仪表板来可视化数据。另有一些贸易工具如 Datadog、New Relic 和 Calico Enterprise,支持数据的网络和可视化。我们将介绍一些对 Kubernetes 集群有用的常见可视化方式。
Service Graph
这是将您的 Kubernetes 集群表示为一个图表,显示 Kubernetes 集群中的服务及其之间的交互。假如我们回到 Google 微服务在线精品店的示例,图 5-4 显示了实施并表示为服务图的在线精品店应用步伐。
图 5-4 是将在线精品店命名空间表示为服务图的可视化,此中节点表示服务和支持服务或摆设的一组 Pod,无论是独立的还是作为摆设的一部分。边缘显示了网络活动和策略操作。该图是交互式的,允许您选择一个服务(例如前端服务),并允许查看为该服务网络的具体日志。图 5-5 显示了所选服务(前端)的全部网络数据的汇总视图。
图 5-5 显示了前端服务的具体视图,作为一种钻取方式——它展示了来自全部泉源的信息,因此非常容易分析服务的操作。
服务图是表示 Kubernetes 集群拓扑结构的一种非常常见的模式。有几种工具提供了这种视图,例如 Kiali、Datadog 和 Calico Enterprise。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0504.png
图 5-4. 在线精品店应用步伐的服务图表示
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0505.png
图 5-5. 前端微服务的具体视图
网络流量的可视化
图 5-6 显示了一种用于可视化流量的常见模式。这是基于环的可视化,此中每个环代表一个聚合级别。在 图 5-5 中显示的示例中,最外层的环代表一个命名空间及其内的全部流量。选择中间的环显示了一个服务的全部流量,选择最内层的环显示了支持该服务的 Pod 的全部流量。右侧面板是一个选择器,可以通过过滤和具体信息如选择的流量和策略操作来启用更细粒度的视图。这是在集群中可视化网络流量的一个绝佳方式。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0506.png
图 5-6. 网络流量可视化
在本节中,我们介绍了一些常见的可视化模式,并尝试展示它们怎样应用于 Kubernetes。请注意,有几种可应用于 Kubernetes 的可视化方法;这些只是示例,展示了怎样表示在 Kubernetes 集群中网络的数据。
现在我们已经讲解了数据网络、聚合、关联和可视化,让我们探讨一些高级主题,使用网络的数据来洞察 Kubernetes 集群的运行情况。
分析和故障清除
在这一节中,我们将探讨分析应用步伐,这些应用步伐使用网络、聚合和关联组件来提供额外的洞察力。请注意,有许多应用步伐可以构建以使用 Kubernetes 集群中的上下文丰富数据。我们提供一些应用步伐作为示例。
分布式跟踪
我们之前解释太过布式跟踪,并讨论了它在基于微服务的架构中的重要性,在这种架构中,跟踪单个用户哀求穿越须要在各种微服务之间发生的多个事务是至关重要的。有两种众所周知的实现分布式跟踪的方法,
仪器化事务哀求头
在这种方法中,HTTP 头部被仪器化为一个哀求 ID,而且哀求 ID 在调用其他服务时通过头部保存。Envoy是一个非常盛行的工具,用于实现分布式跟踪。它支持与其他知名应用步伐跟踪器如 Lightstep 和 AWS X-Ray 的集成。假如您可以接受仪器化应用步伐以在微服务之间的调用中添加和保存哀求 ID,我们建议您使用 Envoy。
eBPF 和 kprobes
在使用 Envoy 描述的方法中,须要对应用步伐流量进行更改。可以使用 eBPF 和 Linux 内核探针为服务间调用实现分布式跟踪。您可以将 eBPF 步伐附加到内核中的 kprobes/uprobes 和其他跟踪点,并构建一个分布式跟踪应用步伐。请注意,此类应用步伐的具体实现超出了本书的范围,但我们想提到这是实现分布式跟踪的一个选项,以防您担心修改应用步伐流量。
现在我们已经讲解了分布式跟踪,让我们看看怎样在您的 Kubernetes 集群中实现数据包捕获。
数据包捕获
在你的 Kubernetes 集群中,我们建议您实施或选择一个支持 pod 之间原始数据包捕获的工具。该工具应支持基于选择器的数据包捕获(例如,pod 标签)和基于脚色的访问控制,以便启用和查看数据包捕获。这是一个简单而非常有效的功能,可以作为响应变乱(例如,应用步伐延迟增加)的一种操作来分析原始数据包流,以理解问题并找到根本缘故原由。为了实施原始数据包捕获,我们建议使用 libpcap,它支持在 Linux 系统上的接口上捕获数据包的能力。
结论
在本章中,我们讨论了什么是可观察性,以及怎样为您的 Kubernetes 集群实施它。以下是本章的要点:
- 监控须要成为您可观察性战略的一部分;仅仅进行监控是不够的。
- 在实施可观察性解决方案时,使用 Kubernetes 的声明性特性非常重要。
- 为实施 Kubernetes 集群的可观察性,关键组件包括日志网络、日志聚合与关联、可视化、分布式追踪和分析。
- 您必须使用适用于 Kubernetes 的当地工具来实现您的可观察性。
- 您应该使用 Linux 内核中提供的工具来驱动数据的高效网络和聚合(例如,NFLOG、基于 eBPF 的探针)。
第六章:观测性和安全性
本章将解释一个观测性平台怎样资助提升您的 Kubernetes 集群的安全性。我们将涵盖以下主题:
警报
在第五章中,我们介绍了实施日志网络的最佳实践。本章将重点讨论怎样构建一个能够天生高保真警报的系统。我们还将讨论使用呆板学习进行异常检测。
安全运营中心
我们将审查一个安全运营中心(SOC)的参考实现,以及观测性怎样资助您为 Kubernetes 集群构建 SOC。
行为分析
我们将介绍用户与实体行为分析(UEBA)的概念,以及怎样在您的 Kubernetes 集群中实施它。
警报
在前一章中,我们讨论了怎样为您的 Kubernetes 集群实施日志记录。一个有效的警报系统必须包括以下内容:
- 系统应能够自动在各种日志数据源(例如 Kubernetes 活动日志、网络日志、应用步伐日志、DNS 日志等)上运行查询。
- 系统必须能够支持一个状态机,用于在指定持续时间内天生特定数量标阈值违规变乱。系统还必须支持设置查询的时间段(称为回溯)。我们将在下一节中介绍一个示例。
- 系统必须能够向外部安全、信息和变乱管理(SIEM)导出可操作的警报,以便它们成为企业中的变乱响应过程的一部分。
主要的云服务提供商提供的警报系统可以资助您在云服务提供商环境中定义基于日志的警报。Google Cloud 提供了关于其警报能力的学习资源。Amazon Web Services(AWS)也有类似的警报能力。这些警报可以在云提供商的日志系统中网络的日志上定义规则,以基于阈值触发警报。例如,在给定时间段内 API 调用的数量大概表明大概存在拒绝服务(DoS)攻击。虽然这些系统适用于一样平常的日志记录和警报,但是对于 Kubernetes 的日志网络系统来说,像我们在第五章中讨论的那种当地化系统是须要的,以便在 Kubernetes 集群中检测基于安全性的变乱,因为它在网络时干系数据,而且可以轻松地在一个日志源上定义警报。此外,一个适用于 Kubernetes 的警报系统将资助您使用 Kubernetes 构建如摆设、标签等的构造定义警报,因为它可以加强精确的上下文与查询网络活动服务的服务和 IP 的标签集。
图 6-1 和 6-2 展示了怎样定义警报来检测您的 Kubernetes 集群中的横向移动的示例。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0601.png
图 6-1. 设置警报操作
图 6-1 显示了怎样设置警报的操作及元数据,如名称、描述、严重程度和时间段,以轮询数据和回溯期限。回溯期限指系统在查询数据时查看的时间跨度。您还可以定义在触发警报之前发生阈值违规的次数阈值。此外,能够设置输特别式也非常重要;在本例中,当报告警报时,数据将按流量泉源(命名空间和摆设)进行聚合。输出的警报数据有助于卑鄙系统(例如 SIEM)管理警报。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0602.png
图 6-2. 警报查询设置
图 6-2 展示了一个警报查询设置的示例。在查询中须要注意的是能够使用 Kubernetes 元数据(例如标签)与网络流活动(例如目标地、协议)和策略判断(例如操作)进行单一查询。这使您能够在定义有效的 Kubernetes 集群警报时具有极大的机动性。请注意,这是怎样考虑构建有效警报系统的代表性示例。除了云提供商的警报系统之外,另有多种其他工具如 Datadog、Sysdig 和 Calico Enterprise 提供了基于 Kubernetes 的警报系统。
我们之前介绍的警报系统非常擅长在系统具有可预测行为而且您可以轻松定义系统正常活动阈值时检测和报告警报。假如警报系统能够“学习”系统的行为并能够动态定义阈值,那将黑白常有用的;这将有助于天生高保真度的警报,并减少由于阈值未随系统状态变化而产生的误报。让我们探讨一下呆板学习怎样解决这个问题。
呆板学习
呆板学习的基础知识及其工作原理超出了本书的范围。在本节中,我们将回顾一些呆板学习的概念,这些概念将向我们展示它怎样资助学习给定指标的行为,并在偏离预期行为时发出警报。在我们进行这些回顾之前,让我们来看看呆板学习中的高级技能:
监视学习
这是一种通过一段时间内标记测试数据来训练系统的技能。它允许系统使用所学来对新数据进行分类并预测结果。
无监视学习
这是一种使用算法来检测和分类未标记数据中模式的技能。请注意,有许多资源可以理解这些概念;此中一个例子是朱利安娜·德卢亚的“监视学习与无监视学习的区别是什么?”。考虑到 Kubernetes 集群中实体(例如 pod)的短暂性,以及我们检测来自该活动产生的数据中的异常的目标,我们建议使用无监视学习技能来检测异常。
基线设定
基线设定是一种在呆板学习中用来一连预测给定度量标准(例如每秒毗连数)的值并检测偏离的技能。CMU ML 的博客文章“3–Baselines”是理解基线设定怎样工作以及可以使用基线设定构建哪些类型模型的好资源。正如博客中提到的,可以创建简单但非常有效的模型,以到达人类程度的性能。这正是我们在警报系统中想要的:系统应该自动定义阈值,并在偏离基线时发出警报。
现在我们相识了应该使用的高级技能之后,让我们看一些例子,这些例子可以资助实现对 Kubernetes 集群的可观察性和安全性。在像 Kubernetes 这样的动态环境中,工作负载是短暂的,可以在不同节点上重新启动/调度,因此在大多数情况下,使用基于规则的引擎来检测异常是不切实际的。须要的是将异常检测引擎层叠在呆板学习引擎之上,该引擎报告给定度量标准的基线偏离。
呆板学习工作的例子
怎样创建呆板学习模型超出了本书的范围;您应该让数据科学团队为您的摆设构建模型。像谷歌云这样的主要云服务提供商为 Kubernetes 工作负载提供了一个构建呆板学习模型的服务,可以资助数据科学团队实现合适的 ML 模型。以下是在您的集群中检测异常变乱的一些有效的 ML 工作负载的示例:
IP 扫描检测
该工作负责查找您集群中向多个目标发送数据包的 pod。这大概表明攻击者已经控制了一个 pod,并正在网络有关别的可达目标的谍报。该工作将 pod 与其复制会集的其他 pod,以及集群中的其他 pod 进行比较。
端口扫描检测
该工作负责查找您集群中向一个目标发送数据包的 pod。这大概表明攻击者已经控制了一个 pod,并正在网络有关别的可达目标的谍报。该工作将 pod 与其复制会集的其他 pod,以及集群中的其他 pod 进行比较。
服务字节异常
该工作查找接收/发送异常高数据量的服务。这大概表明拒绝服务攻击、数据外泄或其他攻击。该工作查找相对于其副本集不寻常的服务,以及相对于集群其他部分不寻常的副本集。
进程重启异常
该工作查找具有过多进程重启的 Pod。这大概表明进程存在问题,如资源问题或攻击。该工作查找相对于其进程重启行为不寻常的 Pod。
DNS 延迟异常
该工作查找具有过高 DNS 哀求延迟的客户端。这大概表明拒绝服务攻击。
L7 延迟异常
该工作查找具有过高 L7 哀求延迟的 Pod。全部 HTTP 哀求在此丈量。此异常大概表明拒绝服务攻击或其他攻击。
HTTP 毗连峰值异常
该工作查找接收过多 HTTP 入站毗连的服务。这种异常大概表明拒绝服务攻击。
此列表提供了检测异常的作业示例。您可以使用Google Cloud 提供的此资源为您的 Kubernetes 集群构建呆板学习作业。请注意,每个作业的描述依赖于一组与 Kubernetes 原生干系的上下文丰富的日志(例如,比较副本会集的 Pod 与其他 Pod,使用发送到/从服务的字节)。
现在我们已经讨论了怎样构建有效的警报系统来检测和报告异常,让我们看一个基于 Kubernetes 集群的安全运营中心的示例实现。
安全运营中心
在本节中,我们将审查基于 Kubernetes 的 SaaS 服务的安全运营中心(SOC)的参考实现。SOC 用于检测和响应安全变乱;我们将探讨在实施 SOC 时怎样使用可观察性。请注意,这是一个示例,应用于指导您的实施。在生产中实施时,您应该使用这些概念,但须要设计和实施得当您用例的 SOC。图 6-3 展示了 Google Cloud 中托管的服务的 SOC 实现示例。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0603.png
图 6-3. Google Cloud 中的 SOC 示例实现
图 6-3 显示了一组运行在 Google Cloud 中的 Kubernetes 集群,每个租户都有一个命名空间表示。每个租户集群可以摆设在 Google Kubernetes Engine (GKE) 中,也可以作为 Google Cloud 中的上游 Kubernetes 集群。有一个入口表示外部实体怎样访问服务。图中省略了工作负载摆设和供应的具体信息,因为我们想重点关注怎样确保服务的安全性。为了确保服务的安全性,您须要日志记录、监视和警报。这可以通过使用 Google Cloud 运营套件 实现,该套件提供支持日志记录、监视和警报的能力。假如您正在使用 GKE,Google Cloud 的博客 描述了怎样使用这些服务来检测和管理 Kubernetes 集群的警报。如前所述,您须要使用呆板学习进行基线订定,并进步警报的质量。Google 提供了一组称为 AI Hub 的呆板学习服务。请注意,您仍然须要构建与您的 SaaS 服务干系且有效的呆板学习模型(请参阅本章前面的示例 ML 作业)。然后,您可以使用众所周知的工具,如 OpsGenie,将警报路由到 SIEM、Slack、PagerDuty、JIRA 和其他工具进行警报管理。这些警报将触发由安全团队定义的修复工作流。请注意,我们以 Google Cloud 为例,但您可以使用前面提到的方法为 AWS 和 Azure 构建 SOC。这些云提供商也为用户提供了类似的一组服务。
如前所述的方法在您仅使用一个云提供商而且没有任何工作负载在当地或其他云提供商环境中时非常有效。此外,前面提到的全部服务都会增加摆设本钱,您还须要委派部分 DevOps/DevSecOps 资源来实施和管理这些服务。因此,我们建议您使用一种不特定于任何云提供商且可以跨云提供商/当地环境使用的工具来构建您的 SOC。
图 6-4 显示了怎样替换一些特定于云提供商的组件,并使用基于 Kubernetes 的可观测性和安全平台创建 SOC。您可以自行构建这个平台,也可以选择使用产品,例如 Datadog、VMware 和 Calico Enterprise 提供的平台。选择产品时,请记着前一节涵盖的警报概念,并确保平台支持与您的修复/管理系统的集成。
现在我们已经回顾了怎样构建一个对您的 Kubernetes 集群有效的 SOC,让我们再来看看怎样将可观测性应用于保护您的 Kubernetes 集群。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0604.png
图 6-4. 使用 Kubernetes 原生平台的 SOC
用户和实体行为分析
用户和实体行为分析(UEBA)是一个领域,在此领域中,您使用基于 ML 和 AI 的技能来分析用户或实体(如 pod、服务或摆设)随时间的行为,并通过用户/实体的异常行为检测来检测异常行为。Microsoft Azure 作为其云平台的一部分提供 UEBA。Microsoft Azure 的博客文章,《在 Azure Sentinel 中使用用户和实体行为分析(UEBA)识别高级威胁》(https://oreil.ly/FDspV)是一篇优秀的资源,描述了怎样在安全用例中使用 UEBA。请注意,实体的异常行为并不总是可疑行为;您须要将行为映射到如 MITRE 攻击框架或其他妥协指标的框架,以确认它是一个安全问题。
让我们举一个简单的例子,说明怎样在 Kubernetes 中为实体(如服务)实施 UEBA。
图 6-5 展示了你的 Kubernetes 集群中的一个服务以及我们在分析服务行为时将考虑的各种交互。作为其正常操作的一部分,该服务将与 Kubernetes API 服务器和 Kubernetes 数据存储交互。此外,它将与入口资源交互,以与集群外的实体通信,并使用集群网络与集群内的其他实体交互。该服务还将使用集群中的 DNS 服务进行操作。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0605.png
图 6-5. Kubernetes 服务行为分析
为了为服务建立一个档案,我们须要考虑服务的以下方面。这些在呆板学习中被称为特征。
- 服务组成(如 pod 的端点数、RBAC、策略)
- 对服务的文件系统活动、进程信息和系统调用活动
- 与服务干系联的服务账户
- 服务的生命周期操作(例如创建、删除、缩放)
- 向服务的流量(网络、应用步伐)和从服务的流量
- 服务中 pod 的 DNS 活动
图 6-5 中显示的 UEBA 引擎将从各种数据源(网络流日志、应用步伐流日志、Kubernetes 审计日志、DNS 活动日志、进程信息、文件系统、系统调用活动日志)网络日志,并将它们存储在数据存储中。这些日志由分析引擎聚合和关联,以天生服务在各种特征上的关联日志。
呆板学习引擎使用复杂模型来基线服务在各种特征上的行为。这是呆板学习中的一个高级概念,此中模型考虑每个特征及其相互作用等因素来构建服务的设置文件。这最好由您的数据科学团队实施。然后,此设置文件用于预测异常并天生偏离的警报。有一个仪表板允许 SOC 操作员审查分析数据并用于取证或威胁狩猎。请注意,使用第五章描述的概念构建的安全和可观察性平台将有助于构建有效的 UEBA 系统。
UEBA 是一种高级技能,实施起来复杂,但却是快速查找集群中潜在脆弱实体的非常有效方式。这使得 SOC 运营非常高效和可扩展。一旦您的摆设扩展到多个集群(50+),使用警报/仪表板手动审查以查找实际问题就不再实际。UEBA 将警告您有异常且须要立即关注的实体。
结论
当您考虑怎样使用可观察性来资助保护您的集群时,请考虑以下几点:
- 您使用的警报系统必须是基于 Kubernetes 的,而且必须支持使用呆板学习进行基线设置,以便您无需手动定义各种特征的阈值。
- 建议您考虑选择一个基于 Kubernetes 的平台,可以跨云和当地摆设,以建立您的 SOC。
- UEBA 是一个高级概念,实施起来复杂,但在保护 Kubernetes 集群方面非常有效。
第七章:网络策略
在本章中,我们将描述网络策略并讨论其在保护 Kubernetes 集群中的重要性。我们将回顾各种网络策略的实现和支持网络策略实施的工具。我们还将介绍带有示例的网络策略最佳实践。
什么是网络策略?
网络策略是保护 Kubernetes 网络的主要工具。它允许您轻松地限定集群中的网络流量,使只有您渴望流动的流量被允许。
要理解网络策略的重要性,让我们简要探讨一下在引入网络策略之前怎样典范地实现网络安全。在企业网络的汗青上,网络安满是通过设计网络设备(交换机、路由器、防火墙)的物理拓扑及其干系设置来实现的。物理拓扑定义了网络的安全边界。在捏造化的第一阶段中,云中同样对网络和网络设备构造进行了捏造化,并使用相同的技能来创建(捏造)网络设备的特定网络拓扑,以提供网络安全。添加新的应用步伐或服务通常须要更新网络拓扑和网络设备设置,以提供所需的安全性。
相比之下,Kubernetes 网络模型定义了一个“扁平”的网络,在这种网络中,默认情况下,每个 Pod 可以直接与集群中的全部其他 Pod 进行通信。这种方法极大地简化了网络设计,并允许新的工作负载在集群中的任何位置动态调度,而无需依赖于网络设计。
在这种模型中,与其通过网络拓扑边界来定义网络安全,不如使用独立于网络拓扑的网络策略来定义。网络策略进一步通过使用标签选择器作为其主要机制来定义哪些工作负载可以与哪些工作负载通信,而不是使用 IP 地址或 IP 地址范围。
可以将网络策略实行视为每个 Pod 都受其自身的专用捏造防火墙保护,并根据已定义的网络策略自动编程和及时更新。图 7-1 展示了在 Pod 上使用其专用捏造防火墙进行网络策略实行的情况。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0701.png
图 7-1. 由捏造防火墙保护的 Pod
为什么网络策略很重要?
在攻击者变得越来越复杂的期间,作为防线的网络安全比以往任何时间都更为重要。
虽然您可以(而且应该)使用防火墙来限定网络的边界流量(通常称为南北流量),但由于 Pod 调度的动态性和 Pod IP 地址,它们通常只能以集群整体的粒度进行 Kubernetes 流量的管控,而不能针对特定的 Pod 组进行细粒度管控。此外,一旦攻击者在边界内部得到小小的驻足点,他们的大多数量标是横向移动(东西流量)以获取对更高代价目标的访问权限,而基于边界的防火墙无法对其进行管控。随着应用架构从单块到微服务的演变,东西流量的数量和因此横向移动的攻击面仍在继承增长。
另一方面,网络策略设计用于 Kubernetes 的动态特性,遵循标准的 Kubernetes 范式,使用标签选择器来定义 Pod 组,而不是 IP 地址。由于网络策略在集群内部实行,它可以保护南北和东西流量。
网络策略代表了网络安全的重要进步,不仅因为它处理了当代微服务的动态特性,而且因为它使开发和 DevOps 工程师能够轻松地自定义网络安全,而无需学习低级网络细节。网络策略使得定义意图变得容易,例如只有这个微服务能毗连到数据库,将该意图编写为代码(通常是 .yaml 文件),并将网络策略的编写集成到 Git 工作流程和 CI/CD 过程中。
网络策略实现
Kubernetes 定义了一个标准的网络策略 API,因此您可以在任何集群上盼望一组基本特性。但 Kubernetes 本身除了存储外不对网络策略进行任何操作。网络策略的实行委托给了网络插件,允许一系列实现。大多数网络插件支持 Kubernetes 网络策略的主要元素,尽管许多插件并未实现规范的每个功能。值得注意的是,大多数实现与网络插件特定的 Pod 网络实现耦合。然而,某些网络策略实现可以在多种不同的 Pod 网络插件上强制实行网络策略。图 7-2 显示存储在 Kubernetes 数据存储中的网络策略,由网络插件用于实行。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0702.png
图 7-2. 由网络插件实施的存储在 Kubernetes 中的网络策略
有多种网络和网络策略实现可供选择,如图 7-3 所示。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0703.png
图 7-3. 顶级网络技能实现的采取情况
无论您选择哪种网络策略实现,我们建议出于以下缘故原由选择此中一种:
- 它实现了完备的 Kubernetes 网络策略规范。
- 除了支持 Kubernetes 网络策略规范外,其自身的策略模型还提供额外的功能,可以与 Kubernetes 网络策略一起使用,支持额外的企业安全用例。
- 一些网络插件,如 Weave Net、Kube-router 和 Calico,可以在其自身丰富的网络功能集之上强制实行网络策略,也可以在包括亚马逊的弹性 Kubernetes 服务(EKS)、Azure Kubernetes 服务(AKS)和谷歌 Kubernetes 引擎(GKE)在内的几个其他网络选项上强制实行。这使它们成为多云策略的特别强大选择,因为它使您可以从广泛的选项中选择最得当您环境的网络,并在全部环境中使用相同丰富的网络策略功能。
- 网络策略可以应用于主机端点/接口,允许使用相同的机动策略模型来保护 Kubernetes 节点或非集群主机/捏造机。
- 它支持在网络/基础设施层以及上层(包括支持 L5-L7 匹配标准的策略规则,如 HTTP 方法和路径)强制实行的网络策略。多个实行点有助于保护您的基础设施免受受损工作负载的影响,并保护您的工作负载免受受损基础设施的影响。它还避免了须要在应用和基础设施层分别进行安全设置的须要,或者须要学习每一层不同的策略模型。
- 它须要是生产级的,这意味着它必须在任何巨细的集群中表现出色,从单节点集群到数千节点集群。
- 它提供企业增加新功能的能力,并作为企业级 Kubernetes 网络安全解决方案的基础组件。
网络策略最佳实践
在本节中,我们将探讨怎样使用示例实现网络策略,并涵盖实施的最佳实践。以下示例使用 Calico 网络策略模式,该模式扩展了 Kubernetes 网络策略模式。我们之所以选择这些示例,是因为我们熟悉 Calico 网络策略,但这些最佳实践也可以与其他可用的网络策略模型一起实现。
入口和出口
当人们考虑网络安全时,第一个想法往往是怎样保护工作负载免受南北向的外部攻击者的侵害。为了资助防御此类攻击,您可以使用网络策略来限定可以从集群外部访问的任何 Pod 的入口流量。
然而,当攻击者乐成找到毛病时,他们通常会使用受损的工作负载作为横向移动的出发点,探测您网络的其余部分,以使用额外的毛病来访问更有代价的资源或提升权限以发动更强大的攻击或窃取敏感数据。
纵然您在集群中的全部 Pod 上设置了限定入口流量的网络策略,横向移动大概会针对集群外保护较弱的资产。因此,最佳实践是始终为集群中的每个 Pod 定义入口和出口网络策略规则。
尽管这并不能包管攻击者无法找到额外的毛病,但它确实大大减少了可用的攻击面,使攻击者的工作变得更加困难。此外,假如联合适当的策略违规警报,可以大大紧缩确定工作负载已受损的时间。以 2020 年 IBM 数据泄露本钱报告为例,IBM 报告企业均匀须要 207 天才能发现一次数据泄露,然后须要额外的 73 天来进行控制!通过精确编写的网络策略和违规警报,可以防止或大大减少泄露,潜在地将其减少到几分钟甚至几秒钟,而且甚至可以自动响应以隔离可疑工作负载。
不仅仅是使命关键的工作负载
最佳实践已建议确保每个 Pod 都具有限定其入口和出口流量的网络策略。这意味着当您考虑怎样保护使命关键的工作负载时,您确实须要保护全部工作负载。假如不这样做,那么一些看似不重要、无害的工作负载终极大概成为攻击您网络其余部分的基础,终极导致最关键工作负载的失败。
策略和标签模式
Kubernetes 标签和网络策略的一个优势是您可以以多种方式机动使用它们。然而,结果是通常存在多种标记和编写策略的方式可以实现相同的特定目标。因此,另一个最佳实践是考虑使用同等的模式或设计模式标准化标记 Pod 和编写网络策略的方式。这可以使编写和理解每个网络策略的意图变得更加简单明了,特别是假如您的集群托管大量微服务时。
例如,您可以指定每个 Pod 都将具有标识其所属微服务的“app”标签,而且每个 Pod 将使用该 app 标签应用单一网络策略,该策略使用该 app 标签订义与其预期交互的微服务的入口和出口规则:
- apiVersion: projectcalico.org/v3
- kind: NetworkPolicy
- metadata:
- name: back-end-policy
- namespace: production
- spec:
- selector: app == 'back-end'
- ingress:
- - action: Allow
- protocol: TCP
- source:
- selector: app == 'front-end'
- destination:
- ports:
- - 80
- egress:
- - action: Allow
- protocol: TCP
- destination:
- selector: app == 'database'
- ports:
- - 80
复制代码 或者,您可以决定在策略规则中使用权限样式标签,而不是在其入口规则中列出允许访问每个服务的微服务。
- apiVersion: projectcalico.org/v3
- kind: NetworkPolicy
- metadata:
- name: database-policy
- namespace: production
- spec:
- selector: app == 'database'
- ingress:
- - action: Allow
- protocol: TCP
- source:
- selector: database-client == 'true'
- destination:
- ports:
- - 80
- egress:
- - action: Deny
复制代码 这可以使得单独的微服务团队能够编写自己的网络策略,而无需知道必须消费该服务的其他微服务的完备列表。
另有许多其他方法可以解决这个问题,这里没有对错之分。但是,在前期定义怎样标记和定义网络策略的方法会使得恒久来看生活变得更加轻松。
假如不确定哪种方法最得当您,那么“应用步伐”方法是一个很好的出发点。稍后总是可以扩展为包括为那些具有大量客户端的微服务定义权限样式标签的想法,假如维护策略规则变得耗时。
默认拒绝和默认应用策略
Kubernetes 网络策略规范允许全部入口 Pod 流量通过,除非存在一个或多个适用于该 Pod 的入口规则的网络策略,然后只有策略明确允许的入口流量才被允许。出口 Pod 流量同理。因此,假如忘记为新的微服务编写网络策略,它将保持不安全状态。假如忘记为该微服务编写入口和出口规则,那么它将部分保持不安全状态。
鉴于此,一个良好的做法是订定一个“默认拒绝策略”,防止未经其他网络策略明确允许的任何流量。通常的做法是订定一个适用于全部 Pod 的策略,包括入口和出口规则,但本身不明确允许任何流量。因此,假如没有其他明确允许流量的网络策略适用,那么流量将被拒绝:
- apiVersion: networking.k8s.io/v1
- kind: NetworkPolicy
- metadata:
- name: default-deny
- Namespace: my-namespace
- spec:
- podSelector: {}
- policyTypes:
- - Ingress
- - Egress
复制代码 由于 Kubernetes 网络策略是有命名空间的,前面提到的网络策略须要为每个命名空间重复,而且最好纳入集群中新命名空间设置的标准操作流程中。别的,一些网络策略实现逾越了 Kubernetes 网络策略,提供了指定整个集群范围网络策略的能力(不限于单一命名空间)。下面的示例展示了怎样创建一个策略,将整个集群切换到默认拒绝行为,包括将来创建的任何命名空间:
- apiVersion: projectcalico.org/v3
- kind: GlobalNetworkPolicy
- metadata:
- name: default-deny
- spec:
- selector: all()
- types:
- - Ingress
- - Egress
复制代码 然而,值得注意的是,这个策略适用于全部 Pod,而不仅仅是应用 Pod,包括 Kubernetes 的控制平面 Pod。假如在创建此类策略之前没有精确的网络策略或设置故障安全端口,大概会导致集群出现严重问题。
一个风险较低的最佳实践是定义一个仅适用于 Pod 的网络策略,清除控制平面 Pod。除了触发默认拒绝行为外,此策略还可以包括您渴望应用于全部应用 Pod 的任何规则。例如,您可以包括一个允许全部应用 Pod 访问 kube-DNS 的规则。这有助于简化须要编写的每个微服务策略,使其能够专注于所需的每个微服务特定行为:
- apiVersion: projectcalico.org/v3
- kind: GlobalNetworkPolicy
- metadata:
- name: default-app-policy
- spec:
- namespaceSelector: has(projectcalico.org/name) &&
- projectcalico.org/name not in {"kube-system", "calico-system"}
- types:
- - Ingress
- - Egress
- egress:
- - action: Allow
- protocol: UDP
- destination:
- selector: k8s-app == "kube-dns"
- ports:
- - 53
复制代码 由于此策略故意清除控制平面组件,为了保护控制平面,您可以为每个控制平面组件编写特定的策略。最好在集群创建时进行此类策略创建,而不是在集群托管工作负载之前,因为策略堕落大概会使您的集群处于破损状态,大概导致重大的生产中断。此外,猛烈建议在开始尝试为控制平面创建任何策略之前,始终确保已设置了您使用的网络插件的精确故障转移端口。
策略工具化
在这一节中,我们将探讨可用于有效向您的 Kubernetes 集群添加网络策略的工具。
开发过程和微服务的好处
与传统网络安全控制相比,网络策略的一个优点是定义网络策略不须要网络或防火墙专业知识。网络策略使用与其他 Kubernetes 资源相同的概念和范式。理论上,任何熟悉在 Kubernetes 中摆设微服务的团队都可以轻松掌握网络策略。因此,网络策略代表了采用向左转移(shift-left)哲学的机会,此中网络安全在开发周期的早期定义,而不是在过程的后期定义。这是安全和开发团队合作以保护您的 Kubernetes 集群的绝佳机会。
与此同时,许多组织正在从单体应用架构转向微服务架构,此中一个目标通常是增加开发和组织的机动性。在这种方法中,每个微服务通常由一个开发团队维护,该团队对微服务有显著的专业知识,但不一定相识微服务所属应用的整体。微服务的转移与网络策略的向左转移机会互补。负责开发微服务的团队通常很相识其消耗和依赖的其他微服务。他们大概也很相识哪些微服务消耗他们的微服务。
当与明确定义的、标准化的政策和标签模式方法联合时,这使他们在实施微服务网络策略时处于一个强势位置,作为微服务开发过程的一部分。在这种模型中,网络策略被视为内嵌并在开发过程中进行测试的代码,就像微服务代码的任何其他关键部分一样。
同样有效的方法是让开发团队专注于他们负责的微服务的内部,并将微服务的操作责任留给 DevOps 团队。然而,相同的理念仍然适用。这样的 DevOps 团队通常须要深入相识他们负责操作的微服务之间的依赖关系,以管理应用步伐的运行和微服务的生命周期。网络安全可以由 DevOps 团队定义为代码,并在使用之前像他们开发的其他操作代码或脚本一样进行测试。
当然,今天的实际是,许多组织在实现微服务、敏捷和左移安全的天堂方面另有很长的路要走。网络安全大概在组织的流程中来得更晚,甚至作为已经投入生产的系统的事后想法。在这种情况下,定义网络策略大概会更具挑战性,错误的网络策略大概会对生产造成重大影响。好消息是,有一系列工具可资助管理网络策略的生命周期,使这一过程更容易,包括政策保举、政策影响预览和政策暂存/考核模式。
政策建议
政策保举工具在那些负责网络安全的团队对他们须要保护的应用步伐或微服务之间全部网络依赖关系没有很好、自信理解的情况下提供了极大的资助。这些工具还资助您精确开始编写网络策略,并使网络策略的创建比手工编写容易得多。
保举工具通常的工作方式是分析每个微服务在一段时间内与其他微服务之间的网络流量。这意味着要得到保举,微服务须要在生产中运行,或者在能够准确反映微服务与应用步伐其余部分之间生产交互的暂存或测试环境中运行。
有许多可供选择的政策保举工具,通常具有不同程度的复杂性、对 Kubernetes 的熟悉程度和政策模式方法。建议您使用集成到您的网络策略解决方案中的 Kubernetes 感知政策保举引擎。
政策影响预览
政策影响预览工具在应用到集群之条件供了一种检查网络策略的方法。类似政策建议,通常通太过析一段时间内集群的汗青网络流量来完成,计算新策略大概会影响哪些网络流。例如,识别以前允许但现在会被拒绝的流量,以及以前被拒绝但现在会被允许的流量。
政策影响预览在任何情况下都是极大的资助,特别是在你并非完全依赖政策建议的场景下。例如,当你手动定义网络策略或者修改政策建议以与特定的政策和标签模式标准同等时,这将非常有用。纵然团队对微服务的网络策略定义有很高的信心,相识微服务的网络依赖,政策影响预览也是无价的,它有助于捕捉任何意外错误,例如难以发现的拼写错误,这些错误大概会显著影响合法的网络流量。
政策影响预览工具比政策建议更少见。使用提供基于分析所网络的流日志数据的影响可视化表示的工具非常有用,无论在任何所需的时间段内。这将有助于减少由于不精确撰写的政策或由于操作员错误而导致的停机问题。
政策分阶段和审计模式
甚至比政策影响预览更少见但大概更有代价的是支持政策分阶段,有时称为政策审计模式。
政策分阶段允许应用于集群的网络策略变动,而不会影响网络流量。然后,分阶段的策略会记录其将与之交互的全部流的具体信息,而实际上不会影响任何流。在须要对个别政策进行汗青数据的政策影响预览大概过于简单化的应用步伐运行复杂性的情况下,这非常有用。例如,假如须要同时更新多个相互依赖的策略,或者渴望使用及时而非汗青网络流来监视策略影响。
为了使撰写有效网络策略的任务不再艰巨,你须要使用政策建议,然后将策略分阶段以相识其影响,然后再将其推广以供实行。这种基于汗青网络流量的政策建议循环,随后是分阶段(将策略应用于当前和未来的网络流),然后进行所需的调整,末了实施策略,是确保策略变动能够确切到达预期效果的最佳方式。
结论
在本章中,我们讨论了网络策略的重要性以及各种网络策略的实施和工具,以资助您进行实施。以下是网络策略的一些关键方面:
- 网络策略应该用于保护 Kubernetes 网络,而且它与在集群外围实施的防火墙相辅相成。
- 建议选择一个能够识别 Kubernetes 的实现,扩展基本的 Kubernetes 网络策略。
- 有许多网络策略实施提供工具,资助在 Kubernetes 集群中实施网络策略。
第八章:管理团队之间的信托
在前一章中,我们探讨了网络策略怎样代表一种采用左移哲学来进行网络安全的机会,即由开发周期早期的团队定义安全,而不是由安全团队在过程晚期定义和维护安全。这种方法可以带来许多好处,但为了可行性,须要在涉及的团队之间建立相应的信托程度和责任分别。
在大多数组织中,将安全责任的 100%向左移动并不实际,其他团队(平台、网络和安全)不会完全摆脱安全责任。例如,尽管大概会将个体微服务安全的较低级别细节的责任向左移动,但安全团队仍大概负责确保您的 Kubernetes 摆设具有符合内部和外部合规要求的安全姿态。
一些企业通过定义内部流程来处理这个问题,例如确保安全团队在应用安全更改之前审查全部安全更改。这种方法的缺点是大概会降低敏捷性,这与左移的动机之一相抵牾,即增加敏捷性。
幸运的是,在 Kubernetes 环境中可以设置各种类型的防护栏,从而减少对这些传统流程控制的需求。在本章中,我们将探讨一些这些能力以及它们怎样用于控制在安全左移方法背景下从一个团队委托给另一个团队的信托程度。
基于脚色的访问控制(RBAC)
Kubernetes 基于脚色的访问控制(RBAC)是定义个别用户或用户组在 Kubernetes 集群中被允许做什么的主要工具。RBAC 权限是使用脚色定义的,并通过脚色绑定授予给用户或用户组。每个脚色包括一系列资源(按资源类型指定,集群范围内,在命名空间内,甚至是特定的资源实例)以及每个资源的权限(例如,获取、列出、创建、更新、删除等)。
许多 Kubernetes 资源是有命名空间的,包括摆设、守护进程集、Pod 和 Kubernetes 网络策略。这使得命名空间成为团队之间理想的信托边界。关于怎样使用命名空间没有固定的规则,但一种常见的做法是为每个微服务使用一个命名空间。然后可以使用 RBAC 授予权限,以便团队能够管理对应微服务的命名空间中的资源。
假如安全已经向左移动,这通常包括管理适用于微服务的网络策略的权限,但不包括管理他们不负责的微服务适用的任何网络策略。
假如对入口和出口流量都遵循了默认拒绝式最佳实践,那么团队不能忘记编写网络策略,因为没有网络策略,微服务将无法正常工作。此外,由于其他团队已定义了覆盖其负责的微服务的入口和出口流量的等效网络策略,因此仅当两个团队都指定了允许该流量的网络策略时,两个微服务之间的流量才被允许。这进一步控制了每个团队委托的程度。
当然,根据安全左移的程度,定义网络策略的责任大概由不同的团队承担,而不是负责操作微服务的团队。同样,Kubernetes RBAC 可以用于轻松反映这种责任分担。
Kubernetes 网络策略的限定
使用 RBAC 与 Kubernetes 网络策略在左移环境中存在一些值得注意的限定:
- 默认拒绝式策略须要在为命名空间提供服务时创建。负责为微服务定义网络策略的团队还可以修改或删除此默认策略。
- 网络策略是基于 IP 的,不能使用完全合格的域名 (FQDN)。这在定义到集群外部资源的策略时大概是一个限定。
- Kubernetes RBAC 控制资源的访问,但不限定资源的内容。在网络策略的上下文中尤为干系的是 pod 标签,因为它们被用作网络策略规则中识别其他微服务的主要机制。例如,假如一个团队为其微服务编写了一个网络策略,允许来自具有特定标签的 pod 的流量访问它,那么理论上任何有权限管理 pod 的团队都可以将该标签添加到其 pod 中,并得到对该微服务的访问权限。通过始终在策略规则中使用命名空间部分而且有选择地授予哪些团队修改命名空间标签的权限,可以减少这种暴露。
假如已定义了标准化的策略和标签模式,而且团队被信托遵循它们,那么这些限定更多是理论上的问题而不是实际问题。然而,对于某些组织来说,它们大概代表了真正影响其安全需求的问题。这些组织因此大概渴望使用超出 Kubernetes RBAC 和 Kubernetes 网络策略之外的额外能力。特别是,他们大概考虑:
- 更丰富的网络策略实现支持额外的网络策略类型、匹配条件和非命名空间网络策略,这些开放了更多的选项来分配责任和 RBAC 给团队。
- 准入控制器可在资源内的每个字段级别强制实行控制,例如确保遵循标准化的网络策略和标签模式,包括限定团队使用特定标签。
我们现在将审查扩展 Kubernetes 网络策略的网络策略实现及怎样使用它们来管理信托。
更丰富的网络策略实现
一些网络策略实现支持 Kubernetes 网络策略及其自定义网络策略资源,可与或代替 Kubernetes 网络策略使用。根据实现情况,这些大概会为怎样分割责任和跨团队使用 RBAC 提供额外选项。有些供应商提供更丰富的网络策略实现,支持 Kubernetes 网络策略并添加更多功能(例如,Weave Net,Kube-router,Antrea,Calico)。我们鼓励您审查这些内容,并选择最符合您需求的最佳选项。在本节中,我们将通过 Calico 来看具体示例,因为它是最广泛摆设的容器网络插件。
Calico 支持 Kubernetes 网络策略功能集,以及其自身的 Calico 网络策略资源,可与 Kubernetes 网络策略并存使用。Calico 网络策略有两种类型,均属于 projectcalico.org/v3 API 组:
NetworkPolicy
这些策略是命名空间作用域的(与 Kubernetes 网络策略类似)。
GlobalNetworkPolicy
这些策略适用于整个集群,与命名空间无关。
Calico 网络策略的两种类型均支持超出 Kubernetes 网络策略的共同功能集,包括:
- 比 Kubernetes 网络策略具有更丰富的匹配条件集,例如能够匹配 Kubernetes 服务账户。
- 明确允许、拒绝或记录策略规则中的操作,而不是隐式始终允许的 Kubernetes 网络策略操作。
- 优先次序排序以定义网络策略对同一工作负载应用时的评估次序。(请注意,假如仅使用 Kubernetes 网络策略,或者 Calico 策略只包含允许操作,则评估次序对策略结果没有影响。但是,一旦存在任何带有拒绝操作的策略规则,次序就变得重要起来。)
我们想提到另有其他扩展 Kubernetes 网络策略的网络策略实现,如 Antrea,提供 ClusterNetworkPolicy(类似于 GlobalNetworkPolicy)。
以下示例展示了怎样使用 Kubernetes RBAC 实现网络策略。在示例中,您可以基于分配给服务账号的标签来控制网络访问。在 Kubernetes 中,Pod 与其关联的服务账号干系联,因此可以通过服务账号来识别 Pod。您应使用 RBAC 来控制哪些用户可以为服务账号分配标签。示例中的网络策略使用分配给服务账号的标签来控制网络访问。具有 intern 服务账号的 Pod 只能与标记为role == intern的服务账号的 Pod 通信。
- apiVersion: projectcalico.org/v3
- kind: NetworkPolicy
- metadata:
- name: restrict-intern-access
- namespace: prod-engineering
- spec:
- serviceAccountSelector: 'role == "intern"'
- ingress:
- - action: Allow
- source:
- serviceAccounts:
- selector: 'role == "intern"'
- egress:
- - action: Allow
- destination:
- serviceAccounts:
- selector: 'role == "intern"'
复制代码 通过这种方式,您可以扩展 RBAC 的概念,该概念用于控制服务账号访问 Kubernetes 资源的网络访问。这是一个两步过程。RBAC 用于控制对服务账号的标签分配,而基于标签的服务账号选择器用于控制网络访问。可以使用这些额外的功能与 Kubernetes 网络策略联合使用,更清晰地分离高级集群运维或安全团队与各个微服务团队之间的责任。
例如,大概如下所示:
- 将集群运维或安全团队的 RBAC 权限扩展至管理 Calico 网络策略,以覆盖整个集群范围,使其能够定义设定集群整体安全姿态的基本高级规则。例如,像在第七章讨论的默认拒绝式应用策略和限定集群出口到特定 Pod 的策略。
- 将每个微服务团队授予 RBAC 权限,以在微服务的命名空间中定义 Kubernetes 网络策略,使他们能够为其负责的微服务定义自己的细粒度约束。
在基础的网络策略 RBAC 权限分配之上,集群运维或安全团队可以通过使用命名空间或服务账号标签来定义规则,而不是简化匹配 Pod 标签,为每个微服务团队分配不同的信托级别。例如,他们可以使用服务账号标签来定义限定集群出口到特定 Pod 的策略,并授权各个微服务团队使用但不编辑分配给其命名空间的任何服务账号。通过这种机制,一些微服务团队大概被授予权限选择性地允许其某些 Pod 的集群出口,而其他团队则没有同样的权限。
图 8-1 提供了这些思想怎样联合的简化示例。
虽然这些功能相当强大,但在一些组织中,跨团队责任的分割大概更为复杂,特别是在团队层级更多的情况下。例如,合规团队、安全团队、集群运维团队和各个微服务团队大概具有不同层次的责任。为了更轻松地满意这些要求,一种方法是使用支持分层网络策略概念的网络策略实施。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0801.png
图 8-1. 展示了使用网络策略实现信托边界的示例
有一些贸易实现支持使用策略层级实现分层网络策略。类似的概念(分层命名空间和策略)也在 Kubernetes 社区中讨论。可以为每个层级的 RBAC 定义,以限定谁可以与该层级进行交互。在此模型中,网络策略被分层在多个层级中,按照定义的次序进行评估,以匹配组织责任分割的须要。可以为每个层级的 RBAC 定义,以限定谁可以与该层级进行交互。每个层级的网络策略可以做出允许或拒绝决定(制止后续策略的评估),或将决定转达给层级结构中的下一个层级,以根据该层级中的策略进行评估。
图 8-2 提供了一个简化的示例,展示了怎样使用这些功能来在组织内部的三个不同责任层之间分割责任。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0802.png
图 8-2. 使用层级实现分层网络策略
准入控制器
我们已经讨论了定义和遵循标准化网络策略和标签模式的代价。早期讨论的团队之间责任分割的方法是围绕资源和命名空间级别的 RBAC,团队在被允许管理的资源和命名空间范围内具有自由度,因此不能包管全部团队都遵循了这些模式。
Kubernetes 本身没有内置能力以在这种粒度级别强制实行限定,但它支持准入控制器 API,允许将第三方准入控制器插入 Kubernetes API 机制,以在创建、更新和删除操作期间实行对象的语义验证。您还可以使用准入控制器,也称为变异准入控制器,用于修改已准入的对象。
例如,在实施网络策略的上下文中,准入控制器可以资助以下操作:
- 验证网络策略是否具有符合组织试图遵循的最佳实践的入口和出口规则。
- 确保每个 Pod 都具有一组特定的标签,以符合组织定义的标签标准。
- 限定不同组的用户对特定标签值的访问。
但是准入控制器的安全用例不仅限于网络策略。例如,Kubernetes 服务包括支持使用服务的 ExternalIP 字段关联的任意 IP 地址。假如没有一定程度的监管,这是一个非常强大的功能,大概会被具有 RBAC 权限创建和管理 Kubernetes 服务的任何人恶意使用,拦截 Pod 流量并将其重定向到 Kubernetes 服务。根据涉及团队内的信托程度,使用准入控制器对此进行监管大概是须要的。
根据组织的技能组合和具体需求,有几种准入控制器实现选项:
- 假如存在专门满意组织需求的预先存在的第三方准入控制器,则使用它
- 编写一个根据组织需求优化的自定义准入控制器
- 使用具有丰富策略模型的通用准入控制器,可以映射到广泛的用例范围
对于许多场景来说,选择一个通用准入控制器可以在机动性和编码复杂性之间取得良好的均衡。例如,您可以考虑 Kyverno,它具有专为 Kubernetes 设计的策略引擎,或者围绕 Open Policy Agent 构建的准入控制器,其策略模型使用 Rego 定义机动的匹配和语言能力。
尽管准入控制器非常强大,但通常建议仅在确实须要时才实施它们。对于某些组织来说,以这种方式使用准入控制器大概过分,考虑到团队之间的责任和信托程度。对于其他组织来说,它们大概是满意内部合规要求的重要工具,而且使用它们的理由非常明确。
结论
Kubernetes 安全须要各个团队实施,并须要团队之间的协作。本章涵盖了以下关键概念:
- 您应该使用 RBAC 和网络策略来定义边界,以资助您管理跨团队的活动。
- 您可以通过使用网络策略中的服务账户来扩展 RBAC 的概念,以控制网络访问,资助您管理信托。
- 准入控制器有助于控制访问并在各个团队之间实施信托边界。
- 开发、平台和安全团队之间的协尴尬刁难于实施安全非常重要。
第九章:将服务暴露给外部客户端
在早期的章节中,我们探讨了网络策略是保护 Kubernetes 的主要工具之一。这适用于集群内部的 pod-to-pod 流量(东西向流量)以及 pod 与集群外部实体(南北向流量)之间的流量。对于全部这些流量类型,最佳实践都是相同的:使用网络策略来限定允许的网络毗连到最窄的须要范围,因此只有您盼望和须要的特定应用步伐或微服务的毗连才被允许。
对于须要由集群外部客户端访问的 pods,这意味着限定毗连:
- 与相应微服务盼望接收传入毗连的特定端口(s)。
- 从须要毗连到微服务的特定客户端。
特定的微服务通常只在企业内部(无论是当地还是公共云)被有限数量标客户端消耗是常见的。在这种情况下,理想情况下 Kubernetes 网络策略规则应该限定传入毗连到与客户端干系的 IP 地址或 IP 地址范围。纵然微服务暴露给公共互联网(例如,为公共可访问的 SaaS 或网站暴露前端微服务),仍然有一些情况须要在一定程度上限定访问。例如,基于合规性缘故原由大概须要阻止某些地理位置的访问,或者大概渴望阻止已知的不良行为者或威胁源的访问。
不幸的是,实施这一最佳实践的方式须要考虑使用哪些网络插件和 Kubernetes 原语来将微服务暴露在集群外部。特别是,在某些情况下,原始客户端源 IP 地址会被保存到达 pod,这使得 Kubernetes 网络策略能够轻松地限定对特定客户端的访问。在其他情况下,客户端源 IP 地址大概会被与网络负载均衡干系的网络地址转换(NAT)或与应用层负载均衡干系的毗连制止所模糊。
在本章中,我们将探讨在三种主要选项中暴露应用步伐或微服务到集群外部时可用的不同客户端源 IP 行为:直接 pod 毗连、Kubernetes 服务和 Kubernetes Ingress。
相识直接 pod 毗连
Pods 直接被集群外的客户端访问而不是通过 Kubernetes 服务或 Kubernetes Ingress 访问相对较少见。然而,在某些场景下大概渴望或须要这样做。例如,某些类型的分布式数据存储大概须要多个 pod,每个 pod 都有特定的 IP 地址,可以设置用于数据分发或客户端对等毗连。
支持从集群外部直接毗连到 pod IP 地址须要使用使 pod IP 地址在集群边界之外可路由的 pod 网络。通常意味着使用以下之一:
- 公共云集群中的云提供者网络插件(例如,默认在 EKS 中使用的 Amazon VPC CNI 插件)
- 可以使用 BGP 与当地企业网络集成的网络插件(例如,Kube-router、Calico CNI 插件)。
除了底层网络支持的毗连性之外,客户端还须要一种方法来找出 pod IP 地址。这可以通过 DNS、客户端的显式设置或其他第三方服务发现机制来完成。
从安全角度来看,客户端直接到 pod 的毗连非常简单:它们在整个过程中都保存着原始客户端源 IP 地址,这意味着可以轻松使用网络策略来限定特定 IP 地址的客户端访问或特定 IP 地址范围的访问。
请注意,在任何 pod IP 地址在集群边界之外可路由的集群中,确保遵循网络策略的最佳实践变得更为重要。假如没有网络策略,本应仅接收东西向毗连的 pod 大概会被从集群外访问,而无需设置相应的可外部访问的 Kubernetes 服务类型或 Kubernetes Ingress。
理解 Kubernetes 服务
Kubernetes 服务通过 NodePort 或 LoadBalancer 类型的服务或通过显式设置服务的外部 IP,为从集群外部访问 pod 提供了一种便捷的机制。默认情况下,Kubernetes 服务由 kube-proxy 实现。kube-proxy 在集群中的每个节点上运行,并负责拦截到 Kubernetes 服务的毗连,并跨支持相应服务的 pod 进行负载均衡。这种毗连处理具有对源 IP 地址保存和不保存的明确定义行为,我们将在每种服务类型中进行具体讨论。
Cluster IP 服务
在我们探讨怎样使用 Kubernetes 服务将 pod 暴露给外部客户端之前,值得相识的是,为集群内部发起的毗连(即 pod 到 pod 的毗连)提供服务发现和负载均衡的主要机制使用的是 Cluster IP 类型的 Kubernetes 服务。对于 Cluster IP 服务,kube-proxy 能够使用目标网络地址转换(DNAT)将毗连映射到服务的 Cluster IP 到支持相应服务的 pod。毗连返回数据包时会反向映射此映射。此映射不会更改源 IP 地址,如图 9-1 中所示。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0901.png
图 9-1. Kubernetes 服务广告集群 IP 的网络路径
重要的是,目标 Pod 看到毗连是从客户端 Pod 的 IP 地址发起的。这意味着适用于目标 Pod 的任何网络策略都按预期行为,不受毗连通过服务的集群 IP 进行负载均衡的影响。此外,适用于客户端 Pod 的任何网络策略出口规则在从集群 IP 映射到目标 Pod 后进行评估。这意味着适用于客户端 Pod 的网络策略也按预期行为,与毗连通过服务的集群 IP 进行负载均衡无关。(作为提醒,网络策略规则匹配 Pod 标签,而不是服务标签。)
节点端口服务
从集群外部访问服务的最基本方法是使用类型为 NodePort 的 Kubernetes 服务。节点端口是集群中每个节点上保存的端口,通过它可以访问每个服务支持的 Pod。在典范的 Kubernetes 摆设中,kube-proxy 负责拦截对节点端口的毗连,并在支持每个服务的 Pod 之间进行负载均衡。
在此过程的一部分中,NAT 用于将节点 IP 和节点端口的目标 IP 地址和端口映射到所选的后备 Pod 和服务端口。然而,与毗连到集群 IP 不同,此中 NAT 仅映射目标 IP 地址,对于节点端口而言,源 IP 地址也从客户端 IP 映射到节点 IP。
假如源 IP 地址没有以这种方式映射,那么毗连上的任何响应数据包都将直接流回到外部客户端,绕过原始入口节点上 kube-proxy 反向映射目标 IP 地址的能力。(实行 NAT 的节点具有反向 NAT 所需的毗连跟踪状态。)结果,外部客户端将丢弃数据包,因为它无法识别这些数据包是否属于其与原始入口节点上节点端口建立的毗连。
这个过程在图 9-2 中有所说明。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0902.png
图 9-2. 使用节点端口的 Kubernetes 服务的网络路径
由于 NAT 更改了源 IP 地址,适用于目标 Pod 的任何网络策略都不能匹配原始客户端 IP 地址。通常这意味着任何此类策略仅限于限定目标协议和端口,而且无法基于外部客户端的 IP 地址进行限定。这反过来意味着在这种设置下,很难像最佳实践那样限定须要毗连到微服务的特定客户端的访问,无法轻松地通过 Kubernetes 网络策略来实现。
幸运的是,有多种解决方案可用于规避节点端口默认行为的限定:
- 设置服务使用 externalTrafficPolicy:local
- 使用支持节点端口感知网络策略扩展的网络插件
- 使用替换实现的服务负载均衡,代替保存客户端源 IP 地址的 kube-proxy
我们将在本章后面具体介绍这些内容。但在此之前,为了完备地相识主流 Kubernetes 服务默认行为的情况,让我们看看类型为 LoadBalancer 的服务。
负载均衡器服务
类型为 LoadBalancer 的服务基于节点端口的行为,与外部网络负载均衡器集成。具体的网络负载均衡器类型取决于与您的集群集成的公共云提供商,或者在当地情况下,取决于集成的特定硬件负载均衡器。
默认情况下,可以通过网络负载均衡器上的特定 IP 地址从集群外部访问服务,该负载均衡器将默认均衡负载到服务的节点端口上的全部节点。
大多数网络负载均衡器位于网络中的某个点,毗连的返回流量始终通过网络负载均衡器路由,因此它们可以仅使用 DNAT 实施负载均衡,网络负载均衡器不会改变客户端源 IP 地址,如 图 9-3 所示。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0903.png
图 9-3. 类型为 LoadBalancer 的 Kubernetes 服务的网络路径
然而,由于网络负载均衡器正在负载均衡到服务的节点端口,而且 kube-proxy 的默认节点端口行为在其负载均衡实现中更改了源 IP 地址,目标 Pod 仍然无法匹配原始客户端源 IP 地址。就像使用原始节点端口服务一样,这反过来意味着在这种设置中很难通过 Kubernetes 网络策略实施限定毗连到微服务的特定客户端的最佳做法。
幸运的是,可以与 NodePort 类型服务的默认行为限定相同的解决方案一起使用,与 LoadBalancer 类型服务一起使用:
- 设置服务为 externalTrafficPolicy:local
- 使用支持节点端口感知网络策略扩展的网络插件
- 使用替换实现的服务负载均衡,代替保存客户端源 IP 地址的 kube-proxy
现在让我们分别看看这些。
externalTrafficPolicy:local
默认情况下,与服务关联的节点端口在集群中的每个节点上都可用,而且类型为 LoadBalancer 的服务将负载均衡到服务的节点端口,独立于实际托管服务的节点。可以通过设置服务为 externalTrafficPolicy:local 来更改此行为,该设置指定连策应仅负载均衡到当地节点上支持服务的 Pod。
当与负载均衡器类型的服务联合使用时,毗连将仅定向到至少托管一个支持该服务的 pod 的节点。这样可以减少与 kube-proxy 正常节点端口处理干系的节点之间的潜在额外网络跳数。更重要的是,由于每个节点的 kube-proxy 仅对同一节点上的 pod 进行负载均衡,所以 kube-proxy 在负载均衡时无需实行源网络地址转换,这意味着客户端源 IP 地址可以一直保存到 pod。
网络流程示例见 图 9-4。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0904.png
图 9-4. 使用优化路由到支持 pod 的节点的 Kubernetes 服务的网络路径
由于原始客户端源 IP 地址一直保存到支持的 pod,因此现在可以将应用于支持的 pod 的网络策略限定为仅允许访问服务的特定客户端 IP 地址或地址范围。
注意,并非全部负载均衡器都支持此操作模式。因此,重要的是检查特定公共云提供商是否支持此功能,或者假如在当地摆设,检查与集群集成的特定硬件负载均衡器是否支持此功能。好消息是,大多数大型公共提供商都支持此模式。一些负载均衡器甚至可以更进一步,跳过 kube-proxy,直接向支持的 pod 进行负载均衡,而不使用节点端口。
网络策略扩展
一些 Kubernetes 网络插件提供了标准 Kubernetes 网络策略能力的扩展,可用于资助安全地访问集群外的服务。
存在许多解决方案提供网络策略扩展(例如 Weave Net、Kuberouter、Calico)。让我们再次关注 Calico,因为这是我们的专业领域。Calico 支持主机端点,允许将网络策略应用于集群内的节点,而不仅仅是集群内的 pod。标准 Kubernetes 网络策略可以被认为是在每个 pod 网络前面提供捏造防火墙,而 Calico 的主机端点扩展可以被认为是在每个节点/主机前面提供捏造防火墙,如 图 9-5 所示。
此外,Calico 的网络策略扩展支持指定主机端点应用的策略规则是在 kube-proxy 负载均衡干系的 NAT 之前还是之后。这意味着它们可以用于限定哪些客户端能够毗连到特定的节点端口,不受 kube-proxy 大概即将做出的负载均衡决定的影响。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0905.png
图 9-5. 使用主机端点保护的捏造防火墙
替换 kube-proxy
Kube-proxy 提供了 Kubernetes 服务的默认实现,而且在大多数集群中作为标准包含。然而,一些网络插件提供了替换的 Kubernetes 服务实现来代替 kube-proxy。
对于某些网络插件,由于插件实现的 pod 网络方式与 kube-proxy 的数据平面不兼容(kube-proxy 使用由 iptables 和/或 IPVS 控制的标准 Linux 网络管道),因此须要进行这种替换实现。对于其他网络插件,替换实现是可选的。例如,实现了 Linux eBPF 数据平面的 CNI 将选择替换 kube-proxy,采用其当地服务实现。
这些替换实现中的一些提供了超出 kube-proxy 行为的额外功能。从安全角度来看,此中一个干系的附加功能是在从外部客户端进行负载均衡时保存客户端源 IP 地址直到后端 pod。
例如,图 9-6 展示了基于 eBPF 的数据平面怎样实现这种行为。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0906.png
图 9-6. 基于 eBPF 实现的 Kubernetes 服务的网络路径
这允许原始客户端源 IP 地址一直保存到服务的打包 pod,适用于类型为 NodePort 或 LoadBalancer 的服务,无需网络负载均衡器支持 externalTrafficPolicy:local 或节点端口的节点选择。这反过来意味着应用于支持 pod 的网络策略能够限定只有特定客户端、IP 地址或地址范围能够访问服务。
除了安全考虑,这些替换的 Kubernetes 服务实现(如基于 eBPF 的数据平面)相比于 kube-proxy 的实现还提供其他优势,例如:
- 在运行非常多服务时提升了性能,包括减少了首个数据包的延迟和减少了控制平面的 CPU 使用率
- 直接服务器返回(DSR),用于减少返回流量的网络跳数
我们将更具体地查看 DSR,因为它确实具有一些安全方面的影响。
直接服务器返回
DSR 允许目标 Pod 的返回流量直接流回客户端,而不必经过原始入口节点。有几种网络插件可以用它们自己的实现替换 kube-proxy 的服务处理,支持 DSR。例如,包括当地服务处理的 eBPF 数据平面(可选地)可以使用 DSR 处理返回流量,如图 9-7 所示。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0907.png
图 9-7. Kubernetes 服务的网络路径,具有直接服务器返回
消除返回流量的一个网络跳跃会减少:
- 服务的整体延迟(因为每个网络跳跃都会引入延迟)
- 原始入口节点的 CPU 负载(因为它不再处理返回流量)
- 集群内部的东西向网络流量
对于特别网络密集或延迟敏感的应用步伐,这大概是一个巨大的优势。然而,DSR 也有安全影响。特别是,底层网络大概须要设置相对放宽的反向路径过滤(RPF)设置。
RPF 是一种网络路由机制,阻止来自特定源 IP 地址的任何流量,假如没有相应的路由可以通过同一链路发送到该 IP 地址,则会阻止该流量。也就是说,假如路由器没有一条路由表明可以通过网络链路发送到特定的 IP 地址,则它不会允许来自该 IP 地址的流量通过网络链路。RPF 使攻击者更难“诱骗”IP 地址,即假装成不同于设备分配的 IP 地址。
在 DSR 和 Kubernetes 服务的背景下,图 9-7 展示了几个关键点:
- 假如通过节点 1 上的节点端口访问服务,则来自节点 2 的返回流量将具有节点 1 的源 IP 地址。因此,底层网络必须设置放宽的 RPF 设置,否则网络将过滤返回流量,因为网络通常不会通过节点 2 的网络链路路由到节点 1。
- 假如通过服务 IP 广告(例如,直接发送流量到服务的集群 IP、外部 IP 或负载均衡器 IP)访问服务,则来自节点 2 的返回流量将具有服务 IP 的源 IP 地址。在这种情况下,不须要放宽反向路径过滤(RPF),因为服务 IP 应该从集群中的全部节点广告,意味着网络将通过全部节点路由到服务 IP。我们将在本章后面更具体地讨论服务 IP 广告。
正如前面所解释的,DSR 是一种优秀的优化技能,您可以使用它,但须要审查您的用例,并确保您能够禁用 RPF 检查而感到舒适。
限定服务的外部 IP
到目前为止,在本章中,我们专注于服务类型和实现方式怎样影响网络策略的使用,以限定只有特定的客户端 IP 地址或地址范围可以访问每个服务。
另一个重要的安全考虑是具有权限创建或设置 Kubernetes 服务的用户所拥有的权利。特别是,任何具有 RBAC 权限修改 Kubernetes 服务的用户实际上控制着该服务负载均衡到哪些 Pod。假如恶意使用,这大概意味着用户能够将本应发送到特定微服务的流量重定向到他们自己的恶意 Pod。
由于 Kubernetes 服务是命名空间资源,这很少会成为主流服务功能的真正安全问题。例如,已被授予在特定命名空间中定义服务权限的用户通常也有权限修改该命名空间中的 Pod。因此,对于标准服务功能(如处理集群 IP、节点端口或负载均衡器),在命名空间中定义和修改服务的权限实际上并不表示比在命名空间中定义或修改 Pod 的更高信托级别。
然而,另有一个显著的例外,即能够为服务指定外部 IP 的能力。服务定义中的 externalIP 字段允许用户将任意 IP 地址与服务关联起来。在集群中的任何节点上接收到对此 IP 地址的毗连将被负载均衡到支持该服务的 Pod。
正常使用情况是提供一个面向 IP 的替换方案,用于外部客户端毗连到服务。此用例通常须要在底层网络中进行特别处理,以便将毗连路由到集群中的节点上。这可以通过在底层网络中编程静态路由来实现,或者在支持 BGP 的网络中,使用 BGP 动态广播外部 IP。 (有关广告服务 IP 地址的更多具体信息,请参阅下一节。)
与主流服务功能类似,此用例在用户信托级别上相对温和。它允许用户为管理权限的命名空间中的 Pod 提供一种额外的访问方式,但不会干扰流向其他命名空间中的 Pod 的流量。
然而,与节点端口一样,从 Pod 到外部 IP 的毗连也会被拦截并负载均衡到支持该服务的 Pod。由于 Kubernetes 不会对外部 IP 地址进行监控或尝试提供任何级别的验证,这意味着恶意用户实际上可以截取到任何 IP 地址的流量,而无需任何命名空间或其他范围限定。这对于恶意用户来说是一个极为强大的工具,同时也代表着相应的巨大安全风险。
假如您遵循最佳实践,即在整个集群中为入站和出站流量都采用默认拒绝的策略,那么这将极大地拦阻恶意用户试图访问应该在两个其他 Pod 之间的流量。然而,虽然网络策略将阻止它们访问流量,但服务负载均衡不会阻止将流量从其预期的目标地转移,这意味着恶意用户可以有效地阻止任何两个 Pod 之间的流量,纵然他们自己无法接收到流量。
因此,除了遵循网络策略的最佳实践外,建议使用准入控制器来限定可以指定或修改外部 IP 字段的用户。对于允许指定外部 IP 地址的用户,还大概渴望将 IP 地址值限定在被认为安全的特定 IP 地址范围内(即未用于任何其他目标的范围)。有关准入控制器的更多讨论,请拜见第八章。
广告服务 IP
使用节点端口或网络负载均衡器的一种替换方法是通过 BGP 广告服务 IP 地址。这须要集群在支持 BGP 的底层网络上运行,通常意味着使用标准顶部机架路由器的当地摆设。
例如,Calico 支持广告服务集群 IP、负载均衡器 IP 或设置了一个外部 IP 的服务。假如您不使用 Calico 作为您的网络插件,那么 MetalLB 提供了类似的功能,可以与各种不同的网络插件一起使用。
广告服务 IP 有效地允许底层网络路由器充当负载均衡器,而无需实际的网络负载均衡器。
广告服务 IP 的安全考虑与本章前面讨论的基于节点端口或负载均衡器的服务相当。在使用 kube-proxy 时,默认情况下会通过模糊示原始客户端 IP 地址,如图 9-8 所示。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0908.png
图 9-8. 通过 BGP 广告集群 IP 的 Kubernetes 服务的网络路径
这种行为可以通过使用externalTrafficPolicy:local来更改,该选项(截至撰写本文时)由 kube-proxy 支持,适用于负载均衡器 IP 和外部 IP 地址,但不适用于集群 IP 地址。然而,应注意,当使用externalTrafficPolicy:local时,负载均衡的均匀性变为依赖于拓扑结构。为了规避这一问题,可以使用 Pod 反亲和性规则,以确保在拓扑结构中均匀分布支持 Pod,但这确实增加了摆设服务的复杂性。
或者,可以使用具有当地服务处理的网络插件(替换 kube-proxy),支持源 IP 地址保存。由于其操作简单性和无需在网络拓扑中构建网络负载均衡器设备,这种组合对于当地摆设非常有吸引力。
理解 Kubernetes Ingress
Kubernetes Ingress 构建在 Kubernetes 服务之上,提供应用层负载均衡,将特定域名或 URL 的 HTTP 和 HTTPS 哀求映射到 Kubernetes 服务。假如多个微服务组成单个 Web 应用步伐,Kubernetes Ingress 可以是一种方便的方式来通过单个外部接入点公开多个微服务。此外,它们可以用于在将流量负载均衡到后端微服务之前制止 SSL/TLS(用于接收来自外部客户端的 HTTPS 加密毗连)。
Kubernetes Ingress 的实现细节取决于您使用的入口控制器。入口控制器负责监视 Kubernetes Ingress 资源,并设置一个或多个入口负载均衡器以实现所需的负载均衡行为。
与 Kubernetes 服务不同,后者在网络层(L3-L4)处理,入口负载均衡器在应用层(L5-L7)操作。入站毗连在负载均衡器处制止,以便检查单独的 HTTP/HTTPS 哀求。然后,哀求通过从负载均衡器到选择的服务的分开毗连进行转发。因此,应用于支持服务的 Pod 的网络策略将入口负载均衡器视为客户端源 IP 地址,而不是原始外部客户端 IP 地址。这意味着它们可以限定仅允许来自负载均衡器的毗连,但不能限定对特定外部客户端的访问。
为了限定对特定外部客户端的访问,须要在应用负载均衡器内或应用负载均衡器前强制实行访问控制。假如选择基于 IP 的访问控制,则须要在流量转发到后端服务之前实行。怎样实行这一点取决于您使用的具体入口控制器。
广义上说,有两种类型的入口解决方案:
In-cluster ingress
入口负载均衡由集群内的 Pod 实行。
外部入口
入口负载均衡由设备或云提供商的功能在集群外实现。
现在我们已经介绍了 Kubernetes Ingress,让我们来回顾一下入口解决方案。
集群内入口解决方案
集群内入口解决方案使用运行在集群内部 Pod 中的软件应用负载均衡器。有许多不同的入口控制器遵循此模式。例如,NGINX 入口控制器实例化和设置 NGINX Pod 以充当应用步伐负载均衡器。
集群内 Ingress 解决方案的优势在于:
- 您可以程度扩展您的 Ingress 解决方案,直至到达 Kubernetes 的极限。
- 有许多不同的集群内 Ingress 控制器解决方案,因此您可以选择最得当您特定需求的 Ingress 控制器 — 例如,具有特定负载均衡算法、安全选项或可观测性功能。
要将您的 Ingress 流量发送到集群内的 Ingress Pod,通常将 Ingress Pod 作为 Kubernetes 服务外部公开,如 图 9-9 所示。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0909.png
图 9-9. Kubernetes 集群中内部 Ingress 实现的示例
这意味着您可以使用任何标准的方式从集群外部访问服务。一个常见的方法是使用外部网络负载均衡器或服务 IP 广告,以及以下方法之一:
- 一个具有当地 Kubernetes 服务处理的网络插件,始终保存原始客户端源 IP
- externalTrafficPolicy:local(和 Pod 反亲和规则以确保在 Ingress Pod 之间均衡负载)以保存原始客户端源 IP
应用于入口 Pod 的网络策略可以像本章前面描述的那样限定对特定外部客户端的访问,而且支持通过 Ingress 暴露的任何微服务的 Pod 可以限定毗连仅限于来自入口 Pod 的毗连。
外部 Ingress 解决方案
外部 Ingress 解决方案使用集群外的应用步伐负载均衡器,如 图 9-10 所示。
https://github.com/OpenDocCN/ibooker-devops-zh/raw/master/docs/k8s-sec-obsrv/img/ksao_0910.png
图 9-10. Kubernetes 集群中外部 Ingress 的示例
具体的细节和功能取决于您使用的 Ingress 控制器。大多数公共云提供商都有自己的 Ingress 控制器,可以自动化云提供商的应用步伐负载均衡器的设置和管理,以提供 Ingress。
大多数应用步伐负载均衡器支持将流量转发到所选服务后端 Pod 的基本操作模式,通过相应服务的节点端口。除了负载均衡到服务节点端口的基本方法外,一些云提供商支持应用步伐负载均衡的第二模式,直接负载均衡到每个服务后端的 Pod,而不经过节点端口或其他 kube-proxy 服务处理,这样做的优势是消除了与节点端口负载均衡到不同节点上的 Pod 干系的潜在第二个网络跳转。
外部 Ingress 解决方案的主要优势是云提供商为您处理 Ingress 的操作复杂性。潜在的缺点如下:
- 可用的功能集通常比集群内 Ingress 解决方案的丰富范围更有限。例如,假如您须要特定的负载均衡算法、安全控制或可观察性功能,则云服务提供商的实现大概或大概不支持这些功能。
- 支持的服务最大数量(以及大概支持的服务后端的 Pod 数量)受限于特定云服务提供商的限定。例如,假如您在非常高的规模下运行,每个服务后端支持数百个 Pod,您大概会超出应用层负载均衡器在此模式下能够负载均衡的最大 IP 数量限定。在这种情况下,切换到集群内的 Ingress 解决方案大概更得当您。
- 由于应用负载均衡器不托管在 Kubernetes 集群内,假如您须要限定对特定外部客户端的访问,则无法使用 Kubernetes 网络策略,而必须使用云服务提供商的特定机制。仍然可以按照本章开头提出的最佳实践进行,但这将依赖于云服务提供商的具体能力和 API,大概会引入一些额外的运维复杂性。
在这一节中,我们讨论了 Kubernetes Ingress 的工作原理以及现有的解决方案。我们建议您细致查看这些部分,并决定是否得当您使用集群内的 Ingress 解决方案,或者应该选择外部的 Ingress 解决方案。
结论
在本章中,我们讨论了将 Kubernetes 服务暴露到集群外部的主题。以下是涵盖的关键概念:
- Kubernetes 服务的概念,如直接 Pod 毗连、广告服务 IP 和节点端口,是您可以使用的技能,以将 Kubernetes 服务暴露到集群外部。
- 我们建议使用基于 eBPF 的数据平面来优化 Ingress 路径,将流量路由到托管服务后端的 Pod。
- 由于其能够保存源 IP 到 Pod 的能力,eBPF 数据平面是默认 Kubernetes 服务实现 kube-proxy 的一个优秀替换方案。
- Kubernetes Ingress 实现的选择将取决于您的用例。我们建议您考虑集群内的 Ingress 解决方案,因为它更符合 Kubernetes 的当地化特性,比使用外部 Ingress 解决方案更具控制性。
我们渴望您能根据自己的用例使用这些概念,实施 Kubernetes 服务。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |