SNS TopicPolicy Self-Lockout
sns-topic-policy-self-lockout
What this rule checks
Detects AWS::SNS::TopicPolicy resources containing a Deny statement on sns:DeleteTopic, sns:RemovePermission, sns:*, or * with a broad Principal and no NotPrincipal or aws:PrincipalArn carveout for the account root or admin role. Such a policy locks the account out of its own topic โ recovery requires breaking glass on the account root credentials to remove the topic policy, or delete-and-recreate the topic if no subscribers depend on its ARN. In fan-out architectures that is often a multi-stack rebuild.
How to fix it
- 1Add a NotPrincipal exemption for the account root (arn:aws:iam::<account>:root) or admin role(s)
- 2Or use a Condition with StringNotEquals on aws:PrincipalArn to exempt admin role ARNs
- 3If the Deny is intended to scope to AWS services, use aws:PrincipalIsAWSService rather than a blanket Deny on Principal: '*'
import { aws_sns as sns, aws_iam as iam } from 'aws-cdk-lib';
const topic = new sns.Topic(this, 'Topic');
topic.addToResourcePolicy(new iam.PolicyStatement({
sid: 'DenyAdmin',
effect: iam.Effect.DENY,
principals: [new iam.AnyPrincipal()],
actions: ['sns:DeleteTopic', 'sns:RemovePermission'],
resources: [topic.topicArn],
}));import { aws_sns as sns, aws_iam as iam } from 'aws-cdk-lib';
const topic = new sns.Topic(this, 'Topic');
topic.addToResourcePolicy(new iam.PolicyStatement({
sid: 'DenyAdmin',
effect: iam.Effect.DENY,
notPrincipals: [new iam.AccountRootPrincipal()],
actions: ['sns:DeleteTopic', 'sns:RemovePermission'],
resources: [topic.topicArn],
}));CDK Insights pinpoints the exact file and line in your CDK source for every finding, so you can jump straight to the fix.
Affected resource types
AWS::SNS::TopicPolicyIntentional? Suppress this finding
Sometimes a flag is deliberate โ a genuinely public endpoint, say. You can dismiss sns-topic-policy-self-lockout and the reason is kept in the report, not silently hidden.
In .cdk-insights.json:
{
"ignoreRules": [
{ "id": "sns-topic-policy-self-lockout", "reason": "Why this is intentional" }
]
}Or inline in your CDK code:
Validations.of(scope).acknowledge({
id: 'cdk-insights::sns-topic-policy-self-lockout',
reason: 'Why this is intentional',
});Use the rule ID sns-topic-policy-self-lockout shown above โ not the CDK-* ID from SARIF / GitHub code scanning. To dismiss every finding on one construct instead, use ignorePaths. Suppression docs โ
Catch this in your stack
$ npx cdk-insights scanCDK Insights runs this and 118+ other rules locally against your synthesised CDK app โ free, no account, your code never leaves your machine.