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

Jos*_*iah 5 amazon-s3 terraform terraform-provider-aws

我们希望将我们的每个 terraform 环境都放在一个单独的 AWS 账户中,以防止意外部署到生产中。这是如何最好地完成的?

Jos*_*iah 6

我们假设一个帐户专用于生产,另一个用于 PreProduction 和潜在的其他沙盒环境也有唯一的帐户,可能是在每个管理员的基础上。另一种假设是,您在每个 AWS 账户中都有一个特定于您的环境的 S3 存储桶。此外,我们希望您的 AWS 账户凭证在 ~/.aws/credentials(或可能具有 IAM 角色)中进行管理。

Terraform 后端配置

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

Terraform 配置设置

这意味着我们声明后端缺少一些细节,然后将它们作为参数提供给terraform init. 一旦初始化,它就会被设置,直到.terraform目录被删除。

terraform {
  backend "s3" {
    encrypt = true
    key     = "name/function/terraform.tfstate"
  }
}
Run Code Online (Sandbox Code Playgroud)

工作流注意事项

我们只需要改变我们的初始化方式。我们使用 上的-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"'
Run Code Online (Sandbox Code Playgroud)

意外的错误配置结果

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

Terraform 远程状态

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

模块设置

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

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")}"
}
Run Code Online (Sandbox Code Playgroud)

Terraform 配置设置

首先,我们必须将 aws-account 传递给模块。这可能会接近main.tf.

module "environment" {
  source    = "./aws-account"
  aws-account = "${var.aws-account}"
}
Run Code Online (Sandbox Code Playgroud)

然后将变量声明添加到您的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."
}
Run Code Online (Sandbox Code Playgroud)

现在我们有从模块输出的特定于帐户的变量,它们可以像这样在远程状态声明中使用。

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}"
  }
}
Run Code Online (Sandbox Code Playgroud)

工作流注意事项

如果这样设置后工作流没有任何变化,则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:
Run Code Online (Sandbox Code Playgroud)

您可以通过在命令行上提供变量来跳过提示,如下所示

terraform plan -var="aws-account=PP"
Run Code Online (Sandbox Code Playgroud)

意外的错误配置结果

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