Terraform,Mono存储库和合规性作为代码

大家好。OTUS在“基于Kubernetes的基础架构平台”课程中为一个新团队开放了招聘,与此相关的是,我们准备了关于该主题的有趣材料的翻译。




您可能是将terraform用于基础结构作为代码的人之一,并且您想知道如何更高效,更安全地使用它。总的来说,最近,这困扰了许多人。我们所有人都使用不同的工具,语言编写配置和代码,并花费大量时间使其更具可读性,可扩展性和可伸缩性。


也许问题出在我们自己身上?

书面代码应能创造价值或解决问题,并可重复使用以进行重复数据删除。通常,这种讨论以“让我们使用模块”结尾。我们都使用terraform模块,对不对?由于过多的模块化,我可能会写很多有问题的故事,但这是完全不同的故事,我不会。


不我不会。不要坚持,不。好吧,也许以后。

有一种众所周知的做法-在使用模块锁定根模块时标记代码,以便即使更改模块代码也能保证其运行。这种方法应成为团队原则,在其中适当地标记和适当地使用适当的模块。

...但是依赖项呢?如果我120个不同的存储库中120个模块,并且更改一个模块会影响其他20 模块,该怎么办。这是否意味着我们需要执行20 + 1拉取请求?如果审核者的最少人数为2,则意味着21 x 2 = 44评论。认真!我们只需通过“更改一个模块”使命令瘫痪,每个人都将开始发送《指环王》的模因或gif,而一天中的其余时间将丢失。


一个PR通知每个人,一个PR召集每个人,sha铐并陷入黑暗

,工作值得吗?我们应该减少评论者的数量吗?或者,如果更改有很大的影响,则可以将模块作为例外,而无需PR。真?您想在一片黑暗的黑暗森林中盲目行走吗?还是将他们聚在一起,感到无聊而陷入黑暗

不,请不要更改评论的顺序。如果您认为与PR合作是正确的,那么请坚持下去。如果您拥有智能管道或将其推向高手,那么请继续使用此方法。

在这种情况下,问题不是“您如何工作”,而是“ git存储库的结构是什么”



这与我最初应用以下建议时的感觉类似,

让我们回到基础知识。具有terraform模块的存储库的一般要求是什么?

  1. 必须对其进行标记,以便没有重大更改。
  2. 任何更改都应该能够测试。
  3. 变更必须经过相互审查。

然后,我提出以下建议- 不要将 微型存储库用于terraform模块。使用一个单存储库

  • 有变更/要求时,您可以标记整个存储库
  • 可以测试任何更改,PR或推送。
  • 任何更改都可以通过审核。


我有力量!

好的,但是此存储库的结构是什么?在过去的四年中,我与此相关的失败很多,我得出的结论是,将模块放在单独的目录中将是最佳解决方案。


Mono存储库的示例目录结构。看到tags_override变更了吗?

因此,影响其他20个模块的模块更改仅为1 PR!即使您在此PR中添加了5位审阅者,与微型存储库相比,审阅也非常快。如果您使用Github,那就更好了!您可以将CODEOWNERS用于具有维护者/所有者的模块,并且对这些模块的任何更改都必须得到该所有者的批准。

很好,但是如何使用位于mono-repository目录中的模块?

简单:

module "from_mono_repo" {
 source = "git::ssh://.../<org>/<repo>.git//<my_module_dir>"
 ...
}
module "from_mono_repo_with_tags" {
  source = "git::ssh://..../<org>/<repo>.git//<mod_dir>?ref=1.2.4"
  ...
}
module "from_micro_repo" {
  source = "git::ssh://.../<org>/<mod_repo>.git"
  ...
}
module "from_micro_repo_with_tags" {
  source = "git::ssh://.../<org>/<mod_repo>.git?ref=1.2.4"
  ...
}

这种结构的缺点是什么?好吧,如果您尝试使用PR / change测试“每个模块”,那么您可以获得1.5个小时的CI管道。您需要在PR中找到修改后的模块。我这样做是这样的:

changed_modules=$(git diff --name-only $(git rev-parse origin/master) HEAD | cut -d "/" -f1 | grep ^aws- | uniq)

还有一个缺点:每当您运行“ terraform init”时,它将整个存储库加载到.terraform目录中。但是我从来没有遇到过问题,因为我在可伸缩的AWS CodeBuild容器中运行管道。如果您使用詹金斯和持久詹金斯奴隶,那么您可能会遇到此问题。


不要让我们哭泣。

