Terraform-provider-aws: Adding custom cognito user pool attribute forces new resource

Created on 22 Mar 2018  ·  44Comments  ·  Source: hashicorp/terraform-provider-aws

Adding new custom attributes should not force re-creation of the cognito user pool.

Terraform Version

$ terraform -v
Terraform v0.11.4
+ provider.aws v1.11.0

Affected Resource(s)

aws_cognito_user_pool

Terraform Configuration Files

variable "region" {
  default = "us-east-1"
}

provider "aws" {
  region = "${var.region}"
}

resource "aws_cognito_user_pool" "pool" {
  name = "bug-test-pool"

  /*
  schema {
    attribute_data_type      = "Number"
    developer_only_attribute = false
    mutable                  = false
    name                     = "custom-attribute"
    required                 = false
  }
  */
}

Debug Output

Output of running terraform plan after adding the custom attribute above.

Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

aws_cognito_user_pool.pool: Refreshing state... (ID: us-east-1_Cj77gRCdj)

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

-/+ aws_cognito_user_pool.pool (new resource required)
      id:                                               "us-east-1_Cj77gRCdj" => <computed> (forces new resource)
      admin_create_user_config.#:                       "1" => <computed>
      arn:                                              "arn:aws:cognito-idp:us-east-1:326947223243:userpool/us-east-1_Cj77gRCdj" => <computed>
      creation_date:                                    "2018-03-22T19:06:44Z" => <computed>
      email_verification_message:                       "" => <computed>
      email_verification_subject:                       "" => <computed>
      lambda_config.#:                                  "0" => <computed>
      last_modified_date:                               "2018-03-22T19:06:44Z" => <computed>
      mfa_configuration:                                "OFF" => "OFF"
      name:                                             "bug-test-pool" => "bug-test-pool"
      password_policy.#:                                "1" => <computed>
      schema.#:                                         "" => "1" (forces new resource)
      schema.2616754751.attribute_data_type:            "" => "Number"
      schema.2616754751.developer_only_attribute:       "" => "false"
      schema.2616754751.mutable:                        "" => "false"
      schema.2616754751.name:                           "" => "custom-attribute"
      schema.2616754751.number_attribute_constraints.#: "" => "0"
      schema.2616754751.required:                       "" => "false"
      schema.2616754751.string_attribute_constraints.#: "" => "0"
      verification_message_template.#:                  "1" => <computed>


Plan: 1 to add, 0 to change, 1 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

Panic Output

None

Expected Behavior

Add the attribute without destroying and rebuilding the cognito user pool. This is supported through the cognito UI and API (https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AddCustomAttributes.html).

Actual Behavior

The cognito user pool was rebuilt.

schema.#: "" => "1" (forces new resource)

Steps to Reproduce

  1. terraform apply - Create new user pool
  2. Add a new custom attribute
  3. terrform plan - viewing the output shows that it would re-build the cognito user pool.

Important Factoids

None

References

None

enhancement serviccognito

Most helpful comment

Any progress on this? You guys are forcing us to blow away a resource that involves asking the customer to reset their passwords (assuming we even have backup data to import in the first place), or for me, I setup a lifecycle ignore_changes * and hope someone finally gets around to fixing this before I need another change.

The fact this has been sitting out there for 9 months is seriously making me wonder whether I should trust critical infrastructure to Terraform.

All 44 comments

I am not sure how the deletion of custom attributes work as AWS doesn't seem to support deletion of custom attributes or updating custom attributes.

As suspected, One cannot update or delete custom attributes once created as part of the user_pool. So the current behavior is the only way out I think 🤔 Further details in the AWS documentation

Right, once the attributes are added they cannot be removed. However you can add new attributes.

Is there a workaround for adding new attributes via terraform without having to re-create the entire user pool? Seems like it'll be tricky to add a new attribute in the future when the application is live.

Edit: Looks like pegging the version to 1.12 fixed this for us.

In the meantime, you can do it outside Terraform (web console, CLI, etc.) and just sync your Terraform configuration afterwards.

