Skip to main content
HIGHIAMReliability

Event Source Mapping Missing Required IAM Permissions

TL-PERM-002

What this rule checks

An AWS::Lambda::EventSourceMapping polls an in-template SQS queue, Kinesis stream, or DynamoDB stream but the function execution role lacks the documented required actions (e.g. sqs:ReceiveMessage / DeleteMessage / GetQueueAttributes). The mapping fails to create or the poller fails with AccessDenied.

How to fix it

  1. 1Grant the poller permissions in CDK: queue.grantConsumeMessages(fn), stream.grantRead(fn), or table.grantStreamRead(fn)
  2. 2Or attach the matching AWS managed policy: AWSLambdaSQSQueueExecutionRole, AWSLambdaKinesisExecutionRole, or AWSLambdaDynamoDBExecutionRole
  3. 3The Lambda service polls the source with the function's execution role, so the role itself needs these actions
FlaggedThe raw CfnEventSourceMapping wires the queue to the function but grants nothing. The Lambda service polls SQS with the function's execution role, which is missing sqs:ReceiveMessage, sqs:DeleteMessage, and sqs:GetQueueAttributes — the mapping fails to create.
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as sqs from 'aws-cdk-lib/aws-sqs';

const queue = new sqs.Queue(this, 'Jobs');

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

new lambda.CfnEventSourceMapping(this, 'Mapping', {
  functionName: worker.functionName,
  eventSourceArn: queue.queueArn,
});
FixedThe L2 addEventSource wiring creates the same event source mapping AND grants the execution role the full consume action set, so the poller has everything it needs.
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { SqsEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
import * as sqs from 'aws-cdk-lib/aws-sqs';

const queue = new sqs.Queue(this, 'Jobs');

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

worker.addEventSource(new SqsEventSource(queue));

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::EventSourceMappingAWS::Lambda::FunctionAWS::IAM::Role

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-002 and the reason is kept in the report, not silently hidden.

In .cdk-insights.json:

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

Or inline in your CDK code:

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

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