skip to Main Content

I am trying to hook up a SQS Queue into a SNS Topic, both are in different AWS Accounts and are encrypted using different KMS keys (CMKs).

Let me know elaborate the setup a little bit better:

AWS Account 1:
 - Encrypted (SSE) SNS Topic
 - KMS CMK used to encrypt SNS Topic
 - Policy to Allow AWS Account 2 to subscribe to the SNS Topic
AWS Account 2:
 - Encrypted SQS Queue
 - KMS CMK used to encrypt SQS Queue
 - Cross-account subscription to the AWS Account 1's SNS Topic
 - Unencrypted DLQ for the SQS Queue

The thing is, with encryption disabled in the AWS Account 2’s SQS Queue, everything works fine, the SNS Topic is able to send all messages into the Queue.

When I enable encryption in the SQS Queue, the messages now go straight into the DLQ despite giving permission to the AWS Account 1 on the KMS key.

Here is the overall cdk setup I am trying for Account 2:

const keyAlias = new Key(this, `Key`).addAlias(`KeyAlias`)

const dlq = new Queue(this, `DLQ`, {
    queueName: `dlq`,
    retentionPeriod: Duration.days(14),
})

const queue = new Queue(this, `Queue`, {
    queueName: `queue`,
    deadLetterQueue: {
        queue: dlq,
        maxReceiveCount: 5,
    },
    encryption: QueueEncryption.KMS,
    encryptionMasterKey: keyAlias,
})

// This creates a reference to the SNS Topic form the other account
const SNSTopic = Topic.fromTopicArn(this, `Topic`, "<topic_arn>")

keyAlias.addToResourcePolicy(new PolicyStatement({
    sid: "Allow SNS to use the KMS key",
    actions: ["kms:GenerateDataKey", "kms:Decrypt"],
    resources: ["*"],
    effect: Effect.ALLOW,
    principals: [new ServicePrincipal("sns.amazonaws.com")],
}))

keyAlias.addToResourcePolicy(new PolicyStatement({
    sid: "Allow Account to use the KMS key",
    actions: ["kms:GenerateDataKey", "kms:Decrypt"],
    resources: ["*"],
    effect: Effect.ALLOW,
    principals: [new AccountPrincipal("<account_1_id>")],
}))

SNSTopic.addSubscription(new SqsSubscription(queue, {
    deadLetterQueue: dlq,
    filterPolicy: {
    ProtobufMessageType: SubscriptionFilter.stringFilter({
        allowlist: ["Event1", "Event2", "Event3"],
    }),
    },
    rawMessageDelivery: true,
}))

2

Answers


  1. Chosen as BEST ANSWER

    Adding this as the answer that solved the problem:

    The SNS Topic and SQS queue were in a region: us-west-2. The resources that would consume from the SQS queue were in another region: us-east-1. This was a cross-account, cross-region setup.

    So, in order for all of them (SNS, SQS, Consumers) to access the KMS key used to encrypt/decrypt the SQS queue, the key MUST be a multi-region key with the primary in one of the two regions and a Key Replica in the other region (this is not explicitly documented by AWS anywhere).

    As of now, this is still not supported by CDK, so this has to be done manually in the AWS console.

    The created keys, aliases and key replicas can be referenced in the CDK stack using Key.fromKeyArn and Alias.fromAliasAttributes so that it can be set as the SQS queue encryption key and given access permission by the consumers.

    Keep in mind that even if referencing the Key and Replicas in the CDK stack, you cannot interact (add, remove, edit) with the resource policies.


  2. Try adding kms permissions like this:

    keyAlias.grantEncryptDecrypt(new ArnPrincipal(arn:aws:iam::Account:role/roleName`));
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search