如何测试你的红队基础设施(下) - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

如何测试你的红队基础设施(下)

李白 资讯 2020-03-02 09:13:49
725807
收藏

导语:在我们继续测试 Ansible 角色之前,有个值得一提的事情是在你的开发工作流程中使用 Molecule 的另一个优势。

在我们继续测试 Ansible 角色之前,有个值得一提的事情是在你的开发工作流程中使用 Molecule 的另一个优势。我一直发现,使用 Ansible 开发的痛点之一是,为了让事情如预期的那样运作,你必须进行大量的调整,然后清理环境,并重复这些调整操作。谢天谢地,Molecule 公开了 molecule converge  命令,它允许你在你的 Docker 容器上应用一个 Ansible 角色,而不需要运行任何测试。 这意味着你可以不断地将你的角色应用于容器,以确保在开发过程中容器是按预期的方式执行。 为了检查你是否在正确的轨道上,molecule login 允许你检查容器,如果你犯了一个错误,你可以通过 molecule destroy 清理。

现在我们已经掌握了 Ansible 角色的处理方法,让我们使用 InSpec 确保实际部署到 AWS 时一切如我们所期望的那样。

InSpec

InSpec 是来自 Chef 创建者的一个非常棒的工具,它允许我们测试已部署的基础设施以获得所需的状态。从可用的CIS基准测试,到验证环境中的漏洞是否已经修补,InSpec 有许多用途。 对于我们的例子来说,我们希望使用 InSpec 来确保我们部署的基础设施满足一些简单的要求:

1. 我们是否只公开 HTTP 和 HTTPS 端口?

2. 我们的管理 IP 能否使用 SSH 连接?

3. NGINX 是否已经启动并运行在这两个重定向器上?

4. 我们的反向代理配置是否适用于我们的重定向器?

确定了这些简单的测试用例之后,让我们创建一组 InSpec 测试来验证我们部署的基础结构是否符合我们的期望。

首先,我们需要初始化我们的 AWS 测试,我们可以这样做:

inspec init profile --platform aws aws_tests

这将创建一个模板,布局看起来像下面这样:

.
├── README.md
├── attributes.yml
├── controls
│   └── example.rb
├── inspec.lock
└── inspec.yml

在这篇文章中,我们将致力于 example.rb (重命名为某个合理的名称) ,以介绍一些由 Terraform 构建的 AWS 环境的测试。

如果我们专注于确保我们的重定向器是在线的,并且我们的安全组只公开暴露 HTTP/S,而 公开暴露 SSH ,那么我们最终会得到一组测试用例,比如:

title "AWS"
describe aws_ec2_instance(name: 'Redirector-LongHaul') do
  it { should exist }
end
describe aws_ec2_instance(name: 'Redirector-ShortHaul') do
  it { should exist }
end
describe aws_security_group(group_name: 'redirector-sg') do
  it { should exist }
  it { should allow_in(port: 80, ipv4_range: '0.0.0.0/0') }
  it { should allow_in(port: 443, ipv4_range: '0.0.0.0/0') }
  it { should allow_in(port: 22, ipv4_range: '1.2.3.4/32') }
end

确保你的 AWS 配置文件是通过 AWS configure 命令或通过环境变量进行配置的,我们可以使用我们的默认配置文件运行 InSpec 测试:

cd test-aws; inspec exec . -t aws://

如果一切顺利的话,我们应该看到我们收到了来自 InSpec 的确认信息,一切正常:

 image.png

但是我们的重定向器配置怎么办,我们怎么知道我们的 Ansible 角色被实际应用了呢? 同样,这也很容易检查,我们可以创建一个模板,可以使用下面的命令:

inspec init profile redirectors

然后添加一些测试用例,类似于我们上面的 Molecule 测试:

title "Service Config"
describe service('nginx') do
  it { should be_installed }
  it { should be_enabled }
  it { should be_running }
end
describe service('ssh') do
  it { should be_installed }
  it { should be_enabled }
  it { should be_running }
end
describe file('/etc/nginx/conf.d/default.conf') do
    its('content') { should match %r{proxy_pass } }
