-
Notifications
You must be signed in to change notification settings - Fork 1k
New serverless pattern - Stripe-EventBridge-Lambda #2297
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| # Stripe EventBridge Integration with AWS Lambda | ||
|
|
||
| This pattern demonstrates how to use the Stripe Amazon EventBridge SaaS integration and AWS Lambda to process events from Stripe. This pattern is leveraging the Stripe Amazon EventBridge SaaS integration to send payment events from the customer's Stripe account to their AWS account, via an Amazon EventBridge Partner event bus. Once the Stripe events are in the customer's account, an Amazon EventBridge rule routes failed payment events to a downstream Lambda function. The Lambda function transforms the event, stores the failed payment details in a DynamoDB table, and can potentially trigger additional actions such as sending a notification email to the customer using SES. | ||
|
|
||
| Amazon CloudWatch Log Groups are provisioned for debugging and auditing of all Stripe events as well as the failed payment events specifically. This pattern deploys two EventBridge rules, one Lambda function, two CloudWatch Log Groups, and a DynamoDB table to store the failed payment details. | ||
|
|
||
| Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/stripe-eventbridge-lambda | ||
|
|
||
| Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example. | ||
|
|
||
| ## Requirements | ||
|
|
||
| * [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources. | ||
| * [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured | ||
| * [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) | ||
| * [AWS CDK CLI](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html) (AWS CDK) installed | ||
| * [Create a Stripe account](https://stripe.com/register) if you do not already have one and log in. | ||
| * [Set up the Stripe Amazon EventBridge SaaS integration](https://docs.stripe.com/event-destinations/eventbridge) if you have not already configured the integration. | ||
|
|
||
| ## Deployment Instructions | ||
|
|
||
| 1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository: | ||
| ``` | ||
| git clone https://github.com/aws-samples/serverless-patterns | ||
| ``` | ||
| 2. Change directory to the pattern directory: | ||
| ``` | ||
| cd stripe-eventbridge-lambda | ||
| ``` | ||
| 3. From the command line, use AWS CDK to deploy the AWS resources for the pattern as specified in the app.py file. A command-line argument is needed to deploy the CDK stack, "stripeEventBusName". This argument should be the name of the **SaaS event bus** associated with your Stripe [partner event source](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-saas.html). | ||
| ``` | ||
| cdk deploy --parameters stripeEventBusName=SAAS_EVENT_BUS_NAME_HERE | ||
| ``` | ||
|
|
||
| 4. Note the outputs from the CDK deployment process. These contain the resource names and/or ARNs which are used for testing. This stack will output the name of the Lambda function deployed for testing to the CLI. See the example below. | ||
|
|
||
| ``` | ||
| Outputs: | ||
| StripeIntegrationStack.StripeProcessFailedPaymentLambdaOutput = StripeIntegrationStack-StripeProcessFailedPaymentL-nIPhn7sPQx9e | ||
| ``` | ||
|
|
||
| ## How it works | ||
|
|
||
| This service interaction uses an existing Stripe SaaS integration in the customer's AWS account. If you do not have the Stripe SaaS integration set up in your AWS account, please set it up before deploying this pattern. View the [integration on the Stripe Docs](https://docs.stripe.com/event-destinations/eventbridge). See [Stripe's documentation](https://stripe.com/docs/api/events/types) for available events. | ||
|
|
||
| This pattern demonstrates how to: | ||
| 1. Write EventBridge rules that match Stripe's event pattern | ||
| 2. Send events from Stripe's EventBridge SaaS integration to Amazon CloudWatch for logging and debugging | ||
| 3. Transform Stripe events using AWS Lambda | ||
| 4. Store failed payment details in a DynamoDB table | ||
|
|
||
| See the below architecture diagram from the data flow of this pattern. | ||
|
|
||
|  | ||
|
|
||
| ## Testing | ||
|
|
||
| ### Test the AWS Lambda Function | ||
|
|
||
| The event.json file included in this pattern is a sample EventBridge event from Stripe. This event can be used to test the Lambda function and EventBridge rules deployed by this pattern. | ||
|
|
||
| To test the Lambda function via the CLI, copy and paste the following command, replacing the variables in <> with your own values: | ||
| ``` | ||
| aws lambda invoke --function-name <StripeIntegrationStack-StripeProcessFailedPaymentL-nIPhn7sPQx9e> --payload file://event.json response.json | ||
| ``` | ||
|
Comment on lines
+64
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you need to add |
||
|
|
||
| You should receive a response that looks like: | ||
| ``` | ||
| { | ||
| "StatusCode": 200, | ||
| "ExecutedVersion": "$LATEST" | ||
| } | ||
|
Comment on lines
+69
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I get an error message instead (account id redacted):
|
||
| ``` | ||
|
|
||
| The command should have create a response.json file in your directory. If you open this file, you see the output of the Lambda function. | ||
|
|
||
| ### Test the EventBridge Rule | ||
|
|
||
| You cannot put events on the Stripe SaaS event bus, only Stripe can publish events to this event bus. To test that the EventBridge rules deployed by this pattern were successfully deployed, follow these instructions: | ||
|
|
||
| 1. Navigate to the Amazon EventBridge console. Select "Rules". | ||
|
|
||
| 2. From the Event bus list, choose the SaaS event bus associated with your Stripe partner event source. | ||
|
|
||
| 3. From the Rules list, select the "StripeIntegrationStack-StripeFailedPaymentEventsRul-cSTSp1wtPkkB" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The suffix is randomly generated and will not match the users resources. It's probably better to word this differently |
||
|
|
||
|  | ||
|
|
||
| 4. Choose "Edit" to enter the rule editor. Click through to "Step 2. Build Event Pattern." | ||
|
|
||
|  | ||
|
|
||
| 5. Scroll down to "Sample event - optional." Select "Enter my own," and delete the pre-populated event. Copy the contents of event.json into the event editor. | ||
|
|
||
|  | ||
|
|
||
| 6. Scroll down to "Event pattern." Choose "Test Pattern." | ||
|
|
||
|  | ||
|
|
||
| You should see a green box appear that says "Sample event matched the event pattern." This means that the rule will successfully route incoming events to the AWS Lambda function. | ||
|
|
||
|  | ||
|
|
||
| ## Cleanup | ||
|
|
||
| 1. Delete the stack | ||
| ```bash | ||
| cdk destroy | ||
| ``` | ||
|
|
||
| ---- | ||
| Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
|
|
||
| SPDX-License-Identifier: MIT-0 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
|
|
||
| import os | ||
| import aws_cdk as cdk | ||
| from aws_cdk import ( | ||
| Stack, | ||
| aws_dynamodb as dynamodb, | ||
| aws_events as events, | ||
| aws_events_targets as targets, | ||
| aws_iam as iam, | ||
| aws_lambda as _lambda, | ||
| aws_logs as logs, | ||
| CfnOutput, | ||
| CfnParameter, | ||
| Duration, | ||
| RemovalPolicy | ||
| ) | ||
| from constructs import Construct | ||
|
|
||
| class StripeIntegrationStack(Stack): | ||
| def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: | ||
| super().__init__(scope, construct_id, **kwargs) | ||
|
|
||
| # Stack inputs | ||
| STRIPE_PARTNER_EVENT_BUS = CfnParameter( | ||
| self, id="stripeEventBusName", type="String", | ||
| description="The name of event bus the the Stripe Partner EventSource is associated with." | ||
| ) | ||
|
|
||
| # Turn partner event bus from string to IEventBus object | ||
| partner_event_bus = events.EventBus.from_event_bus_name( | ||
| scope=self, id='partner-event-bus', event_bus_name=STRIPE_PARTNER_EVENT_BUS.value_as_string | ||
| ) | ||
|
|
||
| # CloudWatch Logs Group that stores all events sent by Stripe for debugging or archive | ||
| log_group_all_events = logs.LogGroup( | ||
| self, "Stripe-all-events", | ||
| retention=logs.RetentionDays.ONE_DAY, | ||
| removal_policy=RemovalPolicy.DESTROY | ||
| ) | ||
|
|
||
| # CloudWatch Logs Group that stores all failed payment events from Stripe for debugging or archive | ||
| log_group_failed_payments = logs.LogGroup( | ||
| self, "Stripe-failedpayment-events", | ||
| retention=logs.RetentionDays.ONE_DAY, | ||
| removal_policy=RemovalPolicy.DESTROY | ||
| ) | ||
|
|
||
| lambda_role = iam.Role( | ||
| scope=self, id='stripe-cdk-lambda-role', | ||
| assumed_by=iam.ServicePrincipal('lambda.amazonaws.com'), | ||
| managed_policies=[ | ||
| iam.ManagedPolicy.from_aws_managed_policy_name( | ||
| 'service-role/AWSLambdaBasicExecutionRole' | ||
| ) | ||
| ] | ||
| ) | ||
|
|
||
| # DynamoDB table to store failed payment events | ||
| stripe_failed_payments_table = dynamodb.Table( | ||
| self, "StripeFailedPaymentsTable", | ||
| partition_key=dynamodb.Attribute(name="payment_intent_id", type=dynamodb.AttributeType.STRING), | ||
| billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST, | ||
| removal_policy=RemovalPolicy.DESTROY | ||
| ) | ||
|
|
||
| # A Lambda function to consume and process failed payment events | ||
| stripe_process_failed_payment_lambda = _lambda.Function( | ||
| self, | ||
| id='StripeProcessFailedPaymentLambda', | ||
| runtime=_lambda.Runtime.PYTHON_3_8, | ||
| code=_lambda.Code.from_asset('src'), | ||
| handler='StripeProcessFailedPayment.handler', | ||
| role=lambda_role, | ||
| timeout=Duration.seconds(15), | ||
| environment={ | ||
| "StripeFailedPayments": stripe_failed_payments_table.table_name | ||
| } | ||
| ) | ||
|
|
||
| # EventBridge Stripe all events rule | ||
| stripe_all_events_rule = events.Rule( | ||
| self, | ||
| id="StripeAllEventsRule", | ||
| event_bus=partner_event_bus | ||
| ) | ||
|
|
||
| # Add event pattern to rule | ||
| stripe_all_events_rule.add_event_pattern( | ||
| source=events.Match.prefix('aws.partner/stripe.com') | ||
| ) | ||
|
|
||
| # CloudWatch Log Group as target for EventBridge Rule | ||
| stripe_all_events_rule.add_target(targets.CloudWatchLogGroup(log_group_all_events)) | ||
|
|
||
| # EventBridge Stripe failed payment events | ||
| stripe_failed_payment_events_rule = events.Rule( | ||
| self, | ||
| id="StripeFailedPaymentEventsRule", | ||
| event_bus=partner_event_bus | ||
| ) | ||
|
|
||
| # Add rule to the event bus for the "failed_payment" pattern | ||
| stripe_failed_payment_events_rule.add_event_pattern( | ||
| source=events.Match.prefix('aws.partner/stripe.com'), | ||
| detail_type=["charge.failed"], | ||
| ) | ||
|
|
||
| # Lambda as target for EventBridge Rule | ||
| stripe_failed_payment_events_rule.add_target(targets.LambdaFunction(stripe_process_failed_payment_lambda)) | ||
|
|
||
| # CloudWatch Log Group as target for EventBridge Rule | ||
| stripe_failed_payment_events_rule.add_target(targets.CloudWatchLogGroup(log_group_failed_payments)) | ||
|
|
||
| # Output the IAM role ARN for the Lambda function | ||
| CfnOutput(self, "StripeProcessFailedPaymentLambdaOutput", value=stripe_process_failed_payment_lambda.function_name) | ||
|
|
||
| # Output the DynamoDB table name | ||
| CfnOutput(self, "StripeFailedPaymentsTableOutput", value=stripe_failed_payments_table.table_name) | ||
|
|
||
| app = cdk.App() | ||
| description = "Stripe EventBridge Integration" | ||
| StripeIntegrationStack(app, "StripeIntegrationStack", description=description) | ||
| app.synth() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| { | ||
| "app": "python3 app.py", | ||
| "watch": { | ||
| "include": [ | ||
| "**" | ||
| ], | ||
| "exclude": [ | ||
| "README.md", | ||
| "cdk*.json", | ||
| "requirements*.txt", | ||
| "source.bat", | ||
| "**/__init__.py", | ||
| "python/__pycache__", | ||
| "tests" | ||
| ] | ||
| }, | ||
| "context": { | ||
| "@aws-cdk/core:stackRelativeExports": true, | ||
| "@aws-cdk/aws-lambda:recognizeVersionProps": true, | ||
| "@aws-cdk/aws-lambda:recognizeLayerVersion": true, | ||
| "@aws-cdk/core:target-partitions": [ | ||
| "aws" | ||
| ] | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this missing any instructions? I am getting the below error
/serverless-patterns/stripe-eventbridge-lambda/app.py", line 3, in
import aws_cdk as cdk
ModuleNotFoundError: No module named 'aws_cdk'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe so, I do not see that error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let me take a deeper look