Search code examples
amazon-web-servicesaws-lambdaamazon-sqsamazon-kms

Encrypting an sqs queue(us-east-2) using a key from another account(us-east-1) and access it using lambda - facing error


Consider two accounts Account A and Account B. We have to Encrypt an SQS queue in account B using a KMS key from account A and then, send and receive message to the queue using a lambda(which is in account A). SQS CFN TEMPLATE:

MyQueue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: !Ref QueueName
      DelaySeconds: '0'
      MaximumMessageSize: '262144'
      MessageRetentionPeriod: '345600'
      ReceiveMessageWaitTimeSeconds: '0'
      VisibilityTimeout: '30'
      KmsMasterKeyId: <Key_id of the custom CMK> (I have a doubt here also, should i input the key id or the alias of my key?)

KEY POLICY:

{
    "Version": "2012-10-17",
    "Id": "key-consolepolicy-3",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::<Account_B_id>:root",
                    "arn:aws:iam::<Account_A_id>:root",
                    "arn:aws:iam::<Account_A_id>:role/lambda-execution-role"
                ]
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "Allow access for Key Administrators",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<Account_A_id>:role/lambda-execution-role"
            },
            "Action": [
                "kms:Create*",
                "kms:Describe*",
                "kms:Enable*",
                "kms:List*",
                "kms:Put*",
                "kms:Update*",
                "kms:Revoke*",
                "kms:Disable*",
                "kms:Get*",
                "kms:Delete*",
                "kms:TagResource",
                "kms:UntagResource",
                "kms:ScheduleKeyDeletion",
                "kms:CancelKeyDeletion",
                "kms:ReplicateKey",
                "kms:UpdatePrimaryRegion"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::<Account_B_id>:root",
                    "arn:aws:iam::<Account_A_id>:role/lambda-execution-role"
                ]
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow attachment of persistent resources",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::<Account_B_id>:root",
                    "arn:aws:iam::<Account_A_id>:role/lambda-execution-role"
                ]
            },
            "Action": [
                "kms:CreateGrant",
                "kms:ListGrants",
                "kms:RevokeGrant"
            ],
            "Resource": "*",
            "Condition": {
                "Bool": {
                    "kms:GrantIsForAWSResource": "true"
                }
            }
        }
    ]
}

SQS Queue policy:


{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<Account_A_id>:role/lambda-execution-role"
      },
      "Action": "sqs:*",
      "Resource": "arn:aws:sqs:us-east-2:<Account_B_id>:queue"
    }
  ]
}

Lambda function - Python code for send and receive message to the queue:

import json
import boto3
def lambda_handler(event, context):
    sqs = boto3.client('sqs', region_name='us-east-2')
    queue_url = 'https://sqs.us-east-2.amazonaws.com/<Account_B_id>/queue'
    response = sqs.send_message(QueueUrl=queue_url,DelaySeconds=0,MessageBody=('hey there 123 !'))
    response1 = sqs.send_message(QueueUrl=queue_url,DelaySeconds=0,MessageBody=('hey there 1234 !'))
    response2 = sqs.send_message(QueueUrl=queue_url,DelaySeconds=0,MessageBody=('hey there 123345 !'))
    print('message sent')
    response5 = sqs.receive_message(
    QueueUrl=queue_url,
    AttributeNames=['All'],
    MaxNumberOfMessages=10,
    WaitTimeSeconds=7)
    message = response5['Messages'][0]['Body']
    print(message) 

After doing all these things, I have created a test event in lambda and tested it. Getting the below error:

[ERROR] ClientError: An error occurred (KMS.AccessDeniedException) when calling the SendMessage operation: null (Service: AWSKMS; Status Code: 400; Error Code: AccessDeniedException; Request ID: d6913dbc-e22f-4ccf-ba5a-9844ab1156e0; Proxy: null)
Traceback (most recent call last):
  File "/var/task/lambda_function.py", line 6, in lambda_handler
    response = sqs.send_message(QueueUrl=queue_url,DelaySeconds=0,MessageBody=('hey there 123 !'))
  File "/var/runtime/botocore/client.py", line 386, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/var/runtime/botocore/client.py", line 705, in _make_api_call
    raise error_class(parsed_response, operation_name)

Without KMS this set up is working. Can someone help me out for integrating the KMS in this?


Solution

  • For resolving this, i reached out to AWS Support and got the solution. Initially i had my key in us-east-1 and trying to use it. In order to access an SQS in us-east-2, the key must also be in us-east-2. So the solution suggested to me was, Create a replica of the key in us-east-2 and input the arn of the replica key (I did a mistake here too, i gave the key id in the cfn template) in the cloudformation template (Since i was using a multi-region key). If it isn't a multi-region key, we must create a new key in the same region of the SQS queue.