使用terraform初始设置terraform后端

Jed*_*der 36 amazon-s3 terraform

我刚刚开始使用terraform,我希望能够使用AWS S3作为我的后端来存储我的项目状态.

terraform {
    backend "s3" {
      bucket = "tfstate"
      key = "app-state"
      region = "us-east-1"
    }
}
Run Code Online (Sandbox Code Playgroud)

我觉得使用terraform为后端存储基础架构设置我的S3存储桶,IAM组和策略是明智的.

如果我在应用初始terraform基础设施之前设置后端状态,则会合理地抱怨后端存储桶尚未创建.所以,我的问题是,如何设置我的terraform后端与terraform,同时保持我的状态为terraform追踪的后端.看起来像一个嵌套的玩偶问题.

我对如何编写脚本有一些想法,例如,检查存储桶是否存在或是否已设置某个状态,然后引导terraform,最后在第一次运行后将terraform tfstate从本地文件系统复制到s3.但在走下这条艰难的道路之前,我想我会确保自己没有遗漏一些明显的东西.

Aus*_*vis 40

要使用terraform远程状态进行设置,我通常remote-state在dev和prod terraform文件夹中有一个单独的文件夹.

以下main.tf文件将为您发布的内容设置远程状态:

provider "aws" {
  region = "us-east-1"
}

resource "aws_s3_bucket" "terraform_state" {
  bucket = "tfstate"

  versioning {
    enabled = true
  }

  lifecycle {
    prevent_destroy = true
  }
}

resource "aws_dynamodb_table" "terraform_state_lock" {
  name           = "app-state"
  read_capacity  = 1
  write_capacity = 1
  hash_key       = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}
Run Code Online (Sandbox Code Playgroud)

然后使用cd remote-state,运行进入此文件夹terraform init && terraform apply- 这应该只需要运行一次.您可以添加一些内容到bucket和dynamodb表名来分隔您的不同环境.

  • 很棒的答案.任何阅读"Terraform Up and Running"并且陷入第3章后端(使用较旧版本的terreform)的人都是解决方案. (4认同)
  • 啊——我想通了。这是因为内置的 s3 后端支持使用 dynamodb_table 参数通过 dynamodb 表进行锁定:https://www.terraform.io/docs/backends/types/s3.html#dynamodb_table (2认同)
  • 我仍然无法完全理解答案。当我们执行“ cd remote-state”并运行“ terraform apply”-terraform.state时,该基础设施仍在本地保存(未配置后端),对吗?这如何解决鸡肉/鸡蛋问题?此状态文件现在也受Terraform管理吗? (2认同)

Mat*_*vin 13

在奥斯汀戴维斯的巨大贡献的基础上,我使用的变体包括数据加密的要求:

provider "aws" {
  region = "us-east-1"
}

resource "aws_s3_bucket" "terraform_state" {
  bucket = "tfstate"

  versioning {
    enabled = true
  }

  lifecycle {
    prevent_destroy = true
  }
}

resource "aws_dynamodb_table" "terraform_state_lock" {
  name           = "app-state"
  read_capacity  = 1
  write_capacity = 1
  hash_key       = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

resource "aws_s3_bucket_policy" "terraform_state" {
  bucket = "${aws_s3_bucket.terraform_state.id}"
  policy =<<EOF
{
  "Version": "2012-10-17",
  "Id": "RequireEncryption",
   "Statement": [
    {
      "Sid": "RequireEncryptedTransport",
      "Effect": "Deny",
      "Action": ["s3:*"],
      "Resource": ["arn:aws:s3:::${aws_s3_bucket.terraform_state.bucket}/*"],
      "Condition": {
        "Bool": {
          "aws:SecureTransport": "false"
        }
      },
      "Principal": "*"
    },
    {
      "Sid": "RequireEncryptedStorage",
      "Effect": "Deny",
      "Action": ["s3:PutObject"],
      "Resource": ["arn:aws:s3:::${aws_s3_bucket.terraform_state.bucket}/*"],
      "Condition": {
        "StringNotEquals": {
          "s3:x-amz-server-side-encryption": "AES256"
        }
      },
      "Principal": "*"
    }
  ]
}
EOF
}
Run Code Online (Sandbox Code Playgroud)


sam*_*tav 11

我创建了一个带有一些引导命令/说明的 terraform 模块来解决这个问题:

https://github.com/samstav/terraform-aws-backend

README 中有详细说明,但要点是:

# conf.tf

module "backend" {
  source         = "github.com/samstav/terraform-aws-backend"
  backend_bucket = "terraform-state-bucket"
}
Run Code Online (Sandbox Code Playgroud)

然后,在你的 shell 中(确保你还没有写你的terraform {}块):

terraform get -update
terraform init -backend=false
terraform plan -out=backend.plan -target=module.backend
terraform apply backend.plan
Run Code Online (Sandbox Code Playgroud)

现在写你的terraform {}块:

# conf.tf

terraform {
  backend "s3" {
    bucket         = "terraform-state-bucket"
    key            = "states/terraform.tfstate"
    dynamodb_table = "terraform-lock"
  }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以重新初始化:

terraform init -reconfigure
Run Code Online (Sandbox Code Playgroud)


djt*_*djt 9

正如您所发现的那样,您不能首先使用terraform来构建组件所需的组件.

虽然我理解让terraform"追踪一切"的倾向,但这是非常困难的,而且比它的价值更令人头痛.

我通常通过创建一个简单的bootstrap shell脚本来处理这种情况.它创造了以下内容:

  1. 用于状态存储的s3存储桶
  2. 向所述存储桶添加版本控制
  3. 具有某些策略的terraform IAM用户和组,我将需要用于terraform构建

虽然你应该只需要运行一次(技术上),但我发现当我开发一个新系统时,我会反复旋转并撕下来.因此,在一个脚本中使用这些步骤可以使这更简单.

我通常将脚本构建为幂等的.这样,您可以多次运行它,而无需担心您正在创建重复的存储桶,用户等

  • 实际上,您可以使用 Terraform 构建远程状态组件(S3 存储桶和 DynamoDB 表)——只需使用单独的子文件夹来构建这些组件,该文件夹具有自己的(本地)Terraform 状态文件。请参阅[此答案](/sf/answers/3385363901/)。 (5认同)

hyp*_*erd 9

利用 AWS s3 存储桶设置 Terraform 后端相对容易。

\n\n

首先,在您选择的区域(例如 eu-west-1)创建一个存储桶,命名为terraform-b​​ackend-store(记住选择一个唯一的名称。)

\n\n

为此,请打开终端并运行以下命令,假设您已正确设置 AWS CLI(否则,请按照官方文档中的说明进行操作):

\n\n
aws s3api create-bucket --bucket terraform-backend-store \\\n    --region eu-west-1 \\\n    --create-bucket-configuration \\\n    LocationConstraint=eu-west-1\n# Output:\n{\n    "Location": "http://terraform-backend-store.s3.amazonaws.com/"\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

该命令应该是不言自明的;要了解更多信息,请查看此处的文档。

\n\n

存储桶就位后,需要进行适当的配置以确保安全性和可靠性。\n对于保存 Terraform 状态的存储桶,\xe2\x80\x99 是启用服务器端加密的常识。为了简单起见,首先尝试AES256方法(尽管我建议使用KMS并实现适当的密钥轮换):

\n\n
aws s3api put-bucket-encryption \\\n    --bucket terraform-backend-store \\\n    --server-side-encryption-configuration={\\"Rules\\":[{\\"ApplyServerSideEncryptionByDefault\\":{\\"SSEAlgorithm\\":\\"AES256\\"}}]}\n# Output: expect none when the command is executed successfully\n
Run Code Online (Sandbox Code Playgroud)\n\n

接下来,\xe2\x80\x99 是限制对存储桶的访问的关键;创建一个非特权 IAM 用户,如下所示:

\n\n
aws iam create-user --user-name terraform-deployer\n# Output:\n{\n    "User": {\n        "UserName": "terraform-deployer",\n        "Path": "/",\n        "CreateDate": "2019-01-27T03:20:41.270Z",\n        "UserId": "AIDAIOSFODNN7EXAMPLE",\n        "Arn": "arn:aws:iam::123456789012:user/terraform-deployer"\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

记下命令\xe2\x80\x99s 输出中的 Arn(如下所示:\xe2\x80\x9cArn\xe2\x80\x9d:\xe2\x80\x9carn:aws:iam::123456789012:user/terraform -部署\xe2\x80\x9d)。

\n\n

为了在稍后阶段与 s3 服务和 DynamoDB 正确交互以实现锁定,我们的 IAM 用户必须拥有足够的权限集。\n建议对生产环境实施严格的限制,但为了简单起见,请开始分配AmazonS3FullAccessAmazonDynamoDBFullAccess

\n\n
aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess --user-name terraform-deployer\n# Output: expect none when the command execution is successful\n\naws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess --user-name terraform-deployer\n# Output: expect none when the command execution is successful\n
Run Code Online (Sandbox Code Playgroud)\n\n

必须启用新创建的 IAM 用户才能对您的 s3 存储桶执行所需的操作。您可以通过创建并应用正确的策略来做到这一点,如下所示:

\n\n
cat <<-EOF >> policy.json\n{\n    "Statement": [\n        {\n            "Effect": "Allow",\n            "Principal": {\n                "AWS": "arn:aws:iam::123456789012:user/terraform-deployer"\n            },\n            "Action": "s3:*",\n            "Resource": "arn:aws:s3:::terraform-remote-store"\n        }\n    ]\n}\nEOF\n
Run Code Online (Sandbox Code Playgroud)\n\n

此基本策略文件向委托人授予 arn \xe2\x80\x9carn:aws:iam::123456789012:user/terraform-deployer\xe2\x80\x9d 的权限,以执行所有可用操作 (\xe2\x80\x9cAction\xe2 \x80\x9d: \xe2\x80\x9cs3:*") 针对带有 arn \xe2\x80\x9carn:aws:s3:::terraform-remote-store\xe2\x80\x9d 的存储桶。\n再次,在生产中希望强制执行更严格的策略。作为参考,请查看AWS 策略生成器

\n\n

返回终端并运行如下所示的命令,以在您的存储桶中强制执行该策略:

\n\n
aws s3api put-bucket-policy --bucket terraform-remote-store --policy file://policy.json\n# Output: none\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后一步,启用存储桶\xe2\x80\x99s 版本控制:

\n\n
aws s3api put-bucket-versioning --bucket terraform-remote-store --versioning-configuration Status=Enabled\n
Run Code Online (Sandbox Code Playgroud)\n\n

它允许保存不同版本的基础设施\xe2\x80\x99s 状态并轻松回滚到前一阶段,而无需费力。

\n\n

AWS s3 存储桶已准备就绪,是时候将其与 Terraform 集成了。下面列出了设置此远程后端所需的最低配置:

\n\n
# terraform.tf\n\nprovider "aws" {\n  region                  = "${var.aws_region}"\n  shared_credentials_file = "~/.aws/credentials"\n  profile                 = "default"\n}\n\nterraform {  \n    backend "s3" {\n        bucket  = "terraform-remote-store"\n        encrypt = true\n        key     = "terraform.tfstate"    \n        region  = "eu-west-1"  \n    }\n}\n\n# the rest of your configuration and resources to deploy\n
Run Code Online (Sandbox Code Playgroud)\n\n

就位后,必须(再次)初始化 terraform。\n terraform init\n远程后端已准备好运行,请对其进行测试。

\n\n

锁定怎么样?\n远程存储状态会带来陷阱,尤其是在多个任务、作业和团队成员可以访问它的情况下工作时。在这些情况下,多次并发尝试更改状态的风险很高。这里来帮助锁定,这是一种防止打开已在使用的状态文件的功能。

\n\n

您可以通过创建AWS DynamoDB 表来实现锁定,terraform 使用该表来设置和取消设置锁定。\n使用 terraform 本身配置资源:

\n\n
# create-dynamodb-lock-table.tf\nresource "aws_dynamodb_table" "dynamodb-terraform-state-lock" {\n  name           = "terraform-state-lock-dynamo"\n  hash_key       = "LockID"\n  read_capacity  = 20\n  write_capacity = 20\nattribute {\n    name = "LockID"\n    type = "S"\n  }\ntags {\n    Name = "DynamoDB Terraform State Lock Table"\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

并按如下所示部署它:\nterraform plan -out "planfile" && terraform apply -input=false -auto-approve "planfile"

\n\n

命令执行完成后,必须将锁定机制添加到后端配置中,如下所示:

\n\n
# terraform.tf\n\nprovider "aws" {\n  region                  = "${var.aws_region}"\n  shared_credentials_file = "~/.aws/credentials"\n  profile                 = "default"\n}\n\nterraform {  \n    backend "s3" {\n        bucket         = "terraform-remote-store"\n        encrypt        = true\n        key            = "terraform.tfstate"    \n        region         = "eu-west-1"\n        dynamodb_table = "terraform-state-lock-dynamo"\n    }\n}\n\n# the rest of your configuration and resources to deploy\n
Run Code Online (Sandbox Code Playgroud)\n\n

全做完了。请记住再次运行terraform init并享受您的远程后端。

\n


小智 8

我通常做的是在没有远程后端的情况下开始创建初始基础设施(如您所说)、S3、IAM 角色和其他重要内容。一旦完成,我只需添加后端配置并运行 terraform init 即可迁移到 S3。

这不是最好的情况,但在大多数情况下,我不会每天重建整个环境,因此这种半自动化方法已经足够好了。我还将基础设施的下一个“层”(VPC、子网、IGW、NAT 等)分为不同的状态。


Ana*_*han 5

我一直在解决这个问题,您可以注释掉初始运行的“后端”块,并仅将选定的 terraform 应用到状态存储桶和任何相关资源(例如存储桶策略)。

#  backend "s3" {
#    bucket         = "foo-bar-state-bucket"
#    key            = "core-terraform.tfstate"
#    region         = "eu-west-1"
#  }
#}
provider "aws" {
    region = "eu-west-1"
    profile = "terraform-iam-user"
    shared_credentials_file = "~/.aws/credentials"
  }
Run Code Online (Sandbox Code Playgroud)
terraform apply --target aws_s3_bucket.foobar-terraform --target aws_s3_bucket_policy.foobar-terraform
Run Code Online (Sandbox Code Playgroud)

这将配置您的 s3 状态存储桶,并将 .tfstate 文件本地存储在您的工作目录中。

稍后,取消注释“后端”块并重新配置后端 ,这将提示您将本地存在的 .tfstate 文件(跟踪后端 s3 存储桶的状态terraform init --reconfigure) 复制到远程后端,该后端现在可供 terraform 用于任何后续运行。

提示将现有状态复制到远程后端