Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.
like image 459
prowla Avatar asked Mar 27 '19 09:03

prowla


People also ask

What is life cycle rule in S3?

An S3 Lifecycle configuration is an XML file that consists of a set of rules with predefined actions that you want Amazon S3 to perform on objects during their lifetime. You can also configure the lifecycle by using the Amazon S3 console, REST API, AWS SDKs, and the AWS Command Line Interface (AWS CLI).

Can we create S3 bucket using Terraform?

Once you have all the tools and utilities installed, the next step is to create a Terraform configuration to provision an S3 bucket on AWS. Navigate into the directory and create a Terraform configuration. Open the file and add the following configuration to create an S3 bucket using your favorite text editor.


1 Answers

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

like image 188
Moe Avatar answered Sep 21 '22 14:09

Moe