Security

SNS/SQS KMS Access Denied: Fixing Cross-Service Encryption Permissions

2026-05-03 · 8 min read

You have just enabled server-side encryption on your SQS queue. Responsible move — data at rest should always be encrypted. But now your SNS topic can no longer deliver messages to the queue. The messages silently vanish, and when you check the SNS delivery status logs, you see this:

{
  "notification": {
    "messageId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE",
    "topicArn": "arn:aws:sns:us-east-1:123456789012:order-events"
  },
  "delivery": {
    "statusCode": 403,
    "providerResponse": "{\"ErrorCode\":\"KMS.AccessDeniedException\",\"ErrorMessage\":\"User: arn:aws:iam::123456789012:root is not authorized to perform: kms:GenerateDataKey on resource: arn:aws:kms:us-east-1:123456789012:key/abc123-def456\",\"sqsRequestId\":\"xxx\"}"
  }
}

Or perhaps your Lambda function is failing when polling an encrypted SQS queue:

[ERROR] KMSAccessDeniedException: The ciphertext refers to a customer master
key that does not exist, does not exist in this region, or you are not allowed
to access.

These errors are frustrating because the encryption configuration looks correct — the queue is encrypted, the key exists, and the IAM policies seem fine. The problem is that KMS key policies operate on a different permission model than most AWS services, and cross-service encryption requires permissions that are not obvious.

Understanding the Problem: Why Cross-Service KMS Fails

When you encrypt an SQS queue with a KMS key, every service that writes to or reads from that queue needs permission to use that key. This is a critical distinction from unencrypted queues:

  • SNS needs kms:GenerateDataKey and kms:Decrypt to publish messages
  • Lambda needs kms:Decrypt to poll and read messages
  • S3 event notifications need kms:GenerateDataKey to publish to encrypted SNS topics
  • EventBridge needs similar permissions when targeting encrypted queues

The permissions must be granted in two places: the IAM policy of the calling principal and the KMS key policy itself. Missing either one causes the AccessDeniedException.

Root Cause 1: AWS-Managed Key (aws/sqs) Used with Cross-Service Communication

This is the most common mistake I see in the field. When you enable encryption on an SQS queue through the console, the default option is the AWS-managed key alias/aws/sqs. This key works fine for direct API calls from IAM users and roles, but it cannot be used by AWS service principals like sns.amazonaws.com.

Check which key your queue is using:

aws sqs get-queue-attributes \
  --queue-url https://sqs.us-east-1.amazonaws.com/123456789012/order-queue \
  --attribute-names KmsMasterKeyId \
  --query 'Attributes.KmsMasterKeyId' \
  --output text

If this returns alias/aws/sqs or an ARN containing alias/aws/sqs, that is your problem. You must switch to a customer-managed KMS key (CMK) so you can modify the key policy to grant access to other AWS services.

The Fix: Create and Use a Customer-Managed Key

# Create a customer-managed key
aws kms create-key \
  --description "Key for order processing queue encryption" \
  --query 'KeyMetadata.KeyId' \
  --output text

Save the key ID, then create an alias for easy reference:

aws kms create-alias \
  --alias-name alias/order-queue-key \
  --target-key-id YOUR_KEY_ID

Update the SQS queue to use the new key:

aws sqs set-queue-attributes \
  --queue-url https://sqs.us-east-1.amazonaws.com/123456789012/order-queue \
  --attributes '{"KmsMasterKeyId":"YOUR_KEY_ID"}'

Root Cause 2: KMS Key Policy Missing Service Principal Permissions

Even with a customer-managed key, the KMS key policy must explicitly grant permissions to the AWS service principals that need to interact with the encrypted queue. By default, a new KMS key only trusts the account root and key administrators.

Check the current key policy:

aws kms get-key-policy \
  --key-id YOUR_KEY_ID \
  --policy-name default \
  --output text

The Fix: Add SNS Service Principal to Key Policy

Add a statement to the key policy that grants the SNS service principal permission to use the key:

{
  "Sid": "AllowSNSToUseKey",
  "Effect": "Allow",
  "Principal": {
    "Service": "sns.amazonaws.com"
  },
  "Action": [
    "kms:GenerateDataKey",
    "kms:Decrypt"
  ],
  "Resource": "*",
  "Condition": {
    "ArnLike": {
      "aws:SourceArn": "arn:aws:sns:us-east-1:123456789012:order-events"
    }
  }
}

Apply the updated key policy:

aws kms put-key-policy \
  --key-id YOUR_KEY_ID \
  --policy-name default \
  --policy file://key-policy.json

The Condition block is critical for security. Without it, any SNS topic in any account could use your key. Always scope the condition to specific source ARNs.

Adding S3 Service Principal (for S3 Event Notifications)

If S3 event notifications publish to an encrypted SNS topic or SQS queue, add the S3 service principal as well:

{
  "Sid": "AllowS3ToUseKey",
  "Effect": "Allow",
  "Principal": {
    "Service": "s3.amazonaws.com"
  },
  "Action": [
    "kms:GenerateDataKey",
    "kms:Decrypt"
  ],
  "Resource": "*",
  "Condition": {
    "ArnLike": {
      "aws:SourceArn": "arn:aws:s3:::my-bucket"
    }
  }
}

Root Cause 3: Lambda Execution Role Missing kms:Decrypt

When Lambda polls an encrypted SQS queue, the Lambda execution role must have kms:Decrypt permission on the KMS key. This is separate from the SQS permissions — having sqs:ReceiveMessage is not enough.

Check the Lambda execution role:

# Get the execution role ARN
aws lambda get-function-configuration \
  --function-name order-processor \
  --query 'Role' \
  --output text

# List attached policies
aws iam list-attached-role-policies \
  --role-name order-processor-role

# Check inline policies
aws iam list-role-policies \
  --role-name order-processor-role

The Fix: Add KMS Permissions to the Lambda Role

Add this policy to the Lambda execution role:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "kms:Decrypt",
        "kms:DescribeKey"
      ],
      "Resource": "arn:aws:kms:us-east-1:123456789012:key/YOUR_KEY_ID"
    }
  ]
}
aws iam put-role-policy \
  --role-name order-processor-role \
  --policy-name KMSDecryptForSQS \
  --policy-document file://kms-decrypt-policy.json

Also ensure the KMS key policy includes a statement allowing the Lambda execution role:

{
  "Sid": "AllowLambdaRoleToDecrypt",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::123456789012:role/order-processor-role"
  },
  "Action": [
    "kms:Decrypt",
    "kms:DescribeKey"
  ],
  "Resource": "*"
}

Root Cause 4: Cross-Account Encrypted Queue Subscriptions

Cross-account setups add another layer of complexity. When an SNS topic in Account A publishes to an encrypted SQS queue in Account B, you need permissions configured in three places: the SNS topic policy, the SQS queue policy, and the KMS key policy in Account B.

The KMS key policy in Account B must grant access to the SNS service principal, conditioned on the source topic ARN from Account A:

{
  "Sid": "AllowCrossAccountSNS",
  "Effect": "Allow",
  "Principal": {
    "Service": "sns.amazonaws.com"
  },
  "Action": [
    "kms:GenerateDataKey",
    "kms:Decrypt"
  ],
  "Resource": "*",
  "Condition": {
    "ArnLike": {
      "aws:SourceArn": "arn:aws:sns:us-east-1:111111111111:order-events"
    }
  }
}

Verify the SQS queue policy also allows the SNS topic from Account A to send messages:

aws sqs get-queue-attributes \
  --queue-url https://sqs.us-east-1.amazonaws.com/222222222222/order-queue \
  --attribute-names Policy \
  --query 'Attributes.Policy' \
  --output text | python3 -m json.tool

Root Cause 5: KMS Key in a Different Region

KMS keys are regional. If your SQS queue is in us-east-1 but the KMS key ARN points to a key in eu-west-1, the encryption will fail. This can happen when copying infrastructure configurations between regions.

Verify the key region matches the queue region:

# Parse the region from the key ARN
aws sqs get-queue-attributes \
  --queue-url https://sqs.us-east-1.amazonaws.com/123456789012/order-queue \
  --attribute-names KmsMasterKeyId \
  --output text

The key ARN format is arn:aws:kms:REGION:ACCOUNT:key/KEY_ID. Ensure REGION matches the SQS queue's region.

Step-by-Step Diagnosis Workflow

When you hit a KMS access denied error with SNS/SQS, follow this systematic checklist:

  1. Identify the KMS key used by the queue or topic
  2. Check if it is an AWS-managed key — if so, switch to a customer-managed key
  3. Read the KMS key policy and verify the necessary service principals are listed
  4. Check IAM policies on the publishing/consuming role for kms:GenerateDataKey and kms:Decrypt
  5. Test with a manual publish to confirm the fix
# Test SNS publish to the queue
aws sns publish \
  --topic-arn arn:aws:sns:us-east-1:123456789012:order-events \
  --message '{"test": "kms-permissions-check"}' \
  --output text
# Verify the message arrives in the queue
aws sqs receive-message \
  --queue-url https://sqs.us-east-1.amazonaws.com/123456789012/order-queue \
  --max-number-of-messages 1 \
  --wait-time-seconds 5

Prevention: Best Practices for Encrypted Queues

  1. Always use customer-managed keys for queues that receive messages from other AWS services. AWS-managed keys are simpler but cannot grant cross-service permissions.

  2. Use CloudTrail to audit KMS usage. Enable CloudTrail logging for KMS API calls so you can see exactly which principals are being denied:

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=Decrypt \
  --start-time 2026-05-03T00:00:00Z \
  --max-results 20 \
  --query 'Events[*].{Time:EventTime,User:Username,Error:CloudTrailEvent}' \
  --output table
  1. Scope conditions tightly. Always use aws:SourceArn or aws:SourceAccount conditions in key policies to prevent unintended access.

  2. Use infrastructure as code. Define KMS key policies alongside the queues and topics in CloudFormation or CDK. This ensures the permissions are always deployed together and reviewed in pull requests.

  3. Test encryption end-to-end in your CI/CD pipeline before deploying to production. A simple integration test that publishes a message and receives it from the encrypted queue catches permission issues before they hit production.

Need Help Untangling KMS Permissions?

Cross-service encryption in AWS is powerful but the permission model is genuinely complex. If you are spending hours debugging KMS access denied errors, or you want to ensure your encryption architecture follows AWS best practices from the start, we can help. Get in touch for a free AWS consultation — we have untangled hundreds of these permission configurations and can typically identify the issue within the first call.

Need help with your AWS infrastructure?

Book a free 30-minute consultation to discuss your challenges.