在Terraform中将多个AWS账户作为环境处理的最佳方法是什么?

时间:2018-07-20 22:18:58

标签: amazon-s3 terraform terraform-provider-aws

我们希望将每个terraform环境放在一个单独的AWS帐户中,这样可以避免意外地将其部署到生产中。如何做到最好?

2 个答案:

答案 0 :(得分:4)

我们假设一个帐户专用于生产,另一个帐户专用于Production,并且可能其他沙箱环境也具有唯一的帐户,也许基于每个管理员。另一种假设是,每个AWS账户中都有一个特定于您的环境的S3存储桶。另外,我们希望您的AWS账户凭证将通过〜/ .aws / credentials(或可能具有IAM角色)进行管理。

平台后端配置

有两种状态。对于主要状态,我们使用Partial Configuration的概念。我们无法通过模块或其他方式将变量传递到后端配置中,因为在确定变量之前先读取变量。

Terraform Config设置

这意味着我们声明缺少一些细节的后端,然后将它们作为terraform init的参数提供。初始化后,将对其进行设置,直到删除.terraform目录为止。

terraform {
  backend "s3" {
    encrypt = true
    key     = "name/function/terraform.tfstate"
  }
}

工作流程注意事项

我们只需要更改初始化方式即可。我们在-backend-config上使用terraform init自变量。这提供了配置的缺失部分。我正在~/.bash_profile中通过bash别名提供所有缺少的部分。

alias terrainit='terraform init \
-backend-config "bucket=s3-state-bucket-name" \ 
-backend-config "dynamodb_table=table-name" \
-backend-config "region=region-name"'

意外的错误配置结果

如果省略了必需的-backend-config自变量,则初始化将提示您输入它们。如果提供不正确,可能会由于权限原因而导致失败。另外,必须将远程状态配置为匹配,否则也会失败。为了部署到生产环境,在确定适当的帐户环境时必须发生多个错误。

Terraform远程状态

下一个问题是,远程状态也需要更改,并且无法通过从后端配置中提取配置来进行配置;但是,可以通过变量设置远程状态。

模块设置

为简化帐户切换,我们设置了一个非常简单的模块,该模块接收单个变量aws-account,并返回一堆输出,远程状态可以使用这些输出以适当的值。我们还可以包括环境/帐户特定的其他内容。该模块是一个简单的main.tf,其映射变量的键为aws-account,其值特定于该帐户。然后,我们有一堆输出,可以像这样简单地查找map变量。

variable "aws-region" {
  description = "aws region for the environment"
  type = "map"
  default = {
    Production  = "us-west-2"
    PP      = "us-east-2"
  }
}

output "aws-region" {
  description = “The aws region for the account 
  value = "${lookup(var.aws-region, var.aws-account, "invalid AWS account specified")}"
}

Terraform Config设置

首先,我们必须将aws-account传递给模块。这可能在main.tf的顶部附近。

module "environment" {
  source    = "./aws-account"
  aws-account = "${var.aws-account}"
}

然后将变量声明添加到您的variables.tf

variable "aws-account" {
  description = "The environment name used to identify appropriate AWS account resources used to configure remote states. Pre-Production should be identified by the string PP. Production should be identified by the string Production. Other values may be added for other accounts later."
}

现在,我们已经从模块输出了帐户特定的变量,可以将它们用在这样的远程状态声明中。

data "terraform_remote_state" "vpc" {
  backend = "s3"
  config {
    key = "name/vpc/terraform.tfstate"
    region = "${module.environment.aws-region}"
    bucket = "${module.environment.s3-state-bucket-name}"
  }
}

工作流程注意事项

如果在这样设置之后工作流没有任何变化,则无论何时执行计划/应用等,都将通过这样的提示提示用户提供aws-account变量的值。提示的内容是variables.tf中变量的描述。

$ terraform plan
var.aws-account
  The environment name used to identify appropriate AWS account
resources used to configure remote states. Pre-Production should be
identified by the string PP. Production should be identified by the
string Production. Other values may be added for other accounts later.

  Enter a value:

您可以通过在命令行上像这样提供变量来跳过提示

terraform plan -var="aws-account=PP"

意外的错误配置结果

如果未指定aws-account变量,则将请求它。如果提供了aws-account模块无法识别的无效值,它将多次返回错误,包括“指定的无效AWS帐户”字符串,因为这是查找的默认值。如果aws-account正确传递,但与terraform init中标识的值不匹配,则它将失败,因为所使用的aws凭证将无法访问所标识的S3存储桶。

答案 1 :(得分:3)

我们遇到了类似的问题,并且解决了(部分)在Jenkins或任何其他CI工具中创建管道的问题。

我们有3个不同的环境(dev,staging和prod)。相同的代码,不同的tfvar,不同的AWS帐户。

将terraform代码合并到master时,可以将其应用于登台,并且只有在登台为Green时,才可以执行生产。 没有人在产品中手动运行terraform,aws凭据存储在CI工具中。

此设置可以解决您所描述的事故,但也可以防止不同的用户应用不同的本地代码。