云端自动渗透测试实验室构建指南(一)

原文:annas-archive.org/md5/a334f79c3a6685441151c41395f76b68

译者:飞龙

协议:CC BY-NC-SA 4.0

序言

随着全球越来越多的组织将其数据和工作负载迁移到云端,工程团队以及安全专业人士面临着在生产环境中防范日益增多的与云相关的威胁和风险的复杂任务。这导致了对能够攻击和防御云应用程序和系统的安全专业人员的需求激增。寻求职业发展并希望在职业生涯中脱颖而出的安全专业人士应该学会如何在云中建立各种类型的易受攻击的实验环境,以进一步磨练他们的技能。

我写这本书是为了帮助您和其他专业人士设计、构建和自动化运行在亚马逊网络服务AWS)、微软 Azure谷歌云平台GCP)上的渗透测试实验室环境。您将学习如何使用基础设施即代码IaC)解决方案和策略自动化准备和配置云资源。您将有机会利用生成式人工智能工具的潜力,显著加速构建和自动化易受攻击的实验环境的过程。除此之外,您还将学习如何使用各种攻击性安全工具和技术来验证和测试我们基于云的实验室中的漏洞和配置错误。

通过本书,您应该能够在多个云平台上构建和自动化各种类型的渗透测试实验室,从而可以练习和尝试不同类型的攻击和技术。

本书适合对象

本书旨在面向安全工程师、云工程师和有志于学习更多有关渗透测试、云安全和基础设施自动化的安全专业人士。它强调了使用基础设施即代码解决方案以及生成式人工智能工具,加速在AWSAzureGCP上准备易受攻击的实验环境。如果您计划在云安全领域发展自己的职业,并希望学习如何管理在云中构建和管理黑客实验环境所涉及的复杂性、成本和风险,那么这本书适合您。

本书涵盖内容

第一章开始使用云中的渗透测试实验室,介绍了帮助您开始构建云中渗透测试实验室的关键概念。在本章中,我们还将研究在云中构建这些易受攻击的实验环境时涉及的考虑因素和风险。

第二章准备我们的第一个易受攻击的云实验室环境,让您通过在云中设置和配置您的第一个易受攻击的实验环境来入门。

第三章, 成功使用基础设施即代码工具和策略,详细介绍了如何使用 IaC 解决方案自动构建渗透测试实验室环境。

第四章, 在 GCP 上设置隔离渗透测试实验室环境,展示了如何使用正确配置的网络环境将脆弱的实验室资源与外部未授权攻击隔离和保护。在这个安全的网络环境中,我们将设置一个目标虚拟机实例,托管一个故意存在漏洞的 Web 应用程序,名为 OWASP Juice Shop。除此之外,我们还将启动一个攻击者虚拟机实例,并将其配置为通过浏览器访问其桌面环境。

第五章, 在 Azure 上设置隔离渗透测试实验室环境,介绍了如何在 Azure 上设置和自动化一个隔离的渗透测试实验室环境。在本章中,我们将构建一个实验室,练习容器突破技术,以便未经授权访问主机系统。此外,我们还将讨论如何滥用 Azure 中的托管身份,以获得对其他云资源的未授权访问。

第六章, 在 AWS 上设置隔离渗透测试实验室环境,重点讲解如何在 AWS 上构建和自动化隔离的渗透测试实验室环境的准备工作。在本章中,我们将准备一个实验室环境,练习可以使用初始被攻破的机器访问内部系统和网络的枢纽技术。

第七章, 设计和构建 IAM 权限提升实验室,展示了如何在 AWS 上设置一个脆弱的 IAM 权限提升实验室环境。在本章中,我们还将首次了解如何使用生成性 AI 解决方案生成代码,用于渗透测试模拟。

第八章, 设计和构建脆弱的 Active Directory 实验室,重点讲解如何在 Azure 上设置一个脆弱的 Active Directory 实验室。在这里,我们还将学习如何使用各种工具,如 Kerbrute、Impacket 和 John the Ripper,来验证和评估渗透测试实验室环境是否已正确设置和(误)配置。

第九章, 推荐的策略和最佳实践,介绍了改善和增强前几章中讨论的实验室环境的最佳实践和技术。在本章中,我们还将深入探讨如何使用生成性 AI 工具来创建 IaC 模板代码、进行基础设施成本估算和开发自动化脚本。

为了最大化本书的学习效果

你需要一个 AWS 账户、一个 Microsoft Azure 账户、一个 GCP 账户以及一个 ChatGPT(即 OpenAI)账户,并且需要稳定的互联网连接,才能完成本书中的动手实验。

本书中涵盖的软件/硬件操作系统要求
Chrome/Firefox/Safari/Edge/Opera(或其他替代浏览器)Windows/macOS/Linux

如果你使用的是本书的数字版,我们建议你自己输入代码或通过本书的 GitHub 仓库访问代码(下一节将提供相关链接)。这样做可以帮助你避免与复制粘贴代码相关的潜在错误

下载示例代码文件

你可以从 GitHub 下载本书的示例代码文件,链接为 github.com/PacktPublishing/Building-and-Automating-Penetration-Testing-Labs-in-the-Cloud。如果代码有更新,它会在 GitHub 仓库中更新。

我们还有其他来自丰富书籍和视频目录的代码包,可以在 github.com/PacktPublishing/ 上找到。快来看看吧!

使用的约定

本书中使用了许多文本约定。

文中的代码:表示文本中的代码词汇、数据库表名、文件夹名称、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 账号。例如:“确保将<ATTACKER VM PUBLIC IP ADDRESS>替换为运行terraform apply命令后得到的attacker_vm_public_ip输出值。”

代码块如下所示:

 module "attacker_vm" {
  source = "./attacker_vm"
}

当我们希望引起你对代码块中特定部分的注意时,相关的行或项目会以粗体显示:

 module "attacker_vm" {
  source = "./attacker_vm"my_public_ssh_key = var.my_public_ssh_key source_image_id = var.kali_image_id rg_location = module.secure_network.rg_02_location rg_name = module.secure_network.rg_02_name subnet = module.secure_network.subnet_02 asg = module.secure_network.asg_02 nsg = module.secure_network.nsg_02 }

粗体:表示新术语、重要词汇或屏幕上显示的词语。例如,菜单或对话框中的词汇会以粗体显示。示例:“在最后一个标签页(EC2 串行控制台)中,点击连接按钮通过 EC2 串行控制台访问实例。”

提示或重要说明

如下所示。

联系我们

我们始终欢迎读者的反馈。

一般反馈:如果你对本书的任何部分有疑问,请通过电子邮件与我们联系:customercare@packtpub.com,并在邮件主题中提及书名。

勘误表:尽管我们已尽最大努力确保内容的准确性,但难免会出现错误。如果你在本书中发现任何错误,我们非常感谢你向我们报告。请访问 www.packtpub.com/support/errata 并填写表格。

盗版:如果你在互联网上发现我们的作品的非法复制版本,烦请提供该材料的地址或网站名称。请通过 copyright@packtpub.com 与我们联系,并附上该材料的链接。

如果您有兴趣成为作者:如果您擅长某个话题,并且有兴趣撰写或参与书籍的创作,请访问 authors.packtpub.com

分享您的想法

在阅读完*《云端渗透测试实验室的构建与自动化》*后,我们非常希望听到您的反馈!请点击这里直接进入亚马逊的评论页面并分享您的想法。

您的评价对我们和技术社区非常重要,将帮助我们确保提供高质量的内容。

下载本书的免费 PDF 副本

感谢购买本书!

您是否喜欢在路上阅读,但又无法随身携带纸质书籍?

您的电子书购买是否与您选择的设备不兼容?

不用担心,现在购买每本 Packt 书籍,您都会免费获得该书的无 DRM PDF 版本。

在任何地方、任何设备上随时阅读。搜索、复制并将您最喜欢的技术书籍中的代码直接粘贴到您的应用程序中。

福利不仅仅是这些,您还可以获得独家的折扣、新闻通讯以及每天直接发送到您邮箱的精彩免费内容。

按照这些简单的步骤来获取福利:

  1. 扫描二维码或访问以下链接

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_QR_Free_PDF.jpg

packt.link/free-ebook/9781837632398

  1. 提交您的购买凭证

  2. 就是这样!我们会直接通过电子邮件向您发送免费的 PDF 和其他福利。

第一部分:易受攻击设计环境简明介绍

本部分将介绍如何在云端构建和自动化渗透测试实验室的关键概念。

本部分包含以下章节:

  • 第一章云端渗透测试实验室入门

  • 第二章准备我们的第一个易受攻击的云实验室环境

  • 第三章成功使用基础设施即代码工具和策略

第一章:开始使用云中的渗透测试实验室

随着与云相关的威胁和事件每年显著增加,对云安全专业人员的需求持续增长。为了管理学习云渗透测试和道德黑客过程中涉及的风险,安全工程师若想提升职业发展,掌握如何在云中搭建渗透测试环境将大有裨益。

在本章介绍中,我们将快速了解在云中设置渗透测试实验室的好处。我们将探讨现代云应用是如何设计、开发和部署的,因为这在接下来的章节中建立渗透测试实验室时至关重要。在本章的最后部分,我们将深入探讨在设计和构建易受攻击的云基础设施时需要考虑的若干相关因素。

话虽如此,我们将涵盖以下主题:

  • 为什么要在云中构建渗透测试实验室?

  • 认识云计算对网络安全格局的影响

  • 探索现代云应用的设计、开发和部署方式

  • 在云中构建渗透测试实验室环境时需要考虑的事项

了解这些内容后,让我们开始吧!

为什么要在云中构建渗透测试实验室?

在职业生涯的某个阶段,安全专业人员可能会建立渗透测试实验室,在一个隔离的环境中安全地练习他们的技能。此时,你可能会问自己:渗透测试实验室环境里 有什么内容呢?

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_01_1.jpg

图 1.1 – 渗透测试实验室示例

图 1.1中,我们可以看到,渗透测试实验室环境只是一个受控环境,里面托管着若干个设计上存在漏洞的应用和服务。这些应用存在已知的漏洞和配置错误,利用正确的工具和技术可以加以利用。这些漏洞的设计是为了提供一个真实的环境,让渗透测试人员进行练习并模拟现实世界的攻击场景。此外,安全研究人员和渗透测试人员可以深入探索各种攻击路径,研究新的利用技术,并制定相应的对策。

在讨论在云中设置渗透测试实验室的好处之前,让我们先来讨论为什么拥有一个渗透测试实验室环境是个好主意。以下是推荐拥有渗透测试实验室环境的一些原因:

  • 在专用的实验室环境中学习渗透测试可以帮助你避免法律麻烦。未经合同、同意或协议,攻击他人或公司拥有的系统是非法的。

  • 鉴于渗透测试可能会破坏数据、崩溃服务器并使环境处于不稳定状态,拥有一个独立的渗透测试实验室将有助于确保生产环境不受渗透测试模拟可能产生的副作用影响。

  • 我们还可以在开发自定义渗透测试工具时,利用这些实验室环境来自动化和加速渗透测试过程中的某些步骤。

  • 我们还可以在这些环境中练习防御规避,通过设置各种防御机制,检测并阻止某些类型的攻击。

  • 我们可以通过黑客实验室环境来教授渗透测试的基础知识,面向安全爱好者和初学者。

  • 渗透测试实验室可以用来验证新披露的漏洞。这些隔离的环境还可以用来验证在应用了更新、配置更改或补丁之后,之前已知的漏洞是否已经得到修复。

既然我们已经讨论了为什么拥有渗透测试实验室环境是一个好主意,那么接下来该讨论在哪里托管这些黑客实验室了。过去,大多数安全从业人员主要在他们的本地机器上(例如,个人计算机或笔记本电脑)设置实验室环境。他们投资购买专用硬件,以便使用VirtualBox或其他虚拟化软件运行虚拟实验室环境:

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_01_2.jpg

图 1.2 – 在本地机器上运行渗透测试实验室环境

图 1.2中,我们可以看到,在家庭实验室环境中,一种常见的做法是在执行测试之前创建快照(用于捕捉当前状态),因为渗透测试过程中的某些步骤可能会影响目标机器的配置和稳定性。然后,这些快照可以用来恢复设置到原始状态,从而让安全专家和研究人员能够进行一系列测试和实验,而无需担心之前测试的副作用。

注意

过去,渗透测试实验室环境中常见的目标之一是一个故意设计为脆弱的 Linux 镜像,名为Metasploitable。它包含了多个脆弱的运行服务,映射到若干个开放端口,等待被扫描和攻击。实践者会使用BackTrack Linux(现已更名为Kali Linux)设置攻击机,并配置多种工具,如NmapMetasploit,来攻击目标机器。

当然,在本地机器上设置一个设计脆弱的实验室环境也存在一系列挑战和限制。这些可能包括以下一种或多种情况:

  • 在个人计算机或笔记本电脑上设置渗透测试实验室环境(这些设备很可能包含个人和工作文件)可能会带来意想不到的后果,因为如果黑客实验室环境设置不当,整个系统可能会被攻破。在最坏的情况下,当系统由于硬件退化或故障完全崩溃时,我们可能会失去所有文件。

  • 用于实验室环境的虚拟机可能需要大量资源。因此,我们可能需要更昂贵的本地配置,以满足正在运行的虚拟机的需求。

  • 设置易受攻击的实验室环境可能需要大量时间,并且可能需要先前了解所涉及的工具和应用程序。配置和准备实验室环境所需组件(如易受攻击的软件或网络设置)的过程可能非常复杂且要求很高。必须对工具及其依赖关系有深入了解,这对新手或经验有限的人来说可能是一个限制。

  • 某些漏洞和配置错误可能很难进行测试,尤其是那些涉及云服务使用和存在的漏洞。

注意

在某些情况下,我们还可能遇到许可证问题,导致无法在黑客实验室环境中使用某些虚拟机、操作系统和应用程序。

为了解决上述挑战之一或多个,考虑在云中设置我们的渗透测试实验室是一个好主意。以下是在设置云渗透测试实验室时的一些优势:

  • 托管在云中的实验室环境可能更接近实际在云中部署的生产环境的样子。

  • 通过在云中运行我们的黑客实验室环境几小时,并在测试和实验结束后删除(或关闭)云资源,我们可以显著管理成本。

  • 自己设置云实验室环境将帮助我们更深入地理解渗透测试实验室环境中部署的云资源的实施和安全配置。

  • 在云中扩展易受攻击的实验室环境更为容易,因为资源可以立即提供,我们无需担心硬件的先决要求。

  • 某些攻击在本地难以模拟,但在云环境中执行起来相对简单(例如,针对云函数及其他无服务器资源的攻击)。

  • 在云中设置复杂的实验室环境可能会借助自动化工具、框架和服务变得更快速。

  • 我们无需担心存储在本地计算机上的个人和工作文件被删除或盗取。

  • 在云中部署的黑客实验室环境中,更容易让多个用户练习渗透测试。

注意

除了这些,学习渗透测试在云中可以更快。首先,下载大文件和设置易受攻击的虚拟机在云中会显著更快。除此之外,重建云环境通常更容易,因为有多种选项可以重新创建和重建这些实验环境。

到此为止,我们应该知道为什么在云中构建渗透测试实验环境是一个很棒的主意!在接下来的部分,我们将快速讨论云计算是如何影响并塑造现代网络安全格局的。

认识到云计算对网络安全格局的影响

过去,公司必须主要在自己的数据中心托管应用程序。由于管理自有数据中心的运营开销,大多数企业已经考虑将数据和工作负载迁移到云中。有些组织将所有的应用程序和数据迁移到了云中,而其他则使用混合云架构将应用程序托管在本地数据中心和云中。云计算使得公司能够做到以下几点:

  • 确保持续运营:云中的高可用性确保应用程序和服务即使在发生故障或中断的情况下仍然可访问和运行。通过利用云服务提供商提供的冗余和容错架构,可以将停机时间降到最低,并保持对资源的不间断访问。

  • 节省资金:不需要投资硬件基础设施即可开始使用,因为云资源可以在几秒钟或几分钟内创建和删除。除此之外,云平台通常采用按需付费的模型来使用云资源。

  • 轻松管理应用程序工作负载:云中的应用程序工作负载可以远程管理。此外,资源可以根据业务需求轻松扩展或缩减。

  • 轻松管理数据:由于云环境中提供了各种服务、功能和能力,数据管理变得更加流畅和方便。此外,云提供的几乎无限的存储容量消除了处理大文件时的顾虑。这种增强的数据管理能力有助于提高企业的效率和可扩展性。

  • 自动化相关流程:在云中构建自动化的管道和工作流变得更容易,因为大多数云服务可以通过应用程序编程接口APIs)和软件开发工具包SDKs)进行管理。

随着越来越多的公司将数据存储在云中,过去几年云攻击显著增加。由于云计算的兴起,攻击面发生了变化,与此同时,攻击的类型也发生了变化。黑客可以利用易受攻击和配置错误的云资源,这可能导致存储在云中的敏感数据被窃取。

我们说的攻击面是什么意思?

攻击面是指系统内一组潜在的脆弱点,攻击者可以利用这些脆弱点进行攻击。它包括多个元素,包括网络接口、API、用户访问点、操作系统和已部署的云资源。理解和管理攻击面对于评估和减轻云中的安全风险至关重要,因为它可以帮助组织识别并解决可能被恶意行为者利用的弱点。

有鉴于此,以下是有关基于云的数据和应用程序的相关网络攻击的简要列表:

  • 针对易受攻击的应用服务器和配置错误的云存储资源的攻击:针对易受攻击和配置错误的云资源(如 API、虚拟机、CI/CD 管道和存储资源)的攻击已导致全球范围内的严重数据泄露。被窃取的身份和信息常用于身份盗窃和钓鱼攻击。

  • 云中的勒索软件攻击:存储在云中的敏感数据不断成为黑客的攻击目标。勒索软件的受害者通常被要求支付比特币或其他加密货币作为赎金。比特币和其他加密货币使用户能够保持匿名。这与其他技术一起,使得当局很难追踪勒索软件黑客。

  • 云账户劫持:一旦黑客接管了一个组织的云账户,黑客就可以自由地创建资源、访问敏感文件,并使用账户内的资源攻击其他公司和账户。

  • 分布式拒绝服务(DDoS)和钱包拒绝服务(DoW)攻击:在 DDoS 攻击中,攻击者试图通过生成的流量淹没和冲击已部署的云资源,使在线服务不可用。在 DoW 攻击中,使用类似的技术造成财务损失(由于巨额账单)。

多年来,随着云安全威胁的发展和蔓延,专注于云安全的工具数量和质量不断增加。随着每年披露的漏洞数量增加,更多的安全工具和实用程序也变得可用。这些工具从简单的脚本到复杂的框架和模块不等,可以根据攻击者的需求进行配置。安全专业人士也见证了工具和产品的演变。在过去,云安全产品需要由公司内部团队进行安装和设置。近年来,越来越多的托管云工具和服务变得可用,其中大多数可以在最小的配置下立即使用。以下是一些最新的云安全解决方案:

  • 各种攻击性安全云工具和框架

  • 无代理虚拟机漏洞评估工具

  • 容器镜像漏洞评估工具

  • 无服务器计算资源的漏洞评估工具和服务

  • 基于机器学习的代码安全扫描工具和服务

  • 云网络安全审计工具

  • 托管云防火墙

  • 托管的云威胁检测服务

  • 基于人工智能的安全工具

到目前为止,我们应该对云计算如何塑造和影响网络安全格局有了更好的理解。在下一节中,我们将深入探讨现代应用程序如何在云中设计、开发和部署。

探索现代云应用程序如何设计、开发和部署

在构建渗透测试实验室时,主要目标之一是准备一个按设计漏洞构建的环境,模拟真实的云环境。也就是说,我们必须对现代云应用程序的架构有充分的了解,这将使我们具备构建符合需求的环境所需的知识。

多年前,大多数部署在云中的应用程序是作为单体应用程序设计和开发的。这意味着应用程序的前端、后端和数据库层一起构建,作为一个单一的逻辑单元。大多数时候,多个开发人员会在同一个项目的代码库中工作。此外,整个应用程序以及数据库,很可能会作为一个单元一起部署在同一服务器或虚拟机中(类似于图 1.3中简化的示意图):

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_01_3.jpg

图 1.3 – 单体应用程序的部署(简化版)

从安全的角度来看,能够获得root 访问权限的攻击者,很可能能够访问并窃取存储在同一虚拟机上运行的数据库中的敏感信息。