end

然后通过以下方式运行:

inspec exec . -t ssh://ubuntu@HOST -i ./keys/remotekey

image.png

这里我们有一个 NGINX 配置文件的例子,但它与我们预期的测试不匹配。经过一个简单快速的修改后,就可以修复 Ansible 的角色或 InSpec 测试,执行后,我们可以看到所有检查项的结果:

image.png

太棒了,那么让我们来确认一下我们目前所拥有的... 我们有 Terraform 脚本,它可以创建我们的基础设施。 我们有可用于重定向器的剧本和角色。 我们有 Molecule 测试,让我们能够快速开发和验证我们的角色,最后我们有 InSpec 测试,以确保我们的基础设施完全按照我们的期望创建。

接下来是相当有趣的一部分... ... 接下来的内容可以保持我们未来基础设施发展的良好状态。

在 CI 管道中将所有东西粘合在一起

因此,我们现在有了解决这个难题的所有细节,并且我们相信,我们的角色和基础设施将按照预期的方向发展。 但是,我们如何确保每次有人对这些组件中的任何一个进行更改时,在下一次我们启动或重新启动环境时,一切都能顺利运行呢? 在开发世界中,持续集成已经成为保持代码在可控范围内的一种有用实践。 通过强制将测试推送到 Git 服务器上运行,我们就可以确保在下次部署时将代码更改合并到 Master 中不会导致中断。

为了创建我们的 CI 管道,我们将使用 Gitlab,这是我目前选择的托管 Git 服务器。 Gitlab 除了是托管 Git 代码仓库的好地方,它还具有 CI/CD 平台的功能,允许我们通过 Gitlab Runners 执行测试、构建和部署。 如果你更喜欢使用 Github,请查看 James 发表的 Github 操作 这篇文章,了解他们的 CI/CD 平台。

