Terraform-provider-aws: aws_s3_bucket_notification - lambda - append new instead of deleting all previous

Created on 13 Jun 2017  ยท  29Comments  ยท  Source: hashicorp/terraform-provider-aws

_This issue was originally opened by @ventz as hashicorp/terraform#11536. It was migrated here as part of the provider split. The original body of the issue is below._


Terraform Version

Terraform v0.8.5

Affected Resource(s)

  • aws_instance

If this issue appears to affect multiple resources, it may be an issue with Terraform's core, so please mention this.

Terraform Configuration Files

resource "aws_s3_bucket_notification" "LambdaS3Notification" {
    bucket = "${var.LogBucket}"
    lambda_function = [
        {
                id = "${var.customer}-LambdaFunction"
                lambda_function_arn = "${aws_lambda_function.LambdaFunction.arn}"
                events = ["s3:ObjectCreated:*"]
                filter_suffix = "gz"
        }
    ]
}

Debug Output

N/A

Panic Output

N/A

Expected Behavior

It should appends the added lambda functions to the existing S3 Event notification set - in this case, the existing set of lambda functions.

Actual Behavior

It deletes all existing lambda functions, and adds the new one. It seems to treat the item as a single value, instead of a list which contains multiple items.

Steps to Reproduce

Please list the steps required to reproduce the issue, for example:
terraform apply -parallelism=1

Important Factoids

N/A - full access, admin account.

References

Are there any other GitHub issues (open or closed) or Pull Requests that should be linked here? For example:
I found this which seems semi-related: https://github.com/hashicorp/terraform/issues/6934
However, that's more about the end-user creating multiple functions/resources as events.

enhancement servics3 upstream

Most helpful comment

Personally, I think there's a bigger issue (and potentially simpler solution) here - if terraform is to "support" AWS functionality, they simply need to mirror AWS support.

That is, if AWS overrides it, they need to override it.
If AWS appends, they need to append.

In my opinion, having a split decision on "what functions and how" is much worse.

Currently, AWS appends, and this is what terraform should do/support.

All 29 comments

so yeah. this is no bueno.
i want to manage a bucket notification to trigger a lambda, but i want to manage it with the lambda.
the bucket is multi-use and i don't have control over all the bucket notifications that other teams use.

the cause is that the notifications are a subresource of the bucket, right? and tf handles subresources of a resource as a single unit?

https://github.com/hashicorp/terraform/issues/11536

Are there plans to circle back on the augment-vs-replace bucket notification model? I would think the fundamentals are there with the 'id' argument to transition to the former. Look at notifications setup for specific bucket, if new id...augment, if existing id...replace.

Or has a deeper foundational architectural decision been made here that S3 buckets should not be shared across services? I can't imagine that the conclusion would be the _datastore_ needing to know about every function making use of it to ensure those services are properly notified. It would be like a traditional database (e.g. mysql server) having to know of all of its consumers to ensure it can provide the data they need. Its an inversion of the client-server model. Just as scalability in compatibility testing between distributed application services warrants the use of consumer-driven contracts ... the consumer of an S3 bucket should define what it needs to successfully interact with the data.

OUR SCENARIO: An application that uses domain-modeled lambdas that orchestrate an entire pipeline of input/output file processing to get raw data, clean/filter through NLP, and inevitably run through various stages of machine learning to generate insight. Each stage creates output artifacts which trigger the launch of the next lambda in the workflow. We want those artifacts in one place so that it is incredibly easy to access all the artifacts used in the journey and provide a quick mechanism to determine opportunities and gaps.

Personally, I think there's a bigger issue (and potentially simpler solution) here - if terraform is to "support" AWS functionality, they simply need to mirror AWS support.

That is, if AWS overrides it, they need to override it.
If AWS appends, they need to append.

In my opinion, having a split decision on "what functions and how" is much worse.

Currently, AWS appends, and this is what terraform should do/support.

+1

+1

+1

+1

+1

+1

+1

Can we get an official statement from Hashicorp regarding the behavior of this resource? If the desire is to alter the behavior to support multiple notification 'attachments', I imagine there are those in the community (myself included) that wouldn't mind putting together a PR to make this work, with guidance from Hashicorp.

In the project I'm working on, we're using SQS notifications where the same replace instead of add behavior is seen. We're trying to avoid bucket sprawl, but because of this behavior we're having to make an architectural decision that buckets:notifications need to be 1:1. This means we stand the chance of hitting the 100 bucket per account limit in AWS, as this is a design pattern we're likely to use in multiple projects (using S3 as a sort of drop box for batch file processing).

@acobaugh I had a similar situation where I needed to send the s3 notification to multiple queues and ran up against this. I was able to work around it by sending the s3 notification to an SNS topic which was then configured to forward the notification into an arbitrary number of SQS queues. It's not as nice as just being able to attachment multiple notifications, but it works well and doesn't require 100 buckets.

@bflad @jbardin @apparentlymart ^ ping -- it seems this very significant bug was accidentally classified as an "enhancement" and forgotten.

The original was here: https://github.com/hashicorp/terraform/issues/11536
It was then moved here: https://github.com/terraform-providers/terraform-provider-aws/issues/501

This is pretty major functionality -- as of right now, Terraform has limited S3 notification to a single lambda function.

  • The AWS spec for it is a _list of lambda functions._
  • Terraform treats it as single lambda function, and overrides previous when additional are added.

Hi all,

This resource is exposing the functionality of the S3 _PUT Bucket notification_ operation, which treats the entire notification set as a single object that must be replaced atomically.

Because individual notification rules are not independently addressable, Terraform can't get any more granular than what it's already doing within the current design of the API.

It would theoretically be possible to implement separate resource types like aws_s3_bucket_notification_lambda_function, aws_s3_bucket_notification_sqs_queue, etc that represent individual notification targets within a bucket by attempting to fetch the current configuration, search for any rule with a matching id, replace it, and re-submit the whole object.

resource "aws_s3_bucket_notification_lambda_function" "example" {
  bucket = "${var.LogBucket}"
  id = "${var.customer}-LambdaFunction"
  lambda_function_arn = "${aws_lambda_function.LambdaFunction.arn}"
  events = ["s3:ObjectCreated:*"]
  filter_suffix = "gz"
}

Resource types like this would have to somehow avoid creating race conditions for other concurrent writers to the notification configuration for the same bucket, particularly if there were multiple resources of these types in the same configuration where Terraform _itself_ might try to write them all concurrently. Since the underlying API provides no locking mechanism for this, it is not totally solvable. It may be _partially_ solvable with certain caveats, but it would mean that these resources types would have quite complex implementations in relation to other resource types.

I didn't originally set the labels here, but my guess is that the "enhancement" label here is representing that implementing management of individual rules in isolation from inside a single remote notification object would be additional functionality above what the underlying API provides and is thus an extension of the current behavior, not a fix for an implementation defect.

Just throwing this out there that I'm experiencing pain around this same issue:

resource "aws_s3_bucket_notification" "S3BucketNotification" {
  bucket = "${data.aws_s3_bucket.S3Bucket.id}"

  queue {
    queue_arn     = "${module.sqs.queue_arn}"
    events        = ["s3:ObjectCreated:*"]
    filter_prefix = "${local.S3EventsPrefix}/"
    filter_suffix = ".gz"
  }
}

Consider the above example, if I'm using multiple Terraform Workspaces to have staging, production, etc. environments operate on the same bucket, I'm going to overwrite every other notification set up for every other environment. This means if I apply any changes to staging, production is affected. So yeah, if this could be prioritized and a fix released, that would be absolutely fantastic.

The problem is not with Hashicorp. The Problem is AWS and their poor API
for S3 events.
This is a huge design bug of AWS.

On Sat, Jan 19, 2019 at 1:26 AM David Lewis notifications@github.com
wrote:

Just throwing this out there that I'm experiencing pain around this same
issue:

resource "aws_s3_bucket_notification" "S3BucketNotification" {
bucket = "${data.aws_s3_bucket.S3Bucket.id}"

queue {
queue_arn = "${module.sqs.queue_arn}"
events = ["s3:ObjectCreated:*"]
filter_prefix = "${local.S3EventsPrefix}/"
filter_suffix = ".gz"
}
}

Consider the above example, if I'm using multiple Terraform Workspaces to
have staging, production, etc. environments operate on the same bucket, I'm
going to overwrite every other notification set up for every other
environment. This means if I apply any changes to staging, production is
affected. So yeah, if this could be prioritized and a fix released, that
would be absolutely fantastic.

โ€”
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/terraform-providers/terraform-provider-aws/issues/501#issuecomment-455719824,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AB-znxjPve9oGIIuu4fJ_VJuXoYj1_wMks5vElgVgaJpZM4N49yk
.

--
Regards,
Ofer Eliassaf

It looks like it's possible to get and put a bucket's notification configuration, so no, not a limitation on AWS's side. It should be possible to put a configuration rule and store the id of that configuration rule in the tfstate to reference later if Terraform detects a change in the configuration. Maybe there's another limitation I'm not aware of, if so I'd be interested to hear it.