使用单一存储库,您仍然拥有微型存储库的所有优点,但是作为一项奖励,您可以减少维护模块的成本。

老实说,以这种方式工作之后,将微型存储库用于terraform模块的建议应视为犯罪。

太好了,单元测试呢?你真的需要这个吗? ...一般来说,单元测试到底是什么意思。您是否真的要检查AWS资源是否正确创建?这是谁的责任:terraform或处理资源创建的API?也许我们应该更多地关注代码的负面测试和幂等性

为了检查代码的幂等性,terraform提供了一个出色的参数,称为-detailed-exitcode。赶紧跑:

> terraform plan -detailed-exitcode

之后,运行即可terraform apply。至少您将确保您的代码是幂等的,并且不会由于随机字符串或其他原因而创建新资源。

负面测试呢?一般而言,负面测试是什么?实际上,这与单元测试没有太大区别,但是您要注意负面情况。

例如,不允许任何人创建未加密的公共S3存储桶

因此,实际上,您不是基于一组策略,而是检查代码是否创建了资源,而不是检查是否实际上在创建S3存储桶。怎么做? Terraform Enterprise为此提供了一个很好的工具Sentinel

...但是也有开源替代方案。当前,有许多用于静态分析HCL代码的工具。这些工具基于通用的最佳实践,将不允许您做任何不需要的事情,但是如果它没有您需要的测试……或者,如果您的情况略有不同,则更糟。例如,您希望允许根据某些条件将某些S3存储桶公开,实际上,这将是这些工具的安全漏洞。

这是出现符合地形的地方该工具不仅允许您编写自己的测试,可以在其中确定所需的内容作为公司的策略,还可以通过将安全性向左移动来帮助您将安全性与开发分开。听起来很有争议,对吧?没有。怎么了


Terraform-compliance徽标

首先,terraform-compliance使用行为驱动开发(BDD)。

Feature: Ensure that we have encryption everywhere.

    Scenario: Reject if an S3 bucket is not encrypted
        Given I have aws_s3_bucket defined
        Then it must contain server_side_encryption_configuration

检查是否启用了加密,

如果这还不够,您可以编写更详细的信息:

Feature: Ensure that we have encryption everywhere.

    Scenario: Reject if an S3 bucket is not encrypted with KMS
        Given I have aws_s3_bucket defined
        Then it must contain server_side_encryption_configuration
        And it must contain rule
        And it must contain apply_server_side_encryption_by_default
        And it must contain sse_algorithm
        And its value must match the "aws:kms" regex

我们会更深入地验证KMS是否用于加密

,该测试的terraform代码:

resource "aws_kms_key" "mykey" {
 description             = "This key is used to encrypt bucket objects"
 deletion_window_in_days = 10
}

resource "aws_s3_bucket" "mybucket" {
 bucket = "mybucket"

 server_side_encryption_configuration {
   rule {
     apply_server_side_encryption_by_default {
       kms_master_key_id = "${aws_kms_key.mykey.arn}"
       sse_algorithm     = "aws:kms"
     }
   }
 }
}

因此,组织中的所有内容都能真正理解测试。在这里,您可以将这些测试的编写委托给安全服务或具有足够的安全知识的开发人员。该工具还允许您将BDD文件存储在另一个存储库中。当代码更改和与代码关联的安全策略更改将是两个不同的实体时,这将有助于区分责任。这些可以是具有不同生命周期的不同团队。对不对?好吧,至少对我而言。

有关terraform-compliance的更多信息请参见此演示文稿

我们解决了符合Terraform的许多问题,尤其是在安全服务与开发团队相距甚远且可能不了解开发人员正在做什么的情况下。您已经猜到了此类组织中正在发生什么。通常,安全服务开始阻止对它们可疑的一切,并基于外围安全性构建安全系统。哦,上帝...

在许多情况下,仅对设计(或/和陪同)基础架构的团队使用terraformterraform-compliance有助于将这两个不同的团队放在同一张桌子上。当您的安全团队开始从所有开发管道中获得即时反馈来开发某些东西时,他们通常会动力更大。好吧,通常...

因此,在使用terraform时,我们按以下方式构建git存储库:



当然,这非常自大。但是我很幸运(或者不是很幸运?)可以在几个组织中使用更详细的结构。不幸的是,所有这些并没有很好地结束。幸福的结局应该隐藏在数字3中。

如果您有微型存储库的成功案例,请告诉我,我真的很感兴趣!



我们邀请您参加免费的课程,在其中我们将考虑未来基础架构平台的组件,并了解如何正确交付我们的应用程序

All Articles