Terraform如何添加到现有的AWS策略,或在需要时创建策略

32次阅读
没有评论

问题描述

在使用Terraform时,遇到了一个问题:他需要将多个Terraform根模块添加到一个现有的策略中,该策略为S3存储桶提供只读权限,每个模块都有自己的存储桶。用户无法确定如何将模块添加到现有策略中,并将新值(新存储桶)合并到策略中。

在最初的尝试中,用户只是将一个新的策略附加到角色上(实际上有三个策略,一个用于开发、一个用于演练、一个用于生产)。但他们只能附加最多20个策略。因此,用户使用了AWS命令行界面(AWS CLI),将所有生产存储桶列在一个策略中,演练和开发也是如此。这一步已经很成功。

现在,用户希望通过Terraform实现相同的目标。他已经创建了一个子模块,根模块可以调用该子模块,并传递他们的存储桶信息。用户使用了如下所示的Terraform代码定义了新的策略:

data "aws_iam_policy_document" "read_only" {
  statement {
    actions   = [
      "s3:ListBucket",
      "s3:GetObject",
      "s3:GetBucketLocation",
    ]
    effect    = "Allow"
    resources = [
      "${var.bucket_arn}/*",
      var.bucket_arn,
    ]
  }
}

他还可以通过以下代码查找现有策略:

data "aws_iam_policy" "existing" {
  name = "read-only-s3-${terraform.workspace}"
}

并使用以下代码合并新策略和现有策略:

data "aws_iam_policy_document" "merged" {
  source_json = [
    data.aws_iam_policy_document.read_only.json,
    data.aws_iam_policy.existing.json
  ]
}

然后,用户尝试创建资源:

resource "aws_iam_policy" "read_only_policy" {
  name        = "read-only-s3-${terraform.workspace}"
  path        = "/"
  policy = data.aws_iam_policy_document.merged.json
}

但是,如果没有data.aws_iam_policy.existing,AWS无法找到现有策略,Terraform将抛出错误。

虽然关于如何合并策略有很多文档,但关于如何确定是否存在现有策略的方法却很少。用户可以重新创建整个策略,如果他能找到现有的策略并将其与新策略合并,或者仅仅知道现有策略中存储桶的名称,那将是理想的。但是现有的策略是在其他根模块中创建的,而且没有办法通过名称以外的方式查找存储桶(没有tags或在data "aws_s3_bucket"上的filter)。

用户想知道是否有一种方法可以确定是否存在现有策略,而不会抛出错误?然后他可以获取其策略文档并使用source_json方法。用户是否可以将新的策略文档合并到现有的文档中(无论存在与否)?用户对其他方法也持开放态度,但是他真的希望将其保留在IAM中,而不是使用存储桶策略,因为后者过于不透明和分散。

解决方案

请注意以下操作注意版本差异及修改前做好备份。

方法1:使用外部数据源检查策略是否存在

在Terraform中,可以使用外部数据源来检查策略是否存在。以下是一个示例,演示如何使用外部数据源来实现这个目标。

  1. 首先,创建一个外部数据源,用于检查策略是否存在。在Terraform配置文件中添加以下内容:
data "external" "iam-policy-exists" {
  program = ["bash", "${path.module}/iam-policy-exists.sh"]
  query = {
    policy = "read-only-s3-${terraform.workspace}"
  }
}
  1. 创建一个bash脚本,用于检查IAM策略是否存在。在与Terraform配置文件相同的目录下创建一个名为iam-policy-exists.sh的文件,并将以下内容添加到该文件:
#!/bin/bash
aws iam get-policy --policy-arn arn:aws:iam::ACCOUNT_ID:policy/read-only-s3-${1}
# 如果策略存在,返回状态码0,否则返回非零状态码
if [ $? -eq 0 ]; then
  echo '{"exists":"yes"}'
else
  echo '{"exists":"nope"}'
fi

请将ACCOUNT_ID替换为您的AWS帐户ID。

  1. 现在,在Terraform中使用data "aws_iam_policy"来检查策略是否存在,并根据结果来决定是否创建新策略。在Terraform配置文件中添加以下内容:
data "aws_iam_policy" "existing" {
  count = data.external.iam-policy-exists.exists == "yes" ? 1 : 0
  name  = "read-only-s3-${terraform.workspace}"
}

resource "aws_iam_policy" "read_only_policy" {
  count = data.external.iam-policy-exists.exists == "nope" ? 1 : 0
  name  = "read-only-s3-${terraform.workspace}"
  path  = "/"
  policy = data.aws_iam_policy_document.merged.json
}
  1. (可选) 如果您想要获取合并策略的JSON表示,可以使用locals块将结果保存到本地。在Terraform配置文件中添加以下内容:

“`hcl
locals

正文完