Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

s3-notifications: Unable to update the s3 event notifications on an existing S3 bucket. #31303

Open
1 task
satanupa opened this issue Sep 3, 2024 · 5 comments · May be fixed by #31431
Open
1 task

s3-notifications: Unable to update the s3 event notifications on an existing S3 bucket. #31303

satanupa opened this issue Sep 3, 2024 · 5 comments · May be fixed by #31431
Assignees
Labels
@aws-cdk/aws-s3-notifications @aws-cdk/aws-s3 Related to Amazon S3 bug This issue is a bug. effort/medium Medium work item – several days of effort p1

Comments

@satanupa
Copy link

satanupa commented Sep 3, 2024

Describe the bug

I am facing an error when trying to update the s3 event notification configuration on an existing S3 bucket using CDK.
Created a stack to add s3 event notification on an existing s3 bucket. Create operation goes through successfully.
When I update the cdk stack to add event notifications on the same s3 bucket, the Update operation fails with below error.

Error:

Received response status [FAILED] from custom resource. Message returned: Error: An error occurred (InvalidArgument) when calling the PutBucketNotificationConfiguration operation: Configuration is ambiguously defined. Cannot have overlapping suffixes in two rules if the prefixes are overlapping for the same event type.. See the details in CloudWatch Log Stream:

Here the lambda code backing the BucketNotifications custom resource is unable to identify that the existing event notifications were also managed by the same cdk stack thereby creating duplicate notifications resulting in error.

Regression Issue

  • Select this option if this issue appears to be a regression.

Last Known Working CDK Version

No response

Expected Behavior

Should be able to add additional notification configuration on the existing s3 bucket.

Current Behavior

Issue
Created a cdk stack and added an event notification on an existing s3 bucket. Create operation is successful.
Updated the same stack to add a new event notification along with the existing ones. The update operation fails with below error.

Error:

Received response status [FAILED] from custom resource. Message returned: Error: An error occurred (InvalidArgument) when calling the PutBucketNotificationConfiguration operation: Configuration is ambiguously defined. Cannot have overlapping suffixes in two rules if the prefixes are overlapping for the same event type.. See the details in CloudWatch Log Stream:

Reproduction Steps

Steps:
1. Create a stack by commenting out the 2nd event notification (notificationfilter2)
2. once stack is created, update the stack after uncommenting the 2nd event notification.



 my_lambda = _lambda.Function(
          self, 'HelloHandler',
            runtime=_lambda.Runtime.PYTHON_3_8,
            code=_lambda.Code.from_asset('lambda'),
            handler='hello.handler',
        )  


        bucket = _s3.Bucket.from_bucket_name(self, "Bucket", "bucketname")
        notification = _s3_notify.LambdaDestination(my_lambda)

        notificationfilter1 = _s3.NotificationKeyFilter(prefix="foo/", suffix="bar/")
        bucket.add_event_notification(_s3.EventType.OBJECT_CREATED, notification, notificationfilter1
        )

       # notificationfilter2 = _s3.NotificationKeyFilter(prefix="fo1/",suffix="ba1/",)
      # bucket.add_event_notification(_s3.EventType.OBJECT_CREATED, notification, notificationfilter2
      #  )

Possible Solution

Analysis details:
Create a cdk stack to add below event notification to an existing s3 bucket. The Create operation is successful.

'Events': ['s3:ObjectCreated:*'], 'Filter': {'Key': {'FilterRules': [{'Name': 'Prefix', 'Value': 'bar/'}, {'Name': 'Suffix', 'Value': 'foo/'}]}}}

In the notifications-resource-handler code

For unmanaged buckets, there is a get_id function used to evaluate the hash for each event notification to confirm if this is created by the stack or is an existing external configuration:

def get_id(n):
    n['Id'] = ''
    strToHash=json.dumps(n, sort_keys=True).replace('"Name": "prefix"', '"Name": "Prefix"').replace('"Name": "suffix"', '"Name": "Suffix"')
    return f"{stack_id}-{hash(strToHash)}"

During creation, this goes fine as it treats all existing configurations as external.
Then it appends incoming + external and creates the final notification configuration as expected.

During an update operation, the lambda code will first get the existing event notifications on the s3 bucket.
Then it validates if the existing event notifications matches the notification in the incoming request from Cloudformation.
It does this by evaluating the hash for each existing event notification and validating if this matches with the hash of the incoming event notifications from Cloudformation.
When there is a match, it identifies this existing event configuration as managed by the stack.
This helps in eliminating the duplicates.

There is an issue with this hash evaluation, due to a change in order of the prefix and suffix within the filter rules between the existing notification and the notification coming from Cloudformation.

Sample event notification from Cloudformation request

{
    "Events": [
        "s3:ObjectCreated:*"
    ],
    "Filter": {
        "Key": {
            "FilterRules": [
                {
                    "Name": "Suffix",
                    "Value": "foo/"
                },
                {
                    "Name": "Prefix",
                    "Value": "bar/"
                }
            ]
        }
    },
    "Id": "",
    "LambdaFunctionArn": "arn:aws:lambda:<aws-region>:<aws-account-id>:function:<FunctionName>"
}

Sample existing S3 event notification:

    "Events": [
        "s3:ObjectCreated:*"
    ],
    "Filter": {
        "Key": {
            "FilterRules": [
                {
                    "Name": "Prefix",
                    "Value": "bar/"
                },
                {
                    "Name": "Suffix",
                    "Value": "foo/"
                }
            ]
        }
    },
    "Id": "",
    "LambdaFunctionArn": "arn:aws:lambda:<aws-region>:<aws-account-id>:function:<FunctionName>"
}

Note: Even though the content of the above jsons are the same, the order of the filter rules (prefix and suffix) are different.
Due to this, the hash evaluated will also be different. So, it is unable to identify that the existing configuration was also added by the stack itself.
This ends up in a configuration which includes the duplicates (existing configurations on s3 + incoming event configuration from Cloudformation stack)
resulting in below error:

Received response status [FAILED] from custom resource. Message returned: Error: An error occurred (InvalidArgument) when calling the PutBucketNotificationConfiguration operation: Configuration is ambiguously defined. Cannot have overlapping suffixes in two rules if the prefixes are overlapping for the same event type.

This can be workaround by changing the order of filters in the cdk synthesized stack template, by passing the prefix first and then suffix within the filter rules array.

Additional Information/Context

No response

CDK CLI Version

2.152.0

Framework Version

No response

Node.js Version

v20.16.0

OS

Linux

Language

Python

Language Version

No response

Other information

No response

@satanupa satanupa added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Sep 3, 2024
@github-actions github-actions bot added the @aws-cdk/aws-s3 Related to Amazon S3 label Sep 3, 2024
@pahud pahud self-assigned this Sep 3, 2024
@pahud pahud added the investigating This issue is being investigated and/or work is in progress to resolve the issue. label Sep 3, 2024
@pahud
Copy link
Contributor

pahud commented Sep 4, 2024

Yes this is reproducible.

class IssueTriagePyStack(Stack):
  def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
    super().__init__(scope, construct_id, **kwargs)
  
    my_lambda = _lambda.Function(
          self, 'HelloHandler',
            runtime=_lambda.Runtime.PYTHON_3_8,
            code=_lambda.Code.from_asset('lambda'),
            handler='hello.handler',
    )    
  
    bucket = s3.Bucket.from_bucket_name(self, "Bucket", "my-existing-bucket-name")
    notification = s3_notify.LambdaDestination(my_lambda)

    notificationfilter1 = s3.NotificationKeyFilter(prefix="foo/", suffix="bar/")
    bucket.add_event_notification(s3.EventType.OBJECT_CREATED, notification, notificationfilter1)

    notificationfilter2 = s3.NotificationKeyFilter(prefix="fo1/",suffix="ba1/",)
    bucket.add_event_notification(s3.EventType.OBJECT_CREATED, notification, notificationfilter2)

On cdk deploy to update the stack:

issue-triage: creating CloudFormation changeset...
10:35:14 PM | UPDATE_FAILED        | Custom::S3BucketNotifications | BucketNotifications8F2E257D
Received response status [FAILED] from custom resource. Message returned: Error: An error occurred (InvalidArgument) when calling the PutBucketNotificati
onConfiguration operation: Configuration is ambiguously defined. Cannot have overlapping suffixes in two rules if the prefixes are overlapping for the sa
me event type.. See the details in CloudWatch Log Stream: 2024/09/04/[$LATEST]ff56425363ce4d8db0b594f6d560320a (RequestId: 9b4cb9c7-2141-4e7b-ba02-b4a880
70d580)

