-
Terraform 如何导入以及管理 AWS 现有安全组
HashiCorp Terraform 是一个IT基础架构自动化编排工具,可以用代码来管理维护 IT 资源。Terraform的命令行接口(CLI)提供一种简单机制,用于将配置文件部署到 AWS 或其他任意支持的云上,并对其进行版本控制。它编写了描述云资源拓扑的配置文件中的基础结构,例如虚拟机、存储账户和网络接口。
Terraform是一个高度可扩展的工具,通过 Provider 来支持新的基础架构。Terraform能够让您在云上轻松使用简单模板语言来定义、预览和部署云基础结构。您可以使用Terraform来创建、修改、删除ECS、VPC、RDS、SLB等多种资源。
在本文中,我们将了解如何使用 Terraform 管理现有和已创建的 AWS 安全组。基础设施革命的新时代已经开始,我们已经开始在配置管理工具(如 Ansible、Terraform、SaltStack 等)的帮助下以代码的形式配置、管理和管理我们的基础设施。
如果您是 Terraform 的新手并且想了解如何将 Terraform 与 AWS 基础知识结合使用,可以参考本文。
本文的目的
我们知道 Terraform 很强大,我们可以使用 Terraform 高效的管理或创建整个 AWS/GCP/DigitalOcean 云基础设施,但我们经常发现自己有一些额外的资源,这些资源通常是早期手动创建的,而不是由 Terraform 管理的。
将所有这些非托管资源(安全组)引入 Terraform 并使它们成为基础设施即代码。我们可以使用Terraform import命令。
但是将这些资源一一导入是非常麻烦的。所以我们尝试使用 Ansible 将其自动化,结果就是这样。
使用 Terraform 导入和管理现有 AWS 安全组
尽管如此,许多 DevOps 工程师仍在登录 AWS 管理控制台以手动更新安全组入站和出站流量路由,例如打开端口、启用流量路由等。这没有任何问题,但问题是您无法跟踪您的团队所做的更改除非您将其统一使用版本控制来管理。这就是 Infra as code 的优势所在。
想象一下,您将安全组作为代码,并且您所做的每项更改都在您的 Git 存储库(如 BitBucket 或 Github)中正确提交和管理。每个更改都将使用 git 日志和提交消息进行跟踪,并且还会有配置的备份,以防您想要回滚。不仅如此。
我列出了您应该将 AWS 安全组作为代码进行管理的几个原因。
- 它使您能够跟踪所有更改,例如打开/关闭端口以及更改的原因。
- 您可以使用 Commit 消息进行更好的安全审计
- 轻松高效的管理
- 使您能够进一步自动化您的基础架构
- 轻松找到您的公开路线并在发生任何安全事件之前进行预防
- 更好的业务连续性/灾难恢复策略。
- 单击 Jenkins 作业允许/禁止 IP/端口/组
因此,将您的 AWS 安全组作为代码来管理是非常高效的。
所以现在让我们看看我是如何设法将我现有的 AWS 安全组(所有安全组)导入 Terraform 并对其进行管理的。
Ansible + Terraform– 提供帮助
我是 Ansible 和 Terraform 的粉丝,两者在管理基础设施方面都很棒,而 Ansible 是 pythonic,Terraform 有自己的语言,称为 Hashicorp 配置语言,也支持 JSON。
我们在这里使用 Python 的原因是我们将使用 Ansible 的ec2_group_facts模块获取所有安全组及其信息,这也可以使用 AWS CLI 完成,但我更喜欢这种方式来更好地处理数据。
这是我们的设计将如何进行的图示。
如果您看不懂我的图,我在这里写下相同的内容以供参考。
在我们的设置中。Ansible playbook 是使用模块调用 Terraform 和 EC2 数据收集的主要组件ec2_group_facts。
为了让 Ansible 能够访问 AWS,您需要在环境变量中启用 AWS 编程访问和身份验证密钥。
$ export AWS_ACCESS_KEY_ID=AK************IEVXQ $ export AWS_SECRET_ACCESS_KEY=gbaIbK*********************iwN0dGfS
这足以使 Ansible 和 Terraform 能够访问您的 AWS 基础设施。但是,您可能会遇到一些隐藏的细节和问题(就像我遇到的那样)如果您遇到困难或在评论中让我知道,您可以参考以下文章,我会尽快提供帮助
- 为 Ansible AWS 设置 Boto python:(https://www.middlewareinventory.com/blog/ansible-aws-ec2/#Environment_Setup_for_Ansible_to_work_with_AWS_EC2_module)
- 为 AWS 设置编程访问——密钥和秘密:(https://www.middlewareinventory.com/blog/terraform-aws-example-ec2/#Setup_Programmatic_Access)
- 安装和配置 AWS CLI:(https://www.middlewareinventory.com/blog/aws-cli-ec2/#Install_AWS_CLI)
- Terraform AWS 配置基础知识:(https://www.middlewareinventory.com/blog/terraform-aws-example-ec2/)
为 Ansible 和 Terraform 准备好您的环境后,我们可以继续进行。
Ansible 和 Terraform如何协同工作
完成 AWS 和 Ansible 集成的访问设置后,您将能够从 ansible 访问您的 AWS 帐户并执行所有 AWS 相关模块。
在本 playbook 中,我们还将使用这样一个名为的模块ec2_group_facts,它可以帮助我们获取有关安全组的所有信息。那将是我们的第一步。
然后我们将为从 AWS 帐户获取的每个安全组创建一个目录,并使用terraform import命令和安全组 ID创建 Terraform 配置文件。
导入完成后,我们需要删除 terraform 配置文件中的一些配置元素,例如ownerid、arn、group id等,这些值/元素应该由 Terraform 自动填充,因此 terraform 不会让您事先定义它。
从配置文件中删除这些自动生成的元素/变量后,我们将使用以下terraform validate命令验证文件。
因此,这些是我们要执行的四个步骤,以使您的所有安全组都由 Terraform 管理。
Ansible Playbook
导入所有安全组
并添加到 Terraform
所以,是时候编写一些代码了,理论就够了。
执行剧本之前要记住的几点:
- 您需要更新destdir变量,ansible 将为它正在获取的每个安全组创建新目录。目录名称将与安全组名称相同(如果安全组名称中有空格,它将被转换为-连字符)
- 你需要替换你对应vpc的vpc-id变量
The Playbook
--- - name: Security Group Playbook hosts: localhost vars: destdir: /apps/gritfy/Terraform/SecGroups itemstochange: ['arn\s+=.+$','\sid\s+=.+$','owner_id\s+=.+$'] tasks: - name: ec2 security group information fetch ec2_group_facts: filters: vpc-id: vpc-0a8ae2c90f5ca6cfa register: result - name: Creating a dictionary of Security Group IDs and Names set_fact: secdict: "{{ secdict | default ([]) + [ { 'name': item.group_name.replace(' ','-'), 'id': item.group_id } ] }} " with_items: "{{result.security_groups}}" loop_control: label: "{{ item.group_name}}" - name: Create the Directory file: path: "{{destdir}}/{{item.name}}{{item.id[0:7]}}" # required. Path to the file being managed. state: directory register: dircrt loop: "{{secdict}}" - name: Terraform Import shell: | git init echo 'provider "aws" {\n\tregion = "us-east-1"\n} \n\nresource "aws_security_group" "elb_sg" {\n\n}' > main.tf terraform init terraform import aws_security_group.elb_sg {{item.id}} echo 'provider "aws" {\n\tregion = "us-east-1"\n} \n' > main.tf terraform show -no-color >> main.tf git add . git status git commit -m "Updated Git" pwd && ls -lrt args: chdir: "{{destdir}}/{{item.name}}{{item.id[0:7]}}" loop: "{{secdict}}" when: dircrt is changed - name: Change config lineinfile: path: "{{destdir}}/{{item.0.name}}{{item.0.id[0:7]}}/main.tf" regexp: "{{ item.1 }}" state: absent backup: yes with_nested: - "{{ secdict }}" - "{{ itemstochange }}" - name: Terraform Validate shell: | terraform validate args: chdir: "{{destdir}}/{{item.name}}{{item.id[0:7]}}" loop: "{{secdict}}" register: tfvalidate failed_when: "'Success' not in tfvalidate.stdout"
Ansible Playbook 任务说明
让我们浏览一下剧本,了解每项任务的设计目的。
01任务 :EC2 信息获取
此任务使用名为的模块ec2_group_facts,它使用您环境中的 AWS 访问密钥和秘密直接连接到您的 AWS 帐户并获取所有属于vpc参数中提到的特定的安全组。确保vpc-id在运行剧本之前更新过滤器值。
02任务 :使用收集的值创建字典
ec2_group_facts 模块会产生很多关于安全组的信息,但我们只需要一个security group name和security group id
因此,我们正在遍历上一个任务收集的输出并创建一个名为secdict我们正在使用set_fact模块在运行时创建变量的字典
03任务 :为每个安全组创建一个目录——命名约定
如前所述,我们将为每个安全组创建专用目录,其中将保存相应安全组的 Terraform 配置文件。
此目录的名称将是安全组名称和安全组 ID 的前 7 个字符的组合,这是为了避免重复。AWS 对安全组的命名没有唯一名称约束,因此可以有多个同名的安全组。
04任务 :Terraform 导入任务
在此任务中,我们正在一个接一个地运行多个命令,就像我们在 shell 提示符下键入一样。使用ansible shell 模块
这些是我们将要完成的任务列表:
- 我们在新建的sec组目录下初始化一个git repo
- 创建一个main.tf以 AWS 供应商规范命名的 Terraform 配置文件
- 执行terraform init以在目录上初始化 terraform
- terraform import使用命令和相应安全组的 id执行导入过程
- 将导入的配置写回到main.tf我们在第 2 步创建的配置文件中
- 其余步骤用于版本控制更改,如添加、提交等。
05任务 :Terraform 文件更正并删除不需要的字
在此任务中,我们将从创建的main.tf配置文件中删除不需要的行,否则会使文件在语法上不正确。
06任务 :验证更改后的配置
最后,我们可以使用将在所有安全组目录中执行的命令来验证 Terraform 配置文件main.tf是否对每个安全组有效。当验证命令使用ansible failed_whenterraform validate返回失败消息时,则为失败(https://www.middlewareinventory.com/blog/ansible-changed_when-and-failed_when-examples/)
playbook 执行和结果
如果你做的一切都是正确的。您将能够在您的 AWS 账户中导入属于特定 VPC 的所有安全组,并且能够使用Terraform 进行管理。
您将在 playbook 中定义的 workspace(destdir) 目录下使用安全组名称创建目录。
在 Terraform 文件中进行更改并应用它来验证
导入配置文件并准备就绪后,转到创建的任何安全组目录并编辑main.tf文件并进行更改,例如添加新的入口规则或更改允许的端口号的 CIDR IP 地址等
完成更改后。我们就可以使用terraform plan然后terraform apply它
我们将能够看到我们的安全组已由 Terraform 成功管理。