Skip to main content
HIGHIAMReliability

Lambda Trigger Missing Resource-Based Permission

TL-PERM-003

What this rule checks

An in-template trigger (EventBridge rule, SNS lambda subscription, S3 bucket notification) targets a Lambda function but no AWS::Lambda::Permission grants the service principal invoke access. The trigger silently never invokes the function. CDK custom-resource notification patterns are excluded.

How to fix it

  1. 1Use the CDK L2 wiring, which creates the permission automatically: rule.addTarget(new targets.LambdaFunction(fn)), topic.addSubscription(new subscriptions.LambdaSubscription(fn)), or bucket.addEventNotification(...)
  2. 2Or add an AWS::Lambda::Permission with Action lambda:InvokeFunction, the trigger service principal, and a SourceArn scoped to the trigger
FlaggedThe raw rule targets the function, but no AWS::Lambda::Permission grants events.amazonaws.com permission to invoke it. The schedule fires on time and EventBridge is silently denied — no error surfaces anywhere except the rule's failed-invocation metrics.
import * as events from 'aws-cdk-lib/aws-events';
import * as lambda from 'aws-cdk-lib/aws-lambda';

const reporter = new lambda.Function(this, 'Reporter', {
  runtime: lambda.Runtime.NODEJS_20_X,
  handler: 'index.handler',
  code: lambda.Code.fromInline('exports.handler = async () => {};'),
});

new events.CfnRule(this, 'Nightly', {
  scheduleExpression: 'cron(0 3 * * ? *)',
  targets: [{ id: 'reporter', arn: reporter.functionArn }],
});
FixedThe targets array on the L2 Rule creates the AWS::Lambda::Permission for events.amazonaws.com automatically, scoped to this rule's ARN, so the trigger can actually invoke the function.
import * as events from 'aws-cdk-lib/aws-events';
import * as targets from 'aws-cdk-lib/aws-events-targets';
import * as lambda from 'aws-cdk-lib/aws-lambda';

const reporter = new lambda.Function(this, 'Reporter', {
  runtime: lambda.Runtime.NODEJS_20_X,
  handler: 'index.handler',
  code: lambda.Code.fromInline('exports.handler = async () => {};'),
});

new events.Rule(this, 'Nightly', {
  schedule: events.Schedule.cron({ hour: '3', minute: '0' }),
  targets: [new targets.LambdaFunction(reporter)],
});

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::Lambda::PermissionAWS::Events::RuleAWS::SNS::SubscriptionAWS::S3::Bucket

AWS documentation

Read the AWS guidance

Intentional? Suppress this finding

Sometimes a flag is deliberate — a genuinely public endpoint, say. You can dismiss TL-PERM-003 and the reason is kept in the report, not silently hidden.

In .cdk-insights.json:

{
  "ignoreRules": [
    { "id": "TL-PERM-003", "reason": "Why this is intentional" }
  ]
}

Or inline in your CDK code:

Validations.of(scope).acknowledge({
  id: 'cdk-insights::TL-PERM-003',
  reason: 'Why this is intentional',
});

Use the rule ID TL-PERM-003 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 scan

CDK Insights runs this and 131+ other rules locally against your synthesised CDK app — free, no account, your code never leaves your machine.

More IAM rules