那么 CI 到底是什么呢? CI 的意思是“持续集成“,即通过大量的自动化测试,不断将开发人员的更改合并到一个稳定的分支中,以确保 push 的 commit 没有破坏任何东西。 其想法是,通过在合并期间使用测试来保持质量水平,你可以在任何给定时间将稳定分支连续地部署到生产环境中,因为你知道它应该始终按预期的方式运行(这是对“持续部署”的简化描述。

为了将测试的每个阶段联系起来,我们需要在 gitlab-ci.yml 中描述每个阶段。 该文件位于项目的根目录中。 这将允许我们构建我们的管道,我们可以使用它来进行 Git 测试,推送到一个临时环境,并通过一系列的验证步骤来确保我们的基础设施看起来正如我们所希望的那样。

我们管道的每个阶段将被定义为:

· 测试-通过 Molecule 测试 Ansible 角色

· 测试- Terraform HCL 验证

· 阶段-部署到测试环境

· 提供-提供已部署 Ansible 的服务器

· 验证-测试环境的 InSpec 验证

· 清理-拆除基础设施

让我们将每个阶段分解,并在 gitlab-ci.yml 文件中进行表示。 从我们各个管道阶段的定义开始:

stages:

  - test
  - stage
  - provision
  - validate
  - cleanup

在这里,我们定义了管道的每个阶段,它们可以与上面定义的步骤相匹配。 接下来我们需要告诉 Gitlab 在每个阶段该做什么,从 Terraform 开始:

terraform_validate:
  image: 
    name: hashicorp/terraform:light
    entrypoint:
      - '/usr/bin/env'
      - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
  stage: test
  script:
    - cd terraform 
    - terraform init
    - terraform validate

这里的想法很简单,如果基本的 Terraform 配置没有检查出来,我们不想进入管道的附加步骤,所以我们在继续之前运行一个简单的验证步骤。

一旦这个阶段完成后,我们就可以开始为我们的 Ansible 角色运行 Molecule 测试:

molecule_tests:
  image: docker:latest
  stage: test
  before_script:
    - apk update && apk add --no-cache docker
      python3-dev py3-pip docker gcc git curl build-base
      autoconf automake py3-cryptography linux-headers
      musl-dev libffi-dev openssl-dev openssh
    - docker info
    - python3 --version
  script:
    - pip3 install ansible molecule docker
    - cd ansible/roles/ubuntu-nginx
    - molecule test

在这里,我们将使用 docker,通过使用最新的镜像和“Docker-in-Docker”服务,能够使 Molecule 启动额外的需要运行 Molecule 测试的容器。 值得注意的是,在这个阶段,我们正在安装的 Molecule 框架是在管道的阶段中执行。 我不建议在你自己的管道中这样做,因为这里已经演示了执行 Molecule 需要什么。 实际上,你可以托管一个 Docker 镜像,其中包含所有预先配置的内容,以加速测试。

一旦我们的管道达到这个阶段,我们已经验证了我们的 Terraform 文件在语法上是正确的,并且我们的 Ansible 角色通过了每个创建的测试,所以接下来我们将把我们的基础设施部署到 AWS,作为一个临时环境进行进一步的测试:

deploy_stage:
  image: 
    name: hashicorp/terraform:light
    entrypoint:
      - '/usr/bin/env'
      - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
  stage: stage
  script:
    - cd terraform
    - terraform init
    - terraform apply --auto-approve
  artifacts:
    paths:
      - terraform/terraform.tfstate
    expire_in: 1 day

与我们之前的 Terraform 阶段类似,我们只是简单地使用 Hashicorp 的 Terraform Docker 镜像来提供 Terraform 工具,但是在 Terraform 运行之后,我们希望将状态文件作为一个工件来保存。 工件允许我们从一个阶段公开文件,同时提供将创建的文件传递到管道的后续阶段的能力,这意味着在这种情况下,我们可以传递 Terraform tfstate 文件以便以后进行清理。

现在我们已经在我们的阶段环境中部署了我们的重定向器,我们需要使用 Ansible  提供它们:

provision_stage:
  stage: provision
  when: delayed
  start_in: 30 seconds
  image: 
    name: hashicorp/terraform:light
    entrypoint:
      - '/usr/bin/env'
      - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
  before_script:
    - apk add ansible
    - wget https://github.com/adammck/terraform-inventory/releases/download/v0.9/terraform-inventory_0.9_linux_amd64.zip -O /tmp/terraform-inventory_0.9_linux_amd64.zip
    - unzip /tmp/terraform-inventory_0.9_linux_amd64.zip -d /usr/bin/; chmod 700 /usr/bin/terraform-inventory
  script:
    - cd terraform; terraform init; cd ..
    - cd ansible; chmod 600 .
    - chmod 600 ../terraform/keys/terraformkey
    - ANSIBLE_HOST_KEY_CHECKING=False TF_STATE=../terraform ansible-playbook --inventory-file=/usr/bin/terraform-inventory -u ubuntu --private-key ../terraform/keys/terraformkey site.yml

同样,你通常会创建一个 Docker 镜像来加速这个阶段,并根据需要添加“terraform-inventory”工具。

一旦我们的重定向器准备好了以后,我们就可以在 AWS 的分段环境中运行我们之前精心设计的 InSpec 测试:

inspec_tests:
  stage: validate
  image: 
    name: chef/inspec:4.18.51
    entrypoint:
    - '/usr/bin/env'
    - 'PATH=/usr/local/bundle/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
  before_script:
    - apk add jq
  script:
    - inspec --chef-license=accept-silent
    - cd inspec
    - inspec exec redirectors -t "ssh://ubuntu@$(jq '.redirector_ips.value[0]' -r ../terraform/output.json)“-i ../terraform/keys/terraformkey
    - inspec exec redirectors -t "ssh://ubuntu@$(jq '.redirector_ips.value[1]' -r ../terraform/output.json)“-i ../terraform/keys/terraformkey

最后,一旦所有的事情都完成了,我们需要自己清理完成之后的环境:

cleanup:
  when: always
  image: 
    name: hashicorp/terraform:light
    entrypoint:
    - '/usr/bin/env'
    - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
  stage: cleanup
  script:
    - cd terraform
    - terraform init
    - terraform destroy --auto-approve

你可能会注意到这里的 when:always 语句。 这仅仅意味着即使前一个阶段失败了,这个阶段也将运行。 这使我们有机会清理分段环境,在测试失败的情况下,可以避免支付不必要的 AWS 费用。

当我们把 gitlab-ci.yml 文件放在一起后,我们会得到下面这样的文件:

image: docker:latest
services:
  - docker:dind
cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
  - terraform/.terraform
stages:
  - test
  - stage
  - provision
  - validate
  - cleanup
 
terraform_validate:
  image: 
    name: hashicorp/terraform:light
    entrypoint:
      - '/usr/bin/env'
      - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
  stage: test
  script:
    - cd terraform 
    - terraform init
    - terraform validate
molecule_tests:
  image: docker:latest
  stage: test
  before_script:
    - apk update && apk add --no-cache docker
      python3-dev py3-pip docker gcc git curl build-base
      autoconf automake py3-cryptography linux-headers
      musl-dev libffi-dev openssl-dev openssh
    - docker info
    - python3 --version
  script:
    - pip3 install ansible molecule docker
    - cd ansible/roles/ubuntu-nginx
    - molecule test
deploy_stage:
  image: 
    name: hashicorp/terraform:light
    entrypoint:
      - '/usr/bin/env'
      - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
  stage: stage
  script:
    - cd terraform
    - terraform init
    - terraform apply --auto-approve
    - terraform output --json > output.json
  artifacts:
    paths:
      - terraform/terraform.tfstate
      - terraform/output.json
    expire_in: 1 day
provision_stage:
  when: delayed
  start_in: 30 seconds
  image: 
    name: hashicorp/terraform:light
    entrypoint:
      - '/usr/bin/env'
      - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
  stage: provision
  before_script:
    - apk add ansible
    - wget https://github.com/adammck/terraform-inventory/releases/download/v0.9/terraform-inventory_0.9_linux_amd64.zip -O /tmp/terraform-inventory_0.9_linux_amd64.zip
    - unzip /tmp/terraform-inventory_0.9_linux_amd64.zip -d /usr/bin/; chmod 700 /usr/bin/terraform-inventory
  script:
    - cd terraform; terraform init; cd ..
    - cd ansible; chmod 600 .
    - chmod 600 ../terraform/keys/terraformkey
    - ANSIBLE_HOST_KEY_CHECKING=False TF_STATE=../terraform ansible-playbook --inventory-file=/usr/bin/terraform-inventory -u ubuntu --private-key ../terraform/keys/terraformkey site.yml
inspec_tests:
  stage: validate
  image: 
    name: chef/inspec:4.18.51
    entrypoint:
    - '/usr/bin/env'
    - 'PATH=/usr/local/bundle/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
  before_script:
    - apk add jq
  script:
    - inspec --chef-license=accept-silent
    - cd inspec
    - inspec exec test-aws -t aws:// 
    - inspec exec redirectors -t "ssh://ubuntu@$(jq '.redirector_ips.value[0]' -r ../terraform/output.json)“-i ../terraform/keys/terraformkey
    - inspec exec redirectors -t "ssh://ubuntu@$(jq '.redirector_ips.value[1]' -r ../terraform/output.json)“-i ../terraform/keys/terraformkey
    
cleanup_stage:
  when: always
  image: 
    name: hashicorp/terraform:light
    entrypoint:
    - '/usr/bin/env'
    - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
  stage: cleanup
  script:
    - cd terraform
    - terraform init
    - terraform destroy --auto-approve

一旦投入到我们的项目中,我们就可以看到我们现在拥有了可用的管道,它将在每次 push 时执行。 希望一切顺利,一旦有人对你的基础设施进行了 commit,你将会受到一个明确的指示,表明一切正常:

image.png

这就是我们如何使用测试和 CI 管道来保持我们的 RedTeam 基础设施处于良好状态的一个例子。 希望这篇文章的内容能够对你有所帮助,希望在不久的将来能有更多关于这个主题的文章。

本文翻译自:https://blog.xpnsec.com/testing-redteam-infra/如若转载,请注明原文地址:
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务