Skip to content

S3 Bucket Lifecycle always prompts a change in plan #9314

Description

@zerfahp

I have a module that creates s3 buckets. The module contains 4 lifecycle policies. 1 is enabled by default and 3 disabled by default. To be extra cautious I set the expiry days very high so that if the rule is enabled by accident and no expiry is then objects are no transitioned or expired for a long time.

The module looks like this....

#create the bucket
resource "aws_s3_bucket" "private_bucket" {
  bucket = "${local.bucket_id}"
  acl    = "${var.acl}"
  policy = "${data.aws_iam_policy_document.policy.json}"
  tags   = "${var.tags}"

  logging {
    target_bucket = "${local.logging_bucket_id}"
    target_prefix = "${local.bucket_id}/"
  }

  versioning {
    enabled    = "${var.enable_versioning}"
    mfa_delete = "${var.mfa_delete}"
  }

  #lifecycle rules for non-current versions (defaults to on)
  lifecycle_rule {
    enabled = "${var.enable_lifecycle}"
    id      = "default"

    abort_incomplete_multipart_upload_days = 14

    transition {
      days          = "${var.current_ia_transition_days}"
      storage_class = "STANDARD_IA"
    }

    transition {
      days          = "${var.current_glacier_transition_days}"
      storage_class = "GLACIER"
    }

    expiration {
      expired_object_delete_marker = true
      days          = "${var.current_version_expiration_days}"
    }

    noncurrent_version_transition {
      days          = "${var.noncurrent_ia_transition_days}"
      storage_class = "STANDARD_IA"
    }

    noncurrent_version_transition {
      days          = "${var.noncurrent_glacier_transition_days}"
      storage_class = "GLACIER"
    }

    noncurrent_version_expiration {
      days = "${var.noncurrent_version_expiration_days}"
    }

  }

  #optional extra lifeycle rule 1
  lifecycle_rule {
    enabled = "${var.enable_extra_lifecycle_1}"
    id      = "${var.extra_lifecycle_1_id}"

    abort_incomplete_multipart_upload_days = 14

    prefix = "${var.extra_lifecycle_1_prefix}"

    transition {
      days          = "${var.extra_lifecycle_1_current_ia_transition_days}"
      storage_class = "STANDARD_IA"
    }

    transition {
      days          = "${var.extra_lifecycle_1_current_glacier_transition_days}"
      storage_class = "GLACIER"
    }

    expiration {
      expired_object_delete_marker = true
      days          = "${var.extra_lifecycle_1_current_version_expiration_days}"
    }

    noncurrent_version_transition {
      days          = "${var.extra_lifecycle_1_noncurrent_ia_transition_days}"
      storage_class = "STANDARD_IA"
    }

    noncurrent_version_transition {
      days          = "${var.extra_lifecycle_1_noncurrent_glacier_transition_days}"
      storage_class = "GLACIER"
    }

    noncurrent_version_expiration {
      days          = "${var.extra_lifecycle_1_noncurrent_version_expiration_days}"
    }

  }

  #optional extra lifeycle rule 2
  lifecycle_rule {
    enabled = "${var.enable_extra_lifecycle_2}"
    id      = "${var.extra_lifecycle_2_id}"

    abort_incomplete_multipart_upload_days = 14

    prefix = "${var.extra_lifecycle_2_prefix}"

    transition {
      days          = "${var.extra_lifecycle_2_current_ia_transition_days}"
      storage_class = "STANDARD_IA"
    }

    transition {
      days          = "${var.extra_lifecycle_2_current_glacier_transition_days}"
      storage_class = "GLACIER"
    }

    expiration {
      expired_object_delete_marker = true
      days          = "${var.extra_lifecycle_2_current_version_expiration_days}"
    }

    noncurrent_version_transition {
      days          = "${var.extra_lifecycle_2_noncurrent_ia_transition_days}"
      storage_class = "STANDARD_IA"
    }

    noncurrent_version_transition {
      days          = "${var.extra_lifecycle_2_noncurrent_glacier_transition_days}"
      storage_class = "GLACIER"
    }

    noncurrent_version_expiration {
      days          = "${var.extra_lifecycle_2_noncurrent_version_expiration_days}"
    }

  }

  #optional extra lifeycle rule 3
  lifecycle_rule {
    enabled = "${var.enable_extra_lifecycle_3}"
    id      = "${var.extra_lifecycle_3_id}"

    abort_incomplete_multipart_upload_days = 14

    prefix = "${var.extra_lifecycle_3_prefix}"

    transition {
      days          = "${var.extra_lifecycle_3_current_ia_transition_days}"
      storage_class = "STANDARD_IA"
    }

    transition {
      days          = "${var.extra_lifecycle_3_current_glacier_transition_days}"
      storage_class = "GLACIER"
    }

    expiration {
      expired_object_delete_marker = true
      days          = "${var.extra_lifecycle_3_current_version_expiration_days}"
    }

    noncurrent_version_transition {
      days          = "${var.extra_lifecycle_3_noncurrent_ia_transition_days}"
      storage_class = "STANDARD_IA"
    }

    noncurrent_version_transition {
      days          = "${var.extra_lifecycle_3_noncurrent_glacier_transition_days}"
      storage_class = "GLACIER"
    }

    noncurrent_version_expiration {
      days          = "${var.extra_lifecycle_3_noncurrent_version_expiration_days}"
    }

  }

  #use the kms sse key for default encryption
  server_side_encryption_configuration {
    rule {
      apply_server_side_encryption_by_default {
        kms_master_key_id = "${module.kms_sse_key.key_id}"
        sse_algorithm     = "aws:kms"
      }
    }
  }
}