Relevant docs:

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html?highlight=bucket%20notification%20config#S3.Client.put_bucket_notification_configuration

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html?highlight=bucket%20notification%20config#S3.Client.get_bucket_notification_configuration

Biggest issue seems to be that you can not have two rules with overlapping prefixes. So even if you could define multiple separate rules for one bucket, you could not define two Lambdas to be triggered for same prefix.

image

I am getting the same issue. Are there any workarounds?

@ethicalmohit I've stopped managing these with Terraform. Best workaround I've come across so far :).

Maybe there's another limitation I'm not aware of, if so I'd be interested to hear it.

I think the design flaw mentioned here is the lack of granularity of the AWS service. Yes, you can put/set, and maybe it isn't a big deal in this specific scenario, as contention is unlikely, but seems like this could represent a TOCTOU bug. If two teams were managing these things with terraform, the concern may be that
Terraform for team A checks for the notification on the bucket, there is none(GET).
Terraform for team B checks for the notification on the bucket(GET).
Terraform for team B creates a notification on the bucket(PUT).
Terraform for team A creates a notification on the bucket (PUT), blowing away team B's notification.
AFAIK remedying this isn't possible without a compare-and-set type operation. I didn't see that in the docs.

Any update on this?

It's really a very dangerous function. When you apply a new rule on an existing s3 bucket, all existing rules will be deleted without any prompt warning and can't be rolled back.

The problem is not in Terraform.
It's an aws API bug.

The workaround i found is a dispatcher mechanism in which, a single lambda
is registered, and when it is called, it send a SNS notification with the
path. All the multiple lambdas I have listen to this SNS topic and are
triggered.
This works great and highly reccomended.

ื‘ืชืืจื™ืš ื™ื•ื ื”ืณ, 30 ื‘ืืคืจืณ 2020, 18:10, ืžืืช Bryan Yang โ€<
[email protected]>:

It's really a very dangerous function. When you apply a new rule on an
existing s3 bucket, all existing rules will be deleted without any prompt
warning and can't be rolled back.

โ€”
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/terraform-providers/terraform-provider-aws/issues/501#issuecomment-621915622,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAP3HHYYOWLDYXH6OVLLVZLRPGIFNANCNFSM4DPD3SSA
.

@bryanyang0528 Yes - exactly the reason I first created this issue 3+ years ago.

But I believe somewhere a while back (can't keep track at this point since this ticket has been moved/re-opened 4-5x) it was mentioned that the problem is the Amazon API available for lambda? That said, I really think this is something that should be brought up and fixed (be it Amazon or TF) quickly.

@ventz I'm not sure if terraform could refer to this project serverless-plugin-existing-s3? This serverless plugin will fetch all existing rules, add a new rule, and deploy them together for implementing this function.

@bryanyang0528 That would be fantastic!

Hi folks ๐Ÿ‘‹

The core of this aws_s3_bucket_notification resource issue is still pending any sort of enhancement from the S3 API to identify or support individual bucket notification configuration operations. Essentially, this comment still applies where the S3 PutBucketNotificationConfiguration API call has the following behavior:

This operation replaces the existing notification configuration with the configuration you include in the request body.

The current maintainers are still very hesitant to implement a custom solution of individual notification management since this would be extremely prone to S3 eventual consistency behaviors and unable to handle race conditions across Terraform AWS Provider instances. Our best recommendation would still be to reach out to the S3 service team about this particular API via AWS Support cases or discussions with your Technical Account Manager, should you have one.

However, I did want to mention here the feature request for Terraform and Terraform AWS Provider to give an error message for conflicting resources in configurations, which falls under the provider-wide enhancement proposal of https://github.com/terraform-providers/terraform-provider-aws/issues/14394. By adding this link here it will add a reference to that issue so we can include it as a use case when thinking about the implementation details about that particular enhancement. Please feel free to ๐Ÿ‘ and provide feedback about that enhancement there.

We solved this issue by using a null resource which calls a python script with the necessary arguments. The script pulls the existing notifications into memory, adds the new one and uploads them all again to s3. The reason we needed this is because we use both Serverless and Terraform and needed a way to handle bucket notifications across stacks.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

modax picture modax  ยท  3Comments

hazmeister picture hazmeister  ยท  3Comments

joelittlejohn picture joelittlejohn  ยท  3Comments

dvishniakov picture dvishniakov  ยท  3Comments

hashibot picture hashibot  ยท  3Comments