4
votes

Creating an aws_cognito_user_pool in Terraform with anything in the 'schema' causes the user pool to be recreated every time Terraform runs. We want to use custom attributes so need to set options in schema.

According to the documentation

"When defining an attribute_data_type of String or Number, the respective attribute constraints configuration block (e.g string_attribute_constraints or number_attribute_contraints) is required to prevent recreation of the Terraform resource. This requirement is true for both standard (e.g. name, email) and custom schema attributes."

If I understand this correctly, I need to list out all standard attributes in the schema too, so I can add the string_attribute_contraints.

  resource "aws_cognito_user_pool" "pool" {
  count = "${var.user_pool_count}"
  name  = "${lookup(var.user_pool[count.index], "name")}"

  username_attributes      = ["email"]
  auto_verified_attributes = ["email"]

  schema = [
    {
      name                = "address"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
    {
      name                = "birthdate"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
    {
      name                = "email"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
    {
      name                = "family_name"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
    {
      name                = "gender"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
    {
      name                = "given_name"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
    {
      name                = "locale"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
    {
      name                = "middle_name"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
    {
      name                = "name"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
    {
      name                = "nickname"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
    {
      name                = "phone_number"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
    {
      name                = "picture"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
    {
      name                = "preferred_username"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
    {
      name                = "profile"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
    {
      name                = "zoneinfo"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
    {
      name                = "updated_at"
      attribute_data_type = "Number"

      number_attribute_constraints = {
        min_value = 1
      }
    },
    {
      name                = "website"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
      }
    },
  ]
}

With the above example, even though I have not added any custom attributes yet, it recreates the user pool on every run.

EDIT - Added gist link to Terraform plan as it would put me over the Stackoverflow character limit.
https://gist.github.com/mehstg/6bf22a35254a168c14b98af57f86ed85
1
Can you share the plan output that shows it needs to be recreated?ydaetskcoR
Sure, added as a gist as I was over my character limit - gist.github.com/mehstg/6bf22a35254a168c14b98af57f86ed85mehstg
It looks like those attributes are missing a bunch of constraints (eg max_length) that you have set on the actual schema so Terraform is detecting the drift and forcing an update. Because the schema is immutable in AWS Terraform knows it needs to destroy and recreate. Adding the missing constraints should fix this.ydaetskcoR

1 Answers

7
votes

The plan output shows that most of your schema attributes are missing the max_length constraint that is set on the schema attributes in the pool:

      schema.1286155211.attribute_data_type:                       "" => "String" (forces new resource)
      schema.1286155211.developer_only_attribute:                  "" => ""
      schema.1286155211.mutable:                                   "" => ""
      schema.1286155211.name:                                      "" => "locale" (forces new resource)
      schema.1286155211.number_attribute_constraints.#:            "" => "0"
      schema.1286155211.required:                                  "" => ""
      schema.1286155211.string_attribute_constraints.#:            "" => "1" (forces new resource)
      schema.1286155211.string_attribute_constraints.0.max_length: "" => ""
      schema.1286155211.string_attribute_constraints.0.min_length: "" => "1" (forces new resource)
...
      schema.3812649078.developer_only_attribute:                  "false" => "false"
      schema.3812649078.mutable:                                   "false" => "false"
      schema.3812649078.name:                                      "locale" => "" (forces new resource)
      schema.3812649078.number_attribute_constraints.#:            "0" => "0"
      schema.3812649078.required:                                  "false" => "false"
      schema.3812649078.string_attribute_constraints.#:            "1" => "0" (forces new resource)
      schema.3812649078.string_attribute_constraints.0.max_length: "2048" => "" (forces new resource)
      schema.3812649078.string_attribute_constraints.0.min_length: "1" => "" (forces new resource)

Terraform is detecting this drift and trying to change your user pool to match your config. Unfortunately user pool schema attributes are immutable so Terraform is forced to destroy the whole user pool and create a new one.

Adding the missing constraints should fix this.

resource "aws_cognito_user_pool" "pool" {
  count = var.user_pool_count
  name  = var.user_pool[count.index]["name"]

  username_attributes      = ["email"]
  auto_verified_attributes = ["email"]

  schema = [
    # ...
    {
      name                = "locale"
      attribute_data_type = "String"

      string_attribute_constraints = {
        min_length = 1
        max_length = 1
      }
    },
    # ...
  ]
}