Произойдет ли сбой terraform, если данные не существуют?

#amazon-web-services #terraform

#amazon-web-services #terraform

Вопрос:

Произойдет ли сбой terraform, если пользователь в данных не существует? Мне нужно указать пользователя в непроизводственной среде с помощью блока данных:

 data "aws_iam_user" "labUser" {
  user_name = "gitlab_user"
}
 

Затем я использую этого пользователя для предоставления пользовательских разрешений:

 resource "aws_iam_role" "ApiAccessRole_abc" {
 name = "${var.stack}-ApiAccessRole_abc"
 tags = "${var.tags}"
 assume_role_policy = <<EOF
{
 "Version": "2019-11-29",
 "Statement": [
   {
     "Action": "sts:AssumeRole",
  "Principal": {
    "AWS": [
    "${aws_iam_user.labUser.arn}"
    ]
  },
  "Effect": "Allow",
  "Sid": ""
 }
 ]
}
EOF
}
 

В рабочей среде этот пользователь не существует. Будет ли сбой terraform, если этот пользователь не существует? Каков был бы хороший подход к использованию одного и того же terraform в обеих средах?

Комментарии:

1. Что вы собираетесь делать, если пользователь не существует? И да, сбой Terraform произойдет, если источник данных вернет нулевые результаты.

2. Что-то мешает вам напрямую управлять пользователем IAM?

3. @Mattschuchardтерраформ удалит ручные настройки после запуска

Ответ №1:

В Terraform data блок, подобный тому, который вы показали здесь, является одновременно механизмом извлечения данных, а также утверждением автора (вас) о том, что ожидается существование определенного внешнего объекта, чтобы эта конфигурация могла быть применима.

В вашем случае ответ заключается в том, чтобы гарантировать, что утверждение о существовании объекта появляется только в ситуациях, когда оно должно существовать. Ответ «в целом» на этот вопрос заключается в том, чтобы просмотреть руководство по составлению модуля и рассмотреть, следует ли эту часть вашего модуля разбить на отдельный модуль, если он не всегда является частью модуля, в который он встроен, но я также покажу меньшее решение, которое использует условные выражения для полученияповедение, которое вы хотели, без какого-либо рефакторинга:

 variable "lab_user" {
  type    = string
  default = null
}

data "aws_iam_user" "lab_user" {
  count = length(var.lab_user[*])

  user_name = var.lab_user
}

resource "aws_iam_role" "api_access_role_abc" {
 count = length(data.aws_iam_user.lab_user)

 name = "${var.stack}-ApiAccessRole_abc"
 tags = var.tags
 assume_role_policy = jsonencode({
   Version   = "2019-11-29"
   Statement = [
     {
       Sid    = ""
       Action = "sts:AssumeRole"
       Effect = "Allow"
       Principal = {
         AWS = [data.aws_iam_user.lab_user[count.index].arn]
       }
     },
   ]
 })
}
 

В приведенном выше есть несколько разных вещей, на которые я хочу обратить внимание:

  • Я сделал имя пользователя лаборатории необязательной переменной, а не жестко заданным значением. Вы можете изменить поведение в разных средах, присвоив этой lab_user переменной другое значение или вообще не задавая его для сред, которым не нужен «лабораторный пользователь».
  • В data "aws_iam_user" I установите значение count length(var.lab_user[*]) равным . [*] Здесь оператор просит Terraform преобразовать строковую переменную с возможным значением null var.lab_user в список либо из нуля, либо из одного элемента, а затем, используя длину этого списка, решить, сколько aws_iam_user запросов нужно выполнить. Если var.lab_user это null , то длина будет равна нулю, и поэтому запросы выполняться не будут.
  • Наконец, я установил count для aws_iam_role ресурса соответствие длине результата aws_iam_user данных, так что в любой ситуации, когда ожидается один пользователь, также будет создана одна роль.

Если вы поразмыслите над руководством по составлению модуля и придете к выводу, что этот лабораторный пользователь должен быть отдельной проблемой в отдельном модуле, тогда вы сможете удалить эту условную сложность из самого модуля «gitlab user», и вместо этого вызывающий модуль либо вызовет этот модуль, либо нет, в зависимости от того, является ли такой пользовательнеобходимо для этой среды. Эффект будет тем же, но решение будет приниматься в другой части конфигурации, и, таким образом, будет достигнуто другое разделение задач. Какое разделение задач наиболее подходит для вашей системы, в конечном счете, является компромиссом, который вам нужно будет сделать самостоятельно, исходя из ваших знаний о системе и того, как вы ожидаете, что она может развиваться в будущем.

Ответ №2:

Как было предложено в комментариях, произойдет сбой.

Один из подходов, который я могу предложить, — указать имя пользователя в качестве переменной, которую вы передаете извне из файлов dev.tfvars и prod.tfvars, и запустить terraform с:

 terraform apply --var-file example.tfvars
 

Затем в вашем ресурсе данных у вас может быть count или for_each, чтобы проверить, был ли заполнен var или нет (если var не был передан, вы можете пропустить интерполяцию данных)

   count = var.enable_gitlab_user ? 1 : 0
 

Подход AWS direct заключается в переключении с пользователя IAM в основном на условие на основе тегов или даже на цепочку ролей. Некоторые идеи можно найти в этом сообщении в блоге AWS. Есть примеры для обоих случаев.