Amazon web services 从帐号的JSON数组构建AWS IAM策略

Amazon web services 从帐号的JSON数组构建AWS IAM策略,amazon-web-services,terraform,amazon-iam,terraform-provider-aws,Amazon Web Services,Terraform,Amazon Iam,Terraform Provider Aws,我有一个AWS帐号列表,我想动态使用它来构建AWS策略。以下是我的例子: resource "aws_s3_bucket" "splunk-config-bucket" { bucket = "${var.config_bucket_name}" force_destroy = true server_side_encryption_configuration { rule { apply_server_side_encryption_by_defa

我有一个AWS帐号列表,我想动态使用它来构建AWS策略。以下是我的例子:

resource "aws_s3_bucket" "splunk-config-bucket" {
  bucket        = "${var.config_bucket_name}"
  force_destroy = true
  server_side_encryption_configuration {
    rule {
      apply_server_side_encryption_by_default {
        kms_master_key_id = "${data.aws_kms_alias.kms_name.arn}"
        sse_algorithm     = "aws:kms"
      }
    }
  }
  tags = {
    Product = "Splunk - AWS Config Logs"
    Service = "Security"
  }

 lifecycle_rule {
    id      = "log"
    enabled = true

    prefix = "*"

    transition {
      days          = 7
      storage_class = "GLACIER"
    }

    expiration {
      days = 14
    }
  }

  policy = <<POLICY
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AWSConfigAclCheck20150319",
            "Effect": "Allow",
            "Principal": {
                "Service": "config.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::${var.config_bucket_name}"
        },
        {
            "Sid": "AWSConfigWrite20150319",
            "Effect": "Allow",
            "Principal": {
                "Service": "config.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": [
                "arn:aws:s3:::${var.config_bucket_name}/AWSLogs/123456789/*”,
                "arn:aws:s3:::${var.config_bucket_name}/AWSLogs/123456789/*",
                "arn:aws:s3:::${var.config_bucket_name}/AWSLogs/123456789/*",
                "arn:aws:s3:::${var.config_bucket_name}/AWSLogs/123456789/*",
                "arn:aws:s3:::${var.config_bucket_name}/AWSLogs/123456789/*",
                "arn:aws:s3:::${var.config_bucket_name}/AWSLogs/123456789/*",
                "arn:aws:s3:::${var.config_bucket_name}/AWSLogs/123456789/*",
                "arn:aws:s3:::${var.config_bucket_name}/AWSLogs/123456789/*",
                "arn:aws:s3:::${var.config_bucket_name}/AWSLogs/123456789/*",
                "arn:aws:s3:::${var.config_bucket_name}/AWSLogs/123456789/*"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
            }
        }
    ]
}
POLICY
}

resource "aws_s3_bucket_notification" "configlogs_bucketnotification" {
  bucket = "${var.config_bucket_name}"

  queue {
    queue_arn     = "${aws_sqs_queue.splunk_configlogs_sqs_queue.arn}"
    events        = ["s3:ObjectCreated:*"]
  }
}
我正在尝试使用AWS帐号的动态列表生成策略。我们正试图摆脱硬编码账号,并将其从一个“集中配置”项目中提取出来

以下是我尝试过的:

变量.tf:

locals {
    accounts = jsondecode(file("../configuration/envs.json")).accounts
}
Config.tf

            "Principal": {
                "Service": "config.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": ${jsonencode(formatlist("arn:aws:s3:::${var.config_bucket_name}/AWSLogs/%s/*", local.accounts))}
            "Condition": {
当我运行“terraform plan”时,这为我提供了以下输出:

我也试过:

变量.tf

locals {
  accounts = jsondecode(file("../configuration/envs.json")).accounts
}

output "example" {
  value = jsonencode(formatlist("arn:aws:s3:::${var.config_bucket_name}/AWS/AWSLogs/%s/*", local.accounts))
}
config.tf

            "Principal": {
                "Service": "config.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": ${local.accounts.output.value}
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
这是我得到的输出:

Error: Unsupported attribute

  on central_config.tf line 60, in resource "aws_s3_bucket" "splunk-config-bucket":
  60:             "Resource": ${local.accounts.output.value}
    |----------------
    | local.accounts is tuple with 35 elements

This value does not have any attributes.

谢谢,

您可以在代码中重新加载动态配置,在配置文件更改时更新帐户列表并调用S3API

为了查看配置文件(帐户列表),您可以使用一些库。我相信“毒蛇”是个不错的选择

而且,如果您担心由于API调用失败或应用程序崩溃而丢失文件中的此类事件,您可以尝试将更新操作列表设为幂等项,并在应用程序启动时或在一段时间间隔内进行更新

这些链接可能会出现:

关于幂等性:


Viper:

您可以使用加载文件,然后通过使用解码JSON,然后选择
accounts
键来提取所需的帐户列表

例如:

locals {
  accounts = jsondecode(file("accounts.json")).accounts
}

output example {
  value = local.accounts
}
这将返回以下内容:

example = [
  "1234567890",
  "0987654321",
  "1029384756",
  "6574839201",
  "0192837465",
]
如果要将其放入策略中,则需要使用将帐户列表传递为单个字符串格式:

output "example" {
  value = formatlist("arn:aws:s3:::bucket_name/AWSLogs/%s/*", local.accounts)
}
这将产生:

example = [
  "arn:aws:s3:::bucket_name/AWSLogs/1234567890/*",
  "arn:aws:s3:::bucket_name/AWSLogs/0987654321/*",
  "arn:aws:s3:::bucket_name/AWSLogs/1029384756/*",
  "arn:aws:s3:::bucket_name/AWSLogs/6574839201/*",
  "arn:aws:s3:::bucket_name/AWSLogs/0192837465/*",
]
但如果您仔细注意,Terraform在列表中使用尾随逗号,这是无效的JSON,因此会为您的IAM策略创建无效的JSON结构。为了解决这个问题,我们可以使用以下代码将其重新编码为JSON:

然后输出:

example = ["arn:aws:s3:::bucket_name/AWSLogs/1234567890/*","arn:aws:s3:::bucket_name/AWSLogs/0987654321/*","arn:aws:s3:::bucket_name/AWSLogs/1029384756/*","arn:aws:s3:::bucket_name/AWSLogs/6574839201/*","arn:aws:s3:::bucket_name/AWSLogs/0192837465/*"]
不带尾随逗号

总而言之,您可以创建如下IAM策略:

{
    "accounts": [
        "1234567890",
        "0987654321",
        "1029384756",
        "6574839201",
        "0192837465"
    ]
}
locals {
  accounts = jsondecode(file("accounts.json")).accounts
}

resource aws_iam_policy policy {
  name        = "example"
  path        = "/"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": ${jsonencode(formatlist("arn:aws:s3:::bucket_name/AWSLogs/%s/*", local.accounts))}
    }
  ]
}
EOF
}
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "AWSConfigAclCheck20150319"
        Effect = "Allow"
        Principal = {
          Service = "config.amazonaws.com"
        }
        Action   = "s3:GetBucketAcl"
        Resource = "arn:aws:s3:::${var.config_bucket_name}"
      },
      # etc, etc
    ]
  })
本地人{
accounts=jsondecode(文件(“accounts.json”)).accounts
}
资源aws_iam_策略{
name=“示例”
path=“/”

policy=在ydaetskcoR的帮助下,我成功地实现了这一点:

这是我的变量文件:

locals {
  accounts = jsondecode(file("../configuration/envs.json")).accounts
  config = jsonencode(formatlist("arn:aws:s3:::${var.config_bucket_name}/AWSLogs/%s/*", local.accounts))
}
我可以使用Terraform控制台测试输出:

> jsonencode(formatlist("arn:aws:s3:::${var.config_bucket_name}/AWSLogs/%s/*", local.accounts))
["arn:aws:s3:::bby-central-configlogs-splunk/AWSLogs/123456789/*","arn:aws:s3:::bby-central-configlogs-splunk/AWSLogs/123456789/*"]
如您所见,它们周围有[]: 我将以下内容纳入我的政策:

            "Principal": {
                "Service": "config.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": ${local.config},
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }

我想我会给出我的答案:)

使用字符串模板正确地编码JSON可能会令人沮丧。除非有充分的理由以特定的方式格式化JSON,否则我们可以通过直接构建所需的数据结构,然后将其传递给
jsonencode
来避免对JSON进行模板化,如下所示:

{
    "accounts": [
        "1234567890",
        "0987654321",
        "1029384756",
        "6574839201",
        "0192837465"
    ]
}
locals {
  accounts = jsondecode(file("accounts.json")).accounts
}

resource aws_iam_policy policy {
  name        = "example"
  path        = "/"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": ${jsonencode(formatlist("arn:aws:s3:::bucket_name/AWSLogs/%s/*", local.accounts))}
    }
  ]
}
EOF
}
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "AWSConfigAclCheck20150319"
        Effect = "Allow"
        Principal = {
          Service = "config.amazonaws.com"
        }
        Action   = "s3:GetBucketAcl"
        Resource = "arn:aws:s3:::${var.config_bucket_name}"
      },
      # etc, etc
    ]
  })
然后,您可以直接使用Terraform的运算符和函数来构造该对象的部分。例如,要生成所需的ARN列表:

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      # ...
      {
        Sid    = "AWSConfigWrite20150319"
        Effect = "Allow"
        Principal = {
          Service = "config.amazonaws.com"
        }
        Action   = "s3:PutObject"
        Resource = [for acct in local.accounts : "arn:aws:s3:::${var.config_bucket_name}/AWSLogs/${acct}/*"]
      },
      # ...
    ]
  })
如果策略变得足够复杂,您希望将其分解到单独的模板文件中,您仍然可以使用
jsonencode
函数,将整个模板设置为
jsonencode
调用:

${jsonencode({
  # ...
})}

同时对整个结构使用
jsonencode
意味着结果保证是有效的JSON,而无需像构建JSON作为模板时那样担心逗号和其他分隔符的确切位置。

您是否在寻找类似本文所述的内容?我不使用AWS,所以我需要一个还有更多。嘿-谢谢参与,我添加了更多细节。谢谢:)这太棒了。谢谢你花时间回复这个问题。我唯一的问题似乎是试图将输出作为另一个“file.tf”的输入返回到我的策略中当它运行时。我可能没有抓住要点。这是可能的还是我应该从另一个角度来处理它?我遇到了这个问题:错误:资源“aws_s3_bucket”“splunk config bucket”中的central_config.tf行61上不支持的属性:61:${local.accounts.formatted_list}|------------------------------local.accounts是包含35个元素的元组。此值没有任何属性。很抱歉,输出更多用于演示。我添加了一个创建IAM策略的更完整示例。更完整的示例在这里有用吗?如果看不到您的问题,很难判断您遇到了什么问题充分工作的示例肯定会满足您的需要,但您可能会在这里遇到另一个问题,因此可能值得编辑您的问题,将其包括在内(如果相关),或者如果您被困在与此特定问题无关的另一个问题上,甚至可以打开另一个问题。明白了-我说得对。感觉我太接近了!我很高兴现在得到以下信息:“Error:“policy”在object key:value对之后包含一个无效的JSON:invalid字符'”,“谢谢你-我会研究它并尝试让它工作:)