Doing a bit more research. I've found the problem. If the schema attribute (in my case String) does not include the string_attribute_constraints it will force a new resource every time.

The following generates a new resource each time:

schema {
    attribute_data_type      = "String"
    developer_only_attribute = false
    mutable                  = false
    name                     = "picture"
    required                 = true
  }

While this does not:

schema {
    attribute_data_type      = "String"
    developer_only_attribute = false
    mutable                  = false
    name                     = "picture"
    required                 = true

    string_attribute_constraints {
      min_length = 6
      max_length = 32
    }
  }

Most likely it's a different bug.

@leonfs I think we need a customizediff function here. that evaluates thwbrules for when the pool has to be recreated and when it should be modified. @bflad Can you please confirm what needs to be done and I can pick this up.

@Puneeth-n Yes - seems like that will be the case. At the moment there is a ForceNew: true on the schema set, but that is clearly not the case with custom attributes.

I've referenced (see above) another issue I encountered after I added an identity provider (Google) to the user Pool.

Looks like AWS adds a custom attribute called identities after adding a provider, making the schema's set to change and forcing a whole new pool to be recreated. You can see that I provided a short term solution to it but only works if you know before hand (resource creation) that you will use identity providers.

Looks like terraform forces a destroy and create of a user pool even if nothing changed in the .tf file.

$ cat main.tf

provider "aws" {
}

resource "aws_cognito_user_pool" "pankajk_security" {
  name                       = "pankajk-security"
  email_verification_subject = "Your Verification Code"
  email_verification_message = "Please use the following code: {####}"
  alias_attributes           = ["email", "preferred_username"]
  auto_verified_attributes   = ["email"]

  verification_message_template {
    default_email_option = "CONFIRM_WITH_CODE"
  }

  password_policy {
    minimum_length    = 10
    require_lowercase = true
    require_numbers   = true
    require_symbols   = true
    require_uppercase = true
  }

  schema {
    attribute_data_type      = "String"
    developer_only_attribute = false
    mutable                  = true
    name                     = "email"
    required                 = true

    string_attribute_constraints {
      min_length = 7
      max_length = 256
    }
  }

  schema {
    attribute_data_type      = "String"
    developer_only_attribute = false
    mutable                  = true
    name                     = "oid"
    required                 = false

    number_attribute_constraints {
      min_value = 1
      max_value = 256
    }
  }
}

$ terraform -v

Terraform v0.11.7
+ provider.aws v1.14.1

$ terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + aws_cognito_user_pool.pankajk_security
      id:                                                          <computed>
      admin_create_user_config.#:                                  <computed>
      alias_attributes.#:                                          "2"
      alias_attributes.1888159429:                                 "preferred_username"
      alias_attributes.881205744:                                  "email"
      arn:                                                         <computed>
      auto_verified_attributes.#:                                  "1"
      auto_verified_attributes.881205744:                          "email"
      creation_date:                                               <computed>
      email_verification_message:                                  "Please use the following code: {####}"
      email_verification_subject:                                  "Your Verification Code"
      lambda_config.#:                                             <computed>
      last_modified_date:                                          <computed>
      mfa_configuration:                                           "OFF"
      name:                                                        "pankajk-security"
      password_policy.#:                                           "1"
      password_policy.0.minimum_length:                            "10"
      password_policy.0.require_lowercase:                         "true"
      password_policy.0.require_numbers:                           "true"
      password_policy.0.require_symbols:                           "true"
      password_policy.0.require_uppercase:                         "true"
      schema.#:                                                    "2"
      schema.1734507539.attribute_data_type:                       "String"
      schema.1734507539.developer_only_attribute:                  "false"
      schema.1734507539.mutable:                                   "true"
      schema.1734507539.name:                                      "email"
      schema.1734507539.number_attribute_constraints.#:            "0"
      schema.1734507539.required:                                  "true"
      schema.1734507539.string_attribute_constraints.#:            "1"
      schema.1734507539.string_attribute_constraints.0.max_length: "256"
      schema.1734507539.string_attribute_constraints.0.min_length: "7"
      schema.3768180960.attribute_data_type:                       "String"
      schema.3768180960.developer_only_attribute:                  "false"
      schema.3768180960.mutable:                                   "true"
      schema.3768180960.name:                                      "oid"
      schema.3768180960.number_attribute_constraints.#:            "1"
      schema.3768180960.number_attribute_constraints.0.max_value:  "256"
      schema.3768180960.number_attribute_constraints.0.min_value:  "1"
      schema.3768180960.required:                                  "false"
      schema.3768180960.string_attribute_constraints.#:            "0"
      verification_message_template.#:                             "1"
      verification_message_template.0.default_email_option:        "CONFIRM_WITH_CODE"
      verification_message_template.0.email_message:               <computed>
      verification_message_template.0.email_message_by_link:       <computed>
      verification_message_template.0.email_subject:               <computed>
      verification_message_template.0.email_subject_by_link:       <computed>
      verification_message_template.0.sms_message:                 <computed>


Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_cognito_user_pool.pankajk_security: Creating...
  admin_create_user_config.#:                                  "" => "<computed>"
  alias_attributes.#:                                          "" => "2"
  alias_attributes.1888159429:                                 "" => "preferred_username"
  alias_attributes.881205744:                                  "" => "email"
  arn:                                                         "" => "<computed>"
  auto_verified_attributes.#:                                  "" => "1"
  auto_verified_attributes.881205744:                          "" => "email"
  creation_date:                                               "" => "<computed>"
  email_verification_message:                                  "" => "Please use the following code: {####}"
  email_verification_subject:                                  "" => "Your Verification Code"
  lambda_config.#:                                             "" => "<computed>"
  last_modified_date:                                          "" => "<computed>"
  mfa_configuration:                                           "" => "OFF"
  name:                                                        "" => "pankajk-security"
  password_policy.#:                                           "" => "1"
  password_policy.0.minimum_length:                            "" => "10"
  password_policy.0.require_lowercase:                         "" => "true"
  password_policy.0.require_numbers:                           "" => "true"
  password_policy.0.require_symbols:                           "" => "true"
  password_policy.0.require_uppercase:                         "" => "true"
  schema.#:                                                    "" => "2"
  schema.1734507539.attribute_data_type:                       "" => "String"
  schema.1734507539.developer_only_attribute:                  "" => "false"
  schema.1734507539.mutable:                                   "" => "true"
  schema.1734507539.name:                                      "" => "email"
  schema.1734507539.number_attribute_constraints.#:            "" => "0"
  schema.1734507539.required:                                  "" => "true"
  schema.1734507539.string_attribute_constraints.#:            "" => "1"
  schema.1734507539.string_attribute_constraints.0.max_length: "" => "256"
  schema.1734507539.string_attribute_constraints.0.min_length: "" => "7"
  schema.3768180960.attribute_data_type:                       "" => "String"
  schema.3768180960.developer_only_attribute:                  "" => "false"
  schema.3768180960.mutable:                                   "" => "true"
  schema.3768180960.name:                                      "" => "oid"
  schema.3768180960.number_attribute_constraints.#:            "" => "1"
  schema.3768180960.number_attribute_constraints.0.max_value:  "" => "256"
  schema.3768180960.number_attribute_constraints.0.min_value:  "" => "1"
  schema.3768180960.required:                                  "" => "false"
  schema.3768180960.string_attribute_constraints.#:            "" => "0"
  verification_message_template.#:                             "" => "1"
  verification_message_template.0.default_email_option:        "" => "CONFIRM_WITH_CODE"
  verification_message_template.0.email_message:               "" => "<computed>"
  verification_message_template.0.email_message_by_link:       "" => "<computed>"
  verification_message_template.0.email_subject:               "" => "<computed>"
  verification_message_template.0.email_subject_by_link:       "" => "<computed>"
  verification_message_template.0.sms_message:                 "" => "<computed>"
aws_cognito_user_pool.pankajk_security: Creation complete after 3s (ID: us-west-2_t6jMrbPx1)

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

