aws / aws/aws-cdk

(sns-subscriptions): LambdaSubscription and SqsSubscription do not support regionalized service principals for cross-region delivery

Open
#37,873 2 comments 0 reactions 0 assignees View on GitHub
@aws-cdk/aws-sns @aws-cdk/aws-sns-subscriptions effort/medium feature-request p2
Dominant language
TypeScript
Stars
12.9k
Forks
4.6k
Avg merge
1d 19h
Merged PRs (30d)
74

Description

### Describe the feature

`LambdaSubscription` and `SqsSubscription` in `aws-cdk-lib/aws-sns-subscriptions` always grant invoke/send permission to the principal `sns.amazonaws.com`. When the SNS topic lives in an opt-in region (e.g. `ap-east-1`, `me-south-1`, `eu-south-1`, `af-south-1`, `il-central-1`, etc.), AWS requires the subscriber's resource policy to use the regionalized service principal `sns..amazonaws.com` instead. There is currently no way to configure this through the `LambdaSubscription` or `SqsSubscription` props, so cross-region delivery from opt-in regions cannot be modeled in CDK.

This request is to add an opt-in mechanism to both subscription types that lets users specify which SNS regional service principals should be granted permission, while preserving today's behavior as the default.

### Use Case

I have an SNS topic in an opt-in region (for example, `eu-central-1`) and need to subscribe a Lambda function or SQS queue that lives in a different region (either a default-enabled region like `us-east-1`, or another opt-in region). AWS supports this scenario, but only if the Lambda permission / queue resource policy uses the regionalized service principal `sns.ap-east-1.amazonaws.com` rather than `sns.amazonaws.com`.

The same constraint applies in the reverse direction (default-enabled region topic delivering into an opt-in region), and between two opt-in regions. AWS documents the rules here:
- https://docs.aws.amazon.com/sns/latest/dg/sns-cross-region-delivery.html
- https://docs.aws.amazon.com/sns/latest/dg/lambda-prereq.html

Today the only workarounds are:

1. Drop down to L1 (`CfnSubscription`) and hand-write the Lambda permission / queue policy — losing all the convenience of `LambdaSubscription` / `SqsSubscription`.
2. Use `addToResourcePolicy` / `addPermission` to attach an additional regionalized principal after the fact — workable but not discoverable, and easy to get wrong (the existing `sns.amazonaws.com` permission is also still added unnecessarily).

Neither workaround is reasonable for a documented and supported AWS feature.

### Proposed Solution

Add two optional, backward-compatible properties to the shared `SubscriptionProps` interface (consumed by `LambdaSubscriptionProps` and `SqsSubscriptionProps`):

```ts
export interface SubscriptionProps {
// ...existing props...

/**
* Whether the default SNS service principal (`sns.amazonaws.com`) should be granted
* permission. Disable this only if the topic lives in an opt-in region and the
* subscriber should not also accept invocations from default-enabled regions.
*
* @default true
*/
readonly includeDefaultServicePrincipal?: boolean;

/**
* Additional opt-in regions whose regionalized SNS service principals
* (`sns..amazonaws.com`) should be granted permission. Required when the
* topic lives in an opt-in region and the subscriber lives in a different region.
*
* @see https://docs.aws.amazon.com/sns/latest/dg/sns-cross-region-delivery.html
* @default - none
*/
readonly additionalServicePrincipalRegions?: string[];
}
```

Behavior:

- Both unset → identical to current behavior (`sns.amazonaws.com` only).
- `additionalServicePrincipalRegions: ['ap-east-1']` → both `sns.amazonaws.com` and `sns.ap-east-1.amazonaws.com` are granted.
- `includeDefaultServicePrincipal: false, additionalServicePrincipalRegions: ['ap-east-1']` → only `sns.ap-east-1.amazonaws.com` is granted.
- `includeDefaultServicePrincipal: false` with no regions → synth-time `ValidationError` (no principals would be configured, which is invalid).

Synth-time validation against `aws-cdk-lib/region-info`:

- Tokens are skipped.
- Known opt-in regions → accepted.
- Known default-enabled regions → `ValidationError` (the regionalized principal is never needed for those; this is a user error worth surfacing).
- Unknown regions (CDK's `RegionInfo` doesn't have them yet) → accepted with a synth-time warning, so customers aren't blocked when AWS launches new regions.

The shared logic (validation + principal construction) goes into a private helper in `aws-sns-subscriptions/lib/private/util.ts` and is reused by both `LambdaSubscription` and `SqsSubscription`.

### Other Information

**Out of scope:** `FirehoseSubscription` is intentionally excluded. Per the AWS cross-region delivery documentation, only Lambda and SQS support cross-region delivery; Firehose subscriptions use a customer-provided IAM role (`SubscriptionRoleARN`) that SNS assumes via STS, so the regionalized service principal does not apply.

**Why two props instead of a single array with a `'default'` sentinel value:** an early sketch had a single `principalRegions: string[]` prop where the string `'default'` meant `sns.amazonaws.com`. Magic strings are inconsistent with the rest of `aws-cdk-lib`, and splitting into two props makes each prop's job unambiguous and keeps the common case (just enable the default + one opt-in region) readable.

**Why not auto-detect the opt-in region from `topic.env.region`:** auto-detection would silently misbehave for env-agnostic stacks (where `topic.env.region` is a Token) and for cross-account scenarios where the topic is imported by ARN. Explicit configuration is more predictable and matches CDK's convention of preferring explicit user intent over inference for security-relevant policy.

**Backwards compatibility:** the change is strictly additive (new optional props, default behavior unchanged). No feature flag is needed.

### Acknowledgements

- [x] I may be able to implement this feature request
- [ ] This feature might incur a breaking change

### AWS CDK Library version (aws-cdk-lib)

2.248.0

### AWS CDK CLI version

2.253.1

### Environment details (OS name and version, etc.)

MacOS

Contributor guide

Open the contributing guide

Research direction

Start with aws-sns-subscriptions and the private helper in aws-sns-subscriptions/lib/private/util.ts, then inspect how LambdaSubscription and SqsSubscription currently construct permissions. Verify the region-info validation requirements and existing subscription tests before implementing. Done means both subscription types support the optional principals, preserve the default behavior, validate configured regions, and reject configurations with no principals.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, typescript
Domain
cloud, infrastructure
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.