Advice on variable s3_lifecycle_configuration conditional rules

I’ve got a use case that I think is common, and a solution that seems to work, but it’s clumsy and there may be a better way. Advice is welcome.

Use Case:

  1. Multiple AWS s3 buckets, created and managed by TF
  2. Lifecycle rules of two kinds:
  • General lifecycle rules to be applied to all buckets in the account
  • Targeted lifecycle rules to be applied to a single bucket or list of them

In short, general policies and additional policies for lifecycle.

Ordinarily I’d have the general policies in one lifecycle configuration and specific ones in another as needed, but the aws_s3_bucket_lifecycle_configuration resource is strictly limited to one config per bucket.

My original approach was to extract all the lifecycle rules into a variable which would be a data structure keyed by bucket name and containing each rule. That approach proved infeasible because there was enough variation in potential lifecycle rules that the data structures (list of map of objects) became unsupportably clumsy.

The slightly-less-clumsy but apparently working approach is to hardcode the general policies as regular rule{} blocks, and create dynamic blocks for each of the bucket specific policies, activated or skipped by a conditional.

This works, but the mechanism for indicating a match on the dynamic block that I could devise depends on a dummy marker in locals (or variables which is wordier), and seems counterintuitive and clumsy.

Is there a better way? Working example below. The use of the dummy local.rule_enabled seems especially confusing. Is there a clearer way to indicate that if a bucket name matches on a for_each the block should be processed?

locals {
  rule_enabled = {enabled = true}
}


resource "aws_s3_bucket_lifecycle_configuration" "lifecycle" {
  for_each = toset(["bucket1","bucket2","bucket3"])
  bucket = each.value

  # Rules below apply to all buckets without condition
  rule {
    id = "Abort Multipart Uploads"
    filter {}
    status = "Enabled"
    abort_incomplete_multipart_upload {
      days_after_initiation = 2
    }
  }

  # The dynamic rules below apply only to the bucket name in the each.value attribute
  dynamic "rule" {
    for_each = each.value == "bucket1" ? local.rule_enabled : {}
    content {
      id = "SGE Accounting Log Lifecycle Policy"
      filter {
        prefix = "uge/"
      }
      status = "Enabled"
      expiration {
        days = 1095
      }
      transition {
        days          = 0
        storage_class = "DEEP_ARCHIVE"
      }
    }
  }

  dynamic "rule" {
    for_each = each.value == "bucket1" ? local.rule_enabled : {}
    content {
      id = "Test Prefix Lifecycle Delete Policy"
      filter { 
        prefix = "test/*"
      }
      status = "Enabled"
      expiration {
        days = 2
      }
    }
  }

  dynamic "rule" {
    for_each = each.value == "bucket2" ? local.rule_enabled : {}
    content {
          id = "Dummy policy to test dynamic rules"
    filter {
      prefix = "testxxyzzq1237/*"
    }
    status = "Enabled"
    expiration {
      days = 2000
    }
    }
  }

  # END of rules


  lifecycle {
    prevent_destroy = true
  }
}