我们所说的 root 访问权限是什么意思?

Root 访问是指拥有完全的管理员权限和对计算机系统或虚拟机的无限制控制。它授予用户最高级别的访问权限和操作权限,使其能够修改系统文件、安装或卸载软件,并执行通常限制其他用户执行的操作。在安全性方面,如果攻击者获得了托管应用服务器的虚拟机的 root 访问权限,这意味着他们已完全控制了该系统。这可能导致未经授权访问存储在同一机器上的数据库中的敏感数据。

当然,仍然有一些现代应用程序由于具有这种架构的好处,而仍然被设计和架构为单体应用程序。然而,正如我们很快会看到的那样,世界各地的更多团队正在选择从分布式微服务架构开始,而不是单体架构。单体架构的一个显著缺点是,当更多用户开始使用系统时,开发团队可能会面临无法扩展应用程序特定层的问题。一旦应用程序开始变慢,团队可能会选择对运行应用程序的虚拟机进行垂直扩展。通过垂直扩展,通过升级硬件或添加更强大的机器来增加单个服务器的资源,如 CPU 和 RAM。这种方法通过增强服务器的能力来使服务器处理更高的工作负载和需求。相比之下,水平扩展则是通过增加更多的服务器来分担负载,让每个服务器处理部分整体流量。由于垂直扩展通常比水平扩展长期成本更高,因此云架构师建议采用分布式多层架构,因为水平扩展只涉及扩展托管需要扩展的应用组件的基础设施资源。

例如,在分布式电子商务应用程序中,系统可以通过为 Web 服务器、应用服务器和数据库设计独立的层次,而不是对单个单体服务器进行垂直扩展以处理增加的用户流量。通过分离不同的层次,可以根据每一层的具体资源需求独立地扩展每一层。例如,应用服务器层可以水平扩展以处理增加的用户流量,而数据库层则可以垂直扩展以满足日益增长的数据存储需求。这样,当流量激增时,基础设施可以通过增加更多的 Web 服务器进行水平扩展,从而提供更具成本效益和可扩展的解决方案。

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_01_4.jpg

图 1.4 – 自动扩展设置

此外,分布式多层架构能够轻松支持资源的自动缩放,这得益于其固有的架构设计。这种灵活性允许系统在无需人工干预的情况下自动调整资源分配,确保最佳的性能和资源利用率。如果应用程序接收到的流量波动较大或不可预测,云架构师可能会考虑为应用程序的特定层设置自动缩放机制,以确保承载应用程序的基础设施资源不会被闲置使用。

安全专业人员必须考虑到,自动缩放设置的缩减操作可能会在应用程序接收到的流量下降时自动删除资源。需要注意的是,配置错误或不完整的自动缩放实施通常没有在生产环境中正确配置推荐的日志轮转设置。这将使调查变得更加困难,因为存储在受损基础设施资源或服务器中的日志可能会在自动缩减操作过程中被删除。

到目前为止,我们应该已经对初始的云应用程序设计和部署有了清晰的了解。快速跳转到现在,现代应用程序可能是这样的:

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_01_5.jpg

图 1.5 – 现代云架构的样子

哇!情况发展得太快了!图 1.5中,我们可以看到,除了前面讨论的内容之外,现代应用程序架构还可能包括以下一项或多项内容:

  • 使用基础设施即代码(IaC)解决方案来自动化云资源的配置:在构建现代云应用程序时,组织可以利用 IaC 解决方案来简化云资源的配置。例如,他们可能会使用像 Terraform 或 AWS CloudFormation 这样的工具,在代码中定义基础设施要求,从而自动化虚拟机、存储、网络和负载均衡器等资源的配置。

  • 使用托管容器服务来简化 Kubernetes 集群的管理:公司可能选择使用托管容器服务来简化 Kubernetes 集群的管理。例如,他们可以选择云平台提供的托管 Kubernetes 服务,该服务将处理集群的配置、扩展和监控等任务。这使得公司能够专注于应用程序的开发和部署,而无需管理底层的 Kubernetes 基础设施。

  • 持续集成和持续部署(CI/CD)流水线:公司可以设置 CI/CD 流水线,自动化集成代码更改、运行测试以及将应用程序部署到云端的过程。开发人员将代码更改提交到版本控制系统,触发自动化构建过程,该过程编译代码、运行测试并生成工件。CI/CD 流水线随后会将应用程序部署到预生产环境进行进一步测试,并在成功验证后,自动将其推广到生产环境。

  • 函数即服务(FaaS)资源:实施现代云应用的组织可以将 FaaS 资源作为其解决方案的一部分。例如,他们可能会设计应用程序,利用无服务器函数来处理特定任务或工作流。通过将应用程序分解为更小、更独立的函数,公司可以实现更大的可扩展性、减少操作开销并提高资源利用率。

  • 供 Web 和移动应用使用的 API:公司可以采用微服务架构,在这种架构下,设计并暴露 API 供 Web 和移动应用使用。在这种情况下,公司会开发封装特定功能并暴露清晰定义 API 的独立微服务。这些 API 随后将被 Web 和移动应用使用。通过这种设置,前端客户端与后端服务之间的通信和交互将无缝进行。

  • 使用托管防火墙和负载均衡器:组织可以利用云提供商提供的现有托管防火墙服务和解决方案,从而在网络层定义并执行安全策略。此外,他们还可以使用负载均衡器服务,将传入流量分配到多个应用程序实例上。这有助于确保现代云系统的可扩展性和高可用性,同时无需管理这些托管云资源的底层基础设施和操作系统。

  • 使用人工智能(AI)和机器学习(ML)服务:实施现代云应用的公司可以通过利用预训练模型和 API,利用 AI 和 ML 驱动的服务。例如,他们可以使用 AI 服务进行情感分析,以分析客户反馈并改善用户体验。此外,他们还可以使用托管的 ML 服务进行预测分析,以增强应用程序中的决策过程。

随着更多公司将工作负载迁移到云端,全球范围内使用托管服务的趋势也在不断增长。云平台提供的托管服务逐渐取代了公司内部系统管理员团队手动维护的系统中特定的组件。例如,公司现在使用像Google Cloud Pub/Sub这样的托管服务,而不是自己搭建像 RabbitMQ 这样的消息传递系统。这种方式使得企业可以将宝贵的时间和资源集中用于其他重要的业务需求。

使用托管服务时,大部分维护工作由云平台处理和自动化,而不是由公司内部的团队成员负责。以下是使用托管服务的一些优势:

  • 在使用托管服务时,服务器安全补丁和操作维护工作由云平台内部处理。这使得公司内部团队成员能够将宝贵的时间用于其他重要需求。一个很好的例子是Amazon SageMaker,数据科学家和机器学习工程师可以集中精力训练和部署机器学习模型,而无需担心手动维护任务。

  • 使用托管服务时,扩展通常更为容易,因为资源启动可以通过 API 调用或用户界面轻松修改和扩展。在某些情况下,资源甚至可以轻松配置自动扩展。以Azure Kubernetes ServiceAKS)为例,它可以轻松扩展资源,并调整集群中运行的 pod 数量。

  • 通常,部署的云资源已经安装了可靠的监控和管理工具。此外,与同一云平台的其他服务的集成是无缝的,并且可以立即使用。同时,托管的云服务和资源通常具有内置的实用自动化功能,可以立即使用。

注意

安全专业人员需要清楚了解使用托管服务时哪些是可能的,哪些是不可能的。例如,我们无法访问某些托管服务的底层操作系统,因为这些服务是按这种方式设计和实现的。一个很好的例子是 AWS 云平台的托管NAT Gateway。此外,安全专业人员还需要了解使用托管服务时可能的其他机制。例如,在 Amazon Aurora(一种为云端构建的关系型数据库管理系统)中,我们还可以选择使用无密码认证,通过身份和访问管理IAM)角色进行身份验证。这意味着,如果攻击者设法获取了具有正确权限集的 AWS 凭证,即使没有数据库的用户名和密码,也可以访问和修改数据库记录。

近几年,容器的使用量显著增加。如果你在疑惑什么是容器,容器实际上是轻量级的、隔离的环境,用来打包应用程序及其依赖项,以确保一致性和可移植性。另一方面,容器镜像作为自包含的可执行包,包含运行特定应用程序所需的文件和配置。企业选择容器是因为它们提供了更快的启动时间,并且可以在一台虚拟机中托管多个容器,确保在不同开发阶段中的一致性环境。最初,企业在生产环境中使用Docker容器进行部署时有所犹豫。然而,由于KubernetesDocker Compose以及其他类似容器框架的最新进展和生产就绪工具的发布,全球越来越多的公司开始使用容器来托管应用程序。

到现在,你可能会想,使用容器的优势是什么? 下面是一些公司选择使用容器的原因:

  • 从容器镜像启动新容器通常比从镜像创建新虚拟机和服务器更快。这是因为容器利用轻量级虚拟化技术,并共享主机系统的操作系统,使得它们能够快速启动,而无需启动完整的操作系统。此外,容器仅需要与应用程序相关的必要依赖项和库,因此镜像体积较小,部署时间更短。

  • 我们可以在一台虚拟机中运行多个容器。能够在虚拟机内运行多个容器,在资源利用和可扩展性方面提供了显著的优势。每个容器独立运行,可以将进程和服务隔离开,同时共享虚拟机的底层资源。这使得计算资源得到了高效的利用,因为多个容器可以在同一硬件上并行运行,从而优化了 CPU、内存和存储的使用。

  • 使用容器可以在不同环境中实现无缝的一致性,例如本地开发、预发布和生产环境。通过容器化,开发人员可以打包所有必需的依赖项和配置,确保应用程序在这些环境中运行一致。这种方法促使开发人员在早期就考虑环境的一致性,从而能够在开发生命周期的早期发现并解决任何兼容性或部署问题,进而实现更顺畅的部署,减少与环境相关的错误发生的机会。

除此之外,如今越来越多的托管云服务已支持自定义容器环境的使用,这为开发者提供了所需的灵活性,同时确保维护工作最小化。通过利用这些托管云服务,开发者可以专注于应用程序开发和创新,同时减轻基础设施维护的负担,确保容器化应用程序的最佳性能、可扩展性和安全性。

想象一家正在开发基于微服务的应用程序的公司。通过利用容器,他们可以将每个微服务封装在自己的容器中,从而实现独立的开发、测试和部署。这种模块化的方法使团队能够独立迭代和更新特定的服务,而不影响整个应用程序堆栈。此外,容器还可以随着需求的波动实现无缝扩展。当应用程序流量增加时,容器编排平台(如 Kubernetes)会自动启动所需容器的额外实例,以确保最佳性能和资源利用率。这种可扩展性使企业能够高效地处理峰值负载,而无需过度配置基础设施。

话虽如此,鉴于容器日益普及,深入了解容器安全是至关重要的。容器带来了独特的安全挑战,必须加以解决,以保护应用程序和数据。通过实施有效的容器安全措施,组织可以减少风险(例如未经授权的访问、数据泄露和容器突破),从而确保关键系统和敏感信息的安全。

与容器类似,过去几年中,FaaS 服务的使用也显著增加。主要云平台提供的 FaaS 选项,包括 AWS Lambda FunctionsAzure FunctionsGoogle Cloud Functions,允许开发者和工程师在隔离的环境中部署和运行自定义应用程序代码,而无需担心服务器管理。以前,开发者必须处理服务器的配置和配置工作。然而,随着无服务器函数的出现,开发者可以专注于编写和部署自定义应用程序代码,而不必担心基础设施,从而实现更高效、更精简的开发过程。这一转变使得快速迭代、可扩展部署和减少运营开销成为可能,极大地简化了开发者的工作。通过结合事件驱动架构的其他构建块,开发者可以将复杂的应用程序代码分割成更小、更易于管理的组件。为了更好地理解这些服务的工作原理,下面我们快速讨论一些常见的云函数特点:

  • 自动化的上下扩展

  • 按需付费模式

  • 每次调用函数时,运行时环境会被创建并删除

  • 无需维护,因为云平台会处理维护工作

  • 存在资源限制,包括最大执行时间、内存、存储和代码包大小

  • 函数由事件触发

重要说明

FaaS无服务器计算 这两个术语有时被专业人士交替使用。然而,它们是两个不同的概念。FaaS 主要关注的是拥有一个平台,用于加速应用代码功能的开发和部署。另一方面,无服务器计算是指云计算执行模型,通常以事件驱动架构、托管服务以及按使用量计费为特征。也就是说,完全可以在不使用 FaaS 服务的情况下实现无服务器应用(例如,使用云存储服务的静态网站托管功能托管的仅前端的单页应用SPA))。

这与云安全和渗透测试有何关系? 云函数的设计和实现直接影响专业人员的攻防安全策略。开发者和工程师需要确保部署在云函数中的代码能够防范各种注入攻击。例如,创建一个文件并将其保存在存储桶中,而文件名中包含恶意负载,可能会在事件触发云函数时导致命令执行。除此之外,安全专家还必须找到在处理云函数时维持持久性的替代方法(即使在成功突破后),因为运行时环境会在几秒钟内创建和删除。

到此为止,你应该对现代云应用的样子有了很好的了解!这一部分我们还可以讨论更多内容,但目前这些足够了。通过我们迄今为止所学的内容,我们现在可以深入探讨在设计和构建云中的渗透测试实验环境时需要考虑的事项。

在云中构建渗透测试实验环境时需要考虑的事项

在本书接下来的章节中,我们将设计并构建多个具有设计漏洞的云实验室。每次设置完实验室环境后,我们将模拟渗透测试过程,以验证存在的漏洞是否可以被利用。在我们在云环境中执行渗透测试前,我们必须了解以下事项:

  • 哪些活动是无需通知或授权即可进行的

  • 攻击流量是否会经过公共互联网

  • 我们是否会进行网络压力测试

  • 我们的渗透测试实验环境是什么样的

  • 我们将在环境中执行哪些活动

  • 无论我们是在测试服务器内部应用的安全性,还是在测试云服务配置的安全性

除此之外,我们还必须了解云平台禁止的活动和操作。以下是一些在云环境中不允许的例子:

  • 对云平台的员工进行社交工程攻击

  • 攻击资源并尝试访问其他账户拥有者和用户的数据

  • 以违反平台的可接受使用政策服务条款的方式使用云服务

请注意,针对每个云平台的相关文档页面中有一长串禁止的行为和活动。你可以在接下来的页面以及本章的进一步阅读部分找到相关资源链接。

当需要时,我们还必须通知并联系云平台的相关支持和安全团队。这将确保我们不会违反任何规则,尤其是当我们不确定或是第一次在云中进行渗透测试时。

注意

最佳做法是提前通知云平台以获得授权和批准。在某些情况下,可能不需要批准或通知,但在进行渗透测试前向支持团队提交工单不会有什么坏处。

有时,你可能会认为你不再需要从云服务提供商那里获得授权,因为你的渗透测试会“不会损害其他客户”。然而,情况并非总是如此,因为可能存在仍然需要获得云服务提供商授权的操作。图 1.6展示了 AWS 上渗透测试实验室环境的示例:

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_01_6.jpg

图 1.6 – 渗透测试实验室环境设置示例

该实验室环境包含以下组件:

  • 一个位于 VPC 内的攻击者机器,阻止所有外向连接

  • 一个包含易受攻击应用和服务的目标机器

  • 一个 VPC 对等连接,允许攻击者和目标 EC2 实例所在的 VPC 之间进行流量传输(这样攻击流量就会经过此 VPC 对等连接)

  • 一个通过 Private Link 访问的 S3 存储桶,里面包含文件

在 EC2 实例中运行的应用程序进行渗透测试无需批准。另一方面,除非获得 AWS 的批准,否则在 AWS 账户中对您自己的 S3 桶进行渗透测试是被禁止的。为什么? 对您拥有的 S3 桶进行渗透测试与对托管在 S3 上的应用程序进行渗透测试有所不同。在对 Amazon S3 及其他未列在渗透测试客户服务政策中的许可服务下的服务进行渗透测试模拟之前,您必须填写模拟事件表格并提供必要的信息以获得 AWS 的授权。请确保在对 AWS 进行渗透测试之前查看以下链接:

需要注意的是,不同的云平台的渗透测试政策和指南各不相同。以下是您在对 Azure 进行渗透测试之前需要查看的一些资源和链接:

以下是 GCP 的相关资源和链接:

请注意,这些政策和指南可能会在未来发生变化,因此在对云环境中运行的应用程序进行渗透测试之前,请务必查看相关指南。如果有任何问题或需要进一步澄清,请务必联系云平台的支持和安全团队获取指导。

除了之前讨论的内容,还有其他方面需要考虑,特别是在安全性和工程方面:

  • 选择实验室所需云基础设施资源的性能要求:在云中建立渗透测试实验室环境时,考虑性能要求并选择适当的云基础设施资源至关重要。这涉及评估诸如网络带宽、计算能力和存储能力等因素,以确保实验室环境能够有效地模拟真实场景,并处理安全测试中资源密集的特点。

  • 搭建、运行和维护渗透实验室的整体成本:在云中建立、运营和维护渗透测试实验室环境的成本应从安全性和工程角度来考虑。这包括与资源配置、基础设施管理以及持续监控和更新相关的费用。

  • 环境的安全性和可审计性,因为渗透测试实验室必须防止不当的外部攻击:在云中建立渗透测试实验室环境时,确保环境的安全性和可审计性至关重要。必须通过实施强大的安全措施和控制,保护实验室免受不当的外部攻击。这包括利用云平台提供的安全功能,如网络分段、访问控制和监控,以创建一个安全且可审计的测试环境。

  • 实验室环境的可扩展性和模块化:使实验室环境具备可扩展性和模块化,可以高效地根据不同场景和需求定制实验室,帮助渗透测试人员有效地模拟和评估各种攻击场景。

  • 实验室版本的可管理性:利用版本控制系统和工具,渗透测试人员能够高效地管理和跟踪实验室环境配置、软件版本和自定义脚本的变更。这确保了实验室版本易于维护和重现,并且可以根据需要进行回滚或更新。

  • 使用自动化工具和服务进行快速重建和设置:通过利用自动化,渗透测试人员可以更多地专注于实际的测试和分析,而不是花费大量时间在手动设置和维护任务上。

我们可以在此列表中添加更多内容,但这些考虑事项现在应该足够了。我们将在接下来的几章中详细讨论这些安全性和工程考虑事项,并在不同云平台上构建各种按设计脆弱的实验室环境。

总结

在本章中,我们首先快速讨论了在云端搭建渗透测试实验室的优势。接着,我们仔细探讨了云计算如何影响并塑造现代网络安全的格局。我们还研究了现代云应用程序的设计、开发和部署方式。本章的最后,我们深入探讨了在云端设计和构建漏洞环境时需要考虑的几个重要因素。

在下一章中,我们将继续设置我们的第一个云端漏洞实验环境。设置好渗透测试实验室后,我们将使用各种攻击性安全工具和技术验证这些漏洞是否可以被利用。

深入阅读

如果你想了解本章涉及的主题,欢迎查看以下资源:

第二章:准备我们的第一个脆弱云实验环境

第一章《云端渗透测试实验室入门》中,我们讨论了几个在云端构建有意漏洞实验环境的关键主题。此时,你可能已经迫不及待想要动手实践,并非常期待开始进行一些动手练习。好消息是,我们无需再等太久,因为本章将带领我们开始第一个渗透测试云实验环境的构建。

我们将从本章的动手部分开始,通过创建一个空的 Amazon Simple Storage ServiceS3)桶,并将其配置为静态网站托管。接着,我们将通过修改其访问控制设置使该桶配置错误。然后,我们将上传一些示例文件到 S3 桶中,使该环境更加真实。当然,设置脆弱的云实验环境只是第一步!第二步是通过模拟攻击者的攻击过程来测试实验环境的安全配置。测试完成后,我们将进行清理操作,删除桶以及其中存储的文件。

也就是说,我们将涵盖以下主题:

  • 设计我们的第一个云渗透测试实验室环境

  • 准备我们的第一个脆弱环境

  • 测试和黑客攻击我们的第一个脆弱环境

  • 清理工作

在本章的动手解决方案中,我们将介绍与安全相关的概念和机制,这些概念和机制可用于管理 S3 桶的访问控制。深入理解这些安全机制的工作原理,将帮助你为更复杂的渗透测试实验环境准备不同的配置错误的 S3 桶变种。

既然如此,让我们开始吧!

技术要求

在开始之前,我们必须准备好以下内容:

  • 一个 AWS 账户,将作为目标账户,包含脆弱的环境和资源

  • 第二个 AWS 账户,将作为攻击者账户

