第 8 章:保护应用程序

我们讨论过只能使用云原生应用程序来创建基础架构。同时基础架构也负责运行这些应用程序。

运行由应用程序配置和控制的基础架构可以轻松得扩展。我们通过学习如何通过扩展应用的方式来扩展基础架构。我们还通过学习如何保护应用程序来保护基础架构。

在动态环境中,无法通过增加人手来管理这样的复杂性,同样也不能靠增加人手来处理策略和安全问题。

这意味着,就像我们必须创建通过协调器模式强制执行基础架构状态的应用程序一样,我们需要创建实施安全策略的应用程序。在创建应用程序以执行的策略之前,我们需要以机器可解析的格式编写策略。

策略即代码

由于策略没有明确定义的技术实现,所以策略难以纳入代码。它更多地关注业务如何实现而不是谁来实现。

如何实现和谁来实现都会经常变化,但是实现方式变化更频繁且不容易被抽象化。它也是组织特定的,可能需要了解创建基础架构人员的沟通结构的具体细节。

策略需要应用于应用程序生命周期的多个阶段。正如我们在第 7 章中所讨论的,应用程序通常有三个阶段:部署、运行和退役。

部署阶段将在应用程序和基础架构变更发布之前先应用策略。这将包括部署规则和一致性测试。运行阶段将包括持续的遵守和执行访问控制和隔离。退役阶段很重要,以确保没有服务落后于未安排或未维护的状态。

在这些阶段中,您需要将策略分解为明确的,可操作的实现。模糊的策略无法执行。您需要将实现放在代码中,然后创建应用程序或使用现有的应用程序来执行策略规则。

您应该将策略视为代码。策略更改应视为应用程序更改并在版本控制中进行跟踪。

控制应用程序部署的相同策略也应该适用于您的新策略部署。您可以使用与部署应用程序相同的工具跟踪和部署的基础架构组件越多,就越容易了解正在运行的内容以及变更如何影响系统。

将策略作为代码带来的巨大好处是您可以轻松地添加或删除策略并对其进行跟踪,因此记录了谁执行了策略,何时执行了策略以及提交和提交请求的评论。由于该策略以代码形式存在,因此您现在可以为自己的策略编写测试!如果你想验证一个策略是否可以正常工作,你可以使用第 5 章中的测试实践。

让我们更仔细地看看如何将策略应用到应用程序生命周期。

部署 Gateway

部署 gateway 确保应用程序的部署符合业务规则。这意味着您将需要构建部署流水线,并且不允许从用户机器进行直接生产部署。

在实施集中化策略之前,您需要集中控制,但是应该从小规模开始,并在实施之前证明解决方案可行。部署流水线的好处远不止于策略执行,而且应该是任何拥有少数开发人员的组织中的标准。

以下是一些策略示例:

  • 部署只有在所有测试都通过后才能进行。
  • 新应用程序要求高级开发人员检查更改并对提取请求发表评论。
  • 生产工件推送只能从部署流水线发生。

Gateway 不应该强制运行状态或应用程序的 API 请求。应用程序应该知道如何配置基础架构组件,并通过合规性和审计将策略应用于这些组件,而不是在应用程序部署期间应用。

部署 gateway 策略的一个例子是,星期五下午 3 点之后,如果您的组织没有获得经理批准,不允许部署代码。

这个很容易放入代码中。图 8-1 是代表策略的非常简化的图。

f-8-1
f-8-1

您可以看到该策略简单地检查了允许部署部署的一周中的时间和日期。如果是星期五和下午 3 点以后,那么策略会检查管理员确定。

该策略可以通过经理发送的经过验证的电子邮件,经过验证的 API 调用或各种其他方式来获得 OK 通知。决定首选通信方法的内容以及等待批准的时间长度取决于策略。

这个简单的例子可以用很多不同的选项进行扩展,但确保该策略不符合人类解析和执行是很重要的。人的解释是不同的,而不明确的策略通常不会得到执行。

通过确保策略阻止新的部署,可以为解决生产环境的状态节省很多工作。有一系列可以通过软件验证的事件可以帮助您理解系统。版本控制和持续部署流水线可以验证代码;使用策略和流程作为代码可以验证软件的部署方式和时间。

除了确保通过公司策略部署正确的事情之外,我们还应该轻松地使用模板部署受支持的事物,并通过一致性测试强制执行它们。

合规性测试

在任何基础架构中,您都需要提供建议的方式来创建特定类型的应用程序。这些建议成为用户根据需要消费和拼凑在一起的基石。

这些建议是可堆砌的,但又不能太小。需要在其预期的功能和自助服务方面可以理解。我们已经建议将云原生应用程序打包为容器并通过协调器使用;由您决定什么最适合您的用户以及您想要提供哪些组件

您可以通过多种方式为用户提供模板化基础架构。

提供一个模板化的代码,比如 Jsonnet,或者完全模板化的应用程序,例如 Helm 的 chart。

您还可以通过您的部署流水线提供模板。可以是 Terraform 模块或特定于部署的工具,例如 Spinnaker 模板。

创建部署模板允许用户成为模板的消费者,随着最佳实践的发展,用户将自动受益。

基础架构模板的最关键的一点是使做正确的事情变得容易,并且很难做错事情。如果您满足客户的需求,那么获得适配器将会容易得多。

但是,我们需要模板化基础架构的根本原因是可以执行合规性测试。合规性测试的存在是为了确保应用程序和基础架构组件符合组织的标准。

对不符合标准的基础架构进行测试的一些示例如下:

  • 不在自动缩放组中的服务或端点
  • 不在负载均衡器后面的应用程序
  • 前端层直接与数据库通信

这些标准是关于基础架构的信息,您可以通过调用云提供商的 API 来找到这些信息。合规性测试应持续运行,并强制执行公司采用的架构标准。

如果发现基础架构组件或应用程序架构违反了公司提供的标准,则应尽早终止它们。越早可以对模板进行编码,就可以越早检查出不符合标准的应用程序。在应用程序的生命早期解决不受支持的体系结构非常重要,因此可以最大限度地减少对体系结构决策的依赖。

合规性处理如何构建应用程序和维护可操作性。合规性测试确保应用程序和基础架构安全。

一致性测试

合规性测试不会测试架构设计,而是集中于组件的实施,以确保它们遵守定义的策略。放在代码中的最简单的策略是那些有助于安全的策略。围绕组织需求(例如 HIPAA)的策略也应定义为代码并在合规性测试期间进行测试。

合规策略的一些例子:

  • 对象存储的用户访问受限,并且不能被公共因特网读取或写入
  • API 端点全部使用 HTTPS 并具有有效证书
  • 虚拟机实例(如果有的话)没有过分宽松的防火墙规则

虽然这些策略不会使应用程序免受所有漏洞或错误的影响,但是如果应用程序确实被利用,合规性策略应将影响范围降至最低。

Netflix 在其博客文章“The Netflix Simian Army”中通过其 Security Monkey 解释了其执行合规性测试的目的:

Security Monkey 是 Conformity Monkey 的延伸。它会查找安全违规或漏洞(如未正确配置的 AWS 安全组),并终止违规实例。它还确保我们所有的 SSL 和 DRM 证书都是有效的,并且不会延期。

将您的策略放入代码并通过观察云提供商 API 继续运行它,可以让您保持更高的安全性,立即捕获不安全的设置,并随时跟踪版本控制系统的策略。根据这些策略不断测试您的基础架构的模型也非常适合调节器模式。

如果您认为策略是需要应用和实施的配置类型,那么实施它可能会更简单。请务必记住,随着您的基础架构和业务需求的变化,您的合规策略也应该如此。

部署测试在将应用程序部署到基础架构之前进行监视,合规性和合规性测试都处理正在运行的应用程序。确保您拥有策略的最后一个应用程序生命周期阶段是了解何时以及如何废止应用程序和生命周期组件。

活动测试

合规性和一致性测试应该删除那些未通过定义策略的应用和基础架构。还应该有一个应用程序清理旧的和未使用的基础架构组件。高级使用模式应基于应用程序遥测数据,但仍有其他基础架构组件很容易被遗忘并需要退役。

