DEV Community

Cover image for CDK Stack Notification Options
NaDia for AWS Community Builders

Posted on

CDK Stack Notification Options

Today, I discovered yet again that there are countless ways to tackle a single task as a developer.

I was tasked with automating a workflow that involved an AWS Lambda Function triggered by an SNS event source. The goal was to publish a message to an SNS topic in a different AWS account when the status of a CloudFormation stack updated.
We use AWS CDK for infrastructure as code (IAC). While exploring the documentation and blog posts, I found that there is no direct equivalent of the Notification Policy in CloudFormation to publish notifications to an SNS topic on a CloudFormation stack status change. Instead, there are several common patterns to achieve this. Let's start with solution diagram. Here's a simplified version of the architecture diagram of what I implemented:
If this is what you are looking for, you can simply achieve it in 3 different ways:

Using AWS Event Bridge

  • Create SNS Topic as a Stack B CDK resource:
import { Topic } from "aws-cdk-lib/aws-sns";

   const SNSTopic = new Topic(this, "SNS_TOPIC_ID", {
      displayName: "YOUR DISPLAY NAME",
    }); 
Enter fullscreen mode Exit fullscreen mode

_Note: you need to add an event source to your function or any other resources that is going to subscribe to this topic. in my case I needed to configure a lambda event source as _bellow:

MyFunction.addEventSource(new SnsEventSource(SNSTopic));
Enter fullscreen mode Exit fullscreen mode
  • Add Event Rule
 new Rule(this, "Trigger", {
      eventPattern: {
        source: ["aws.cloudformation"],
        detailType: ["CloudFormation Stack Status Change"],
        detail: {
          eventName: ["CREATE_COMPLETE", "UPDATE_COMPLETE", "DELETE_COMPLETE"],
          requestParameters: {
            stackName: [this.stackName],
          },
        },
      },
      targets: [new SnsTopic(SNSTopic)],
    });
Enter fullscreen mode Exit fullscreen mode

Using AWS Custom Resources

Second approach to achieve this is by using AWS Custom Resources.

  • Create an AWS Custom Resource within the Stack B CDK:
import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId } from "aws-cdk-lib/custom-resources";    

const Trigger = new AwsCustomResource(this, "TriggerOnSuccess", {
      onUpdate: {
        service: "SNS",
        action: "publish",
        parameters: {
          TopicArn: "YOUR_TOPIC_ARN",
          Message: "Stack updated successfully",
        },
        physicalResourceId: PhysicalResourceId.of("TriggerOnSuccess"),
      },
      onDelete: {
        service: "SNS",
        action: "publish",
        parameters: {
          TopicArn: "YOUR_TOPIC_ARN",
          Message: "Stack deleted successfully",
        },
        physicalResourceId: PhysicalResourceId.of("TriggerOnSuccess"),
      },
       policy: AwsCustomResourcePolicy.fromStatements( [new PolicyStatement({
        actions: ["sns:Publish"],
        effect: Effect.ALLOW,
        resources: [SNSTopic.topicArn],
      })]),
    });
Enter fullscreen mode Exit fullscreen mode
  • Add Dependency order so that CDK doesn't return Dependency Cycle error
 Trigger.node.addDependency(YOUR_FUNCTION);
 Trigger.node.addDependency(SNSS_TOPIC); 
Enter fullscreen mode Exit fullscreen mode

Using AWS Custom Resource with Lambda Invoke Action

There is also a 3rd solution for this as well which I am not a big fan of it and that is. I personally prefer to use fan out approach, to populate events to Lambda via an "Event Service" such as SNS or EventBridge. If you look for a simplified Custom Resource, here is what you should update your AWS Custom Resource to:

import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId } from "aws-cdk-lib/custom-resources";    

const Trigger = new AwsCustomResource(this, "TriggerOnSuccess", {
      onUpdate: {
        service: "Lambda",
        action: "invoke",
        parameters: {
          FunctionName: "YOUR_FUNCTION_ARN",
          InvokationType: "Event"
        },
        physicalResourceId: PhysicalResourceId.of("TriggerOnSuccess"),
      },
      onDelete: {
        service: "Lambda",
        action: "invoke",
        parameters: {
          FunctionName: "YOUR_FUNCTION_ARN",
          InvokationType: "Event"
        },
        physicalResourceId: PhysicalResourceId.of("TriggerOnSuccess"),
      },
       policy: AwsCustomResourcePolicy.fromStatements( [new PolicyStatement({
        actions: ["lambda:InvokeFunction"],
        effect: Effect.ALLOW,
        resources: [YOUR_FUNCTION_ARN],
      })]),
    });
Enter fullscreen mode Exit fullscreen mode

This concludes our brief discussion. While I'm still hopeful about discovering if CDK offers an API for configuring Stack Notification Options, I wanted to share these workarounds in the meantime.

Top comments (1)

Collapse
 
sloan profile image
Sloan the DEV Moderator

Heyo!

Just a reminder that you likely want to add tags to your post to help with discoverability. Depending on what tags folks are following, posts will appear in their "relevant" feed on the DEV homepage.

You can add popular, established tags, more niche tags, or create a brand new tag if there's one that has yet to be created. Some tags are centered around a technology (#python, #javascript) and others are more functional (#discuss, #help, #tutorial)... you can use a combination of 4 tags on your post, so choose wisely.

Always make sure that the tags you choose fit the subject matter of your post. Different tags have submission guidelines set up for them which you can view on a tag's landing page. For example, view the landing page for #career - dev.to/t/career and you'll see that the submission guidelines read:

All articles and discussions should relate to careers in some way.

Pretty much everything on dev.to is about our careers in some way. Ideally, though, keep the tag related to getting, leaving, or maintaining a career or job.

Note that we recruit Tag Moderators to help us create submission guidelines and ensure that posts are properly tagged.

Those are some of the basics of tags! Feel free to visit DEV Help for other helpful information!