After upgrading Terraform, there was an issue with the AWS Cognito user pool

Hello, hope everyone’s doing good. I’m new to this community. I’m facing an issue with my AWS Cognito user pool. I tried upgrading my Terraform from 1.3.3 to 1.5.2. I know that schema attributes can’t be removed or changed once added to the user pool. But After the upgrade I’m trying to run the github actions(Apply) to check if everything’s fine after the upgrade. And I’m getting this error with my cognito user pool.

│ Error: updating Cognito User Pool (us-east-1): cannot modify or remove schema items
│ 
│   with module.cognito_user_auth.aws_cognito_user_pool.pool,
│   on .terraform/modules/cognito_user_auth/cognito/cognito_auth.tf line 28, in resource "aws_cognito_user_pool" "pool":
│   28: resource "aws_cognito_user_pool" "pool" {
│ 

This is my script:

module "cognito_user_auth" {
  source = "github.com/cognito?ref=v1.1.8"

  providers = {
    aws = aws.cognito-region
  }

  auto_verify      = false
  user_pool_name   = "${local.namespace}-${local.environment}-eks-user-auth"
  user_pool_domain = "${local.namespace}-${local.environment}-eks-user-auth"

  username_attributes              = ["email"] # set email as username attribute
  enable_username_case_sensitivity = false     # disable case sensitivity
  # NOTE: schema attributes can't be removed or changed once added to the user pool
  //  schema_additional_attributes = [
  //    {
  //      attribute_name           = "gender"
  //      attribute_data_type      = "String"
  //      developer_only_attribute = false,
  //      mutable                  = false
  //      required                 = true
  //      min_value                = 1
  //      max_value                = 10
  //    },
  //  ]

  user_groups = {
    "cluster-dev-group" = {
      "description" = "developer users and has access to argo and grafana"
      "precedence"  = 4
    },
    "dev-group" = {
      "description" = "dev users"
      "precedence"  = 5
    },
    "internal-group" = {
      "description" = "internal teams and has access to more resources"
      "precedence"  = 6
    }
  }

Please let me know if there is any possible way without creating a new pool and user migration. Thank you.

This is not a valid module source address.

I think you would need to provide the full Terraform CLI output showing the plan you are trying to apply, in order for people to understand what exactly you’re trying to do.

Sorry about that, @maxb. The source link I provided is incorrect here, but it is correct on my PC.

Here is the output:

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # module.cognito_user_auth.aws_cognito_user_pool.pool will be updated in-place
  ~ resource "aws_cognito_user_pool" "pool" {
        id                        = "us-east-1"
        name                      = "dev-eks-user-auth"
        tags                      = {
            "Name"        = "dev-eks-user-auth"
            "branch"      = "OneM"
            "cost_code"   = "-"
            "department"  = "-"
            "division"    = "-"
            "environment" = "dev"
            "namespace"   = "om"
            "owner"       = "OneM"
            "project"     = "Om"
            "stack_name"  = "dev-eks"
        }
        # (11 unchanged attributes hidden)

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

          - string_attribute_constraints {
              - max_length = "256" -> null
              - min_length = "1" -> null
            }
        }
      - schema {
          - attribute_data_type      = "String" -> null
          - developer_only_attribute = false -> null
          - mutable                  = false -> null
          - name                     = "success_login" -> null
          - required                 = false -> null

          - string_attribute_constraints {}
        }
      - schema {
          - attribute_data_type      = "String" -> null
          - developer_only_attribute = false -> null
          - mutable                  = false -> null
          - name                     = "sucess_login" -> null
          - required                 = false -> null

          - string_attribute_constraints {}
        }
      - schema {
          - attribute_data_type      = "String" -> null
          - developer_only_attribute = false -> null
          - mutable                  = true -> null
          - name                     = "last_login" -> null
          - required                 = false -> null

          - string_attribute_constraints {}
        }
      - schema {
          - attribute_data_type      = "String" -> null
          - developer_only_attribute = false -> null
          - mutable                  = true -> null
          - name                     = "name" -> null
          - required                 = true -> null

          - string_attribute_constraints {
              - max_length = "256" -> null
              - min_length = "1" -> null
            }
        }
      + schema {
          + attribute_data_type = "String"
          + mutable             = false
          + name                = "email"
          + required            = true

          + string_attribute_constraints {
              + max_length = "256"
              + min_length = "1"
            }
        }
      + schema {
          + attribute_data_type = "String"
          + mutable             = true
          + name                = "name"
          + required            = true

          + string_attribute_constraints {
              + max_length = "256"
              + min_length = "1"
            }
        }
      + schema {
        }

      - user_pool_add_ons {
          - advanced_security_mode = "OFF" -> null
        }

        # (5 unchanged blocks hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.
╷
│ Warning: Reference to undefined provider
│ 
│   on cognito_auth.tf line 5, in module "cognito_user_auth":
│    5:     aws = aws.cognito-region
│ 
│ There is no explicit declaration for local provider name "aws" in
│ module.cognito_user_auth, so Terraform is assuming you mean to pass a
│ configuration for "hashicorp/aws".
│ 
│ If you also control the child module, add a required_providers entry named
│ "aws" with the source address "hashicorp/aws".
╵

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: 01_odc_eks.plan

To perform exactly these actions, run the following command to apply:
    terraform apply "01_odc_eks.plan"
Releasing state lock. This may take a few moments...
Acquiring state lock. This may take a few moments...
module.cognito_user_auth.aws_cognito_user_pool.pool: Modifying... [id=us-east-1]
╷
│ Warning: Reference to undefined provider
│ 
│   on cognito_auth.tf line 5, in module "cognito_user_auth":
│    5:     aws = aws.cognito-region
│ 
│ There is no explicit declaration for local provider name "aws" in
│ module.cognito_user_auth, so Terraform is assuming you mean to pass a
│ configuration for "hashicorp/aws".
│ 
│ If you also control the child module, add a required_providers entry named
│ "aws" with the source address "hashicorp/aws".
╵
╷
│ Error: updating Cognito User Pool (us-east-1): cannot modify or remove schema items
│ 
│   with module.cognito_user_auth.aws_cognito_user_pool.pool,
│   on .terraform/modules/cognito_user_auth/cognito/cognito_auth.tf line 28, in resource "aws_cognito_user_pool" "pool":
│   28: resource "aws_cognito_user_pool" "pool" {
│ 
╵
Releasing state lock. This may take a few moments...
Error: Process completed with exit code 1.

You said that:

but at least as far as the plan describes, you appear to be doing just that?

The changes revealed in the plan do not appear to be ones that I would expect to be possible from an upgrade of Terraform. I therefore suspect that something else has changed in your environment besides just upgrading Terraform - possibly multiple other things.

You would need to show the portion of the Terraform code of the cognito_user_auth module that deals with the pool resource, to allow further reasoning about what is happening.

Hello @maxb,

# Define packages versions
ENV TERRAFORM_VERSION="1.5.2"
ENV KUBE_VERSION="1.24.11"

I just updated these packages and did not make any additional changes. I’m not sure why it’s attempting to remove the existing user pool and make a new one, which is not possible.

Here is the Terraform code for the cognito_user_auth module:

module "cognito_user_auth" {
  source = "xxxxxxxxxxx"

  providers = {
    aws = aws.cognito-region
  }

  auto_verify      = false
  user_pool_name   = "${local.namespace}-${local.environment}-eks-user-auth"
  user_pool_domain = "${local.namespace}-${local.environment}-eks-user-auth"

  username_attributes              = ["email"] # set email as username attribute
  enable_username_case_sensitivity = false     # disable case sensitivity
  # NOTE: schema attributes can't be removed or changed once added to the user pool
  //  schema_additional_attributes = [
  //    {
  //      attribute_name           = "gender"
  //      attribute_data_type      = "String"
  //      developer_only_attribute = false,
  //      mutable                  = false
  //      required                 = true
  //      min_value                = 1
  //      max_value                = 10
  //    },
  //  ]

  user_groups = {
    "cluster-dev-group" = {
      "description" = "developer users and has access to argo and grafana"
      "precedence"  = 4
    },
    "dev-group" = {
      "description" = "dev users"
      "precedence"  = 5
    },
    "internal-group" = {
      "description" = "internal teams and has access to more resources"
      "precedence"  = 6
    }
  }

  app_clients = {
    "sandbox-client" = {
      "callback_urls" = [
        "https://${local.host_name}/oauth_callback",
        "https://${local.host_name}"
      ]
      "logout_urls"          = ["https://${local.host_name}"]
      "default_redirect_uri" = "https://${local.host_name}"
      "explicit_auth_flows"  = ["ALLOW_REFRESH_TOKEN_AUTH", "ALLOW_USER_SRP_AUTH", "ALLOW_CUSTOM_AUTH"]
      "token_validity_units" = {
        access_token  = "days"
        id_token      = "days"
        refresh_token = "days"
      }
      "allowed_oauth_scopes"   = ["email", "aws.cognito.signin.user.admin", "openid"]
      "allowed_oauth_flows"    = ["code"]
      "access_token_validity"  = 1
      "id_token_validity"      = 1
      "refresh_token_validity" = 30
    },
    "grafana-client" = {
      "callback_urls" = [
        "https://mt.${local.domain_name}/login/generic_oauth",
        "https://mt.${local.domain_name}"
      ]
      "logout_urls"          = ["https://mt.${local.domain_name}"]
      "default_redirect_uri" = "https://mt.${local.domain_name}"
      "explicit_auth_flows"  = ["ALLOW_REFRESH_TOKEN_AUTH", "ALLOW_USER_SRP_AUTH", "ALLOW_CUSTOM_AUTH"]
      "token_validity_units" = {
        access_token  = "minutes"
        id_token      = "minutes"
        refresh_token = "days"
      }
      "allowed_oauth_scopes"   = ["email", "aws.cognito.signin.user.admin", "openid"]
      "allowed_oauth_flows"    = ["code"]
      "access_token_validity"  = 60
      "id_token_validity"      = 60
      "refresh_token_validity" = 30
    },
    "argo-client" = {
      "callback_urls" = [
        "https://argo.${local.domain_name}/oauth2/callback",
        "https://argo.${local.domain_name}"
      ]
      "logout_urls"          = ["https://argo.${local.domain_name}"]
      "default_redirect_uri" = "https://argo.${local.domain_name}"
      "explicit_auth_flows"  = ["ALLOW_REFRESH_TOKEN_AUTH", "ALLOW_USER_SRP_AUTH", "ALLOW_CUSTOM_AUTH"]
      "token_validity_units" = {
        access_token  = "minutes"
        id_token      = "minutes"
        refresh_token = "days"
      }
      "allowed_oauth_scopes"   = ["email", "aws.cognito.signin.user.admin", "openid", "profile"]
      "allowed_oauth_flows"    = ["code"]
      "access_token_validity"  = 60
      "id_token_validity"      = 60
      "refresh_token_validity" = 30
    },
  }

  # Pinpoint support fixed in AWS Provider 3.29.0
  # https://github.com/hashicorp/terraform-provider-aws/issues/16481#issuecomment-781554589
  enable_pinpoint = local.enable_pinpoint

  admin_create_user_config = {
    allow_admin_create_user_only = false
    unused_account_validity_days = 0
    email_message                = <<EOT
Dear {username},

Your username is {username} and temporary password is {####}.

When you first login you will be asked to enter a new password.
The temporary password will expire in 7 days.

If you have any difficulties please contact us.

Regards

Cloud Team Lead

EOT
    email_subject                = "Your temporary password"
    sms_message                  = <<EOT
Welcome.
Your username is {username} and temporary password is {####}.
EOT
  }

  # Tags
  owner       = local.owner
  namespace   = local.namespace
  environment = local.environment

  # Additional tags
  tags = local.tags
}

As you haven’t mentioned any configuration restricting the version of terraform-provider-aws in use, I’m inclined to suspect you’re just ending up with the latest available version whenever you rebuild your Docker image. A changed version of a key provider seems potentially part of the puzzle.

You’ve provided the contents of the module "cognito_user_auth" block but that’s not really the important part here - what is needed, is the code that the source = "xxxxxxxxxxx" points to.

Considering various attributes are shown as removed in your Terraform plan, such as success_login, but there is no mention of them in the code you have so far posted, another option is that your module definition itself has changed:

but of course you’re xxxxxx-ing that out so that’s a question only you can answer.

Got it.

Sorry @maxb .

This is the cognito_auth on that repo.

# ======================================
# COGNITO

locals {
  alias_attributes = var.alias_attributes == null && var.username_attributes == null ? ["email"] : null

  # admin_create_user_config
  # If no admin_create_user_config list is provided, build a admin_create_user_config using the default values
  admin_create_user_config_default = {
    allow_admin_create_user_only = lookup(var.admin_create_user_config, "allow_admin_create_user_only", null) == null ? var.admin_create_user_config_allow_admin_create_user_only : lookup(var.admin_create_user_config, "allow_admin_create_user_only")
    email_message                = lookup(var.admin_create_user_config, "email_message", null) == null ? (var.email_verification_message == "" || var.email_verification_message == null ? var.admin_create_user_config_email_message : var.email_verification_message) : lookup(var.admin_create_user_config, "email_message")
    email_subject                = lookup(var.admin_create_user_config, "email_subject", null) == null ? (var.email_verification_subject == "" || var.email_verification_subject == null ? var.admin_create_user_config_email_subject : var.email_verification_subject) : lookup(var.admin_create_user_config, "email_subject")
    sms_message                  = lookup(var.admin_create_user_config, "sms_message", null) == null ? var.admin_create_user_config_sms_message : lookup(var.admin_create_user_config, "sms_message")

  }

  admin_create_user_config = [local.admin_create_user_config_default]

  token_validity_units_default = {
    access_token  = "minutes"
    id_token      = "minutes"
    refresh_token = "days"
  }
  allowed_oauth_scopes_default = ["email", "aws.cognito.signin.user.admin", "openid"]
  allowed_oauth_flows_default  = ["code"]
}

resource "aws_cognito_user_pool" "pool" {
  name                     = var.user_pool_name
  alias_attributes         = var.alias_attributes != null ? var.alias_attributes : local.alias_attributes
  username_attributes      = var.username_attributes
  auto_verified_attributes = var.auto_verify ? ["email"] : null

  schema {
    name                = "email"
    attribute_data_type = "String"
    mutable             = false
    required            = true
    string_attribute_constraints {
      min_length = 1
      max_length = 256
    }
  }

  schema {
    name                = "name"
    attribute_data_type = "String"
    mutable             = true
    required            = true
    string_attribute_constraints {
      min_length = 1
      max_length = 256
    }
  }

  dynamic "username_configuration" {
    for_each = var.enable_username_case_sensitivity != null ? [true] : []
    content {
      case_sensitive = var.enable_username_case_sensitivity
    }
  }

  # Limitations:
  # - standard attributes can only be selected during the pool creation and cannot be changed
  # - standard attributes cannot be switched between required and not required after a user pool has been created
  # - custom attributes can be defined as a string or a number only
  # - custom attributes can't be set to required
  # - custom attributes can't be removed or changed once added to the user pool
  dynamic "schema" {
    for_each = var.schema_additional_attributes
    iterator = attribute
    content {
      name                     = attribute.value.attribute_name
      attribute_data_type      = attribute.value.attribute_data_type
      developer_only_attribute = try(attribute.value.developer_only_attribute, false)
      mutable                  = try(attribute.value.mutable, true)
      required                 = try(attribute.value.required, false)

      dynamic "number_attribute_constraints" {
        for_each = attribute.value.attribute_data_type == "Number" ? [true] : []

        content {
          min_value = lookup(attribute.value, "min_value", null)
          max_value = lookup(attribute.value, "max_value", null)
        }
      }

      dynamic "string_attribute_constraints" {
        for_each = attribute.value.attribute_data_type == "String" ? [true] : []

        content {
          min_length = lookup(attribute.value, "min_length", 0)
          max_length = lookup(attribute.value, "max_length", 2048)
        }
      }
    }
  }

  password_policy {
    minimum_length                   = 8
    require_uppercase                = true
    require_lowercase                = true
    require_numbers                  = true
    require_symbols                  = false
    temporary_password_validity_days = 7
  }

  # admin_create_user_config
  dynamic "admin_create_user_config" {
    for_each = local.admin_create_user_config
    content {
      allow_admin_create_user_only = lookup(admin_create_user_config.value, "allow_admin_create_user_only")

      dynamic "invite_message_template" {
        for_each = lookup(admin_create_user_config.value, "email_message", null) == null && lookup(admin_create_user_config.value, "email_subject", null) == null && lookup(admin_create_user_config.value, "sms_message", null) == null ? [] : [1]
        content {
          email_message = lookup(admin_create_user_config.value, "email_message")
          email_subject = lookup(admin_create_user_config.value, "email_subject")
          sms_message   = lookup(admin_create_user_config.value, "sms_message")
        }
      }
    }
  }

  lifecycle {
    # Enable prevent destroy
    # prevent_destroy = true
  }

  tags = merge(
    {
      Name        = var.user_pool_name
      owner       = var.owner
      namespace   = var.namespace
      environment = var.environment
    },
    var.tags
  )
}

resource "aws_cognito_user_pool_client" "clients" {
  for_each                     = var.app_clients
  name                         = each.key
  user_pool_id                 = aws_cognito_user_pool.pool.id
  generate_secret              = true
  supported_identity_providers = ["COGNITO"]

  callback_urls        = each.value.callback_urls
  default_redirect_uri = each.value.default_redirect_uri
  logout_urls          = each.value.logout_urls
  explicit_auth_flows  = each.value.explicit_auth_flows

  allowed_oauth_flows_user_pool_client = true
  allowed_oauth_scopes                 = lookup(each.value, "allowed_oauth_scopes", local.allowed_oauth_scopes_default)
  allowed_oauth_flows                  = lookup(each.value, "allowed_oauth_flows", local.allowed_oauth_flows_default)

  dynamic "analytics_configuration" {
    for_each = var.enable_pinpoint ? [1] : []
    content {
      application_arn  = aws_pinpoint_app.pinpoint_app[each.key].arn
      user_data_shared = true
    }
  }

  token_validity_units {
    access_token  = lookup(each.value, "token_validity_units", null) == null ? local.token_validity_units_default.access_token : each.value.token_validity_units.access_token
    id_token      = lookup(each.value, "token_validity_units", null) == null ? local.token_validity_units_default.id_token : each.value.token_validity_units.id_token
    refresh_token = lookup(each.value, "token_validity_units", null) == null ? local.token_validity_units_default.refresh_token : each.value.token_validity_units.refresh_token
  }
  access_token_validity  = lookup(each.value, "access_token_validity", 60)
  id_token_validity      = lookup(each.value, "id_token_validity", 60)
  refresh_token_validity = lookup(each.value, "refresh_token_validity", 30)

}

resource "aws_cognito_user_pool_domain" "domain" {
  domain       = var.user_pool_domain
  user_pool_id = aws_cognito_user_pool.pool.id
}

resource "aws_cognito_user_group" "group" {
  for_each     = var.user_groups
  user_pool_id = aws_cognito_user_pool.pool.id
  name         = each.key
  description  = each.value.description
  precedence   = each.value.precedence
}

BTW, that’s an old repo where they haven’t updated the code in like two years.

This just loops back around to the original conclusion: It seems that you have removed some attributes, which isn’t supported by AWS Cogito.

It is evident in your plan that attributes:

  • success_login
  • sucess_login
  • last_login

were previously defined and now they are not.

Yes, you are correct. Years ago, someone changed it back.

When I added it back it is working fine.
But what concerns me is that the error did not appear in previous versions and only appeared after the update.

I don’t think it had anything to do with the Terraform version itself.

I think you ended up unwittingly changing something else as a side effect of moving to a new version - I saw implications of Docker being in your setup somewhere - lots of potential for unwittingly caching something odd in an image, and only noticing when you rebuild.

1 Like

Without my knowledge, someone added the schema attributes that were missing from the configuration.
Can’t we force the new attributes to be updated?

I do not understand what you mean.

I’m asking if terraform force apply will update the attributes or if I must update the schema in my config.

I have no idea what you mean by that… there is no way Terraform can “force” AWS to do something that AWS have decided to make impossible.

So yes, you must.

1 Like

These are the custom attributes which were added to the pool:

    {
        "Name": "custom:last_login",
        "AttributeDataType": "String",
        "DeveloperOnlyAttribute": false,
        "Mutable": true,
        "Required": false,
        "StringAttributeConstraints": {}
    },
    {
        "Name": "custom:sucess_login",
        "AttributeDataType": "String",
        "DeveloperOnlyAttribute": false,
        "Mutable": false,
        "Required": false,
        "StringAttributeConstraints": {}
    },
    {
        "Name": "custom:success_login",
        "AttributeDataType": "String",
        "DeveloperOnlyAttribute": false,
        "Mutable": false,
        "Required": false,
        "StringAttributeConstraints": {}
    }

When I’m trying to replace my config in here:

with this

  username_attributes              = ["email"] # set email as username attribute
  enable_username_case_sensitivity = false     # disable case sensitivity
  # NOTE: schema attributes can't be removed or changed once added to the user pool
 schema_additional_attributes = [
  //   {
  //     attribute_name           = "gender"
  //     attribute_data_type      = "String"
  //     developer_only_attribute = false,
  //     mutable                  = false
  //     required                 = true
  //     min_value                = 1
  //     max_value                = 10
  //   },
  
   {
     attribute_name               = "last_login"
     attribute_data_type          = "String"
     developer_only_attribute     = false
     mutable                      = true
     required                     = false
     string_attribute_constraints = {}
   },

   {
     attribute_name               = "success_login"
     attribute_data_type          = "String"
     developer_only_attribute     = false
     mutable                      = false
     required                     = false
     string_attribute_constraints = {}
   },

   {
     attribute_name               = "sucess_login"
     attribute_data_type          = "String"
     developer_only_attribute     = false
     mutable                      = false
     required                     = false
     string_attribute_constraints = {}
   }
 ]

Instead of syncing it is still trying to modify the changes. Is my config good or do I need to make any changes there?

Show the full output of the Terraform plan and what error you are getting on apply, to explain what you mean by that.

Output for Terraform plan:

Terraform will perform the following actions:

  # module.cognito_user_auth.aws_cognito_user_pool.pool will be updated in-place
  ~ resource "aws_cognito_user_pool" "pool" {
        id                        = "us-east-1"
        name                      = "dev-eks-user-auth"
        tags                      = {
            "Name"        = "dev-eks-user-auth"
            "branch"      = "OneM"
            "cost_code"   = "-"
            "department"  = "-"
            "division"    = "-"
            "environment" = "dev"
            "namespace"   = "om"
            "owner"       = "OneM"
            "project"     = "Om"
            "stack_name"  = "dev-eks"
        }
        # (11 unchanged attributes hidden)

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

          - string_attribute_constraints {
              - max_length = "256" -> null
              - min_length = "1" -> null
            }
        }
      - schema {
          - attribute_data_type      = "String" -> null
          - developer_only_attribute = false -> null
          - mutable                  = false -> null
          - name                     = "success_login" -> null
          - required                 = false -> null

          - string_attribute_constraints {}
        }
      - schema {
          - attribute_data_type      = "String" -> null
          - developer_only_attribute = false -> null
          - mutable                  = false -> null
          - name                     = "sucess_login" -> null
          - required                 = false -> null

          - string_attribute_constraints {}
        }
      - schema {
          - attribute_data_type      = "String" -> null
          - developer_only_attribute = false -> null
          - mutable                  = true -> null
          - name                     = "last_login" -> null
          - required                 = false -> null

          - string_attribute_constraints {}
        }
      - schema {
          - attribute_data_type      = "String" -> null
          - developer_only_attribute = false -> null
          - mutable                  = true -> null
          - name                     = "name" -> null
          - required                 = true -> null

          - string_attribute_constraints {
              - max_length = "256" -> null
              - min_length = "1" -> null
            }
        }
      + schema {
          + attribute_data_type      = "String"
          + developer_only_attribute = false
          + mutable                  = false
          + name                     = "success_login"
          + required                 = false

          + string_attribute_constraints {
              + max_length = "2048"
              + min_length = "0"
            }
        }
      + schema {
          + attribute_data_type      = "String"
          + developer_only_attribute = false
          + mutable                  = false
          + name                     = "sucess_login"
          + required                 = false

          + string_attribute_constraints {
              + max_length = "2048"
              + min_length = "0"
            }
        }
      + schema {
          + attribute_data_type      = "String"
          + developer_only_attribute = false
          + mutable                  = true
          + name                     = "last_login"
          + required                 = false

          + string_attribute_constraints {
              + max_length = "2048"
              + min_length = "0"
            }
        }
      + schema {
          + attribute_data_type = "String"
          + mutable             = false
          + name                = "email"
          + required            = true

          + string_attribute_constraints {
              + max_length = "256"
              + min_length = "1"
            }
        }
      + schema {
          + attribute_data_type = "String"
          + mutable             = true
          + name                = "name"
          + required            = true

          + string_attribute_constraints {
              + max_length = "256"
              + min_length = "1"
            }
        }
      + schema {
        }

      - user_pool_add_ons {
          - advanced_security_mode = "ENFORCED" -> null
        }

        # (5 unchanged blocks hidden)
    }

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

Error message:

│ Error: updating Cognito User Pool (us-east-1): cannot modify or remove schema items
│ 
│   with module.cognito_user_auth.aws_cognito_user_pool.pool,
│   on .terraform/modules/cognito_user_auth/cognito/cognito_auth.tf line 28, in resource "aws_cognito_user_pool" "pool":
│   28: resource "aws_cognito_user_pool" "pool" {
│ 
╵
Releasing state lock. This may take a few moments...
Error: Process completed with exit code 1.

You have three issues here:

  1. Copy all of the schema entries in the Terraform plan that are showing as to be removed into one text document. Copy all of the ones that are showing as to be added into another. View them side by side. You will be able to observe that there are differences between the current actual AWS configuration (shown as to be removed) and the current declarations in Terraform configuration (shown as to be added) do not match exactly in all details.

  2. Something weird is going on here:

I have not been able to figure out what in your configuration is causing this.

  1. You probably don’t want this change either, so will need to update another part of your configuration: