Lambda functions should be configured with a dead-letter queue
When a Lambda function exhausts retries on an asynchronous invocation, the event payload disappears unless a dead-letter queue captures it. That means data loss with no notification, no forensic trail, and no path to remediation. In regulated environments, silent failure is not acceptable.
A DLQ backed by SQS or SNS gives your operations team a concrete signal when processing breaks. You can wire alerts, reprocess failed events, and keep an audit trail of failures. An SQS queue sitting idle costs virtually nothing, so there is no good reason to skip this.
Retrofit consideration
Retrofitting means auditing each function to identify an appropriate SQS or SNS target, then updating its IAM execution role with sqs:SendMessage or sns:Publish on that ARN. Also verify that downstream consumers can handle replayed events before the DLQ goes live. If a queue has never received traffic before, a sudden replay can surprise unprepared consumers.
Implementation
Choose the approach that matches how you manage Terraform.
Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.
module "lambda" {
source = "soc2.compliance.tf/terraform-aws-modules/lambda/aws"
version = ">=8.0.0"
create_package = false
function_name = "abc123"
handler = "index.lambda_handler"
local_existing_package = "lambda_function.zip"
runtime = "python3.12"
dead_letter_target_arn = "arn:aws:sqs:us-east-1:123456789012:example-queue"
}
module "lambda" {
source = "hipaa.compliance.tf/terraform-aws-modules/lambda/aws"
version = ">=8.0.0"
create_package = false
function_name = "abc123"
handler = "index.lambda_handler"
local_existing_package = "lambda_function.zip"
runtime = "python3.12"
dead_letter_target_arn = "arn:aws:sqs:us-east-1:123456789012:example-queue"
}
module "lambda" {
source = "nist80053.compliance.tf/terraform-aws-modules/lambda/aws"
version = ">=8.0.0"
create_package = false
function_name = "abc123"
handler = "index.lambda_handler"
local_existing_package = "lambda_function.zip"
runtime = "python3.12"
dead_letter_target_arn = "arn:aws:sqs:us-east-1:123456789012:example-queue"
}
module "lambda" {
source = "fedrampmoderate.compliance.tf/terraform-aws-modules/lambda/aws"
version = ">=8.0.0"
create_package = false
function_name = "abc123"
handler = "index.lambda_handler"
local_existing_package = "lambda_function.zip"
runtime = "python3.12"
dead_letter_target_arn = "arn:aws:sqs:us-east-1:123456789012:example-queue"
}
module "lambda" {
source = "nist800171.compliance.tf/terraform-aws-modules/lambda/aws"
version = ">=8.0.0"
create_package = false
function_name = "abc123"
handler = "index.lambda_handler"
local_existing_package = "lambda_function.zip"
runtime = "python3.12"
dead_letter_target_arn = "arn:aws:sqs:us-east-1:123456789012:example-queue"
}
module "lambda" {
source = "ffiec.compliance.tf/terraform-aws-modules/lambda/aws"
version = ">=8.0.0"
create_package = false
function_name = "abc123"
handler = "index.lambda_handler"
local_existing_package = "lambda_function.zip"
runtime = "python3.12"
dead_letter_target_arn = "arn:aws:sqs:us-east-1:123456789012:example-queue"
}
module "lambda" {
source = "rbiitfnbfc.compliance.tf/terraform-aws-modules/lambda/aws"
version = ">=8.0.0"
create_package = false
function_name = "abc123"
handler = "index.lambda_handler"
local_existing_package = "lambda_function.zip"
runtime = "python3.12"
dead_letter_target_arn = "arn:aws:sqs:us-east-1:123456789012:example-queue"
}
module "lambda" {
source = "fedramplow.compliance.tf/terraform-aws-modules/lambda/aws"
version = ">=8.0.0"
create_package = false
function_name = "abc123"
handler = "index.lambda_handler"
local_existing_package = "lambda_function.zip"
runtime = "python3.12"
dead_letter_target_arn = "arn:aws:sqs:us-east-1:123456789012:example-queue"
}
module "lambda" {
source = "hipaasecurity2003.compliance.tf/terraform-aws-modules/lambda/aws"
version = ">=8.0.0"
create_package = false
function_name = "abc123"
handler = "index.lambda_handler"
local_existing_package = "lambda_function.zip"
runtime = "python3.12"
dead_letter_target_arn = "arn:aws:sqs:us-east-1:123456789012:example-queue"
}
module "lambda" {
source = "nistcsfv11.compliance.tf/terraform-aws-modules/lambda/aws"
version = ">=8.0.0"
create_package = false
function_name = "abc123"
handler = "index.lambda_handler"
local_existing_package = "lambda_function.zip"
runtime = "python3.12"
dead_letter_target_arn = "arn:aws:sqs:us-east-1:123456789012:example-queue"
}
If you use terraform-aws-modules/lambda/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.
module "lambda" {
source = "terraform-aws-modules/lambda/aws"
version = ">=8.0.0"
create_package = false
function_name = "abc123"
handler = "index.lambda_handler"
local_existing_package = "lambda_function.zip"
runtime = "python3.12"
dead_letter_target_arn = "arn:aws:sqs:us-east-1:123456789012:example-queue"
}
Use AWS provider resources directly. See docs for the resources involved: aws_lambda_function.
resource "aws_lambda_function" "this" {
filename = "lambda_function.zip"
function_name = "pofix-abc123"
handler = "index.handler"
reserved_concurrent_executions = 100
role = "arn:aws:iam::123456789012:role/example-role"
runtime = "python3.12"
source_code_hash = "base64encodedhashabcdef1234567890=="
dead_letter_config {
target_arn = "arn:aws:sqs:us-east-1:123456789012:example-queue"
}
}
What this control checks
This control validates that every aws_lambda_function resource has a dead_letter_config block with a non-empty target_arn pointing to an SQS queue or SNS topic ARN. It fails when the block is absent or target_arn is empty. The execution role also needs sqs:SendMessage or sns:Publish on the target ARN, though this check only evaluates the dead_letter_config.target_arn value, not the IAM policy.
One important distinction: aws_lambda_function_event_invoke_config with destination_config.on_failure configures Lambda Destinations, a separate mechanism. Only the dead_letter_config block on the aws_lambda_function resource satisfies this control.
Common pitfalls
Missing IAM permissions on execution role
DLQ delivery silently fails if the Lambda execution role lacks
sqs:SendMessageorsns:Publishon the target ARN. Lambda records these asDeadLetterErrorsin CloudWatch but does not surface them as invocation failures, so the function appears to run normally while events are being lost. Always attach the required policy to the role specified in the function'sroleargument.Confusing Lambda Destinations with dead_letter_config
Lambda Destinations and
dead_letter_configare not interchangeable.aws_lambda_function_event_invoke_configwithdestination_config.on_failureis a different mechanism from thedead_letter_configblock onaws_lambda_function. This control checks only the latter. A function with only a Destination configured will fail the check.DLQ target in a different account or region
Lambda DLQ targets must be in the same region as the function. Cross-account targets work when both the target's resource policy and the execution role's IAM permissions allow access, but if the
target_arnreferences something the function cannot reach, the DLQ exists in configuration and nowhere else. Verify reachability before treating the config as evidence of capture.SQS queue message retention too short
The default SQS
MessageRetentionPeriodis 4 days. If nobody monitors or drains the DLQ within that window, failed events are permanently lost regardless of the DLQ being configured. Setmessage_retention_secondsonaws_sqs_queueto a value that matches your incident response SLA, up to the maximum of 1209600 seconds (14 days).
Audit evidence
Config rule evaluation results showing all Lambda functions as compliant, with each having a dead-letter queue target configured. Supporting evidence includes Console screenshots of individual Lambda function configurations with the DLQ section populated, or aws lambda get-function-configuration output showing a non-empty DeadLetterConfig.TargetArn for each function.
CloudWatch DeadLetterErrors metrics for monitored functions show whether DLQ delivery is actually working. Including these metrics rounds out the evidence picture by demonstrating the DLQ configuration is operational, not just present.
Framework-specific interpretation
SOC 2: Processing Integrity and Availability both apply here. Processing Integrity asks whether processing is complete and valid; a silently dropped invocation is a direct failure of that criterion. The DLQ is what gives auditors evidence that incomplete processing events are captured rather than lost.
HIPAA Omnibus Rule 2013: Lambda functions processing ePHI that fail silently create exactly the kind of incident detection gap that the HIPAA Security Rule's administrative safeguards are designed to close. 45 CFR 164.308(a)(6) requires covered entities to identify and respond to security incidents. A DLQ captures processing failures involving ePHI and gives the security team something concrete to investigate, rather than a gap in the audit trail.
NIST SP 800-53 Rev 5: SI-11 says error conditions should be visible only to authorized personnel, not silently discarded. IR-5 requires incident monitoring. Routing Lambda failures to a controlled SQS queue or SNS topic covers both: failures are retained for authorized review and feed directly into the incident monitoring pipeline.
FedRAMP Moderate Baseline Rev 4: SI-11 and IR-6 are the relevant controls. SI-11 requires that systems handle error conditions without discarding data or exposing sensitive information to unauthorized parties; IR-6 requires incident reporting mechanisms. A DLQ satisfies both: failures are captured rather than dropped, and the SQS queue or SNS topic gives the incident response pipeline a concrete notification path.
Related controls
Tool mappings
Use these identifiers to cross-reference this control across tools, reports, and evidence.
Compliance.tf Control:
lambda_function_dead_letter_queue_configuredAWS Config Managed Rule:
LAMBDA_DLQ_CHECKCheckov Check:
CKV_AWS_116Powerpipe Control:
aws_compliance.control.lambda_function_dead_letter_queue_configuredKICS Query:
720f44cf-285e-4b69-8f72-835e6bc1dceb
Last reviewed: 2026-03-09