10:35:18 PM | UPDATE_FAILED        | Custom::S3BucketNotifications | BucketNotifications8F2E257D
Received response status [FAILED] from custom resource. Message returned: Error: An error occurred (InvalidArgument) when calling the PutBucketNotificati
onConfiguration operation: Configuration is ambiguously defined. Cannot have overlapping suffixes in two rules if the prefixes are overlapping for the sa
me event type.. See the details in CloudWatch Log Stream: 2024/09/04/[$LATEST]ff56425363ce4d8db0b594f6d560320a (RequestId: dc73fb2a-5abc-48d6-b0dd-da0625
2e55bc)

cdk synth

  BucketNotifications8F2E257D:
    Type: Custom::S3BucketNotifications
    Properties:
      ServiceToken:
        Fn::GetAtt:
          - BucketNotificationsHandler050a0587b7544547bf325f094a3db8347ECC3691
          - Arn
      BucketName: pahud-foo-bar
      NotificationConfiguration:
        LambdaFunctionConfigurations:
          - Events:
              - s3:ObjectCreated:*
            Filter:
              Key:
                FilterRules:
                  - Name: suffix
                    Value: bar/
                  - Name: prefix
                    Value: foo/
            LambdaFunctionArn:
              Fn::GetAtt:
                - HelloHandler2E4FBA4D
                - Arn
          - Events:
              - s3:ObjectCreated:*
            Filter:
              Key:
                FilterRules:
                  - Name: suffix
                    Value: ba1/
                  - Name: prefix
                    Value: fo1/
            LambdaFunctionArn:
              Fn::GetAtt:
                - HelloHandler2E4FBA4D
                - Arn
      Managed: false
      SkipDestinationValidation: false

As I can't figure out any workaround. Making this a p1 bug.

@pahud pahud added the p1 label Sep 4, 2024
@pahud pahud removed their assignment Sep 4, 2024
@pahud pahud added effort/medium Medium work item – several days of effort and removed investigating This issue is being investigated and/or work is in progress to resolve the issue. needs-triage This issue or PR still needs to be triaged. labels Sep 4, 2024
@pahud pahud changed the title @aws-cdk/aws-s3: Unable to update the s3 event notifications on an existing S3 bucket. s3: Unable to update the s3 event notifications on an existing S3 bucket. Sep 4, 2024
@pahud pahud changed the title s3: Unable to update the s3 event notifications on an existing S3 bucket. s3-notifications: Unable to update the s3 event notifications on an existing S3 bucket. Sep 4, 2024
@stefanopallicca-imagicle

Facing the same issue: I previously defined two notifications, one with
prefix: person/upload
suffix: .csv

another with
prefix: car/upload
suffix: .csv

This configuration worked with 2.146.0, results in same issue by simply updating cdk to 2.155.0

@migurski
Copy link

migurski commented Sep 5, 2024

I’ve been tracking down this same issue, and can confirm that I see an identical error when attempting to update to a new Lambda function ARN on an existing notification configured for an externally-defined bucket.

Abbreviated version of my reproduction, first deployment succeeds:

log_function = aws_lambda.Function(self, "Function1", …)
bucket.add_event_notification(
    aws_s3.EventType.OBJECT_CREATED,
    aws_s3_notifications.LambdaDestination(log_function),
    aws_s3.NotificationKeyFilter(prefix="logs/resource-cdn/", suffix=".gz"),
)

Second deployment fails:

log_function = aws_lambda.Function(self, "Function2", …)
bucket.add_event_notification(
    aws_s3.EventType.OBJECT_CREATED,
    aws_s3_notifications.LambdaDestination(log_function),
    aws_s3.NotificationKeyFilter(prefix="logs/resource-cdn/", suffix=".gz"),
)

@xazhao xazhao self-assigned this Sep 6, 2024
@xazhao
Copy link
Contributor

xazhao commented Sep 6, 2024

Looks like the the same issue #28915.

I was able to reproduce in v2.147+ and it works fine in v2.146.0. However I don't see any related change in the diff. Need to look further into it.

@ashishdhingra
Copy link
Contributor

ashishdhingra commented Sep 12, 2024

@xazhao Related issue #31413. It might give some clue about the root cause.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-s3-notifications @aws-cdk/aws-s3 Related to Amazon S3 bug This issue is a bug. effort/medium Medium work item – several days of effort p1
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants