How to add lifecycle rules to an S3 bucket using terraform?

13,915

Lets first break down whats happening and how we can overcome this issue. Each time you define a resource "aws_s3_bucket", terraform will attempt to create a bucket with the parameters specified. If you want to attach a lifecycle policy to a bucket, do it where you define the bucket, e.g.:

resource "aws_s3_bucket" "quarterly" {
    bucket  = "quarterly_bucket_name"
    #bucket  = "${var.bucket_id}"
    acl     = "private"
    lifecycle_rule {
        id      = "quarterly_retention"
        prefix  = "folder/"
        enabled = true

        expiration {
            days = 92
        }
    }
}

resource "aws_s3_bucket" "permanent" {
    bucket  = "perm_bucket_name"
    acl     = "private"
    lifecycle_rule {
        id      = "permanent_retention"
        enabled = true
        prefix  = "permanent/"

        transition {
            days            = 1
            storage_class   = "GLACIER"
        }
    }
}

A bucket can have multiple lifecycle_rule blocks on it. If you want to define the lifecycle rules as external blocks, you can do it in this way:

// example of what the variable would look like:
variable "lifecycle_rules" {
  type = "list"
  default = []
}

// example of what the assignment would look like:
lifecycle_rules = [{
  id = "cleanup"
  prefix = ""
  enabled = true
  expiration = [{
    days = 1
  }]
}, {...}, {...} etc...]

// example what the usage would look like
resource "aws_s3_bucket" "quarterly" {
    bucket  = "quarterly_bucket_name"
    #bucket  = "${var.bucket_id}"
    acl     = "private"
    source  = "/dev/null"
    lifecycle_rule = [ "${var.lifecycle_rules}" ]
}

Note: the implementation above of having an external lifecycle policy isn't really the best way to do it, but the only way. You pretty much trick terraform into accepting the list of maps, which happens to be the same type as lifecycle_rule, so it works. Ideally, Terraform should have it's own resource block for lifecycle rules, but it doesn't.

Edit: why have separate resource blocks when we now have dynamic blocks! Woohoo

Share:
13,915

Related videos on Youtube

prowla
Author by

prowla

Updated on June 04, 2022

Comments

  • prowla
    prowla almost 2 years

    I am using Terraform to create a bucket in S3 and I want to add "folders" and lifecycle rules to it.

    I can create the bucket (using an "aws_s3_bucket" resource).

    I can create the bucket and define my lifecycle rules within the same "aws_s3_bucket" resource, ie. at creation time.

    I can add "folders" to the bucket (I know they aren't really folders, but they are presented to the client systems as if they were... :-) ), using an "aws_s3_bucket_object" resource, ie. after bucket creation.

    All good...

    But I want to be able to add lifecycle rules AFTER I've created the bucket, but I get an error telling me the bucket already exists. (Actually I want to be able to subsequently add folders and corresponding lifecycle rules as and when required.)

    Now, I can add lifecycle rules to an existing bucket in the AWS GUI, so I know it is a reasonable thing to want to do.

    But is there a way of doing it with Terraform?

    Am I missing something?

    resource "aws_s3_bucket" "bucket" {
        bucket      = "${replace(var.tags["Name"],"/_/","-")}"
        region      = "${var.aws_region}"
    
        #tags                = "${merge(var.tags, map("Name", "${var.tags["Name"]}"))}"
        tags                = "${merge(var.tags, map("Name", "${replace(var.tags["Name"],"/_/","-")}"))}"
    }
    
    
    resource "aws_s3_bucket" "bucket_quarterly" {
        bucket      = "${aws_s3_bucket.bucket.id}"
        #region      = "${var.aws_region}"
    
        lifecycle_rule {
            id      = "quarterly_retention"
            prefix  = "quarterly/"
            enabled = true
    
            expiration {
                days = 92
            }
        }
    
    }
    
    
    resource "aws_s3_bucket" "bucket_permanent" {
        bucket      = "${aws_s3_bucket.bucket.id}"
        #region      = "${var.aws_region}"
    
        lifecycle_rule {
            id      = "permanent_retention"
            enabled = true
            prefix  = "permanent/"
    
            transition {
                days            = 1
                storage_class   = "GLACIER"
            }
        }
    
    }
    
    
    resource "aws_s3_bucket_object" "quarterly" {
        bucket  = "${aws_s3_bucket.bucket.id}"
        #bucket  = "${var.bucket_id}"
        acl     = "private"
        key     = "quarterly"
        source  = "/dev/null"
    }
    
    
    resource "aws_s3_bucket_object" "permanent" {
        bucket  = "${aws_s3_bucket.bucket.id}"
        #bucket  = "${var.bucket_id}"
        acl     = "private"
        key     = "permanent"
        source  = "/dev/null"
    }
    

    I expect to have a bucket with 2 lifecycle rules, but I get the following error:

    Error: Error applying plan:

    2 error(s) occurred:
    
    * module.s3.aws_s3_bucket.bucket_quarterly: 1 error(s) occurred:
    
    * aws_s3_bucket.bucket_quarterly: Error creating S3 bucket: BucketAlreadyOwnedByYou: Your previous request to create the named bucket succeeded and you already own it.
        status code: 409, request id: EFE9C62B25341478, host id: hcsCNracNrpTJZ4QdU0AV2wNm/FqhYSEY4KieQ+zSHNsj6AUR69XvPF+0BiW4ZOpfgIoqwFoXkI=
    * module.s3.aws_s3_bucket.bucket_permanent: 1 error(s) occurred:
    
    * aws_s3_bucket.bucket_permanent: Error creating S3 bucket: BucketAlreadyOwnedByYou: Your previous request to create the named bucket succeeded and you already own it.
        status code: 409, request id: 7DE1B1A36138A614, host id: 8jB6l7d6Hc6CZFgQSLQRMJg4wtvnrSL6Yp5R4RScq+GtuMW+6rkN39bcTUwQhzxeI7jRStgLXSc=
    
    Terraform does not automatically rollback in the face of errors.
    Instead, your Terraform state file has been partially updated with
    any resources that successfully completed. Please address the error
    above and apply again to incrementally change your infrastructure.
    
  • Mendhak
    Mendhak almost 4 years
    > Blocks of type "lifecycle_rule" are not expected here. There doesn't seem to be a lifecycle_rule for aws_s3_bucket_object
  • Moe
    Moe almost 4 years
    Thank you for pointing that out. I've updated the resource names to be correct now.
  • Serhii Popov
    Serhii Popov over 3 years
    @Moe, What do you mean with dynamic blocks?
  • Moe
    Moe over 3 years
    google "dynamic blocks terraform" and the first result explains it in detail: github.com/hashicorp/terraform-guides/tree/master/…