在云环境中,您可以根据需要消费资源,但很容易会忘记需求。如果没有自动清理旧的或未使用的资源,最后您会对账单感到惊讶,或者需要耗费大量人力进行手动审计和清理。

您应该测试并自动清理的资源的一些示例包括:

  • 旧磁盘快照
  • 测试环境
  • 以前的应用程序版本

负责清理的应用程序需要根据默认策略做正确的事情,并为工程师指定的异常提供灵活性。

正如第 7 章所提到的,Netflix 已经实现了它所称的“Janitor Monkey”,它的实现完美地描述了这种需要的模式:

Janitor Monkey 在“标记、通知和删除”过程中工作。当 Janitor Monkey 将资源标记为候选清理对象时,它会安排删除资源的时间。删除时间在标记资源的规则中指定。

每个资源都与一个所有者电子邮件相关联,该电子邮件可以在资源上指定为标签,或者您可以快速扩展 Janitor Monkey 以从您的内部系统获取信息。最简单的方法是使用默认的电子邮件地址,例如您的团队的电子邮件列表中的所有资源。您可以配置若干天,以指定何时让 Janitor Monkey 在计划终止之前向资源所有者发送通知。默认情况下,数字为 3,表示业主将在终止日期前 3 个工作日收到通知。

在这 3 天期间,资源所有者可以决定资源是否可以删除。如果资源需要保留更长时间,则所有者可以使用简单的 REST 接口将资源标记为未被 Janitor Monkey 清除。所有者总是可以使用另一个 REST 接口来删除该标志,然后 Janitor Monkey 将能够再次管理该资源。

当 Janitor Monkey 看到标记为清理候选者的资源并且预定的终止时间已经过去时,它将删除资源。如果资源所有者想要提前释放资源以节省成本,则还可以手动删除该资源。当资源状态改变而使资源不是清理候选者时,例如一个分离的 EBS 卷被附加到一个实例,Janitor Monkey 将取消该资源的标记并且不会终止。

拥有自动清理基础架构的应用程序可以降低您的复杂性和成本。该测试将协调模式应用到应用程序的最后生命周期阶段。

还有其他一些基础架构的实践很重要,需要考虑。其中一些实践适用于传统基础架构,但在云原生环境中需要进行不同的处理。

不断测试基础架构的各个方面有助于您了解自己遵守的策略。当基础架构频繁变更时,很难审计哪些变更可能导致停机或使用历史数据来预测未来趋势。

如果您希望从账单声明中获取该信息或通过基础架构的当前快照来推断,您会很快发现它们所提供的信息是没用的。为了跟踪变化并预测未来,我们需要有审计工具,可以快速提供我们需要的信息。

审计基础架构

在这个意义上审计云原生基础架构与审核调解器模式中的组件不同,它与第 6 章中讨论的测试框架也不同。相反,当我们谈论审计时,我们指的是对变更的高级概述和基础架构内的组件关系。

跟踪基础架构中存在的内容以及它与其他组件的关系,为我们了解当前状态提供了重要的背景。当某些事情中断时,第一个问题几乎总是“什么改变了?”审计为我们回答了这个问题,并且可以用来告诉我们如果我们应用变更会受到什么影响。

在传统的基础架构中,配置管理数据库(CMDB)通常是基础架构当前状态的真相来源。但是,CMDB 不会跟踪基础架构或资产关系的历史版本。

云提供商可以通过库存 API 为您提供 CMDB 替代服务,但它们可能不会激励您显示历史趋势或让您查询您需要进行故障排除的特定详细信息,例如主机名。

一个好的云审计工具可以让你显示当前基础架构与昨天或上周相比的差异(diff)。它应该能够将云提供商数据与其他来源(例如容器编排器)相结合,以便您可以查询云提供商可能没有的数据的基础架构,理想情况下,它可以自动构建组件关系的拓扑表示。

如果您的应用程序完全在单个平台上运行(例如 Kubernetes),则收集资源依赖关系的拓扑信息要容易得多。自动可视化关系的另一种方法是统一关系发生的层次。

对于在云中运行的服务,可以在服务之间的网络通信中识别关系。有很多方法可以识别服务之间的网络流量,但审计的重要考虑是对信息进行历史跟踪。您需要能够轻松识别关系何时发生变化,就像您识别组件之间关系一样容易。

自动识别服务关系的方法

跟踪服务之间的网络流量意味着您需要了解用于通信的网络协议的工具。您不能简单地依赖流入或流出服务端点的原始数据包流量。你需要一种方法来利用信息流来建立关系模型。

检查网络流量和构建依赖关系图的一种流行方式是通过网络代理。

网络代理的一些实现示例是 linkerd 和 envoy。服务通过这些代理来传输所有流量,这些代理知道正在使用的协议和其他相关服务。如附录 B 所述,代理还允许其他网络弹性模式。

跟踪时间拓扑结构是一个强大的审计工具。结合基础架构的历史,它将确保“改变了什么?”问题更容易回答。

还有一个审计方面涉及在当前基础架构状态下建立信任。应用程序通过所描述的测试工具获得信任,但基础架构的某些方面无法应用相同的测试。

用可验证的可重现组件构建基础架构可以提供很大的信任。这种做法被称为不可变基础设施。

不可变基础设施

不可变的基础架构是通过替换而不是修改来创建变更的做法。换句话说,不是运行配置管理来对所有服务器应用更改,而是建立新服务器并丢弃旧服务器。

云环境很大程度上受益于创建变更的方法,因为部署新 VM 的成本通常非常低,比管理可强制配置并保持实例运行的另一个系统要容易。因为服务器是虚拟的(即用软件定义),所以您可以像构建服务器镜像一样应用与构建应用程序相同的实践。

物理服务器的传统基础架构与系统创建时的云具有完全相反的优化。提供物理服务器需要很长时间,并且在修改现有操作系统方面有很大的好处,而不是替换旧的。

不可变基础设施的问题之一是建立信任链,为部署创造黄金镜像。镜像在构建时应该是可验证的(例如,签名密钥或镜像哈希),并且一旦部署就不应改变。

镜像创建也需要自动化。历史上使用黄金镜像的最大问题之一是它们通常依靠人类在对照检查表十分耗时得创建出来。

存在工具(例如,Hashicorp 的 Packer)来自动化构建过程,并且没有理由存在旧镜像。自动化还允许旧的清单成为可以审计和版本控制的脚本。了解配置工具何时发生变化以及由谁建立信任的不可变基础设施的另一方面。

发生变更时,应该经常变更,您需要一种方法来跟踪变更内容和原因。审计将有助于确定发生了什么变化,而不可变的基础架构可以帮助您追踪到 Git 提交或拉取请求。

追踪历史也大大有助于从失败中恢复过来。如果您有一个已知可用的虚拟机映像,另一个虚拟机镜像不可用,则可以像部署新的破损版本一样快速地部署以前的工作版本。

不可变基础设施不是云原生基础架构的要求,但环境从这种基础架构管理风格中受益匪浅。

结论

通过本章介绍的实践,您将能够更轻松地控制在基础架构中运行的内容,并跟踪其运作的方式。将您的策略放在代码中可让您跟踪变更,而且您不用认为来解读策略。

审计和不可变基础设施为您提供了更好的信息,以确保您的系统安全并帮助您更快地从故障中恢复。

除了本章前面讨论的合规性测试要求之外,我们不会在本书中讨论安全性,但您应该及时了解您使用的技术和云提供商的安全最佳实践。安全性最重要的方面之一是在整个堆栈中应用“分层安全”。

换句话说,仅仅在主机操作系统上运行防病毒守护进程不足以保护您的应用程序。您需要查看您控制的所有基础架构层,并应用适合您需求的安全监控。

本章中介绍的所有测试都应以第 4 章中介绍的相同协调模式运行。收集信息以了解当前状态,根据一组规则查找更改,然后使这些更改都适合云原生模式。

如果您可以将您的策略作为代码实施,那么您将超越云的技术优势,并为云原生模式实现商业利益。

历史和拓扑审计可能看起来并不明显,但随着基础架构的增长以及变化率和应用敏捷性的增加,这些审计将非常重要。将传统方法应用于管理云基础架构不是云原生,本章向您展示了您应该利用的一些好处以及您将面临的一些挑战。