Search code examples
amazon-snsaws-cdk

Cross Account SNS Lambda Subscription using CDK


I have 2 AWS CDK applications running in separate AWS accounts, and I'm trying to add CDK to get a lambda in one AWS account to subscribe to notifications in the other AWS account.

I tried adding the subscription in the lambda account, but this didn't work, since the SNS account doesn't grant permissions.

CDK in the SNS account:

val myTopic = Topic(this, "my-topic-id", TopicProps.builder()
            .displayName("topicName")
            .topicName("topicName")
            .build())

CDK in the Lambda account:

val myLambda = Function(...)

val crossAccountTopic = Topic.fromTopicArn(this, "topic-id", "arn:aws:sns:<region>:<accountId>:topicName")

crossAccountTopic.addSubscription(LambdaSubscription(myLambda))

Has anyone tried something like this? Is there a way to grant access purely with changes to CDK in both accounts? Or is a manual action required? There may be a way to do this by granting access through IAM roles, so I will investigate this further.


Solution

  • Yes, you can grant access in both accounts through CDK. First, you must grant access in the providing account, and deploy the CDK/cloudformation stack. Then you can grant access in the client account.

    CDK in the SNS account:

    val myTopic = Topic(this, "my-topic-id", TopicProps.builder()
            .displayName("topicName")
            .topicName("topicName")
            .build())
    PolicyStatement snsAccessPolicy = PolicyStatement.Builder.create()
                .principals(listOf(AccountPrincipal("123456346")))
                .actions(Arrays.asList("SNS:Subscribe"))
                .resources(Arrays.asList(myTopic.getTopicArn()))
                .build();
    myTopic.addToResourcePolicy(snsAccessPolicy);
    

    CDK in the Lambda account:

    val myLambda = Function(...)
    
    val crossAccountTopic = Topic.fromTopicArn(this, "topic-id", "arn:aws:sns:<region>:<accountId>:topicName")
    
    crossAccountTopic.addSubscription(LambdaSubscription(myLambda))
    

    Note that the AccountPrinciple declared in the PolicyStatement of the SNS account refers to the AWS account ID of the subscribing Lambda account. Intuitively, the SNS account is granting access to the Lambda account, so the SNS account policy needs to grant the Lambda account access.