你可以通过访问aws.amazon.com/free/来创建这些 AWS 账户。账户创建好后,你就可以继续进行下一步操作。

注意

本章主要聚焦于在 AWS 上构建一个样本脆弱实验环境。当然,一旦进入后续章节的动手部分,我们还需要准备好Microsoft AzureGoogle Cloud PlatformGCP)账户。在此之前,设置两个 AWS 账户已经足够了。

设计我们的第一个云渗透测试实验室环境

第一章《在云中入门渗透测试实验室》中,我们讨论了现代云应用程序是如何设计、开发和部署的。我们仔细研究了分布式多层架构和水平扩展策略如何使得可以独立地扩展特定层次,以应对增加的用户流量:

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_01.jpg

图 2.1 – 第一章中的通用多层架构图

在这里,我们设计的系统具有单独的层次结构来区分 Web 服务器、应用程序服务器和数据库。鉴于这是云架构实现中的一种常见模式,你可能会想知道,当在像 AWS 这样的云平台上实现时,它会是什么样的? 这个问题的答案很简单!在 AWS 上实现时,它看起来几乎是一样的!首先,图 2.1中的资源将简单地有自己对应的 AWS 资源和服务(类似于图 2.2中展示的内容):

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_02.jpg

图 2.2 – 如何在 AWS 上实现分布式多层架构

图 2.2中,我们可以看到来自图 2.1的通用负载均衡器资源将被Amazon Elastic Load BalancingELB)云资源替换。同样,Web 服务器将被多个Amazon Elastic Compute CloudEC2)实例替换。通用数据库服务器资源随后将被托管的Amazon Relational Database ServiceRDS)数据库资源替换。

到目前为止,你可能会想知道为什么在图 2.2中我们有一个额外的资源框(也就是表示 Amazon S3 存储桶的框)!其实,即使 Amazon EC2 实例已经附加了存储卷,云工程师通常会通过将文件和对象存储在Amazon S3 存储桶中以及将数据库记录存储在Amazon RDS数据库实例中,进一步解耦应用程序架构。这使得部署在 EC2 实例(虚拟机)集群中的应用程序能够保持无状态(从而更容易实现自动扩展),因为状态被存储在 S3 存储桶和 RDS 数据库实例中。

什么是 Amazon S3?

Amazon S3 是一个对象存储服务,旨在存储和检索各种文件。我们可以把 Amazon S3 看作是一个在线服务,我们可以创建文件存储容器(也叫 S3 存储桶),这些容器可以存储通过 Web 界面、CLI 工具、SDK 或 API 上传的任意数量的文件。当然,我们也可以使用类似的选项从这些存储桶中下载文件。

Amazon S3 在现代部署在 AWS 上的应用程序中扮演着重要角色。许多运行在 AWS 上的云应用程序和系统利用 S3 存储桶来存储各种类型和格式的文件。这包括数据工程和机器学习系统,类似于我们在图 2.3中看到的内容:

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_03.jpg

图 2.3 – 机器学习和数据工程系统存储数据的位置

在这里,我们有一个机器学习工程系统,利用Amazon SageMaker(托管的机器学习服务)和Amazon Athena(无服务器的交互式分析服务)等托管机器学习和数据工程服务来处理存储在 Amazon S3 桶中的数据。在数据处理操作之前和之后,云数据存储在哪里? 在大多数情况下,数据会存储在 Amazon S3 桶中,特别是在处理数据工程和机器学习工程工作负载时。如我们所见,Amazon S3 是 AWS 上使用最广泛的服务之一。部署在 AWS 上的应用程序最有可能将文件存储在 S3 桶中(或多个 S3 桶中)。其多功能性和可扩展性使其成为在云中存储各种类型的文件和数据的首选。部署应用程序时,利用 S3 桶进行高效和安全的文件存储是一种常见做法,无论是托管静态网站资源、存储用户上传的内容,还是作为大规模分析的数据湖。

在某些情况下,存储在 Amazon S3 中的文件可能包含个人可识别信息PII)以及其他必须加以保护的敏感信息。这些信息可能包括姓名、地址、社会安全号码或财务信息,如果被未经授权的人访问,可能会造成重大风险。保护这些信息对于维护隐私和遵守数据保护法规至关重要。需要注意的是,S3 桶可能会直接遭到恶意攻击者的攻击,而无需经过负载均衡器和网页应用层,如图 2.2所示。这意味着,如果 S3 桶配置错误(例如,存储在桶中的敏感文件可以公开访问),无论负载均衡器和网页应用层如何安全,攻击者都可以窃取 S3 桶中的文件和数据。

在过去几年中,错误配置的 S3 桶导致了大量数据泄露事件,泄露了包含 PII、敏感企业信息甚至凭证的数百万条记录。以下是过去几年的一些重要事件:

  • 在 2017 年,发现大量 S3 桶配置错误,导致敏感信息的泄露,包括 PII、信用报告,甚至是政府和军事数据。

  • 在 2018 年,一家 IT 公司泄露了多家财富 100 强公司的数据,导致各种类型的敏感信息和专有数据被曝光。

  • 在 2019 年,一家为半数财富 100 强公司提供服务的供应商不小心暴露了 1TB 的备份数据,而一家医疗服务提供商错误配置的 S3 桶暴露了医疗记录和患者与医生的记录。

  • 2020 年,一个消费者评分和评论网站的 S3 存储桶配置错误,暴露了老年人的数据,而一家全球科技公司也经历了一次事件,未经授权的人员闯入了其未加固的 AWS S3 存储空间。

  • 2022 年,一个配置错误的 S3 存储桶泄露了约 3 TB(太字节!)的敏感机场数据,暴露了航空公司员工的个人身份信息(PII)。

这些事件以及过去几年报告的其他泄露事件,突显了 S3 存储桶配置错误的普遍性及其可能带来的风险。

注意

想了解更多关于这个话题的信息,欢迎查看以下链接:github.com/nagwww/s3-leaks

为什么攻击 S3 存储桶如此普遍?

云工程师和开发人员通常对不同的访问控制机制如何协同工作以保护 S3 存储桶的理解较差。除此之外,在 S3 存储桶内管理访问控制策略和权限的复杂性增加了另一层挑战。可用的众多选项和设置可能会让经验不足的用户感到不知所措,增加配置错误和敏感信息意外暴露的可能性。这可能导致配置错误的 S3 存储桶泄露并将私密和敏感信息暴露给未经授权的用户。

话虽如此,了解可用的安全措施将有助于我们更好地保护 S3 存储桶中的文件。同时,这也将使我们能够设计和构建涉及 S3 的实际渗透测试实验室。如果你想知道有哪些安全机制可以保护存储在这些 S3 存储桶中的文件,这里有一个快速的列表:

  • 身份与访问管理(IAM)策略:通过配置 IAM 策略,组织可以为其 AWS 账户中的用户、组和角色定义精细的权限和访问控制。这可以更精确地控制谁可以对 S3 存储桶执行操作,如读取、写入或删除操作。

  • 存储桶策略:存储桶策略在存储桶级别提供了额外的访问控制层。通过存储桶策略,组织可以定义管理对特定 S3 存储桶访问的规则和条件。这包括基于各种因素(如 IP 地址、用户代理或特定 AWS 账户)允许或拒绝访问。

  • 访问控制列表(ACLs):ACL 提供了另一种管理对 S3 存储桶和对象访问的机制。ACL 允许组织为存储桶中的单个对象指定权限,从而提供更精细的文件级访问控制。通过设置适当的 ACL,组织可以授予特定用户或组读取或写入权限,同时限制其他人的访问。

  • 虚拟私有云 (VPC) 终端节点策略:VPC 终端节点策略允许组织控制其 VPC 环境内对 S3 存储桶的访问。通过定义终端节点策略,组织可以指定哪些 VPC 或子网可以访问特定的 S3 存储桶。这有助于防止来自 VPC 外部的未经授权访问,并通过限制对受信任网络环境的访问,增强存储在 S3 存储桶中的文件的安全性。

  • AWS 组织服务控制策略 (SCPs):SCPs 是 AWS 组织的一部分,允许组织在多个 AWS 账户之间设置精细的权限。通过定义 SCPs,组织可以强制执行适用于所有成员账户的集中式安全策略。这包括控制对 S3 存储桶的访问,并确保在整个组织内应用一致的安全措施。通过利用 SCPs,组织可以增强其 S3 存储桶的整体安全态势,确保文件在整个企业中得到统一保护。

重要提示

虽然 2023 年 4 月之后创建的新 S3 存储桶在创建过程中默认禁用 ACL,但仍然可以通过配置更改在 S3 存储桶配置和创建时启用 ACL。同时,禁用 ACL 的 S3 存储桶可以在存储桶创建后被修改并启用恢复 ACL。尽管采取了强制安全默认设置,但在 2023 年 4 月之前创建的相当一部分 S3 存储桶仍依赖于 ACL,并与其他讨论的 S3 安全机制一起使用。因此,全面理解这些安全机制对于设置基于云的渗透测试实验环境以及确保 S3 安全设置的正确配置至关重要。

即使云平台发布了安全机制和安全升级的防护措施,仍有相当一部分现有的 S3 存储桶存在错误配置。除此之外,无论云架构的其他组件多么安全,错误配置的 S3 存储桶仍然会导致数据泄露,因为在许多情况下,存储在 S3 存储桶中的文件可以直接访问。

在本章中,我们将专注于在我们的 AWS 账户中准备一个错误配置的 S3 存储桶。在构建我们的第一个云渗透测试实验环境(即单个错误配置的 S3 存储桶)之前,我们必须清楚了解最常见的 S3 存储桶错误配置是什么:

  • 访客/匿名用户可以对存储在存储桶中的对象执行操作:此错误配置使得攻击者或未经授权的个人能够访问和操作存储在存储桶中的文件和文件夹。未经授权的用户可以列出存储桶中的内容,从中检索对象,甚至上传自己的文件,这可能导致未经授权的数据暴露、修改或删除。

  • “已认证用户”(任何拥有 AWS 账户的人)可以列出文件并读取和写入 S3 存储桶中的对象:此配置错误允许任何拥有 AWS 账户的用户列出、读取和写入存储桶中的对象。这意味着任何拥有 AWS 凭证的个人或用户都可以访问并修改存储桶的内容。

  • S3 存储桶的 ACL 配置可以被外部用户读取:此配置错误帮助攻击者获取有关存储桶安全配置的更多信息。

  • S3 存储桶访问日志记录在 CloudTrail 中已禁用:此配置错误阻止 AWS 用户审核 S3 存储桶的事件历史记录(包括实体或资源在 S3 存储桶上执行的操作)。

注意

如果这是您第一次遇到CloudTrail,它是一个 AWS 服务,帮助监控和记录 AWS 账户活动。此服务在帮助启用治理、合规性、操作审计和风险审计方面发挥着重要作用。在 CloudTrail 中禁用 S3 存储桶的访问日志记录意味着不会生成日志来追踪和记录存储桶的访问活动。这可能会限制检测未经授权的访问尝试、排除故障并为合规性和安全目的保持完整的存储桶活动记录的能力。

通过更加清晰地理解 S3 存储桶可能出现的典型配置错误,我们现在可以继续前进,设计并建立我们的第一个云渗透测试实验室环境。具体而言,我们的重点将是设计一个实验室环境,其中包含一个故意配置错误的 S3 存储桶,用于模拟现实世界中的漏洞。我们的配置错误的 S3 存储桶将存储一些示例文件,类似于图 2.4中所示的内容:

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_04.jpg

图 2.4 – 我们的 S3 存储桶将如何配置

图 2.4所示,我们将配置 S3 存储桶,使其具备以下属性和配置设置:

  • 静态网站托管已启用:此配置启用指定 S3 存储桶的静态网站托管,使其能够直接从存储桶提供静态网页和资产。

  • 阻止公共访问已禁用:此配置(启用时)通过强制限制公共访问来帮助防止敏感数据的意外暴露。然而,当此配置设置被禁用时,匿名用户和未经授权的实体可能能够访问存储桶及其中的对象(特别是当 S3 存储桶配置错误时)。

  • 存储桶策略已认证用户可以检索对象:此配置允许已认证用户(即任何拥有 AWS 账户的人)从 S3 存储桶中检索对象,从而允许他们访问存储的数据。

  • 访问控制列表(ACL)认证用户可以列出对象:这允许认证用户列出 S3 存储桶中的对象。

除了这些,我们还将上传一些在典型 S3 存储桶中可能看到的示例文件。现在我们已经讨论了脆弱实验环境的(误)配置,接下来可以进行本章的动手实践部分!

重要提示

需要注意的是,虽然我们在本章中专注于 Amazon S3,但类似的问题和事件也影响了使用 Azure Blob Storage 和 Google Cloud Storage 的公司。这些服务与 Amazon S3 类似,也面临着类似的安全挑战和漏洞。

准备我们的第一个脆弱环境

正如前一部分所讨论的,我们的第一个脆弱环境将由一个配置错误的 Amazon S3 存储桶和一些示例文件组成。创建空 S3 存储桶有多种方式。本章中,我们将使用 AWS 管理控制台来创建存储桶。

本部分包含四个子部分:

  • 创建一个空的 S3 存储桶

  • 配置 S3 存储桶以托管静态网站

  • 更新 S3 存储桶的配置设置

  • 上传文件到 S3 存储桶

重要提示

由于我们将准备一个故意脆弱的 S3 存储桶,请确保不要使用此 S3 存储桶来存储生产数据(或包含敏感信息的文件)。

创建一个空的 S3 存储桶

我们将从创建一个空的 S3 存储桶开始。请确保你使用“目标账户”(第一个 AWS 账户)登录。

重要提示

你也可以选择将 N. Virginia 作为 S3 存储桶创建的区域。在继续操作之前,随时可以使用页面左上角的下拉菜单更新当前区域。

牢记这一点,让我们开始使用 AWS 管理控制台创建空的 S3 存储桶:

  1. 在搜索栏中输入 s3https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_05.jpg

    图 2.5 – 导航到 S3 控制台

    从结果列表中选择 S3(如图 2.5所示)。

  2. 接下来,点击 创建存储桶 按钮,如图 2.6所示:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_06.jpg

    图 2.6 – 定位创建存储桶按钮

    你应该能在页面右上角附近看到 创建存储桶 按钮。

注意

需要注意的是,用户界面可能会每隔几年发生一次变化。然而,这不应妨碍我们继续创建所需资源,因为需要配置的属性和设置基本保持不变(除了少数新增的属性和选项)。

  1. 存储桶名称 下,指定一个全球唯一的存储桶名称:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_07.jpg

    图 2.7 – 创建 S3 存储桶

    如果你在命名 S3 存储桶时遇到困难,可以将 S3 存储桶命名为sample-web-bucket-<6-8 位随机字母数字字符>。可能需要尝试几次才能得出一个有效且全球唯一的 S3 存储桶名称。

注意

有关如何命名 S3 存储桶的指南,请查看以下链接:docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html

此外,请从AWS 区域选择框的选项列表中选择美国东部(弗吉尼亚北部)us-east-1

  1. 选择启用 ACL选项,类似于图 2.8中所示的那样:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_08.jpg

    图 2.8 – 配置对象所有权设置

    对象所有权配置值设置为对象写入者将使对象成为上传它们的 AWS 账户的所有物。这意味着拥有对象的 AWS 账户可以使用 ACL 来授予其他用户访问权限(即使上传对象的 AWS 账户并不是存储桶的所有者)。

重要说明

请注意,AWS 定期更新并改善 AWS 管理控制台的用户体验。在某些情况下,创建资源时的默认配置设置可能会发生变化,尤其是在某些日期之后。例如,从 2023 年 4 月开始,AWS 为 S3 存储桶的公共访问阻止(S3 Block Public Access)和 S3 对象所有权(S3 Object Ownership)设置了一组新的默认设置。因此,到你阅读这本书时,使用 AWS 管理控制台时可能需要点击几个额外的按钮,并且会看到一些差异。有关此主题的更多信息,请查看以下链接:docs.aws.amazon.com/AmazonS3/latest/userguide/create-bucket-faq.html

  1. 取消选中阻止所有公共访问复选框,类似于图 2.9中所示的那样:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_09.jpg

    图 2.9 – 关闭阻止所有公共访问

    除此之外,确保你将我知道当前设置可能导致此存储桶及其中的对象变为公开的复选框设置为ON。这将允许你指定一个存储桶或访问点策略,以授予公共访问权限。

  2. 你应该会看到一个成功通知,类似于图 2.10中所示的那样:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_10.jpg

    图 2.10 – 定位查看详细信息按钮

    点击查看详细信息按钮,跳转到我们刚刚创建的 S3 存储桶的具体页面。

    这不是很简单吗?当然,我们才刚刚开始——接下来的几节内容中,我们将继续配置这个 S3 存储桶!

配置 S3 存储桶以托管静态网站

接着我们在上一节的内容,继续配置我们的 S3 存储桶以进行静态网站托管。你会惊讶于这项配置是多么简单!话不多说,让我们继续:

  1. 点击属性以导航到属性标签,如图 2.11中所示:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_11.jpg

    图 2.11 – 导航到属性标签

    我们应该在属性标签下看到以下内容:(1)桶概览,(2)桶版本控制,(3)标签,(4)默认加密,(5)智能分层归档配置,(6)服务器访问日志,(7)AWS CloudTrail 数据事件,(8)事件通知,(9)Amazon EventBridge,(10)传输加速,(11)对象锁,(12)请求者付费,和(13)静态 网站托管

  2. 向下滚动到页面底部,直到看到静态网站****托管面板:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_12.jpg

    图 2.12 – 编辑静态网站托管设置

    点击编辑按钮,如图 2.12中所示。

  3. 通过选择启用选项来启用静态网站托管(参见图 2.13):https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_13.jpg

    图 2.13 – 为 S3 桶启用静态网站托管

    之后,确保在索引 文档字段中指定index.html

  4. 向下滚动到页面底部并点击保存 更改按钮。

此时,桶仍然为空,因此点击提供的Bucket 网站端点链接(点击保存更改按钮后)将会返回一个404 未找到的错误响应。请不要担心——我们将在下一部分更新桶的访问控制设置后上传自定义的index.html文件。

更新 S3 桶配置设置

现在我们已经为 S3 桶配置了静态网站托管,下一部分涉及配置桶以允许任何拥有 AWS 账户的用户列出和访问存储在桶中的对象。也就是说,我们将在接下来的步骤中更新桶策略和 ACL 配置设置:

  1. 点击权限标签(位于属性标签旁边)。我们应该在权限标签下看到以下内容:(1)权限概览,(2)阻止公共访问(桶设置),(3)桶策略,(4)对象所有权,(5)访问控制列表(ACL),和(6)跨源资源 共享(CORS)

  2. 接下来,点击编辑按钮(如图 2.14中所示),以指定新的桶策略:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_14.jpg

    图 2.14 – 编辑桶策略

    图 2.14中,我们可以看到当前没有指定桶策略。

  3. 点击编辑按钮后,在文本框中指定以下桶策略:

     {
        "Version": "2012-10-17",
        "Id": "n",
        "Statement": [
            {
                "Sid": "SampleStatement",
                "Effect": "Allow",
                "Principal": {
                    "AWS": "*"
                },
                "Action": "s3:GetObject",
                "Resource": "arn:aws:s3:::<BUCKET NAME>/*"
            }
        ]
    }
    

    确保将<BUCKET NAME>替换为你创建的 S3 桶的桶名。这样你应该能得到一个类似于图 2.15中的桶策略:

    https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_15.jpg

    图 2.15 – 指定桶策略

    该 S3 存储桶策略使任何 AWS 账户都可以从sample-web-bucket-abc123 S3 存储桶中检索对象。你可能会惊讶地发现,我们在图 2.15中看到的配置,实际上是全球范围内 S3 存储桶中常见的配置错误!

重要说明

需要注意的是,将"Action"参数值从"s3:GetObject"更改为"*"将允许任何 AWS 账户执行不必要的操作(例如,上传文件)到我们的 S3 存储桶中。我们不希望其他用户拥有写入访问权限到我们的存储桶!为什么呢?首先,恶意的已认证用户将能够向我们的 S3 存储桶上传多个大型文件(这会影响我们的 AWS 账单)。也就是说,在处理策略时,应该尽量避免使用通配符或星号(“*”),即使我们设计的是一个故意脆弱的 S3 存储桶。

  1. 向下滚动到页面底部,点击保存 更改按钮。

  2. 现在,让我们修改访问控制列表(ACL)配置设置。点击编辑按钮,如图 2.16所示:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_16.jpg

    图 2.16 – 编辑 ACL 配置

    在这里,我们可以看到当前的 S3 存储桶 ACL 配置。默认情况下,只有存储桶的所有者(你)才能在存储桶上执行操作。

  3. 编辑访问控制列表(ACL) | 访问控制列表(ACL)下,点击对象列中已认证用户组授权方的列出复选框,并将其设置为开启,类似于我们在图 2.17中看到的:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_17.jpg

    图 2.17 – 允许认证用户组列出存储桶中的对象

    这应该允许任何拥有 AWS 账户的人列出我们 S3 存储桶中的对象。

注释

欢迎查看aws.amazon.com/blogs/security/iam-policies-and-bucket-policies-and-acls-oh-my-controlling-access-to-s3-resources/了解更多关于在多种访问控制机制存在时,权限控制是如何工作的。

  1. 确保将我理解这些更改对我的对象和存储桶的影响复选框设置为开启https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_18.jpg

    图 2.18 – 确认将应用的 ACL 修改

    鉴于此配置更改可能带来意想不到的后果(从安全角度来看),AWS 要求我们审查并确认所应用的更改。

重要说明

AWS 建议禁用 ACL,因为在大多数场景和用例中,我们可以依赖 S3 存储桶策略、IAM 策略、VPC 端点策略以及 AWS 组织的 SCP 来管理 S3 的访问控制。然而,尽管存在警告和防护措施,许多现有的 S3 存储桶仍然配置错误并存在漏洞,因为只有新创建的 S3 存储桶才会受到 AWS 强制执行的最新防护措施的保护。

现在我们已经修改了存储桶策略和 ACL 配置设置,接下来将在下一节中继续上传文件到我们的 S3 存储桶。

将文件上传到 S3 存储桶

如果没有存放在我们的易受攻击的 S3 存储桶中的文件,设置就不完整了。也就是说,我们将上传一些我们可能在典型的 S3 存储桶中看到的示例文件。有多种方法可以将文件上传到 S3 存储桶。一种选择是使用 AWS 管理控制台上传文件。另一种选择是使用 AWS CLI 通过命令行上传文件。

在接下来的步骤中,我们将使用 AWS CLI 将文件上传到我们的 S3 存储桶:

  1. 打开一个新的浏览器标签页,导航到 AWS 控制台。在搜索栏中输入 shell,从结果列表中选择 CloudShell,就像我们在 图 2.19 中看到的那样:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_19.jpg

    图 2.19 – 导航到 CloudShell 控制台

    如果你之前没有使用过 AWS CloudShell,它其实是一个基于浏览器的命令行终端,我们可以在其中运行不同的命令来管理我们的资源。在接下来的步骤中,你会惊讶于使用 CloudShell 的便利性!

注意

需要注意的是,AWS CloudShell 可能不支持其他 AWS 区域。如需更多信息,请随时查看以下链接:docs.aws.amazon.com/cloudshell/latest/userguide/supported-aws-regions.html

  1. 当你看到 欢迎使用 AWS CloudShell 弹出窗口时,点击 关闭 按钮:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_20.jpg

    图 2.20 – 关闭欢迎弹窗

    图 2.20 中,我们可以看到 AWS CloudShell 已预安装 AWS CLI、Python 和 Node.js 以及其他工具。此外,我们还可以使用 1 GB 的免费存储(按 AWS 区域划分),在其中管理、上传和下载用于资源管理和创建的文件。

    关闭弹出窗口后,你应该能看到一个终端,在终端中可以输入并运行 bash 命令。

  2. 在我们的 CloudShell 环境的终端($ 符号后面),运行以下 bash 命令:

    mkdir files
    cd files
    

    mkdir 命令用于创建一个名为 files 的新目录。之后,使用 cd 命令进入新创建的目录。

  3. 接下来,让我们运行以下命令,将 sample_website.zip 文件下载到我们刚创建的 files 目录中:

    SOURCE=`https://github.com/PacktPublishing/Building-and-Automating-Penetration-Testing-Labs-in-the-Cloud/raw/main/ch02/sample_website.zip`
    wget $SOURCE -O sample_website.zip
    

    这将生成一组日志,类似于我们在 图 2.21 中看到的内容:

    https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_21.jpg

    图 2.21 – 在 AWS CloudShell 中运行命令

    我们刚刚下载的 sample_website.zip 文件里面有什么?正如我们在接下来的步骤中看到的,sample_website.zip 文件包含一个 index.html 文件,以及一个目录,里面有应用程序的后端代码备份副本。

  4. 使用 ls 命令列出当前目录中的所有文件:

    ls
    

    此时,我们的当前目录中应该只剩下sample_website.zip文件。

  5. 让我们使用unzip命令提取sample_website.zip文件的内容:

    unzip sample_website.zip
    

    这应该会给我们一组日志,类似于以下代码块中的内容:

    Archive:  sample_website.zip
       creating: backup/
       creating: backup/backend/
       creating: backup/backend/node_modules/
       creating: backup/backend/node_modules/dotenv/
    ... (and so on)
    
  6. 在执行上传命令之前,让我们从files目录删除sample_website.zip文件:

    rm sample_website.zip
    
  7. 现在,让我们使用aws s3 cp命令将文件上传到 S3 存储桶(这大约需要 10 到 15 秒的时间完成):

    aws s3 cp --recursive . s3://<INSERT S3 BUCKET NAME>
    

    确保将<INSERT S3 BUCKET NAME>替换为你的 S3 存储桶名称。

注意

在这一步中,我们使用AWS CLI从 AWS CloudShell 环境中的一个目录将文件上传到我们的 S3 存储桶。如果这是你第一次使用 AWS CLI,它只是一个用于管理 AWS 资源的命令行工具,包括创建和配置资源、部署应用程序和管理安全设置。有关 AWS CLI 的更多信息,请查看以下视频:www.youtube.com/watch?v=EAFRKMe6j08

  1. 返回 S3 控制台,并在属性选项卡下找到静态网站托管配置设置。点击存储桶网站端点链接(如图 2.22所示):https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_22.jpg

    图 2.22 – 定位存储桶网站端点链接

    我们应该看到一个维护页面,类似于图 2.23中所示:

    https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_23.jpg

    图 2.23 – 验证文件是否已上传至 S3

    请注意,我们上传到 S3 存储桶的index.html页面在发出请求时会被返回并渲染,因为它是静态网站的配置索引文档。

这样,我们的设置就完成了!在下一部分,我们将测试我们的脆弱环境,并检查当前设置是否正常工作,并按预期配置。

测试并攻击我们的第一个脆弱环境

在本节中,我们将尝试模拟攻击者在试图攻击我们脆弱的 S3 存储桶时可能的行为。攻击者可能会使用一套专门的自动化工具,但在本章节中,我们即使没有这些工具,也应该能顺利进行。

检查并验证 S3 存储桶的安全性

我们将通过一系列手动检查来验证我们创建的 S3 存储桶的安全配置。

重要提示

攻击属于其他用户或公司拥有的云资源是违反道德且非法的。在我们开始之前,请确保阅读*《构建渗透测试实验室环境时需要考虑的事项》部分,位于《云中的渗透测试实验室入门》第一章*中,因为我们将模拟攻击过程来验证配置错误和漏洞是否存在并且可被利用。

这样一来,我们可以继续测试和攻击我们脆弱的云实验室设置:

  1. 在上一节中继续未完的操作,右键单击维护页面的中心位置,并从可用选项列表中选择查看页面源代码。这将让我们看到与图 2.24所示类似的维护页面前端 HTML 代码:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_24.jpg

    图 2.24 – 查看页面源代码

    由于这是一个静态页面,我们应该无法找到其他链接或资源引用以进一步检查。

  2. 接下来,访问http://<S3 BUCKET URL>.s3-website-us-east-1.amazonaws.com/.git来检查(1)是否存在.git目录,(2).git目录是否为公共的。确保将<S3 BUCKET URL>替换为你创建的存储桶名称。你应该看到类似于图 2.25所示的错误信息:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_25.jpg

    图 2.25 – 404 未找到

    图 2.25所示,存储桶内不存在此类文件或目录。你可以检查其他文件,例如README.md,但由于我们已经对存储桶中的内容有了大致了解,因此目前可以跳过这些附加步骤。

  3. 我们还可以通过访问https://<S3 BUCKET URL>.s3.amazonaws.com/来检查 S3 存储桶内的文件和目录是否会被列出。确保将<S3 BUCKET URL>替换为你的 S3 存储桶名称:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_26.jpg

    图 2.26 – 检查我们是否能列出存储桶内容

    这应该会给我们一个访问被拒绝的错误信息,类似于图 2.26所示。 这是否意味着我们无法作为访客用户(公共访问)访问存储桶内的文件?不一定!我们将在下一步中看到这种情况。

注意

在使用 S3 存储桶时,确保你熟悉可用的不同 URL。除了我们在上一步中检查过的 URL,你还可以检查https://s3.amazonaws.com/<S3 BUCKET URL>/(在此处将<S3 BUCKET URL>替换为 S3 存储桶的名称)。

  1. 接下来,让我们检查是否可以访问存储桶中的一些已知文件。由于 S3 存储桶配置为托管静态网站,它可能包含index.html文件(除非存储桶配置为使用其他索引文件)。因此,让我们访问https://<S3 BUCKET URL>.s3.amazonaws.com/index.html。与上一步相同,确保将<S3 BUCKET URL>替换为你的 S3 存储桶名称:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_27.jpg

    图 2.27 – 检查我们是否能访问 index.html 文件

    这应该呈现维护页面,类似于我们在图 2.27中的内容。请注意,我们应该能够访问存储在此存储桶中的其他文件,因为 S3 存储桶很可能被配置为允许未经身份验证的用户读取。然而,由于我们无法从访客用户的角度得知某些文件的存在,因此我们暂时跳过任何类似或相关的步骤。当然,使用自动化脚本通过暴力破解方法检查存储桶中的所有可能密钥也是一种选择(但不推荐)。

  2. 打开一个私密浏览窗口。访问aws.amazon.com/console/并登录到你的第二个 AWS 账户:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_28.jpg

    图 2.28 – 打开私密浏览窗口

    当登录到第二个 AWS 账户时,你可能会决定完全使用不同的浏览器。请注意,我们正在模拟从攻击者的角度体验这一过程。

  3. 在搜索框中输入shell。从结果列表中选择CloudShell,如图 2.29所示:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_29.jpg

    图 2.29 – 导航到 CloudShell 控制台

    如果看到欢迎使用 AWS CloudShell的弹出窗口,请点击关闭按钮。

  4. S3_BUCKET变量值设置为我们之前创建的 S3 存储桶的名称:

    S3_BUCKET=<INSERT S3 BUCKET NAME>
    

    确保将<INSERT S3 BUCKET NAME>的值替换为我们之前创建的 S3 存储桶的名称。

  5. 使用启用--no-sign-request标志的aws s3 ls命令列出 S3 存储桶的内容:

    aws s3 ls s3://$S3_BUCKET --no-sign-request
    

    这应该产生一个错误消息,内容为调用 ListObjectsV2 操作时发生错误: 访问被拒绝

注意

使用带有--no-sign-request标志的aws s3 ls命令会禁用 AWS 请求签名的要求。默认情况下,AWS CLI 请求会使用 AWS 凭证进行签名,以确保身份验证和授权。然而,当使用--no-sign-request时,命令会跳过签名过程,允许未经身份验证和未签名的请求列出指定 S3 存储桶中的对象或文件。

  1. 使用aws s3 ls命令列出 S3 存储桶的内容,这次不使用--no-sign-request标志:

    aws s3 ls s3://$S3_BUCKET
    

    这应该成功返回存储桶的内容(即index.html文件以及backup文件夹)。

  2. 让我们检查一下能否从 S3 存储桶下载index.html文件到 CloudShell 环境:

    aws s3 cp s3://$S3_BUCKET/index.html .
    

    这应该记录一条类似以下的消息:

    download: s3://<S3 BUCKET>/index.html to ./index.html
    

    这意味着我们可以作为经过身份验证的用户列出和下载文件!

重要提示

请注意,这与我们用来创建存储桶的账户不同。当然,由于我们故意配置了 S3 存储桶以具有此行为,因此这不应令人惊讶。

  1. 接下来,让我们检查一下能否从 CloudShell 环境向 S3 存储桶上传一个示例文件:

     touch test.txt aws s3 cp test.txt s3://$S3_BUCKET/test.txt
    

    这应该返回类似以下的消息:

    upload failed: ./test.txt to s3://<S3 BUCKET>/test.txt An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
    

    这意味着我们无法作为认证用户向 S3 桶上传文件。

注意

请注意,攻击者也可以检查他们是否能够通过使用aws s3api get-bucket-aclaws s3api put-bucket-acl命令来检索和设置桶的 ACL。有关此主题的更多信息,请随时查看bit.ly/3mbwlb5bit.ly/3SAPq2o

需要注意的是,我们故意配置了 S3 桶以允许认证用户只读访问,因为我们不希望其他认证用户向我们的 S3 桶上传文件。

下载并检查存储在 S3 桶中的文件

在上一节中,我们确认了可以使用aws s3 cp命令作为认证用户从 S3 桶下载文件。在本节中,我们将继续下载并检查存储在漏洞 S3 桶中的所有文件:

  1. 让我们先使用mkdir命令创建downloaded目录:

    mkdir downloaded
    
  2. 接下来,使用cd命令进入downloaded目录:

    cd downloaded
    
  3. 使用aws s3 cp命令将目标 S3 桶中存储的所有文件下载到 CloudShell 本地目录:

    aws s3 cp --recursive s3://$S3_BUCKET .
    

    在这里,我们使用了--recursive标志来递归下载存储在 S3 桶中的所有文件:

    https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_30.jpg

    图 2.30 – 执行 aws s3 cp 命令后生成的日志

    在这里,我们使用不同的 AWS 账户从 S3 桶中下载存储的文件。吓人吧?

注意

这意味着任何拥有 AWS 账户的用户,假设包括未授权用户,都有可能访问并下载存储在 S3 桶中的文件。在这里,我们展示了使用一个不同且完全无关的 AWS 账户,只需几个命令就能下载配置错误的桶中的内容。

  1. 现在,让我们使用以下命令安装tree命令:

    sudo yum install tree -y
    
  2. 安装了tree命令后,让我们使用它来生成当前目录的文件树:

    tree
    

    这应该生成并打印一个类似于图 2.31的文件树:

    https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_31.jpg

    图 2.31 – 使用 tree 命令生成的文件树

    使用没有参数/标志tree命令会递归列出所有文件,并给我们一个非常长的文件和目录列表。

  3. 现在,让我们运行以下命令来限制结果(树的深度)并显示隐藏文件:

    tree -aL 4
    

    这应该返回一个类似于图 2.32的文件树:

    https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_32.jpg

    图 2.32 – 运行 tree 命令后的结果

    图 2**.32中显示的树结果中,我们可以推断出正在使用的后端 Web 框架是Hapi.jshapi.dev/)。除此之外,dotenv** **npm软件包用于管理和加载环境变量。图 2*.23*还显示,在/****backup/backend目录中存储了一个.env文件。

注意

为了避免在应用程序代码中硬编码秘密、变量和配置设置,开发团队可以利用dotenv等软件包从.env文件中加载凭据和环境变量。另外,开发和工程团队也可以使用 YAML 或 JSON 文件。开发人员常犯的一个常见错误是忘记在代码存储库中排除这些文件。这意味着任何能访问存储库(或存储库备份)的人都可以获得包含应用程序中使用的凭据和变量的文件的副本。

  1. 让我们运行以下命令查看.****env文件中的内容:

    cat backup/backend/.env
    

    这将为我们提供AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY的占位值,类似于我们在以下配置块中的内容:

    AWS_ACCESS_KEY_ID=XXXXXXXXXX AWS_SECRET_ACCESS_KEY=YYYYYYYYYY
    

    注意,在更现实的情况下,我们可能会在这里找到其他凭据和密钥。值得注意的是,凭据可能会在存储库的代码库中找到硬编码。

注意

一旦攻击者获得这些凭据,他们会做什么? 攻击者现在可以使用与这些凭据相关联的帐户执行恶意操作。例如,攻击者可能使用电子邮件服务(例如,SendGrid)的凭据发送钓鱼邮件来攻击其他个人或组织。在获取*.env*、YAMLJSON文件后,攻击者还可能能够访问数据库,因为这些文件很可能也包含数据库凭据。

到目前为止,我们应该对如何准备和测试一个相对简单的易受攻击的云资源有一个很好的想法。当然,生产环境很可能在同一账户中部署了其他资源。不用担心 - 随着我们在接下来的章节中进行实践示例的工作,我们将看到我们易受攻击的云环境的复杂性增长。

清理

清理我们创建或部署的云资源是处理易受攻击的云应用程序和环境时的关键步骤。如果我们不立即清理创建的资源,我们可能会发现我们的资源受到恶意用户的攻击。因此,让我们继续删除本章中创建的资源:

  1. 让我们开始使用我们用来创建 S3 存储桶的帐户登录到 AWS 管理控制台。请记住,我们有两个帐户 - “目标”AWS 帐户和“攻击者”AWS 帐户。我们将继续登录到“目标”AWS 帐户,因为我们使用该帐户创建了 S3 存储桶。

  2. 在搜索栏中输入shell并从搜索结果中选择CloudShell,如图 2**.33所示:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_33.jpg

    图 2.33 – 导航到 CloudShell 控制台

    当您看到欢迎使用 AWS CloudShell的弹出窗口时,点击关闭按钮。

  3. 在我们的 CloudShell 环境的终端中(在$符号后),运行以下 bash 命令:

    S3_BUCKET=<INSERT S3 BUCKET NAME>
    

    这里,我们正在设置S3_BUCKET变量的值,该值为我们之前创建的 S3 存储桶的名称。确保将<INSERT S3 BUCKET NAME>的值替换为您自己的 S3 存储桶名称。

  4. 现在,让我们使用aws s3 rb(删除存储桶)命令来删除该存储桶以及其中的所有对象:

    aws s3 rb s3://$S3_BUCKET --force
    

    这将生成一组日志,类似于图 2**.34中展示的内容:

    https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_02_34.jpg

    图 2.34 – 执行 aws s3 rb 命令后生成的日志

    我们执行的命令将删除存储桶中的所有对象,然后在存储桶为空时删除该 S3 存储桶。

注意

请注意,在生产环境中使用aws s3 rb命令时需要小心,因为在禁用对象版本控制的情况下,我们将丢失存储桶中的所有文件。在运行此命令之前,必须先备份存储桶中的文件。欲了解更多详情,请访问以下链接:docs.aws.amazon.com/AmazonS3/latest/userguide/delete-bucket.html

就是这样!由于我们只处理相对简单的设置,因此清理过程预计会很简单。

总结

在本章中,我们设计并准备了第一个故意存在漏洞的云实验室环境。我们首先通过 AWS 管理控制台创建了一个空的 S3 存储桶。之后,我们配置了该存储桶用于静态网站托管。我们还修改了 S3 存储桶的访问控制设置,允许其他经过身份验证的 AWS 用户列出并检索我们存储桶中的对象。为了完成设置,我们将示例文件上传到 S3 存储桶中。

我们通过一系列步骤测试了我们的设置,包括一些终端命令,检查并验证了 S3 存储桶的安全配置。在确认可以使用第二个 AWS 帐户(未用于创建存储桶)从 S3 存储桶下载文件后,我们继续下载并检查了存储桶中所有的文件。最后,我们通过清理并删除本章中创建的资源来结束操作。

在下一章中,我们将重点介绍如何使用基础设施即代码IaC)工具和策略,帮助我们在云中构建和管理复杂的易受攻击的实验室环境。如果您在想我们是否可以自动化本章中执行的步骤,那么下一章将为您解答!

深入阅读

若想了解本章涉及的更多信息,可以查看以下资源:

第三章:成功使用基础设施即代码工具和策略

在上一章中,我们使用 AWS 管理控制台 手动创建了第一个易受攻击的实验环境。整个设置过程大约花了我们一个半小时。完成实验环境设置后,我们可能又花了 30 分钟来测试是否一切(误)配置正确。如果我们希望为一个安全培训课程设置 10 个与第二章中相似的实验环境怎么办?我们真的需要大约 20 小时才能完成这些设置吗?此外,请记住,我们只完成了整个云渗透测试实验环境的一个小部分!完整的实验环境一般比我们在第二章中准备的要多出 5 到 10 倍的资源。假设完整环境至少是我们最初准备的五倍大,并且考虑到每次都需要创建和删除整个环境以管理成本,那么是否手动设置这些实验环境(通常每个大约需要 10 小时)真的必要呢?话虽如此,是否有更好的方法来创建和管理我们的渗透测试实验环境的云基础设施资源?

本章将通过深入分析 基础设施即代码IaC)如何解决这些挑战和需求,来回答这些问题!因此,我们将涵盖以下主题:

  • 深入探讨 IaC 工具和策略

  • 在 AWS CloudShell 中设置 Terraform

  • 使用 Terraform 起步

  • 理解 Terraform 配置语言

  • 使用 Terraform 构建我们的易受攻击的实验环境

  • 配置带有状态锁定的 Terraform 后端

  • 验证状态锁定设置

本章的实践解决方案将为你提供将现有云基础设施资源转换为 IaC 配置文件所需的技能和信心。通过这些配置文件,我们应该能够使用自动化工具和服务在几分钟内快速设置多个渗透测试实验环境!

技术要求

在开始之前,我们必须准备以下内容:

  • 必需:在第二章中使用的“目标”AWS 账户,将包含易受攻击的环境和资源

  • 可选:第二个 AWS 账户(同样在第二章中使用),将作为“攻击者的账户”

如果你跳过了第二章准备我们的第一个易受攻击的云实验环境,可以通过以下链接创建 AWS 账户:aws.amazon.com/free/。账户创建好后,便可继续进行后续步骤。

注意

本章主要关注使用 Terraform 在 AWS 上构建一个示例易受攻击的实验室环境。当然,一旦进入本书后续章节的动手部分(第四章及之后章节),我们需要准备好Microsoft AzureGoogle Cloud PlatformGCP)账户。与此同时,当前设置两个 AWS 账户应该足够了。

本书每章使用的源代码和其他文件可以在本书的 GitHub 仓库中找到:

github.com/PacktPublishing/Building-and-Automating-Penetration-Testing-Labs-in-the-Cloud

深入探索 IaC 工具和策略

在我们深入本章的实际练习之前,我们将首先在本节中明确理解 IaC,并讨论如何利用它来构建复杂的渗透测试实验室。

揭开 IaC 的神秘面纱

IaC 是通过代码来配置和管理基础设施资源的实践和过程。这些代码的工作原理类似于房屋蓝图在建造实际房屋时的参考作用。处理 IaC 代码的酷炫之处在于,实际的基础设施资源是根据表示所需最终状态的代码自动创建和配置的。在后台,IaC 自动化工具实际上只是使用我们在尝试自动化特定流程时会使用的相同 API 集。这个过程在下图中进行了说明:

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_03_01.jpg

图 3.1 – 使用 IaC 工具和服务创建和管理云资源

图 3.1中,我们可以看到相同的配置文件集(表示所需的状态)可以用于生成和配置多个具有相同资源和属性的环境。例如,我们可以在配置和确保开发、预生产和生产环境的一致性时使用 IaC 配置文件,这些环境供开发人员和工程师使用。

此时,你可能会好奇配置文件是如何用来生成实际的云基础设施资源的。让我们从定义单个资源的配置文件开始。这个配置文件随后作为输入传递给 IaC 工具,IaC 工具根据指定的代码(命令式方法)执行,或者通过“魔法”将配置代码转换为实际的基础设施资源(声明式方法)。

以下图表展示了 IaC 工具和服务如何管理变更:

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_03_02.jpg

图 3.2 – IaC 工具和服务如何管理变更

假设我们使用声明性方法来配置初始的云资源集,我们能否修改配置代码并再次使用 IaC 工具来更新现有的基础设施资源集? 正如我们在图 3.2中所看到的那样,某些 IaC 工具可以自动管理这些更改,并生成一个执行计划,该计划会修改基础设施,使其达到 IaC 配置模板中指定的期望状态。这些更改随后会应用于现有的基础设施资源。

注意

需要注意的是,IaC 工具可能会(1)在基础设施中执行就地修改,或者(2)替换整个基础设施资源。这取决于所使用的 IaC 工具以及所进行的更改类型。在处理部署在渗透测试实验室环境中的资源时,我们通常希望替换整个资源,因为旧的基础设施资源可能由于先前的利用尝试和活动已经处于不稳定或配置错误的状态。

利用 IaC 进行渗透测试实验室管理

现在,让我们来讨论为什么 IaC 与云端渗透测试实验室的准备和管理相得益彰。创建和管理云端专用渗透测试实验室环境可能是复杂且耗时的。使用 IaC 可以简化这一过程,并带来许多好处。

以下是使用 IaC 构建云端渗透测试实验室的一些优势:

  • 更快的部署:由于配置代码包含了要创建的资源的属性和期望状态,我们可以通过自动化流程在几秒钟内(最多几分钟)快速创建和销毁各种实验室资源。这帮助我们在渗透测试实验室活动或实验后,轻松地重建需要“刷新”的特定云基础设施资源(因为这些活动可能会故意或无意中将某些服务或资源置于不稳定或配置错误的状态)。

  • 协作:我们可以轻松地与其他工程师共享实验室环境的配置和设置代码。这使得在排查部署在渗透测试实验室环境中的资源的安全配置时,可以更轻松地进行协作和讨论(也就是说,无需分享整个云账户)。

  • 一致性:如果从单个 IaC 配置代码实例设置了多个易受攻击的实验室环境,我们只需修改 IaC 代码一次,并将更改自动应用于这些实验室环境。我们可以保证基础设施管理过程的重复性,并确保每次构建渗透测试实验室环境时,资源配置和版本保持一致。需要注意的是,某些漏洞和错误配置的可利用性取决于所使用的应用程序和资源的版本。

  • 透明性:由于我们可以使用表示基础设施的代码检查当前配置,审计基础设施配置错误变得更加容易。

  • 优化:基础设施成本管理变得更加容易,因为我们可以在没有人使用渗透测试实验室环境时关闭(或删除)云资源。一旦需要创建资源,从现有的基础设施配置代码准备资源只需几分钟。

如我们所见,IaC 通过自动化过程实现更快速的实验室资源部署,允许在几秒钟到几分钟内快速创建和销毁资源。协作变得更加简单,因为工程师可以轻松地以代码形式共享实验室环境配置和设置,从而促进了安全设置的故障排除,而无需共享整个云账户。此外,IaC 通过修改代码一次并自动将更改应用于多个实验室环境,确保一致性,保证了重复性,并保持一致的资源配置和版本。

牢记这些要点后,我们可以继续讨论在使用 IaC 解决方案时的最佳实践和策略。

接纳 IaC 最佳实践和策略

过去几年里,开发人员和工程师使用了多种 IaC 工具来创建和管理基础设施。其中一些最流行的工具包括ChefPuppetVagrant(R)?exSaltStackPulumiAnsibleAWS Cloud Development KitAWS CDK)、AWS CloudFormationGCP Deployment ManagerAzure Resource Manager。其中一些工具(如 AWS CDK、AWS CloudFormation、GCP Deployment Manager 和 Azure Resource Manager)是为特定云提供商自动化资源的创建、配置和管理而构建的。其余的则是云中立的——即这些工具应该能跨多个云平台(如AWSMicrosoft AzureGCP)工作。在这个列表中,某些工具(如 Ansible、Chef 和 Puppet)主要集中在设置应用程序和配置虚拟机内部的内容,而其他工具(如 Terraform)主要专注于从代码中部署和提供云基础设施资源。

注意事项

我们可以在部署、配置和管理基础设施时同时使用多个工具。例如,我们可以将 Terraform 与 Ansible 结合使用,自动化部署云基础设施资源以及运行在虚拟机中的应用程序。

在我们进入下一部分之前,让我们讨论一下使用 IaC 工具和服务时可以采取的一些策略:

  • 我们可以使用版本控制系统(例如 Git)来跟踪和管理用于管理和部署渗透测试实验室环境的 IaC 配置代码的变化。除此之外,我们还可以通过持续集成/持续部署CI/CD)管道,在代码更改推送到代码仓库后,自动部署 IaC 文件中指定的资源。

  • 我们可以通过将代码正确地拆分为多个文件,轻松模块化并管理实验室环境中使用的不同资源组。一旦渗透测试实验室的组件被模块化,我们就可以轻松地使用现有模块生成不同变种的漏洞实验环境。

  • 成本在渗透测试实验室环境设计中起着重要作用。基础设施即代码(IaC)允许环境或云账户的拥有者在需要时再启用(或根本没有)云资源。为什么? 因为 IaC 工具使得从配置文件(通常是几秒钟或几分钟内)创建和恢复资源变得非常简单。当我们在云中设计和构建渗透测试实验室环境时,我们还可以选择是否允许多个用户共享同一个环境,或者让每个用户拥有自己的专用环境(这可能会更昂贵)。使用 IaC 时,我们可以轻松地让第二个选项在成本上更具可行性,因为我们只需在用户需要时根据模板创建并配置基础设施。第一个选项的缺点是什么? 由于实验室由多个用户共享,某些用户在渗透测试过程中可能会遇到意外问题,因为涉及的资源可能已经由于其他用户的某个操作(或多个操作)而配置错误。如果其中一个用户决定刷新或重置系统,那么另一个用户的任何正在进行的工作也会被重置。

到此为止,我们应该已经对 IaC 的概念和如何利用它有效管理渗透测试实验室环境有了充分的理解。在下一部分中,我们将首次介绍全球专业人士广泛使用的最流行的 IaC 工具之一。

在 AWS CloudShell 中设置 Terraform

在本章中,我们将重点介绍如何使用Terraform来配置和管理我们的云基础设施。Terraform 是一个由HashiCorp创建的开源基础设施即代码(IaC)工具。目前,它是最强大且最常用的 IaC 工具之一。它使用户能够使用高级配置语言来定义和配置基础设施资源。通过采用简单、声明性和直观的语法,这个 IaC 工具简化了创建、更新和版本控制基础设施的过程,为自动化基础设施管理提供了强大的方法。

下面是 Terraform 代码的一个示例:

 resource "google_compute_firewall" "allow-ssh-from-my-ip" {  name    = "allow-ssh-from-my-ip"
  network = local.net_02
  allow {
    protocol = "tcp"
    ports    = ["22"]
  }source_ranges = ["${var.my_ip}/32"]
}

在这里,我们只是定义了一个防火墙规则(在 GCP 中),它将允许我们从本地机器通过端口22发起 SSH 连接到指定的虚拟私有云VPC)网络中的资源。

注意

如果目前示例中的 Terraform 代码看起来不完全理解,也不用担心!在本书的后续章节中,我们将深入探讨如何使用 Terraform 管理云平台(如 AWS、Azure 和 GCP)上的渗透测试实验室环境资源。我们将探讨这些云提供商的概念、语法和实际示例,帮助我们更清楚地理解 Terraform 在实际场景中的应用。

如我们在提供的示例代码中看到的,构建易受攻击云基础设施的 Terraform 代码是声明式的,并且具有自文档化功能。我们无需关注这些基础设施资源是如何准备的,而只需要指定期望的状态,Terraform 会处理细节,将当前状态转换为期望状态。其他工具则采用命令式方法进行自动化,工程师需要定义一系列命令来达到期望状态。命令式方法的优势在于可以精细控制命令和操作执行的顺序,以达到期望状态。这在需要特定脚本或程序逻辑的复杂场景中非常有用。这与声明式方法形成对比,声明式方法只需指定基础设施的期望状态是什么样的。我们将在本书中尽可能使用声明式方法。如果你刚刚开始接触基础设施即代码(IaC)和自动化的概念,使用 Terraform 中的声明式方法可以提供一种更直观、更简洁的方式来理解和管理基础设施资源。也就是说,声明式方法提供了一个清晰简明的期望状态表示,使学习和使用变得更加容易。

注意

请注意,使用CDK for TerraformCDKTF)时,可以采用命令式方法来使用 Terraform。有关 CDKTF 的更多信息,请随时访问以下链接:developer.hashicorp.com/terraform/cdktf

当然,在使用 Terraform 之前,我们必须确保它已经在我们的环境中正确安装和配置!有多种方式可以安装 Terraform,其中一种方式是使用tfenvTerraform 版本管理器)来帮助我们轻松管理和使用不同版本的 Terraform。

在接下来的步骤中,我们将使用 Terraform 版本管理器在 AWS CloudShell 环境中设置和安装 Terraform:

  1. 打开一个新的浏览器标签页,然后导航到 AWS 控制台。在搜索框中输入shell,然后从搜索结果中选择CloudShell。或者,你也可以直接在 AWS 管理控制台的左上角找到并点击CloudShell按钮(靠近区域选择下拉菜单)。

注意

等待约一到两分钟,直到 AWS CloudShell 环境准备就绪。考虑到 CloudShell 环境每个 AWS 区域提供最大 1 GB 的磁盘空间,因此有必要定期使用df -h(磁盘可用空间)和du -sh(磁盘使用量)等命令监控磁盘使用情况。这些命令可以提供磁盘空间使用的详细信息,帮助我们判断是否接近 1 GB 的限制。通过积极监控磁盘空间,我们可以避免 CloudShell 环境中出现存储限制。欲了解更多信息,请访问以下链接:docs.aws.amazon.com/cloudshell/latest/userguide/limits.html

  1. 在 AWS CloudShell 终端(在$符号后)运行以下git clone命令,将tfutils/tfenv仓库克隆到我们的 CloudShell 环境中:

    git clone `https://github.com/tfutils/tfenv.git` ~/.tfenv
    
  2. 使用mkdir命令创建一个bin目录(位于用户主目录下):

    mkdir ~/bin
    
  3. 使用ls命令列出存储在~/.tfenv/bin/中的文件:

    ls -hF ~/.tfenv/bin/
    

    这应该会产生类似以下的结果列表:

    terraform*  tfenv*
    
  4. 接下来,我们使用ln -s命令为存储在~/.tfenv/bin/中的可执行文件创建一个软符号链接:

    ln -s ~/.tfenv/bin/* ~/bin/
    

什么是软符号链接?

软符号链接,也称为symlinks,是文件系统中的特殊文件,充当指向其他文件或目录的指针。它们通过路径引用目标,实际上创建了一个指向目标文件或目录的快捷方式。

  1. 使用readlink命令验证之前的命令是否按预期工作:

    readlink -f ~/bin/*
    

    这应该会产生以下输出:

    /home/cloudshell-user/.tfenv/bin/terraform /home/cloudshell-user/.tfenv/bin/tfenv
    

    在这里,我们使用readlink命令通过解析符号链接并提供每个文件的绝对路径,获取~/bin目录中文件的完整路径。

注意

由于~/bin已经添加到$PATH中,因此在执行前一步中的ln -s命令后,我们应该能够使用terraformtfenv

  1. 我们使用tfenv install命令安装特定版本(1.3.9)的 Terraform:

    tfenv install 1.3.9
    

    通过运行 tfenv install 1.3.9,我们指示 tfenv 在我们的系统上下载并安装 Terraform 版本 1.3.9。这个特定版本将会安装在一个单独的目录中,确保它与其他已安装的 Terraform 版本隔离开来。

  2. 接下来,让我们使用 tfenv use 命令切换并使用 Terraform 版本 1.3.9

    tfenv use 1.3.9
    

    当我们运行这个命令时,tfenv 将会配置我们的系统,在当前 shell 会话或目录中使用 Terraform 版本 1.3.9 来执行随后的任何 Terraform 命令。这使我们能够使用特定版本的功能和特性。

  3. 最后,让我们使用以下命令检查 Terraform 是否已成功安装:

    terraform --version
    

    这应该会生成以下输出:

    Terraform v1.3.9 on linux_amd64
    

    这确认了已经安装了 Terraform 版本 1.3.9,并且可以开始使用!

重要提示

到你阅读这本书时,可能会有更新版本的 Terraform 可用。然而,仍然建议使用本章中使用的版本,以避免在运行实际操作的解决方案和示例时遇到问题。如果需要,你可以使用 tfenv 命令进行“时间旅行”,切换到旧版本的 Terraform。这将确保本章中的所有示例继续正常工作。如果有更新版本的 Terraform 可用,你也可以使用 tfenv 命令安装并切换到该版本。这种灵活性使你能够跟上最新的功能和改进。然而,值得注意的是,使用书中指定的版本可以确保一致性,避免潜在的兼容性问题。

在我们的 AWS CloudShell 环境中设置好 Terraform 后,让我们继续进入下一节!

初探 Terraform

在这一节中,我们将简要概述基本的 Terraform 工作流,然后进行一个 “Hello World” 示例,来测试我们的设置。

了解核心的 Terraform 工作流

对大多数人来说,学习一个新工具、平台或框架可能需要大约 2 到 4 周的时间。然而,学习 Terraform 可能只需要几个小时(最多几天),因为它的使用非常直接且简单。在使用 Terraform 时,工程师通常遵循一个类似于我们在 图 3.3 中看到的流程:

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_03_03.jpg

图 3.3 – 使用 Terraform 创建和更新资源时的常见工作流

一旦我们准备好了配置文件(或多个文件),我们只需运行 terraform init 来初始化 Terraform 环境。terraform init 命令通常在我们的环境尚未初始化时,或者需要下载额外的文件或插件时执行。接下来的步骤是使用 terraform plan 来处理配置代码并生成执行计划供我们审核。请注意,运行 terraform plan 命令不是必需的,但 推荐 执行。最后,我们可以使用 terraform apply 来实施执行计划中描述的更改。

注意

运行 terraform initterraform plan 通常是 安全 的命令,因为(1)它们涉及 幂等 操作,(2)它们不会创建或修改任何基础设施资源。在这种情况下,幂等意味着多次执行这些命令将会有 相同 的结果,而不会产生意外的副作用。这使得它们非常适合用于安全地初始化和规划基础设施配置。

我们还可以使用其他命令来帮助我们执行特定任务(例如,terraform show),但除了这三个主要命令外,另一个我们需要了解的命令是 terraform destroy。运行此命令将删除通过 Terraform 创建和管理的资源。

使用 Hello World 示例测试我们的 Terraform 设置

现在我们已经对如何使用 Terraform 有了基本了解,接下来我们来做一个非常简单的 Terraform 示例,如下所示:

  1. 使用 mkdir 命令创建一个 hello_terraform 目录。然后使用 cd 命令进入创建的目录:

    mkdir hello_terraform
    cd hello_terraform
    
  2. 使用 touch 命令创建一个空的 main.tf 文件:

    touch main.tf
    
  3. 运行以下命令使用 Vim 打开空的 main.tf 文件:

    vim main.tf
    

    学习如何使用命令行文本编辑器,如 Vim,起初可能会有些令人畏惧。然而,一旦你熟悉了它,你会发现 Vim 相对容易使用且富有乐趣!

注意

你可以输入 :set nu 然后按下 Enter 键来显示行号。

  1. 接下来,按 i 切换到 插入模式,这样我们就可以编辑文件了。

注意

Vim 中的 插入模式 允许我们像在常规文本编辑器中一样输入和修改文本。在这个模式下,我们可以自由地添加、删除或修改字符,而不会影响周围的文本。

  1. 将以下代码块输入或粘贴到我们的 main.tf 文件中:

     resource "null_resource" "hello" {
      provisioner "local-exec" {
        command = "touch hello.txt"
      }
    }
    

    在这里,我们声明了一个 null_resource 资源,它对于不涉及资源创建的操作和任务非常有用。在这个案例中,我们用它来运行一个脚本或命令。

  2. 按下 Esc 键切换到 正常模式。输入 :wq!,然后按 Enter。这将保存对 main.tf 所做的更改,并退出 Vim。

注意

之前,我们描述了 Vim 中插入模式的工作原理。现在,让我们简要谈谈普通模式。普通模式允许我们在文本中导航、执行命令并对文件执行各种操作。在此模式下,可以使用特定的按键组合(如**:wq!)来移动光标、搜索文本、复制和粘贴,并执行编辑操作,如删除、替换和撤销更改。例如,“w”表示写入命令(用于保存文件的更改),而“q”表示退出命令(用于退出编辑器)。感叹号(!**)有什么用?“!”仅仅是一个可选修饰符,它强制命令执行,即使存在未保存的更改或其他警告。

  1. 现在我们的main.tf文件已经准备好,让我们使用terraform init命令来初始化 Terraform 工作目录:

    terraform init
    
  2. 为了更好地了解terraform init为我们初始化并设置了什么,让我们使用以下命令安装tree工具:

    sudo yum install tree -y
    

    安装了tree工具后,让我们使用tree命令帮助我们检查并可视化当前目录中的目录和文件:

    tree -a
    

    这应该生成一棵树,类似于我们在图 3.4中看到的内容:

    https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_03_04.jpg

    图 3.4 – 运行 tree 命令后的结果

    在这里,我们可以看到在运行terraform init后,突然出现了一个.terraform目录,并且包含一个目录和文件的树状结构。

  3. 接下来,让我们运行terraform plan,以预览 Terraform 将执行的更改:

    terraform plan
    

    这应该生成一组日志,类似于我们在下面的日志信息块中看到的内容:

    Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
      + create
    Terraform will perform the following actions:
      # null_resource.hello will be created
      + resource "null_resource" "hello" {
          + id = (known after apply)
        }
    Plan: 1 to add, 0 to change, 0 to destroy.
    

    在这里,我们有一个执行计划,它指示了在稍后的步骤中运行terraform apply命令后,将创建(1)、修改(0)或销毁(0)哪些资源。

注意

Terraform 的执行计划就像是一个蓝图,概述了它将执行的步骤和操作,以实现所需的基础设施状态(如 Terraform 配置代码中所定义的)。它类似于 SQL EXPLAIN 命令提供的详细分解,说明数据库管理系统如何执行特定查询。也就是说,考虑到 Terraform 通过其声明式语法抽象了幕后发生的事情,执行计划作为预览即将对基础设施进行的更改的有价值机制。

  1. 一切准备就绪后,让我们使用terraform apply命令来实现通过运行terraform plan返回的执行计划中指定的更改:

    terraform apply
    

    这应该生成一组日志,类似于我们在图 3.5中看到的内容:

    https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_03_05.jpg

    图 3.5 – 运行 terraform apply 命令后的验证步骤

    在验证步骤中(即,当您看到Enter a value:提示时),输入yes以继续创建hello.txt文件。按下Enter键后,我们应该看到以下一组日志:

     null_resource.hello: Creating...null_resource.hello: Provisioning with 'local-exec'... null_resource.hello (local-exec): Executing: ["/bin/sh" "-c" "touch hello.txt"]
    null_resource.hello: Creation complete after 0s [id=2409621687302957875]
    

    在这里,我们可以看到我们的 terraform apply 命令已成功执行!

提示

运行 terraform apply 命令应执行 touch hello.txt 并创建一个空的 hello.txt 文件。

  1. 在庆祝之前,让我们使用 ls 命令检查我们的 hello.txt 文件是否已经创建:

    ls
    

    这应该产生以下输出:

    hello.txt  main.tf  terraform.tfstate
    
  2. 现在,让我们使用 cat 命令检查 terraform.tfstate 文件:

    cat terraform.tfstate
    

    这应该给我们一个类似于下面代码块的嵌套 JSON 结构:

    {
      "version": 4,
      "terraform_version": "1.3.9",
      "serial": 1,
      "lineage": "6e0599fb-00c6-e724-2dd1-e600ea7726a0",
      "outputs": {},
      "resources": [
        {
          "mode": "managed",
          "type": "null_resource",
          "name": "hello",
           ...     }
      ],
      "check_results": null
    }
    

    在这里,我们已经确认 Terraform 将表示当前基础设施资源集(由 Terraform 管理)的信息存储在 terraform.tfstate 文件中。

重要提示

Terraform 使用 terraform.tfstate 文件来跟踪基础设施的当前状态。该文件存储关键信息,例如资源 ID、依赖关系和元数据。在创建或修改基础设施资源之前,Terraform 会使用此文件进行差异检查。确保不要编辑或删除工作目录中的 terraform.tfstate 文件,因为这可能导致不一致和潜在的错误。万一你不小心删除了 terraform.tfstate 文件,不必惊慌,因为有多种方法可以从这种情况中恢复!此外,我们还可以使用 远程状态后端 来安全地存储状态文件,并使协作和灾难恢复更容易。我们将在本章的 配置具有状态锁定的 Terraform 后端 部分详细讨论这个内容。

  1. 使用 cd 命令导航到用户的主目录:

    cd ..
    
  2. 最后,让我们使用 rm -rf 命令删除 hello_terraform 目录(及其内部的所有内容):

    rm -rf hello_terraform
    

    这将帮助释放一些空间,因为我们在 CloudShell 环境中总共有 1 GB 的存储空间(每个 AWS 区域)。请注意,建议在执行这些删除或清理步骤之前,先在 hello_terraform 目录中运行 terraform destroy(因为我们可能会不小心删除状态文件)。鉴于我们创建的唯一“基础设施资源”是一个 .txt 文件,因此不需要运行 terraform destroy

重要提示

如果您需要一个专门的环境来创建和管理基础设施资源中使用 Terraform,您可以探索AWS Cloud9并设置开发环境。与 CloudShell(目前每个 AWS 地区仅为 1 GB)相比,这种环境提供更多的磁盘空间。此外,Cloud9 允许您使用代码编辑器编写和修改代码,提供了增强的灵活性和便利性。需要注意的是,虽然 AWS CloudShell 是 AWS 提供的免费服务,但 AWS Cloud9 可能会根据您的使用情况产生额外费用。虽然 CloudShell 提供了仅限于 1 GB 的有限磁盘空间,并且不收取额外费用。另一方面,AWS Cloud9 可能根据环境选择的使用情况和实例类型而产生相关费用。在选择 AWS Cloud9 之前,建议查看定价详细信息,并确保其符合您的要求和预算。

这不是很简单吗? 当学习 Terraform(或任何其他新工具)时,建议从类似于本节中我们所使用的简单和小型示例开始。在下一节中,我们将在这个简单示例的基础上继续工作,并处理一个相对较长的 Terraform 配置文件。

理解 Terraform 配置语言

在本节中,我们将深入探讨 Terraform 配置语言的核心方面,然后继续使用相对简单的配置代码,为我们提供管理 Terraform 的 IaC 所需的基础知识。

揭秘常用的 Terraform 配置块

理解如何编写和解释 Terraform 配置代码对于有效的基础设施管理至关重要。这些知识使我们能够自定义和修改使用 Terraform 创建和管理的现有基础设施资源。它还使我们能够在使用 IaC 工具时更有效地解决问题和节省时间。

那么,我们从哪里开始呢? 首先,简单和复杂的 Terraform 配置代码通常使用相同的元素和构建模块。这个共同的基础使我们能够通过从简单配置开始逐步向更复杂的场景发展来逐步建立我们的理解。通过掌握基本元素,我们可以自信地导航和解释简单和复杂的 Terraform 配置代码,从而有效地解决各种基础设施管理挑战。

在我们进行下一个实际操作示例之前,让我们快速查看一下在 Terraform 配置文件中通常会看到的一些元素:

  • 资源 — 这些是用来定义如何配置和配置基础设施资源的代码块。这些块具有以下结构:

    resource "<type>" "<name>" {
      <argument 01> = <value 01>
      <argument 02> = <value 02>
    }
    

    资源是通过一个或多个参数进行配置的,每个参数由一个键值对表示。根据正在创建的具体资源,参数可能包括区域、实例类型、子网 ID、安全组等内容。

    让我们快速看一个如何使用 Terraform 定义 Azure 公共 IP 地址资源块的例子:

    resource "azurerm_public_ip" "public_ip_03" {name= "public-ip-03"
      ...   resource_group_name = local.rg_02.nameallocation_method   = "Dynamic"
    }
    

    在这里,我们指定了各种属性,如从本地变量获取的资源组名称,以及分配方法设置为 “动态”

  • 提供程序—这些是插件,使得云平台和 SaaS API 交互成为可能。它们的结构如下:

    provider "<name>" {
      <argument 01> = <value 01>
      <argument 02> = <value 02>
    }
    

    提供程序可以包括 云服务提供商CSPs),如 AWS、Azure 和 GCP,以及其他第三方提供商。根据使用的具体提供程序,参数可能包括访问密钥、区域和端点等内容。

    让我们快速看一个如何定义提供程序的例子:

    provider "aws" {
      alias  = "default"
      region = "us-east-1"
    }
    

    通过使用适当区域配置此提供程序,Terraform 将能够在指定区域内与 AWS 服务进行交互,用于资源的配置和管理。

  • 数据源—这些是允许我们在运行时查询数据的元素。它们的结构如下:

    data "<type>" "<name>" {
      ... }
    

    数据源的配置取决于使用的具体数据源,可以包括查询、筛选条件和身份验证信息等内容。

    让我们快速看一个如何定义数据源的例子:

    data "aws_ip_ranges" "ec2_instance_connect" {
      regions  = ["us-east-1"]
      services = ["EC2_INSTANCE_CONNECT"]
    }
    

    通过这个数据块,我们可以获取指定区域内 AWS EC2 实例连接服务使用的 IP 范围的信息。

  • 本地值—这些是代码块,允许我们分配和存储静态值以备后用。它们的结构如下:

    locals {
      <name 01> = <expression 01>
      <name 02> = <expression 02>
    }
    

    表达式可以是任何有效的 Terraform 表达式,包括其他变量或函数。通过这个代码块,我们可以轻松地在 Terraform 配置中定义本地变量,使我们的代码更加可读、易于维护和可重用。

    让我们看一个如何定义一些本地变量的例子:

    locals {
      net_01 = google_compute_network.vpc_01.self_linknet_02 = google_compute_network.vpc_02.self_link
    }
    

    在这里,我们简单地定义了两个本地变量(net_01net_02),它们的值等于相应 google_compute_network 资源的 self_link 属性值。

  • 输入变量—这些是代码块,允许用户指定动态值。它们的结构如下:

    variable "<name>" {
      type = <type>
      default = <value>
    }
    

    Terraform 中的变量用于参数化配置,使得代码可以在不同的场景或环境中重用。

    让我们快速看一个如何定义变量的例子:

    variable "instance_name" {
        type = string
        default = "kali"
    }
    

    这个变量可以在 Terraform 配置中使用,根据特定需求动态定制实例名称。

  • 输出值—这些帮助返回和打印值,并在模块之间共享值。它们的结构如下:

    output "<name>" {
      value = <expression>
    }
    

    Terraform 中的输出用于定义在terraform apply操作完成后暴露给用户的值。该输出可以在配置的其他部分或使用当前模块作为依赖项的其他配置中引用。

    让我们快速看一个实际示例:

    output "vm_kali_public_ip" {
      value = local.vm_kali.public_ip_address
    }
    

    在这里,我们简单地定义一个输出块,以检索虚拟机(在 Azure 中)的公共 IP 地址。

虽然 Terraform 中确实有更多要考虑的元素,但我们讨论的这些元素应该足够了。随着你继续深入 Terraform,你可以探索更多的元素,扩展管理基础设施的能力。在我们已经建立的基础上,这些元素将进一步增强我们使用 Terraform 在云中创建各种渗透测试实验室的能力。

使用简单的 Terraform 配置

现在我们已经大致了解了在 Terraform 配置文件中会遇到哪些代码块,让我们继续看下一个示例:

  1. 使用mkdir命令创建一个basics目录。然后使用cd命令进入创建的目录:

    mkdir basics && cd basics
    
  2. 使用touch命令在basics目录中创建一个空的main.tf文件:

    touch main.tf
    
  3. 运行以下命令以使用 Vim 打开空的main.tf文件:

    vim main.tf
    

注意

输入:set nu,然后按Enter键显示行号。

  1. 接下来,按* i *键切换到插入模式,以便我们编辑文件。

注意

到此为止,你应该对如何使用 Vim 有了更好的了解。要切换到插入模式(假设我们当前处于普通模式),只需按* i 键。然后,要切换回普通模式,按Esc*键。

  1. 我们首先通过输入(或粘贴)以下代码块到我们的main.tf文件中来声明和配置 AWS 提供程序:

     terraform {
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "~> 4.0"
        }
      }
    }
    provider "aws" {
      alias  = "default"
      region = "us-east-1"
    }
    

    通过这段代码,Terraform 能够定位并使用指定版本和来源的 AWS 提供程序,以在指定区域(us-east-1)中配置和管理 AWS 资源。

注意

请注意,Terraform 会自动使用在 CloudShell 环境中配置的凭证。

  1. 接下来,还需要添加以下代码:

    data "aws_canonical_user_id" "current" {}
    

    这将使我们能够访问运行 Terraform 的账户的 AWS 标准用户 ID(这是一个字母数字值,用于授予对 S3 存储桶和对象的访问权限)。

注意

AWS 规范用户 ID(即 AWS 账户 ID 的“混淆形式”)主要用于 Amazon S3 中与对象级访问控制相关的操作。当授予 S3 对象或存储桶的访问权限时,此 ID 用于指定谁拥有必要的权限。请注意,AWS 规范用户 ID 与 AWS 账户 ID 不同,后者是与每个 AWS 账户相关联的 12 位数字。有关更多信息,请查看以下链接:docs.aws.amazon.com/AmazonS3/latest/userguide/finding-canonical-user-id.html

  1. 让我们也声明几个本地变量,如下所示:

     locals {
      user = data.aws_canonical_user_id.current
      name = local.user.display_name
    }
    
  2. 最后,让我们添加以下代码,它将打印出我们正在使用的 AWS 账户的规范用户 ID 的 display_name 值:

     resource "null_resource" "debug" {
      provisioner "local-exec" {
        command = "echo NAME=${local.name}"
      }
    }
    
  3. Esc 键切换回正常模式。输入 :wq! 然后按 Enter。这将保存对 main.tf 文件所做的更改,并退出 Vim。

  4. 现在,我们的 main.tf 文件已经准备好,让我们使用 terraform init 命令来初始化 Terraform 工作目录:

    terraform init
    

    这应该会产生类似于以下日志消息的日志输出:

    Initializing the backend... Initializing provider plugins... - Finding hashicorp/aws versions matching "~> 4.0"... - Finding latest version of hashicorp/null... - Installing hashicorp/null v3.2.1... - Installed hashicorp/null v3.2.1 (signed by HashiCorp)
    - Installing hashicorp/aws v4.57.0... - Installed hashicorp/aws v4.57.0 (signed by HashiCorp)
    

    在这里,我们可以看到相关的文件和二进制文件已经从 Terraform Registry 下载。

  5. 让我们运行 terraform plan 来预览 Terraform 将执行的更改:

    terraform plan
    
  6. 使用 terraform apply 命令来实施在运行 terraform plan 后返回的执行计划中的更改:

    terraform apply -auto-approve
    

    请注意,这次我们使用了 -auto-approve 标志来跳过验证步骤,类似于上一节中遇到的情况。运行该命令应产生以下输出:

    Plan: 1 to add, 0 to change, 0 to destroy. null_resource.debug: Creating... null_resource.debug: Provisioning with 'local-exec'... null_resource.debug (local-exec): Executing: ["/bin/sh" "-c" "echo NAME=john.doe"]
    null_resource.debug (local-exec): NAME=john.doe null_resource.debug: Creation complete after 0s [id=6076855428035859265]
    

    这里发生了什么? 代码只是执行了一个命令,打印出 name 本地值(即规范用户的显示名称)的值。

重要注意事项

我们可以看到,当使用 terraform apply -auto-approve 命令时,-auto-approve 标志允许在没有用户确认的情况下自动批准并执行计划的更改。-auto-approve 标志在非交互或自动化场景中非常有用,因为它消除了手动干预的需要。然而,使用 -auto-approve 标志时必须谨慎,因为它跳过了确认提示,且更改会立即应用。因此,在使用 -auto-approve 执行 terraform apply 之前,务必仔细审核 Terraform 代码和更改,以避免对基础设施进行不必要的修改。

  1. 现在,让我们对 main.tf 文件进行小幅修改。再次运行以下命令,使用 Vim 打开空的 main.tf 文件:

    vim main.tf
    

注意

您可以输入 :set nu 然后按 Enter 键来显示行号。

  1. 接下来,按 i 切换到 插入模式,以便我们可以编辑文件。

  2. 使用箭头键定位以下行:

     command = "echo NAME=${local.name}"
    

    一旦找到前面的代码块中的这一行,替换为以下内容:

    command = "echo ID=${local.user.id}"
    

    在这里,我们计划在后续步骤中运行terraform apply命令时,打印并记录 ID(而不是display_name值)。

  3. 按下Esc键以切换回正常模式。输入:wq!然后按Enter键。这将保存对main.tf所做的更改,并退出 Vim。

  4. 在运行terraform plan命令之前,我们先运行terraform fmt来格式化我们的 Terraform 代码:

    terraform fmt
    

    在这里,我们使用terraform fmt来确保所有 Terraform 配置文件遵循一致的编码风格。此命令会扫描 Terraform 配置文件,调整缩进、间距和换行符,以符合官方的 Terraform 风格指南。

注意

terraform fmt命令会自动调整代码块、语句和表达式的缩进,以确保对齐一致。它通常为每一级缩进使用两个空格。除此之外,命令还会添加或删除空格,以保持操作符、冒号、逗号及其他元素周围的间距一致。例如,它会确保在变量赋值的等号前后都有空格。类似地,它会插入或删除换行符,通过在资源块或变量声明之间插入换行符来提高可读性,使代码更加结构化。terraform fmt 还会进行一些其他格式调整,但这些调整应该足够了。

  1. 现在,让我们运行terraform plan以预览 Terraform 将要执行的更改:

    terraform plan
    

    这应该会生成以下输出:

    No changes. Your infrastructure matches the configuration. Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
    

    似乎在更改提供程序命令时未能检测到变化!

注意

在这里,Terraform 应该在修改资源块中的提供程序命令时检测到变化。然而,在某些情况下,修改提供程序命令可能不会被基础设施即代码(IaC)工具识别为修改。因此,Terraform 可能不会执行更新后的提供程序命令,可能导致部署的基础设施出现不一致。有关此主题的更多信息,请随时查看以下链接:github.com/hashicorp/terraform/issues/14405

  1. 要强制替换已创建的资源,我们可以在运行terraform** **apply命令时使用-replace标志:

    terraform apply -auto-approve \
    -replace=null_resource.debug
    

    这应该会生成以下日志:

    null_resource.debug: Destroying... [id=6076855428035859265]
    null_resource.debug: Destruction complete after 0s
    null_resource.debug: Creating... null_resource.debug: Provisioning with 'local-exec'... null_resource.debug (local-exec): Executing: ["/bin/sh" "-c" "echo ID=abcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh"]
    null_resource.debug (local-exec): ID=abcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh null_resource.debug: Creation complete after 0s [id=9009508010716198837]
    

    在这里,我们可以看到 ID 值在运行terraform** **apply命令后被记录了下来。

注意

这里发生了什么? 在这里,我们指示 Terraform 自动应用更改,而无需用户确认,特别是替换null_resource.debug资源。-replace=null_resource.debug参数专门定位null_resource.debug资源,表示它应在apply操作期间被替换。

  1. 使用cd命令导航到用户的主目录:

    cd ..
    
  2. 最后,使用 rm -rf 命令删除 basics 目录(以及其中的所有内容):

    rm -rf basics
    

    这样可以腾出一些空间,因为我们需要管理 CloudShell 环境中的可用空间。

恭喜完成我们的第二个 Terraform 示例!此时,我们应该已经具备了处理更复杂 Terraform 代码所需的信心。

使用 Terraform 构建我们的易受攻击实验室环境

本章的前几节帮助我们更好地理解了 Terraform 的工作原理。我们通过了相对简单的示例,现在是时候开始处理一个更完整、现实的示例了!也就是说,我们将使用 Terraform 自动创建和配置我们在 第二章 中手动准备的易受攻击的实验室环境,准备我们的第一个易受攻击的云实验室环境。通过利用 Terraform,我们应该能够简化设置我们之前手动准备的易受攻击实验室环境的过程。

注意

第二章**发生了什么?第二章 中,我们通过 AWS 管理控制台手动创建了一个空的 S3 存储桶,并将其配置为静态网站托管。然后,我们修改了存储桶的访问控制设置,允许经过身份验证的 AWS 用户列出并检索对象。为了完成设置,我们将示例文件上传到 S3 存储桶。

也就是说,本节由四个子部分组成,如下所示:

  • 使用 Terraform 创建 S3 存储桶

  • 更新 S3 存储桶的安全配置

  • 上传文件到 S3 存储桶

  • 清理并删除 S3 存储桶

事不宜迟,让我们开始吧!

第一部分 / 共 4 部分 – 使用 Terraform 创建 S3 存储桶

继续前一节的内容,让我们使用 mkdir 命令创建一个 basics 目录,然后按以下步骤操作:

  1. 使用 cd 命令导航到已创建的目录:

    mkdir vulnerable_s3_lab
    cd vulnerable_s3_lab
    
  2. 使用 touch 命令在 vulnerable_s3_lab 目录中创建一个空的 main.tf 文件:

    touch main.tf
    
  3. 运行以下命令使用 Vim 打开空的 main.tf 文件:

    vim main.tf
    

注意

你可以输入 :set nu 然后按 Enter 键来显示行号。

  1. 接下来,按 i 切换到 插入模式,这样我们就可以编辑文件了。

  2. 在我们的 main.tf 文件中键入或粘贴以下代码块:

     terraform {
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "~> 4.0"
        }
      }
    }
    provider "aws" {
      alias  = "default"
      region = "us-east-1"
    }
    
  3. 接下来,让我们通过添加以下代码块来声明一个 aws_s3_bucket 资源:

     resource "aws_s3_bucket" "bucket" {
      bucket = "<INSERT BUCKET NAME>"
      force_destroy = true
    }
    

    确保将 <INSERT BUCKET NAME> 替换为一个全球唯一的存储桶名称。如果你想知道 force_destroy 的作用,它只是允许我们在后续步骤中删除 S3 存储桶及其所有对象,而不会遇到问题。

注意

如需了解如何命名 S3 存储桶的指南和规则,欢迎查看以下链接:docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html

  1. Esc键切换回正常模式。输入:wq!,然后按Enter键。这将保存对main.tf文件所做的更改,并退出 Vim。

  2. 现在我们的main.tf文件已准备好,让我们使用terraform init命令初始化 Terraform 工作目录:

    terraform init
    
  3. 接下来,让我们运行terraform plan来预览 Terraform 将执行的更改:

    terraform plan
    

    这应该会生成一组日志,类似于我们在图 3.6中看到的内容:

    https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_03_06.jpg

    图 3.6 - 运行 terraform plan 命令后生成的日志

    在这里,我们可以看到某些属性的值只有在执行terraform apply命令后才会知道(也就是说,当资源被创建时)。

注意

了解某些属性值只有在执行terraform apply命令后才会确定,这是至关重要的。属性值的这种动态特性使得 Terraform 能够准确反映资源创建后的状态。

  1. 使用terraform apply命令来实现执行计划中指定的更改,该计划在运行terraform plan后返回:

    terraform apply -auto-approve
    

    这应该会生成一组日志,显示我们已成功创建 S3 桶。

注意

随时使用terraform show检查我们 S3 桶的当前配置设置。

  1. 在我们庆祝之前,让我们运行以下命令,验证 S3 桶是否已成功创建:

     aws s3 ls | grep <INSERT BUCKET NAME>
    

    确保将<INSERT BUCKET NAME>替换为在main.tf文件中指定的桶名称(来自本节前面的步骤)。这应该会生成一个格式如下的输出:

    <DATE> <TIME> <INSERT BUCKET NAME>
    

    如果你指定的桶名称是vuln-s3-abcdef-12345,我们应该得到一个类似于2023-10-01** **12:00:00 vuln-s3-abcdef-12345格式的输出。

第二部分,共 4 部分 - 更新 S3 桶的安全配置

我们才刚刚开始!在接下来的步骤中,我们将学习如何更新安全配置:

  1. 现在,让我们运行以下命令,再次使用 Vim 打开main.tf文件:

    vim main.tf
    

注意

你可以输入:set nu,然后按Enter键以显示行号。

  1. 接下来,按住Shift键,然后按g键跳转到最后一行。之后按o键。这应该会在当前行之后插入新的一行(并切换到插入模式)。

  2. 现在我们处于插入模式,接下来添加以下代码块,以指定 S3 桶的公共访问阻止配置:

     resource "aws_s3_bucket_public_access_block" "bucket" {
      bucket = aws_s3_bucket.bucket.id
      block_public_acls       = false
      block_public_policy     = false
      ignore_public_acls      = false
      restrict_public_buckets = false
    }
    

    在这里,block_public_aclsblock_public_policyignore_public_aclsrestrict_public_buckets属性被设置为false。这意味着 S3 桶不会阻止公共访问控制列表ACLs)或公共策略,不会忽略公共 ACLs,并且不会限制公共桶。

  3. 我们还可以添加以下内容,以指定 S3 桶的所有权控制:

     resource "aws_s3_bucket_ownership_controls" "bucket" {
      bucket = aws_s3_bucket.bucket.id
      rule {
        object_ownership = "ObjectWriter"
      }
    }
    

    所有权控制设置为ObjectWriter。这确保了只有上传对象的身份与访问管理IAM)用户或角色才能修改存储桶中的对象。

  4. 接下来,让我们通过添加以下代码块来配置 S3 存储桶以进行静态网站托管

     resource "aws_s3_bucket_website_configuration" "bucket" {
      bucket = aws_s3_bucket.bucket.bucket
      index_document {
        suffix = "index.html"
      }
    }
    
  5. 让我们也定义一个aws_iam_policy_document数据源块:

     data "aws_iam_policy_document" "policy" {
      statement {
        sid = "SampleStatement"
        principals {
          type        = "AWS"
          identifiers = ["*"]
        }
        actions = [
          "s3:GetObject"
        ]
        resources = [
          "${aws_s3_bucket.bucket.arn}/*"
        ]
      }
    }
    

    代码块中描述的策略授予 AWS 主体(即任何AWS 账户或 IAM 用户)执行s3:GetObject操作的权限,作用于 S3 存储桶中的对象。resources属性指定了 S3 存储桶的Amazon 资源名称ARN),后跟一个通配符字符(*****),以允许访问存储桶中的所有对象。

注意

如果你在想数据源块是什么,它只是一个我们可以读取数据的资源。它允许我们从现有资源或外部系统中检索信息。此外,它充当一个只读参考,提供可用于配置的有价值数据。我们将在接下来的步骤中看到数据源块的使用。

  1. 让我们还定义s3_policyau_uri本地变量,这些变量将在随后的配置块中使用:

     locals {s3_policy = data.aws_iam_policy_document.policyau_uri = "http://acs.amazonaws.com/groups/global/AuthenticatedUsers"
    }
    
  2. 接下来,使用以下代码块定义一个aws_s3_bucket_policy资源:

     resource "aws_s3_bucket_policy" "allow_access_policy" {
      bucket = aws_s3_bucket.bucket.id
      policy = local.s3_policy.json
    }
    
  3. 让我们再定义另一个数据源块,如下所示:

     data "aws_canonical_user_id" "current" {}
    

注意

这是本章前一部分中使用的相同数据源块。如果你不记得这个是用来做什么的,这个数据源块将让我们访问运行 Terraform 时使用的账户的 AWS 规范用户 ID。

  1. 让我们还定义一个aws_s3_bucket_acl资源,用于设置 S3 存储桶的 ACL 配置设置:

     resource "aws_s3_bucket_acl" "bucket_acl" {
      bucket = aws_s3_bucket.bucket.id
      access_control_policy {grant {grantee {
            id   = data.aws_canonical_user_id.current.id
            type = "CanonicalUser"
          }permission = "FULL_CONTROL" }grant {grantee {
            type = "Group"
            uri  = local.au_uri
          }permission = "READ" }
        owner {
          id = data.aws_canonical_user_id.current.id
        }
      }
    }
    

    这个代码块配置了 S3 存储桶的 ACL。aws_s3_bucket_acl资源为两个授权设置了权限:一个是授予具有FULL_CONTROL权限的规范用户,另一个是授予具有READ权限的组。这里,data.aws_canonical_user_id数据源返回第一个授权人的规范用户 ID。而local.au_uri本地值则返回第二个授权人的 URI(指向一个名为AuthenticatedUsers的 AWS 预定义组)。

注意

你可能已经注意到,我们的main.tf文件变长了。需要注意的是,我们可以将资源划分到不同的文件中并进行分组。当工作目录中有多个.tf文件时,Terraform 会将这些文件简单地连接起来并继续执行它的常规基础设施管理操作。我们在本章中不会深入讨论这些策略和最佳实践,因为我们将在本书接下来的章节中介绍这些内容,同时构建多个 AWS、Azure 和 GCP 中的渗透测试实验室环境。

  1. 按下Esc键切换回正常模式。键入:wq!,然后按Enter。这将保存对main.tf所做的更改,并退出 Vim。

  2. 在运行terraform plan命令之前,让我们运行terraform fmt来格式化我们的 Terraform 代码:

    terraform fmt
    

    在这里,我们使用terraform fmt来确保我们的 Terraform 配置文件采用一致的编码风格。通过分析文件,此命令调整缩进、间距和换行符,以符合指定的 Terraform 风格指南。

  3. 现在,让我们运行terraform plan预览 Terraform 将执行的更改:

    terraform plan
    

    这应该生成类似于图 3**.7中的执行计划:

    https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_03_07.jpg

    图 3.7 – 运行 terraform plan 命令后的结果

    在这里,我们可以看到执行计划现在包括了我们的 S3 存储桶安全配置设置的更新。

  4. 一切准备就绪,让我们运行terraform** **apply命令:

    terraform apply -auto-approve
    

注意

如果您遇到运行terraform apply -auto-approve时出现问题,请随时重新运行相同的命令,这可能会自动解决这些问题,而无需修改 Terraform 代码。例如,如果遇到“Error putting S3 policy: AccessDenied: Access Denied”错误消息,请简单地再次运行terraform apply -auto-approve。请注意,解决问题的另一种方法是首先使用terraform destroy -auto-approve删除资源,然后再使用terraform apply -auto-approve创建资源。

  1. 现在,让我们验证是否已应用桶的 ACL 配置,使用以下命令:

     aws s3api get-bucket-acl --bucket=<INSERT BUCKET NAME>
    

    确保用您的 S3 存储桶的名称替换<INSERT BUCKET NAME>

    运行命令后,我们应该会得到一个类似于图 3**.8的 JSON 响应:

    https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_03_08.jpg

    图 3.8 – 运行 aws s3api get-bucket-acl 命令后返回的结果

    在这里,我们可以看到新的 ACL 配置设置已应用到我们的 S3 存储桶。

第三部分共 4 部分 – 向 S3 存储桶上传文件

接下来,让我们按以下方式向之前创建的 S3 存储桶添加文件:

  1. 使用touch命令创建空的upload.sh文件:

    touch upload.sh
    
  2. 要使upload.sh 脚本文件可执行,请运行以下命令:

    chmod +x upload.sh
    
  3. 运行以下命令打开空的upload.sh文件,使用 Vim:

    vim upload.sh
    

注意

输入**:set nu**然后按Enter键显示行号。

  1. i切换到插入模式,以便我们可以编辑upload.sh文件。

  2. 现在我们处于插入模式中,让我们继续添加以下代码块:

     mkdir files
    cd files
    SOURCE=https://github.com/PacktPublishing/Building-and-Automating-Penetration-Testing-Labs-in-the-Cloud/raw/main/ch03/sample_website.zip wget $SOURCE -O sample_website.zip
    unzip sample_website.zip
    rm sample_website.zip
    aws s3 cp --recursive . s3://$1
    

    此一组命令简单地 (1) 从 GitHub 存储库下载一个 ZIP 文件,其中包含一个示例网站,并且 (2) 将其内容上传到 Amazon S3 存储桶。确保SOURCE变量值正确,通过删除任何额外的空格并检查是否可以直接通过浏览器访问下载链接来验证。

注意

这是在第二章中使用的相同一组终端命令,准备我们的第一个易受攻击的云实验室环境,用于将文件上传到我们的 S3 存储桶。

  1. Esc键切换回正常模式。输入:wq!并按Enter键。这将保存对upload.sh所做的更改并退出 Vim。

  2. 运行以下命令使用 Vim 打开main.tf文件:

    vim main.tf
    
  3. 按住Shift键,然后按g键跳转到最后一行。之后按o键。这将会在当前行之后插入一个新行(并切换到插入模式)。

  4. 在上一步插入的新行之后,添加以下代码块:

     resource "null_resource" "s3_upload" {
      provisioner "local-exec" {
        command = "./upload.sh ${aws_s3_bucket.bucket.id}"
      }
    }
    

    在这里,provisioner块指定将使用local-exec提供者,command属性指定要执行的 shell 命令,在此情况下为名为upload.sh的 shell 脚本。

注意

请注意,在前面的代码块中,提供者代码也可以放在aws_s3_bucket资源块内,或者放在其他资源块中(只需做一些小修改即可使其工作)。有关local-exec提供者的更多信息,请随时查看以下链接:developer.hashicorp.com/terraform/language/resources/provisioners/local-exec

  1. Esc键切换回正常模式。输入:wq!并按Enter键。这将保存对main.tf所做的更改并退出 Vim。

  2. 现在,让我们运行terraform plan来预览 Terraform 将要执行的变更:

    terraform plan
    

    这应该会给我们类似于图 3.9中所示的错误消息:

    https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_03_09.jpg

    图 3.9 – 不一致的依赖锁定文件错误

    Terraform 中的Inconsistent dependency lock file错误通常发生在依赖关系锁定文件与配置文件不匹配时。这种不一致可能是由于对配置做了更改,但没有相应地更新锁定文件所导致的。因此,为了解决Inconsistent dependency lock file错误,我们可以再次使用以下命令:

    terraform init
    

    这将同步锁定文件与配置,解决任何不一致之处,并确保 Terraform 部署的依赖关系一致。

  3. 接下来,让我们运行terraform plan来预览 Terraform 将要执行的变更:

    terraform plan
    

    这次你应该看到命令执行成功。

  4. 一切准备好后,让我们使用terraform apply命令来实现运行terraform plan后返回的执行计划中指定的更改:

    terraform apply -auto-approve
    

    这应该会运行upload.sh脚本中编码的命令。

  5. 让我们通过运行aws s3 ls命令进行一些快速检查,如下所示:

     aws s3 ls s3://<INSERT BUCKET NAME>
    

    这应该会列出我们 S3 桶中存储的对象。

注意

在运行命令之前,请确保将<INSERT BUCKET NAME>替换为你的 S3 桶名称。

  1. 现在,让我们使用aws s3api get-bucket-website命令来检查静态网站托管配置:

     aws s3api get-bucket-website --bucket <INSERT BUCKET NAME>
    

    确保将<INSERT BUCKET NAME>替换为main.tf文件中指定的桶名称(来自本节前面的步骤)。这应该返回以下输出:

    {
        "IndexDocument": {
            "Suffix": "index.html"
        }
    }
    

    这确认了为指定 S3 桶正确设置了静态网站托管配置。

  2. 我们还可以通过访问以下链接来检查我们的静态网站托管设置是否有效:

     http://<BUCKET NAME>.s3-website.<REGION>.amazonaws.com
    

    确保将<BUCKET NAME>替换为我们创建的 S3 桶的名称。别忘了将<REGION>替换为 S3 桶创建所在的区域(例如,us-east-1)。

    如果一切顺利,我们应该能看到类似图 3.10所示的维护页面:

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_03_10.jpg

图 3.10 – 验证静态网站托管设置是否生效

注意

此时,类似于我们在第二章中准备的易受攻击实验环境(准备我们的第一个易受攻击云实验环境),已经准备就绪!可以随意按照第二章测试和黑客攻击我们的第一个易受攻击环境部分的步骤测试我们实验环境的安全配置(在这里我们需要第二个 AWS 账户)。

第四部分 共 4 部分 – 清理并删除 S3 桶

在结束本节之前,让我们进行清理!请按照以下步骤操作:

  1. 使用terraform destroy来清理我们之前创建的资源:

    terraform destroy
    

    在验证步骤(即,当你看到Enter a value:提示时),输入yes继续删除资源。资源删除后,会在同一目录中生成一个包含状态文件属性副本的备份文件(terraform.tfstate.backup)。

  2. 你可以使用lesscat命令来检查存储在terraform.tfstate.backup文件中的属性。或者,我们可以使用terraform show命令读取terraform.tfstate.backup文件的内容:

    terraform show terraform.tfstate.backup
    

    这应该会产生类似于图 3.11的输出:

    https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_03_11.jpg

    图 3.11 – 运行 terraform show 后的输出

    如果你有冲动使用terraform show将状态文件转换为配置文件(类似于我们在main.tf文件中编写的内容),那么需要注意的是,我们在图 3.11中的输出并不是为了直接程序化使用(它主要是供我们人类排查故障和检查存储在文件中的状态)。

注意

如果使用terraform show(不带任何额外参数),我们应该得到一个空响应,因为资源已经在此时通过terraform destroy被删除。

哇!我们成功地将*【第二章】(B19755_02.xhtml)*中的手动步骤转换成了一个配置文件。此时,如果我们想要创建 10 个 S3 桶的克隆(所有资源具有相同的属性和配置设置,除了桶名称),我们只需对现有配置进行少许修改,然后使用 Terraform 自动创建和配置 S3 资源。

配置带状态锁定的 Terraform 后端

本节将探讨 Terraform 远程后端的工作原理,并了解状态锁定如何确保在管理基础设施部署时,基础设施状态的完整性和一致性。接着,我们将深入研究配置远程后端以启用状态锁定的逐步过程。

理解 Terraform 远程后端

到目前为止,我们一直在使用默认的本地后端,它将状态存储为本地文件(即terraform.tfstate文件)。当只有一个工程师参与时,这种配置应该是可以的。一旦另一位工程师希望使用 Terraform 对相同的资源集应用配置更改,使用远程后端将更加合理,因为第二位工程师需要访问现有的状态文件(由第一位工程师使用)。此外,我们需要确保同一资源集的配置更改不会同时应用,以防止竞争条件,这可能导致状态损坏。

使用 Terraform 时的最佳实践之一是使用外部远程后端来存储和锁定状态(类似于图 3.12所示):

https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_03_12.jpg

图 3.12 – 本地后端与远程后端

这允许多位工程师在同一资源集上工作,而无需担心破坏设置。配置正确的后端至关重要,因为 Terraform 后端决定了状态的加载方式,这反过来会影响资源的创建和修改过程。

注意

精心选择和配置后端可以确保安全协作、版本控制和整个基础设施生命周期中的正确状态管理。这增强了 Terraform 工作流的可靠性和可扩展性,特别是对于在相同资源集上工作的团队。欲了解更多信息,请随时查看以下链接:developer.hashicorp.com/terraform/language/settings/backends/configuration

话虽如此,为了解决协作中的挑战并防止潜在的冲突,建议将 Terraform 的默认本地后端切换到远程后端。通过使用远程后端,如 S3 存储桶,多个工程师可以安全地访问和修改同一个状态文件。这有助于协调,并确保在对共享资源进行配置更改时的一致性。此外,使用远程后端有助于缓解竞争条件的风险,因为它提供了一个集中式的机制来管理和锁定状态,从而降低了遇到损坏状态的可能性。

配置 Terraform 远程后端

状态锁定 在避免冲突和竞争条件方面起着至关重要的作用。通过允许每次只有一个用户或进程修改状态,它确保了 Terraform 部署中的完整性和同步性。此机制对于维护数据一致性和防止在协作的基础设施管理过程中发生不必要的更改至关重要。

在 AWS 云环境中配置 Terraform 后端的状态锁定时,通常会使用 S3 存储桶和 DynamoDB 表。S3 存储桶作为 Terraform 状态文件的安全存储,而 DynamoDB 表则充当分布式锁机制。通过状态锁定,只有一个 Terraform 命令能够在任何时刻持有锁,其他命令则等待直到锁被释放。此设置确保一致性,并防止在协作或自动化的 Terraform 环境中发生冲突。我们将把 S3 存储桶标记为 BACKEND_S3,DynamoDB 表标记为 BACKEND_TABLE,因为我们将在本章中多次引用这些资源。请注意,BACKEND_S3BACKEND_TABLE 只是我们在本章中使用的任意标签,目的是方便我们引用将在接下来的步骤中创建的资源。也就是说,这些标签与云基础设施资源的实际名称不同。

注意

如果你在想 DynamoDB 是什么,它是 AWS 中完全托管的 NoSQL 数据库服务。在 DynamoDB 中,表由项目和属性组成。每个项目代表一条独立的数据,类似于传统数据库中的一行。项目由属性组成,属性是存储实际数据的键值对。需要注意的是,DynamoDB 表不要求固定的模式,这意味着每个项目可以有不同的属性集合。为了实现分布式锁机制,Terraform 通过创建一个唯一的项目或记录作为锁指示符,利用 DynamoDB 表。当 Terraform 命令尝试获取锁时,它会检查指定的项目是否存在。如果项目不存在,该命令会将项目添加到 DynamoDB 表中,表示它已获取锁。这可以防止其他 Terraform 命令同时获取锁。

在接下来的步骤中,我们将通过配置 Terraform 后端来存储和锁定状态,从而升级我们的设置:

  1. 使用 cd 命令导航到主目录,如下所示:

    cd ~
    
  2. 让我们使用 mkdir 命令创建一个 backend 目录。创建好 backend 目录后,使用 cd 命令导航到该目录:

    mkdir backend && cd backend
    
  3. 接下来,使用 touch 命令在 backend 目录中创建一个空的 main.tf 文件:

    touch main.tf
    
  4. 运行以下命令使用 Vim 打开空的 main.tf 文件:

    vim main.tf
    

注意

你可以输入 :set nu,然后按 Enter 键来显示行号。

  1. 接下来,按 i 键切换到 插入模式,这样我们就可以编辑文件了。

  2. 将以下代码块添加到我们的 main.tf 文件中:

     terraform {
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "~> 4.0"
        }
      }
    }
    provider "aws" {
      alias  = "default"
      region = "us-east-1"
    }
    
  3. 接下来,让我们定义一个 新的 aws_s3_bucket 资源(用于后端)。请注意,这个 S3 存储桶资源与我们在脆弱实验环境中使用的配置错误的 S3 存储桶不同:

     resource "aws_s3_bucket" "remote_state" {
      bucket = "<INSERT S3 BACKEND BUCKET NAME>"
      lifecycle {
        prevent_destroy = true
      }
    }
    

    在这里,lifecycle 块包括一个将 prevent_destroy 属性设置为 true 的配置,确保存储桶不会被意外销毁。这意味着存储在该存储桶中的 Terraform 状态文件被保护,不会被意外删除。

重要说明

确保将 <INSERT S3 BACKEND BUCKET NAME> 替换为一个唯一的 S3 存储桶名称(例如,tf-remote-backend-abcdef-)。请注意,此时该存储桶应当 还不存在,因为我们还没有执行 terraform** **apply 命令。

  1. 现在,让我们添加以下代码块,以启用 存储桶版本控制 并为我们的 S3 存储桶配置 服务器端加密

     resource "aws_s3_bucket_versioning" "versioning" {
      bucket = aws_s3_bucket.remote_state.id
      versioning_configuration {
        status = "Enabled"
      }
    }
    resource "aws_s3_bucket_server_side_encryption_configuration" "encryption" {
      bucket = aws_s3_bucket.remote_state.id
      rule {
        apply_server_side_encryption_by_default {
          sse_algorithm     = "aws:kms"
        }
      }
    }
    

    在这里,为 S3 存储桶启用了存储桶版本控制和服务器端加密,这将用于存储 Terraform 的远程状态。版本控制确保保留远程状态的先前版本,从而在意外删除或损坏的情况下可以轻松恢复。另一方面,服务器端加密确保远程状态中的敏感数据在静态时被加密,以增加额外的安全层。

  2. 接下来,让我们使用以下代码块定义一个 aws_dynamodb_table 资源(使用我们的 S3 存储桶名称作为 DynamoDB 表的名称):

     resource "aws_dynamodb_table" "state_lock" {
      hash_key = "LockID"
      name = "${aws_s3_bucket.remote_state.id}"
      attribute {
        name = "LockID"
        type = "S"
      }
      billing_mode = "PAY_PER_REQUEST"
    }
    

    在这里,billing_mode 设置为 "PAY_PER_REQUEST",这意味着 (1) 我们只为对表的读写请求付费,(2) 没有预付费用或最低费用。

  3. Esc 键切换回普通模式。输入 :wq!,然后按 Enter 键。这将保存对 main.tf 所做的更改,并退出 Vim。

注意

到此为止,我们应该已经有两个 main.tf 文件:(1) ~/vulnerable_s3_lab/main.tf 和 (2) ~/backend/main.tf

  1. 现在我们的 ~/backend/main.tf 文件已经准备好,接下来让我们使用 terraform init 命令初始化 Terraform 工作目录:

    terraform init
    
  2. 接下来,让我们运行 terraform plan 来预览 Terraform 要执行的更改:

    terraform plan
    
  3. 一切准备好后,让我们使用 terraform apply 命令来实施在运行 terraform plan 后返回的执行计划中的更改:

    terraform apply -auto-approve
    

注意

等待几分钟让这一步完成。成功运行terraform apply命令后,我们应该有一个新的 S3 存储桶和一个新的 DynamoDB 表。让我们分别标记这些资源为BACKEND_S3BACKEND_TABLE,因为我们将在本章中多次引用这些资源。请注意,这个 S3 存储桶将用于 Terraform 远程后端,与用于易受攻击实验环境的故意配置错误的 S3 存储桶(我们将标记为VULNERABLE_S3)不同。有了 Terraform 远程后端准备好后,我们现在可以继续配置我们现有的 Terraform 代码以使用这个远程后端。在继续之前,请确保在运行terraform apply命令后记下 AWS S3 存储桶(BACKEND_S3)和 DynamoDB 表(BACKEND_TABLE)资源的名称。您可以使用terraform show命令检查 Terraform 管理的现有基础设施资源。

  1. 使用cd命令返回到vulnerable_s3_lab目录:

    cd ~/vulnerable_s3_lab
    
  2. 运行以下命令使用 Vim 打开main.tf文件:

    vim main.tf
    
  3. 接下来,按下i切换到插入模式,以便我们可以编辑文件。

  4. 使用箭头键定位以下代码块:

     terraform {
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "~> 4.0"
        }
      }
    }
    
  5. 一旦找到之前的代码块,请用以下代码块更新它:

     terraform {
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "~> 4.0"
        }
      }
      backend "s3" {
        bucket         = "<INSERT BUCKET NAME>"
        key            = "terraform/terraform.tfstate"
        region         = "us-east-1"
        dynamodb_table = "<INSERT TABLE NAME>"
        encrypt        = true
      }
    }
    

    确保用 S3 存储桶(BACKEND_S3)和 DynamoDB 表(BACKEND_TABLE)的名称替换<INSERT BUCKET NAME><INSERT TABLE NAME>

重要提示

在这里,我们将指定在早期步骤中创建的现有 S3 存储桶(标记为BACKEND_S3)和 DynamoDB 表(标记为BACKEND_TABLE)资源的资源名称,用于 Terraform 远程后端设置。请注意,BACKEND_S3BACKEND_TABLE只是我们在本章中使用的任意标签,以便我们更容易地引用我们在早期步骤中创建的资源。也就是说,这些并不是将在代码块中替换<INSERT BUCKET NAME><INSERT TABLE NAME>的资源名称。随时在~/backend目录中再次运行terraform show命令以获取资源名称。

  1. 现在我们的~/vulnerable_s3_lab/main.tf文件已经更新,让我们运行terraform fmt来格式化我们的 Terraform 代码:

    terraform fmt
    

    在这里,我们使用terraform fmt来确保所有 Terraform 配置文件都具有一致的编码风格。

  2. 让我们使用terraform init命令重新初始化 Terraform 工作目录:

    terraform init
    
  3. 接下来,让我们运行terraform plan来预览 Terraform 将执行的更改:

    terraform plan
    
  4. 现在,让我们使用terraform apply命令:

    terraform apply -auto-approve
    

    这将为我们的易受攻击实验环境创建一个配置错误的 S3 存储桶(标记为VULNERABLE_S3)。

重要提示

如果在运行terraform apply -auto-approve时遇到问题,请随时重新运行相同命令,这可能会自动解决这些问题,而无需修改 Terraform 代码。请注意,解决问题的另一种方法是首先使用terraform destroy -auto-approve删除资源,然后再使用terraform apply -auto-approve创建资源。

  1. 在我们庆祝之前,让我们验证一下用于后端(BACKEND_S3)的 S3 存储桶是否有terraform.tfstate文件:

     aws s3 ls s3://<S3 BACKEND BUCKET NAME> --recursive
    

    请确保用我们~/****backend/main.tf文件中指定的 Terraform 后端使用的 S3 存储桶(标记为BACKEND_S3)的名称替换<S3 BACKEND BUCKET NAME>

    运行aws s3 ls命令后,我们应该得到以下输出:

    ... terraform/terraform.tfstate
    

    这意味着我们已成功重新配置了我们的 Terraform 代码,将状态文件存储在 S3 存储桶中(而不是本地目录)。

  2. 接下来,让我们打开一个新的浏览器选项卡,导航到 AWS 管理控制台的主页。

注意

不要关闭我们在 AWS CloudShell 终端内运行命令的浏览器选项卡。

  1. 在搜索栏中键入dynamodb,然后从结果列表中选择DynamoDB,以进入 DynamoDB 控制台。在 DynamoDB 控制台左侧的导航窗格中,选择PartiQL 编辑器

注意

如果你想知道PartiQL是什么,它只是 DynamoDB 的一个与 SQL 兼容的查询语言。使用 PartiQL,我们可以类似于查询 SQL 数据库表的方式查询 DynamoDB 表。这使我们能够在处理 DynamoDB 时利用我们现有的 SQL 知识和技能,更容易地编写和执行复杂的 NoSQL 数据查询。

  1. 在 PartiQL 编辑器(文本区域)中指定以下查询:

     SELECT * FROM "<INSERT TABLE NAME>";
    

    请确保用我们在本节中早期步骤中使用 Terraform 创建的 DynamoDB 表的名称(标记为BACKEND_TABLE)替换<INSERT TABLE NAME>

注意

随时可以在~/backend目录内再次运行terraform show命令,以获取我们标记为BACKEND_TABLE的 DynamoDB 表的资源名称。

  1. 点击运行按钮执行查询。

    我们的查询应返回一个项目,其中LockID值为<BACKEND_S3 BUCKET NAME>/terraform/terraform.tfstate-md5。该项目还应具有类似于51f8a19d543d54b0481f1823b1784896的随机生成的字母数字Digest值。这个digest值是 Terraform 状态文件内容的表示。它用于检测状态文件的更改,并确保在planapplydestroy等操作期间保持一致性。当我们修改基础架构时,Terraform 将对状态文件进行更改,但除非状态文件的内容发生更改,否则摘要本身不会更改。也就是说,这个值充当状态文件内容的校验和或哈希,这使得 Terraform 能够确定状态文件是否已被外部修改(或是否存在可能导致冲突的并发修改)。

  2. 最后,返回 CloudShell 浏览器选项卡,然后使用terraform destroy命令清理我们之前创建的资源:

    terraform destroy
    

    在验证步骤(即看到**输入一个值:**时),输入yes以继续删除资源。

注意

上一步中删除的资源不包括 Terraform 后端资源(即BACKEND_S3BACKEND_TABLE),因为这些资源是在~/backend/main.tf中定义的。

我们还没有完成!在下一节中,我们将验证我们的状态锁定设置是否有效。

验证状态锁定设置

验证 Terraform 状态锁定设置对于确保我们的基础架构管理过程的完整性至关重要。通过验证状态锁定设置,我们可以确认使用上一节中的 S3 和 DynamoDB 的分布式锁定机制是否正常运行。也就是说,当两个用户几乎同时运行terraform apply时会发生什么?我们将在接下来的步骤中看到发生了什么!

注意

并发terraform apply命令的这种情况突出了状态锁定的重要性,以防止冲突并确保数据一致性。在本节中,我们将探讨 Terraform 如何管理状态锁定并处理并发操作。这将帮助我们更好地理解 Terraform 在这种情况下实施的行为和保障措施。

第一部分 - 向上传脚本添加 60 秒延迟

  1. 继续从上一节结束的地方,让我们使用cd命令导航到vulnerable_s3_lab目录:

    cd ~/vulnerable_s3_lab
    
  2. 运行以下命令以使用 Vim 打开upload.sh文件:

    vim upload.sh
    

注意

输入**:set nu**,然后按下Enter键以显示行号。

  1. 使用箭头键将光标放在第一行的第一个字符之前。之后,按下i切换到插入模式,以便我们可以编辑文件。

  2. upload.sh脚本的开头添加以下代码行:

     echo "Sleeping for 60 seconds"
    sleep 60
    

    在脚本开头添加的 2 行应使upload.sh脚本运行时间延长 60 秒。这应该给我们额外的几秒钟来运行所需的命令,以验证状态锁定设置是否正常工作。

  3. 按下Esc键切换到正常模式。输入**:wq!**。然后按Enter。这将保存对upload.sh所做的更改,然后退出 Vim。

  4. 使用cat命令(cat upload.sh)验证我们更新的upload.sh文件看起来是否与以下代码块中的内容类似:

    echo "Sleeping for 60 seconds"
    sleep 60 mkdir files
    cd files
    SOURCE=https://github.com/PacktPublishing/Building-and-Automating-Penetration-Testing-Labs-in-the-Cloud/raw/main/ch03/sample_website.zip wget $SOURCE -O sample_website.zip
    unzip sample_website.zip
    rm sample_website.zip
    aws s3 cp --recursive . s3://$1
    

    在这里,我们基本上有相同的upload.sh文件,只是在运行脚本时添加了前 2 行以增加 60 秒的延迟。

第二部分 4 – 获取状态锁

  1. 现在,让我们在 CloudShell 终端屏幕上垂直分割。按住Ctrl键同时按下b键。释放两个键,然后在大约半秒后按下*%(或Shift* + 5)。这应该创建一个类似于图 3**.13中的垂直分割:https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_03_13.jpg

    图 3.13 – tmux中的垂直分割

    由于 AWS CloudShell 预先安装了tmux,我们应该能够直接使用tmux命令,而无需单独安装该实用程序。

注意

如果这是你第一次使用tmux,不要担心,可能需要几次尝试才能掌握正确的按键组合!随时观看这个教程视频以获取有关如何使用tmux的更多信息:www.youtube.com/watch?v=Yl7NFenTgIo

  1. 让我们跳到左窗格。按住Ctrl键同时按下b键。释放两个键,然后在大约半秒后按下左箭头键。

  2. 现在,在左窗格上运行以下命令:

    cd ~/vulnerable_s3_lab && terraform apply -auto-approve
    

    这应该产生一组类似于在本章使用 Terraform 构建我们的易受攻击实验环境部分运行terraform apply命令后生成的日志。您可以忽略任何AccessDenied错误消息,因为这些可以通过在左窗格中重试命令轻松解决(在这一点上我们不需要这样做)。

重要提示

运行terraform apply命令将获取状态锁,以确保并发操作不会同时修改基础设施状态。这个锁对于保持一致性并防止协作或自动化环境中的冲突至关重要。通过在进行任何修改之前获取锁,我们确保多个terraform apply命令在继续之前等待锁被释放。也就是说,不要等待terraform apply命令完成!在在左窗格上运行命令后立即继续下一组步骤。

第三部分 4 – 测试我们的状态锁设置

  1. 为了测试我们的状态锁设置,我们将在第一个terraform apply命令仍在运行时运行另一个terraform apply命令。也就是说,让我们跳到右窗格。按住Ctrl键同时按下b键。释放这两个键,然后在大约半秒后按下右箭头键。

  2. 当左窗格上运行terraform apply命令时,在右窗格上运行以下命令:

    cd ~/vulnerable_s3_lab && terraform apply -auto-approve
    

    这将给我们一个类似于图 3**.14所示的错误:

    https://github.com/OpenDocCN/freelearn-sec-pt2-zh/raw/master/docs/bd-auto-pentest-lab-cld/img/B19755_03_14.jpg

    图 3.14 – 获取状态锁时出错

    这意味着我们在第一个terraform apply命令仍在运行时(在左窗格中)无法获取状态锁。一旦左窗格中的命令成功(或由于错误而失败),状态锁将被释放。*这是预期的行为吗?是的!*通过在较早的步骤中获取状态锁,我们确保只有一个terraform apply命令可以一次修改状态。这种顺序方法确保一致性并防止竞争条件。因此,正常情况下,后续的terraform apply命令会等待初始命令完成并释放状态锁,然后再继续。

    当然,会有一些情况下状态锁不会自动释放(很可能是由于意外问题)。要解决这个问题,你可以使用terraform force-unlock -force <ID>手动解锁状态。你可以在错误消息的Lock Info部分找到ID值(类似于我们在图 3**.14中看到的)。

重要提示

如果你错过了时机(也就是说,在你能够在右窗格运行terraform apply命令之前,左窗格中的命令已经执行完毕),请随时在~/vulnerable_s3_lab目录内运行terraform destroy -auto-approve来销毁创建的资源,这样你就可以尝试重复上一组步骤。你也可以通过修改upload.sh文件,将 60 秒的延迟替换为 120 秒的延迟,以便给你更多时间在tmux窗格之间切换。

第四部分 4 – 清理工作

  1. 随着我们的状态锁验证实验完成,让我们使用exit命令退出右窗格上的tmux会话:

    exit
    

    这将使我们只留下一个窗格(移除垂直分割)。

  2. 在结束本节之前,让我们使用terraform destroy清理之前创建的资源:

    terraform destroy
    

    在验证步骤中(也就是当你看到**输入一个值:**时),输入yes以继续删除资源。这将删除vulnerable_s3_lab目录内main.tf文件中指定的资源(主要是标记为VULNERABLE_S3的 S3 存储桶)。

注意

随意删除剩余的 S3 存储桶(用作我们标记为BACKEND_S3的远程状态后端)以及 DynamoDB 表(标记为BACKEND_TABLE)。我们将把这留给你作为练习。

哇!这一章真是充满了生产力和行动!到目前为止,我们应该已经很好地掌握了如何利用 Terraform(结合 IaC 概念和策略)来创建和配置云资源。在接下来的章节中,我们将更深入地探讨在本章中学到的内容如何在构建云端渗透测试实验室中发挥关键作用。

摘要

在这一章中,我们讨论了 IaC 如何帮助我们在云端自动准备、配置和管理渗透测试实验室环境。然后,我们使用了 Terraform,这个最强大和最常用的 IaC 工具之一,来创建、修改和删除云基础设施资源。在我们的环境中设置好 Terraform 后,我们进行了几个实践示例,演示了该工具的不同功能。此外,我们还使用 Terraform(这次是自动化的)重建了在 第二章 中准备的脆弱实验室环境。最后,我们简要回顾了如何配置带有状态锁定的 Terraform 后端,以帮助防止多个工程师在使用 Terraform 修改基础设施资源时发生冲突。

在下一章中,我们将深入探讨在云端隔离账户和环境的不同策略。结合下一章的实践解决方案,这些信息将帮助我们妥善地保护和管理我们的云端渗透测试实验室环境。

深入阅读

如果您想了解更多本章涉及的内容,请随时查阅以下资源:

第二部分:在云端搭建隔离渗透测试实验室环境

在本部分中,您将学习如何在 AWS、Azure 和 GCP 上构建和自动化隔离的渗透测试实验室环境。

本部分包含以下章节:

  • 第四章在 GCP 上搭建隔离的渗透测试实验室环境

  • 第五章在 Azure 上设置隔离的渗透测试实验环境

  • 第六章在 AWS 上设置隔离的渗透测试实验环境

考虑柔性负荷的综合能源系统低碳经济优化调度【考虑碳交易机制】(Matlab代码实现)内容概要:本文围绕“考虑柔性负荷的综合能源系统低碳经济优化调度”展开,重点研究在碳交易机制下如何实现综合能源系统的低碳化与经济性协同优化。通过构建包含风电、光伏、储能、柔性负荷等多种能源形式的系统模型,结合碳交易成本与能源调度成本,提出优化调度策略,以降低碳排放并提升系统运行经济性。文中采用Matlab进行仿真代码实现,验证了所提模型在平衡能源供需、平抑可再生能源波动、引导柔性负荷参与调度等方面的有效性,为低碳能源系统的设计与运行提供了技术支撑。; 适合人群:具备定电力系统、能源系统背景,熟悉Matlab编程,从事能源优化、低碳调度、综合能源系统等相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①研究碳交易机制对综合能源系统调度决策的影响;②实现柔性负荷在削峰填谷、促进可再生能源消纳中的作用;③掌握基于Matlab的能源系统建模与优化求解方法;④为实际综合能源项目提供低碳经济调度方案参考。; 阅读建议:建议读者结合Matlab代码深入理解模型构建与求解过程,重点关注目标函数设计、约束条件设置及碳交易成本的量化方式,可进步扩展至多能互补、需求响应等场景进行二次开发与仿真验证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值