$terraform plan

Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

aws_cognito_user_pool.pankajk_security: Refreshing state... (ID: us-west-2_t6jMrbPx1)

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

-/+ aws_cognito_user_pool.pankajk_security (new resource required)
      id:                                                          "us-west-2_t6jMrbPx1" => <computed> (forces new resource)
      admin_create_user_config.#:                                  "1" => <computed>
      alias_attributes.#:                                          "2" => "2"
      alias_attributes.1888159429:                                 "preferred_username" => "preferred_username"
      alias_attributes.881205744:                                  "email" => "email"
      arn:                                                         "arn:aws:cognito-idp:us-west-2:166326852216:userpool/us-west-2_t6jMrbPx1" => <computed>
      auto_verified_attributes.#:                                  "1" => "1"
      auto_verified_attributes.881205744:                          "email" => "email"
      creation_date:                                               "2018-04-18T18:11:08Z" => <computed>
      email_verification_message:                                  "Please use the following code: {####}" => "Please use the following code: {####}"
      email_verification_subject:                                  "Your Verification Code" => "Your Verification Code"
      lambda_config.#:                                             "0" => <computed>
      last_modified_date:                                          "2018-04-18T18:11:08Z" => <computed>
      mfa_configuration:                                           "OFF" => "OFF"
      name:                                                        "pankajk-security" => "pankajk-security"
      password_policy.#:                                           "1" => "1"
      password_policy.0.minimum_length:                            "10" => "10"
      password_policy.0.require_lowercase:                         "true" => "true"
      password_policy.0.require_numbers:                           "true" => "true"
      password_policy.0.require_symbols:                           "true" => "true"
      password_policy.0.require_uppercase:                         "true" => "true"
      schema.#:                                                    "2" => "2"
      schema.1734507539.attribute_data_type:                       "String" => "String"
      schema.1734507539.developer_only_attribute:                  "false" => "false"
      schema.1734507539.mutable:                                   "true" => "true"
      schema.1734507539.name:                                      "email" => "email"
      schema.1734507539.number_attribute_constraints.#:            "0" => "0"
      schema.1734507539.required:                                  "true" => "true"
      schema.1734507539.string_attribute_constraints.#:            "1" => "1"
      schema.1734507539.string_attribute_constraints.0.max_length: "256" => "256"
      schema.1734507539.string_attribute_constraints.0.min_length: "7" => "7"
      schema.3768180960.attribute_data_type:                       "" => "String" (forces new resource)
      schema.3768180960.developer_only_attribute:                  "" => "false" (forces new resource)
      schema.3768180960.mutable:                                   "" => "true" (forces new resource)
      schema.3768180960.name:                                      "" => "oid" (forces new resource)
      schema.3768180960.number_attribute_constraints.#:            "" => "1" (forces new resource)
      schema.3768180960.number_attribute_constraints.0.max_value:  "" => "256" (forces new resource)
      schema.3768180960.number_attribute_constraints.0.min_value:  "" => "1" (forces new resource)
      schema.3768180960.required:                                  "" => "false" (forces new resource)
      schema.3768180960.string_attribute_constraints.#:            "" => "0"
      schema.383977790.attribute_data_type:                        "String" => "" (forces new resource)
      schema.383977790.developer_only_attribute:                   "false" => "false"
      schema.383977790.mutable:                                    "true" => "false" (forces new resource)
      schema.383977790.name:                                       "oid" => "" (forces new resource)
      schema.383977790.number_attribute_constraints.#:             "0" => "0"
      schema.383977790.required:                                   "false" => "false"
      schema.383977790.string_attribute_constraints.#:             "1" => "0" (forces new resource)
      schema.383977790.string_attribute_constraints.0.max_length:  "" => ""
      schema.383977790.string_attribute_constraints.0.min_length:  "" => ""
      verification_message_template.#:                             "1" => "1"
      verification_message_template.0.default_email_option:        "CONFIRM_WITH_CODE" => "CONFIRM_WITH_CODE"
      verification_message_template.0.email_message:               "Please use the following code: {####}" => <computed>
      verification_message_template.0.email_message_by_link:       "" => <computed>
      verification_message_template.0.email_subject:               "Your Verification Code" => <computed>
      verification_message_template.0.email_subject_by_link:       "" => <computed>
      verification_message_template.0.sms_message:                 "" => <computed>


Plan: 1 to add, 0 to change, 1 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

@pankajku The issue you are facing is different. However, IMHO terraform should be able to catch such errors.

There is an error in your config. For oid, you specify attribute_data_type = "String" but specify number_attribute_constraints The corrected config is below:

variable "region" {
  default = "us-east-1"
}

provider "aws" {
  version               = "1.14.1"
  region                = "${var.region}"
}

resource "aws_cognito_user_pool" "pankajk_security" {
  name                       = "pankajk-security"
  email_verification_subject = "Your Verification Code"
  email_verification_message = "Please use the following code: {####}"
  alias_attributes           = ["email", "preferred_username"]
  auto_verified_attributes   = ["email"]

  verification_message_template {
    default_email_option = "CONFIRM_WITH_CODE"
  }

  password_policy {
    minimum_length    = 10
    require_lowercase = true
    require_numbers   = true
    require_symbols   = true
    require_uppercase = true
  }

  schema {
    attribute_data_type      = "String"
    developer_only_attribute = false
    mutable                  = true
    name                     = "email"
    required                 = true

    string_attribute_constraints {
      min_length = 7
      max_length = 256
    }
  }

  schema {
    attribute_data_type      = "String"
    developer_only_attribute = false
    mutable                  = true
    name                     = "oid"
    required                 = false

    string_attribute_constraints {
      min_length = 1
      max_length = 256
    }
  }
}

@Puneeth-n , Thanks for catching the problem in my config. I changed it as per your suggestion and now terraform updates only the changed attributes.

I did notice that after I make a simple change (such as verification message text) in config file and run "terraform apply", the email verification flag gets unset.

$ terraform apply

aws_cognito_user_pool.pankajk_security: Refreshing state... (ID: us-west-2_LKVhvfWsH)

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  ~ aws_cognito_user_pool.pankajk_security
      email_verification_subject: "Your verification code" => "Your Verification Code"


Plan: 0 to add, 1 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_cognito_user_pool.pankajk_security: Modifying... (ID: us-west-2_LKVhvfWsH)
  email_verification_subject: "Your verification code" => "Your Verification Code"
aws_cognito_user_pool.pankajk_security: Modifications complete after 1s (ID: us-west-2_LKVhvfWsH)

Apply complete! Resources: 0 added, 1 changed, 0 destroyed.

$ terraform plan

Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

aws_cognito_user_pool.pankajk_security: Refreshing state... (ID: us-west-2_LKVhvfWsH)

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  ~ aws_cognito_user_pool.pankajk_security
      auto_verified_attributes.#:         "0" => "1"
      auto_verified_attributes.881205744: "" => "email"


Plan: 0 to add, 1 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

Wonder if this is also due to some error in the config file or a bug.

This still seems to be a problem and is going to cause someone a lot of heartache one day when tf drops the user pool and they lose all their users...

Adding this to the schema causes the user pool to be destroyed, despite being able to be created in the console/cli without destroying.

    {
      name                     = "foo"
      attribute_data_type      = "String"
      mutable                  = true
      developer_only_attribute = "false"
      required                 = "false"

      string_attribute_constraints = {
        min_length = 0
        max_length = 256
      }
    },

Yea. I have prevent_destroy set on both the pool and client

Still hitting the resource recreate issue when I try to add new custom attributes.

Terraform Version
Terraform v0.11.8
provider.aws v1.36.0

Before adding new custom attribute

resource "aws_cognito_user_pool" "pool" {
  name                       = "Test"
  username_attributes        = ["email"]
  auto_verified_attributes   = ["email"]

  schema = [
    {
      attribute_data_type          = "String"
      developer_only_attribute     = false
      mutable                      = false
      name                         = "email"
      required                     = true
      string_attribute_constraints = {
        min_length = 1
        max_length = 256
      }
    },
    {
      attribute_data_type          = "String"
      developer_only_attribute     = false
      mutable                      = true
      name                         = "custom1"
      required                     = false
      string_attribute_constraints = {
        min_length = 0
        max_length = 256
      }
    }
  ]
}

Add new custom attribute

{
      attribute_data_type          = "String"
      developer_only_attribute     = false
      mutable                      = true
      name                         = "custom2"
      required                     = false
      string_attribute_constraints = {
        min_length = 0
        max_length = 256
      }
    }

Debug Ouput

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

-/+ aws_cognito_user_pool.pool (new resource required)
 ...
      lambda_config.#:                                             "0" => <computed>
      last_modified_date:                                          "2018-09-19T03:33:52Z" => <computed>
      mfa_configuration:                                           "OFF" => "OFF"
      name:                                                        "Test" => "Test"
      password_policy.#:                                           "1" => <computed>
      schema.#:                                                    "2" => "3" (forces new resource)
      schema.2766842814.attribute_data_type:                       "" => "String" (forces new resource)
      schema.2766842814.developer_only_attribute:                  "" => "false" (forces new resource)
      schema.2766842814.mutable:                                   "" => "true" (forces new resource)
      schema.2766842814.name:                                      "" => "custom2" (forces new resource)
      schema.2766842814.number_attribute_constraints.#:            "" => "0"
      schema.2766842814.required:                                  "" => "false" (forces new resource)
      schema.2766842814.string_attribute_constraints.#:            "" => "1" (forces new resource)
      schema.2766842814.string_attribute_constraints.0.max_length: "" => "256" (forces new resource)
      schema.2766842814.string_attribute_constraints.0.min_length: "" => "0" (forces new resource)
      schema.3686385984.attribute_data_type:                       "String" => "String"
      schema.3686385984.developer_only_attribute:                  "false" => "false"
      schema.3686385984.mutable:                                   "false" => "false"
      schema.3686385984.name:                                      "email" => "email"
      schema.3686385984.number_attribute_constraints.#:            "0" => "0"
      schema.3686385984.required:                                  "true" => "true"
      schema.3686385984.string_attribute_constraints.#:            "1" => "1"
      schema.3686385984.string_attribute_constraints.0.max_length: "256" => "256"
      schema.3686385984.string_attribute_constraints.0.min_length: "1" => "1"
      schema.893709367.attribute_data_type:                        "String" => "String"
      schema.893709367.developer_only_attribute:                   "false" => "false"
      schema.893709367.mutable:                                    "true" => "true"
      schema.893709367.name:                                       "custom1" => "custom1"
      schema.893709367.number_attribute_constraints.#:             "0" => "0"
      schema.893709367.required:                                   "false" => "false"
      schema.893709367.string_attribute_constraints.#:             "1" => "1"
      schema.893709367.string_attribute_constraints.0.max_length:  "256" => "256"
      schema.893709367.string_attribute_constraints.0.min_length:  "0" => "0"
      username_attributes.#:                                       "1" => "1"
      username_attributes.0:                                       "email" => "email"
      verification_message_template.#:                             "1" => <computed>


Plan: 1 to add, 0 to change, 1 to destroy.

FYI: I made custom attribute without string_attribute_constraints, then I faced same bug.

  schema {
    name                     = "custom_id"
    required                 = false
    attribute_data_type      = "String"
    developer_only_attribute = false
    mutable                  = true
  }

After I added empty string_attribute_constraints, I could avoid this bug!

  schema {
    name                     = "custom_id"
    required                 = false
    attribute_data_type      = "String"
    developer_only_attribute = false
    mutable                  = true

    string_attribute_constraints {}
  }

I really appreciate everyone's workaround!

Workaround doesn't work for me.

schema {
    attribute_data_type      = "String"
    developer_only_attribute = false
    mutable                  = true
    name                     = "parent_id"
    required                 = false

    string_attribute_constraints {
      min_length = 1
      max_length = 256
    }
  }

Plan:

schema.#:                                                    "10" => "11" (forces new resource)
schema.2272806367.attribute_data_type:                       "" => "String" (forces new resource)
schema.2272806367.developer_only_attribute:                  "" => "false" (forces new resource)
schema.2272806367.mutable:                                   "" => "false" (forces new resource)
schema.2272806367.name:                                      "" => "parent_id" (forces new resource)
schema.2272806367.number_attribute_constraints.#:            "" => "0"
schema.2272806367.required:                                  "" => "false" (forces new resource)
schema.2272806367.string_attribute_constraints.#:            "" => "1" (forces new resource)
schema.2272806367.string_attribute_constraints.0.max_length: "" => "256" (forces new resource)
schema.2272806367.string_attribute_constraints.0.min_length: "" => "1" (forces new resource)

Versions:

Terraform v0.11.11
+ provider.archive v1.1.0
+ provider.aws v1.52.0

This is a huge issue for anyone who is developing new applications and require to add/experiment with custom attributes. We had our pool destroyed 10+ times because of this.

Any progress on this? You guys are forcing us to blow away a resource that involves asking the customer to reset their passwords (assuming we even have backup data to import in the first place), or for me, I setup a lifecycle ignore_changes * and hope someone finally gets around to fixing this before I need another change.

The fact this has been sitting out there for 9 months is seriously making me wonder whether I should trust critical infrastructure to Terraform.

The workaround doesn't work for me either. It always recreates the pool even if there are no changes to the templates.

> terraform --version
Terraform v0.11.11
+ provider.archive v1.1.0
+ provider.aws v1.54.0

still an isssue

Terraform v0.11.11
+ provider.aws v1.57.0

And still...

Terraform v0.11.11
+ provider.aws v1.59.0

I'm also affected by this, none of the workarounds have worked for me.

Terraform v0.11.11
+ provider.aws v1.60.0

The fact this has been sitting out there for 9 months is seriously making me wonder whether I should trust critical infrastructure to Terraform.

I'm asking myself the same question. There are a lot of critical bugs not handled for more then a year, some - for more than two years. For a lot of these bugs there are ready PR which also hangingin unlandled for more than a year.

Also recently I have filled a bug report for a serious but in jsonencode function - they refused to fiz it. The reply was - it is fixed in version 12, which will be released some unknown time in the future and we don't care about version 11.

BTW the issue from this topic is not the only one, that cognito user pool has. Callback_urls has to be ordered exactly as AWS doing this, otherwise terraform constantly trying to change order.

@voroniys My take away from using Terraform for 3+ years is not to maintain states via Terraform. It is true for any IaC. Terraform is a powerful tool and has God access. Refrain from using it for applications having state.

Still an issue.

I have been investigating this and finding a way to "fix" this.

A better way to allow for managing custom attributes is to make a custom attribute a separate resource, e.g. aws_cognito_user_pool_schema_custom_attribute.

In Terraform a resource is defined by a schema, together with Create, Read, Update & Delete function callbacks. Core Terraform calculates the difference between the current state and what you defined in your Terraform code. We want to rely as much as possible on TF doing the right thing.

If you strip out the schema attribute as a separate resource, one has more fine grained control over the difference calculation: adding a new custom schema attribute resource makes Terraform invoke the Create function of the separate resource, rather than the Destroy/Create sequence of the pool. In the Create function of the schema attribute resource, we can invoke the AWS Cognito AddCustomAttributes API call.

A change to the properties of the schema attribute could also be handled more granular, but that is to be tested.

When you (accidentally) delete your custom schema attribute resource from your Terraform code, TF would invoke the Delete function of the attribute resource. We could error indicating a delete is not supported and your TF code needs to be restored.

Comments?

@bflad, do you know who could help out designing the changes?

Thanks @ringods for your work and suggestion. This could be the right track to tackle this issue!

Still validating the issue while using the latest versions as of today:

