When AWS services are wired together, the part that usually breaks first is not the business logic. It is the permission model.
A Lambda can run but fail to publish to SNS. An SNS subscription can exist but still fail to deliver to SQS. API Gateway can be configured correctly and still return a permission error because Lambda never granted it invoke access.
The easiest way to reason about this is to stop thinking about permissions in the abstract and follow one concrete flow end to end.
In this example, the system looks like this:

- API Gateway receives order requests.
- API Gateway invokes an Order Lambda.
- The Order Lambda writes order state to DynamoDB.
- The Order Lambda publishes an event to SNS.
- SNS fans the event out to SQS queues.
- Consumer Lambdas poll those queues and write audit records to another DynamoDB table.
The permission model by hop
The cleanest way to summarize the whole system is by looking at each hop separately.
1. API Gateway -> Order Lambda
- acting service: API Gateway
- policy type: Lambda resource policy


2. Order Lambda -> Orders DynamoDB table, SNS topic
- acting principal: Order Lambda execution role
- policy type: IAM identity policy

The execution role needs identity-based permissions for the downstream services it calls, such as dynamodb:PutItem and sns:Publish.
3. SNS topic -> SQS queue
- acting service: SNS
- policy type: SQS queue resource policy
This hop usually needs two separate pieces:
- the SNS subscription that connects the topic to the queue
- the SQS queue policy that explicitly allows the SNS topic to send messages



4. Consumer Lambda -> SQS queue, Audit DynamoDB table
- acting principal: consumer Lambda execution role
- policy type: IAM identity policy
Lambda polls SQS through the event source mapping, and the function role still needs permission for the work done after receipt, such as writing to the audit DynamoDB table.



Permission Matrix
| From | To | Principal or Service | Policy Type | Actions | Resource |
|---|---|---|---|---|---|
| API Gateway | Order Lambda | apigateway.amazonaws.com |
Lambda resource policy | lambda:InvokeFunction |
Order Lambda |
| Order Lambda | Orders table | Order Lambda role | IAM identity policy | dynamodb:PutItem, dynamodb:UpdateItem |
Orders table |
| Order Lambda | SNS topic | Order Lambda role | IAM identity policy | sns:Publish |
Orders topic |
| SNS topic | Consumer queue | sns.amazonaws.com |
SQS queue policy | sqs:SendMessage |
Consumer queue |
| Consumer Lambda | Consumer queue | Consumer Lambda role | IAM identity policy | sqs:ReceiveMessage, sqs:DeleteMessage, sqs:GetQueueAttributes, sqs:ChangeMessageVisibility |
Consumer queue |
| Consumer Lambda | Audit table | Consumer Lambda role | IAM identity policy | dynamodb:PutItem |
Audit table |
| Lambda functions | CloudWatch Logs | each Lambda role | IAM identity policy | logs:CreateLogGroup, logs:CreateLogStream, logs:PutLogEvents |
each function’s log group |