The Variables for lifecycles are all set similar to this (I wont paste them all as there are loads)

variable "extra_lifecycle_1_prefix" {
  description = "Prefix to discrimate which objects the rule applies to"
  default     = "extra_1/"
}

#current version lifecycle variables (default to a very long time)
variable "extra_lifecycle_1_current_ia_transition_days" {
  description = "Number of days after which to move current objects to to IA storage tier"
  default     = "9900"
}

variable "extra_lifecycle_1_current_glacier_transition_days" {
  description = "Number of days after which to move current version objects to to glacier storage tier"
  default     = "9950"
}

variable "extra_lifecycle_1_current_version_expiration_days" {
  description = "Number of days after which to expire current versions"
  default     = "9999"
}

#non-current version lifecycle variables (enabled by default)
variable "extra_lifecycle_1_noncurrent_ia_transition_days" {
  description = "Number of days after which to move non-current objects to to IA storage tier"
  default     = "30"
}

variable "extra_lifecycle_1_noncurrent_glacier_transition_days" {
  description = "Number of days after which to move non-current objects to to glacier storage tier"
  default     = "90"
}

variable "extra_lifecycle_1_noncurrent_version_expiration_days" {
  description = "Number of days after which to expire"
  default     = "365"
}
Every time I run a plan, even though I'm not changing the buckets at all it says it's going to change the lifecycle rule.

For example:


  ~ module.tf_module_sagemaker_logs_bucket.aws_s3_bucket.private_bucket
      lifecycle_rule.0.expiration.1717063568.date:                         "" => ""
      lifecycle_rule.0.expiration.1717063568.days:                         "" => "99999"
      lifecycle_rule.0.expiration.1717063568.expired_object_delete_marker: "" => "true"
      lifecycle_rule.0.expiration.66073835.date:                           "" => ""
      lifecycle_rule.0.expiration.66073835.days:                           "99999" => "0"
      lifecycle_rule.0.expiration.66073835.expired_object_delete_marker:   "false" => "false"
      lifecycle_rule.1.expiration.1717063568.date:                         "" => ""
      lifecycle_rule.1.expiration.1717063568.days:                         "" => "99999"
      lifecycle_rule.1.expiration.1717063568.expired_object_delete_marker: "" => "true"
      lifecycle_rule.1.expiration.66073835.date:                           "" => ""
      lifecycle_rule.1.expiration.66073835.days:                           "99999" => "0"
      lifecycle_rule.1.expiration.66073835.expired_object_delete_marker:   "false" => "false"
      lifecycle_rule.2.expiration.1717063568.date:                         "" => ""
      lifecycle_rule.2.expiration.1717063568.days:                         "" => "99999"
      lifecycle_rule.2.expiration.1717063568.expired_object_delete_marker: "" => "true"
      lifecycle_rule.2.expiration.66073835.date:                           "" => ""
      lifecycle_rule.2.expiration.66073835.days:                           "99999" => "0"
      lifecycle_rule.2.expiration.66073835.expired_object_delete_marker:   "false" => "false"
      lifecycle_rule.3.expiration.1717063568.date:                         "" => ""
      lifecycle_rule.3.expiration.1717063568.days:                         "" => "99999"
      lifecycle_rule.3.expiration.1717063568.expired_object_delete_marker: "" => "true"
      lifecycle_rule.3.expiration.66073835.date:                           "" => ""
      lifecycle_rule.3.expiration.66073835.days:                           "99999" => "0"
      lifecycle_rule.3.expiration.66073835.expired_object_delete_marker:   "false" => "false"

I cannot for the life of me figure out why. I'm not sure if this is a bug or if I have some syntax wrong.

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionA question about existing functionality; most questions are re-routed to discuss.hashicorp.com.service/s3Issues and PRs that pertain to the s3 service.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions