Создание политики AWS IAM из массива номеров счетов JSON - PullRequest
1 голос
/ 18 октября 2019

У меня есть список номеров учетных записей 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:*"]
  }
}

У меня есть список номеров счетов в файле envs.json, он выглядит так:

{
    "accounts": [
        "1234567890",
        "0987654321",
        "1029384756",
        "6574839201",
        "0192837465"
    ]
}

Я пытаюсь сгенерировать политикус динамическим списком номеров счетов AWS. Мы пытаемся избавиться от жестко запрограммированных номеров счетов и извлекаем их из проекта «централизованная конфигурация», который у нас есть.

Вот что я пробовал:

variables.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»:

Error: "policy" contains an invalid JSON: invalid character '"' after object key:value pair

  on central_config.tf line 2, in resource "aws_s3_bucket" "splunk-config-bucket":
   2: resource "aws_s3_bucket" "splunk-config-bucket" {

Я также пробовал это:

variables.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.

Спасибо,

Ответы [ 4 ]

1 голос
/ 18 октября 2019

Получение правильного кодирования JSON с помощью строковых шаблонов может быть неприятным. Если нет веских оснований для форматирования JSON определенным образом, мы можем избежать шаблонизации JSON, непосредственно создав желаемую структуру данных и передав ее в jsonencode, например:

  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
    ]
  })

. Затем можно использоватьТерраформ операторы и функции непосредственно для создания частей этого объекта. Например, чтобы создать список требуемых 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 в качестве шаблона.

0 голосов
/ 18 октября 2019

Вы можете загрузить файл с помощью функции file , а затем извлечь список необходимых вам учетных записей, расшифровав JSON с помощью jsondecode, а затем выбравaccounts key.

Например:

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

output example {
  value = local.accounts
}

Это вернет следующее:

example = [
  "1234567890",
  "0987654321",
  "1029384756",
  "6574839201",
  "0192837465",
]

Если вы затем захотите включить это в свою политику, выВы хотите использовать функцию formatlist для передачи списка счетов в единый строковый формат:

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, поэтому создаст недопустимую структуру JSON для вашей политики IAM. Чтобы это исправить, мы можем затем перекодировать его в JSON с jsonencode:

output "example" {
  value = jsonencode(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/*"]

без запятой.

Сложив все это, вы можете создать свою политику IAM следующим образом:

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
}
0 голосов
/ 18 октября 2019

Мне удалось получить эту работу с помощью 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"
                }

Я думал, что поставлю свой ответ :)

0 голосов
/ 18 октября 2019

В вашем коде может быть динамическая перезагрузка конфигурации, которая обновляет список учетных записей и вызывает S3 API при изменении файла конфигурации.

Для просмотра файла конфигурации (списка учетных записей) вы можете использоватьнекоторые библиотеки. Я считаю, что «Viper» - хороший выбор.

А также, если вы беспокоитесь о потере такого рода событий в файле, вызванных сбоями вызовов API или сбоями приложений, вы можете попытаться сделать обновление списка действий идемпотентным исделать это при запуске приложения или через определенный промежуток времени.

Эти ссылки могут прийти в руки:

О идемпотентности: https://nordicapis.com/understanding-idempotency-and-safety-in-api-design/

Viper: https://github.com/spf13/viper

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...