Terraform v0.12.3
+ provider.aws v2.18.0 

Quick recap:

resource "aws_cognito_user_pool" "pool" {
  name = "mypooltest2"
  }

Then add whatever attribute:

resource "aws_cognito_user_pool" "pool" {
  name = "mypooltest2"

  schema {
  attribute_data_type = "String"
  name = "email" 
  required = true
  }
}

Instead of just doing the incremental update like it should do, Terraform destroy then add the resource again:

Plan: 1 to add, 0 to change, 1 to destroy.

We are stuck to deploy new feature to our production environment, we need to a new custom attribute, if we add it through cli it will mess up entire terraform configuration which has lot of other resources too.

@ringods's suggestion might work for us, without disrupting existing tf config. hence trying to contribute for that solution.
Here is first draft of my code. I was successfully able to test it pointing to locally built terraform-provider-aws. I am now writing the acceptance tests. Suggestions/ comments on the PR are appreciated!

We added attributes to cognito without losing our user pool the following way:

  1. Use CLI to add attributes to existing schema: aws cognito-idp --region ... add-custom-attributes --user-pool-id ... --custom-attributes Name=...,AttributeDataType=Boolean,DeveloperOnlyAttribute=false, Mutable=true,Required=false
  2. Remove current state of cognito in order to import updated resource. terraform state rm aws_cognito_user_pool.main
  3. Import updated resource. terraform import aws_cognito_user_pool.main ...

In our case, our resource, state and main.tf file now matched. I suggest trying on a dev env first, hope it helps.

Please fix this! Doing what ePoromaa's work around is ridiculous to have to manually manage state.

Is there still any progress on this? We are eagerly waiting for a solution that doesn't require manual manipulations on the terraform state. :-)

ping as well. Manually managing the state is... ridiculous

Guys, any updates? We are in 2020 now...

Yes, still an issue...

Hope this helps everyone else, easier way than the above solution and potentially less messier than playing around with the terraform state and imports.

Similar to ePoromaa, you will need to run the aws cli cmd manually to add a custom attribute to the cognito user pool.
aws cognito-idp add-custom-attributes --user-pool-id us-west-2_aaaaaaaaa --custom-attributes Name="CustomAttr1",AttributeDataType="String",DeveloperOnlyAttribute=false,Required=false,StringAttributeConstraints="{MinLength=1,MaxLength=15}"
More info on available attributes can be found: https://docs.aws.amazon.com/cli/latest/reference/cognito-idp/add-custom-attributes.html

Once you've added the custom attribute via the aws cli, you will now need to add the schema block for it in your terraform cognito user pool code. For example

schema { name = "CustomAttr1" attribute_data_type = "String" required = false developer_only_attribute = false string_attribute_constraints { min_length = 1 max_length = 15 } }

Once the schema block is added into terraform, terraform picks up no changes. Would consider this safe to do in prod as well.

Terraform v0.12.26

  • provider.aws v2.56.0

Still have the issue...

Hi everyone, any updates on here?

Please fix this issue!

This is still an issue with

Terraform v0.12.28
+ provider.aws v2.67.0

Please address.

Workaround to prevent destruction of the user pool:
1) Add custom attribute via console or cli.
2) Add schema block to terraform template IDENTICAL IN EVERY WAY to the attribute you just created.
3) Run terraform refresh. It should refresh the state file to reflect the schema.
4) Run terraform plan to make sure user pool is no longer destroyed.

Hi there, we are also facing this issue. Any updates? Thanks!

Anybody from HashiCorp out there ? Hellooo....

Facing this as well:

Terraform v0.12.29

Terraform v0.13.3

  • provider registry.terraform.io/hashicorp/aws v2.70.0

Still facing the issue

Hi all! :wave: Just wanted to direct you to our public roadmap for this quarter (Nov-Jan) in which this item has been mentioned.

Due to the significant community interest in resolving this issue, we will be looking at merging existing contributions soon.

We appreciate all the contributions and feedback thus far.

Was this page helpful?
0 / 5 - 0 ratings