S3 Replication Configuration Rules are keep being delete its a bug?

Hi,

I have one bucket that replicates the content of the bucket to several buckets.
the rule was created manually and now I want to create it as code.

I have written this sort code to allow to create multiple rules in a single bucket.

variable "replication_rules" {
  type = any
  default = {}
}

resource "aws_s3_bucket_replication_configuration" "replication_rules" {
  provider  = aws.provider
  count     = var.versioning && length(var.replication_rules) > 0 ? length(var.replication_rules) : 0
  bucket    = aws_s3_bucket.b[0].id
  role      = var.replication_rules[count.index].role
  
  rule {
      id        = var.replication_rules[count.index].id
      priority  = try(var.replication_rules[count.index].priority, null)
      prefix    = try(var.replication_rules[count.index].prefix, null)
      status    = try(var.replication_rules[count.index].status,  "Disabled")
    delete_marker_replication {
      status = try(var.replication_rules[count.index].delete_marker_replication, "Disabled")
    }
    destination {
        bucket        = var.replication_rules[count.index].bucket
        storage_class = try(var.replication_rules[count.index].storage_class, "STANDARD")
    }
    filter {}
  }
}

the above code get variable value

replication_rules = [
 {
   role    = "arn:aws:iam::XXXXXX:role/replication-test-1",
   id      = "replication-test-1",
   status  = true,
   priority = 100,
   bucket        = "arn:aws:s3:::replication-test-1",
   delete_marker_replication = "Enabled"
  },
  {
    role = "arn:aws:iam::XXXXXXX:role/replication-test-2",
    id      = "replication-test-2",
    status  = true,
    priority = 200,
    bucket        = "arn:aws:s3:::replication-test-2",
    delete_marker_replication = "Enabled"
  }
]

my issue is that the terraform show that he wants to create both rules but in the real world he overwrote the first rule with the other

Plan: 2 to add, 0 to change, 0 to destroy.
aws_s3_bucket_replication_configuration.replication_rules[0]: Creating...
aws_s3_bucket_replication_configuration.replication_rules[1]: Creating...
aws_s3_bucket_replication_configuration.replication_rules[1]: Creation complete after 1s [id=replication-bucket]
aws_s3_bucket_replication_configuration.replication_rules[0]: Creation complete after 2s [id=replication-bucket]

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

Outputs:

now if I will run again terraform plan this is the output that I’m getting

aws_s3_bucket.b[0]: Refreshing state... [id=replication-bucket]
aws_s3_bucket_replication_configuration.replication_rules[1]: Refreshing state... [id=replication-bucket]
aws_s3_bucket_replication_configuration.replication_rules[0]: Refreshing state... [id=replication-bucket]

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:

  # aws_s3_bucket_replication_configuration.replication_rules[1] will be updated in-place
  ~ resource "aws_s3_bucket_replication_configuration" "replication_rules" {
        id     = "replication-bucket"
      ~ role   = "arn:aws:iam::XXXXXXXXX:role/replication-test-1" -> "arn:aws:iam::XXXXXXXXX:role/replication-test-2"
        # (1 unchanged attribute hidden)

      ~ rule {
          ~ id       = "replication-test-1" -> "replication-test-2"
          ~ priority = 100 -> 200
            # (1 unchanged attribute hidden)

          ~ destination {
              ~ bucket        = "arn:aws:s3:::replication-test-1" -> "arn:aws:s3:::replication-test-2"
                # (1 unchanged attribute hidden)
            }

            # (2 unchanged blocks hidden)
        }
    }

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

the issue is that every plan applying the terraform resource is updating the existing one and deleting the other.

any idea why it happens and why I can’t attach multiple replication rules?

thanks

As per the documentation for that resource you can only have a single instance of it for any particular S3 bucket. Instead what you need is a single instance with multiple rule {} blocks.

Take a look at using the dynamic method to allow this to be done programmatically.

Hi @stuart-c

Thanks for your reply.

I have already tested multiple ways to achieve it.
for example:

  1. as you mention dynamic “rule” which did the same as my count
  2. separated the rule into multiple resources e.g.
    • s3_bucket_replication_configuration.replica_a
    • s3_bucket_replication_configuration.replica_b
      added depens_on = [ s3_bucket_replication_configuration.replica_a ]
  3. count as shown above
  4. create manual rules and import them into the state file

The results were the same the rules were overwritten and only one rule was left in AWS UI.

if you want I will show It live.

here is my dynamic rule that should work
variable

    replication_configuration = [ 
      {
        role = "arn:aws:iam::XXXX:role/replication-test-2"
        rules = [
            {
              id       = "replication-test-2"
              status   = true
              priority = 1
              delete_marker_replication = true
              filter = {
                prefix = "one"
                tags = {
                  ReplicateMe = "Yes"
                }
              }
              destination = {
                bucket        = "arn:aws:s3::replication-test-2"
                storage_class = "STANDARD"
              }
            }
        ]
      },
      {
        role = "arn:aws:iam::XXXX:role/replication-test-1"
        rules = [
            {
              id       = "replication-test-1"
              status   = true
              priority = 2
              delete_marker_replication = true
              filter = {
                prefix = "two"
                tags = {
                  ReplicateMe = "Yes"
                }
              }
              destination = {
                bucket        = "arn:aws:s3:::replication-test-1"
                storage_class = "STANDARD"
              }
            }
        ]
      }
    ]

resource creation

resource "aws_s3_bucket_replication_configuration" "replication_configuration" {
  provider  = aws.provider
  count     = var.versioning && length(var.replication_configuration) > 0 ? length(var.replication_configuration) : 0

  bucket    = aws_s3_bucket.b[0].id
  role   = var.replication_configuration[count.index]["role"]
  
  dynamic "rule" {
    for_each = flatten(try([var.replication_configuration[count.index]["rules"]], []))

    content {
      id     = "replication-${random_uuid.test.result}"
      priority = try(rule.value.priority, null)
      prefix   = try(rule.value.prefix, null)
      status   = try(tobool(rule.value.status) ? "Enabled" : "Disabled", title(lower(rule.value.status)), "Enabled")

      dynamic "destination" {
        for_each = try(flatten([rule.value.destination]), [])
        content {
          bucket        = destination.value.bucket
          storage_class = try(destination.value.storage_class, null)
          account       = try(destination.value.account_id, null)
          }
        }

      dynamic "delete_marker_replication" {
        for_each = flatten(try([rule.value.delete_marker_replication_status], [rule.value.delete_marker_replication], []))
        content {
            status = try(tobool(delete_marker_replication.value) ? "Enabled" : "Disabled")
        }
      }
      filter { }
    }
  }
}

You still have a count which needs removing. You can only have a single instance of that resource for a bucket. With that count it will still be making multiple resources.

Hi @stuart-c
Thanks for your reply.

I don’t understand your comment, the whole thread here is talking about creating multiple rules replication rules in a single bucket.

as you can see in the image below, I’ve created this replication manually,
I want to manage those rules via terraform resource, so the count || for_each in the resource is mandatory

Thanks

The resource represents all rules for a single S3 bucket. In the code you gave above the S3 buket name is fixed, so therefore there needs to be only a single instance of that resource. Having a count is therefore not needed.

I understand what you mean, the only block I can use is the “rules” as “dynamic”.
another question:
when I create the rule via AWS UI it allows me to choose which role I want to use

  • why can’t I change the role id for each rule?

Looking at the API Terraform will be using (PutBucketReplication - Amazon Simple Storage Service) it looks like the role is set for the bucket as a whole and not for each rule, which is why Terraform offers it the way it does.

Thank you for your assistance and guides of the issue,
I took this resource with a wrong direction, so thank you.