I am attempting to call sqs:SendMessage on an SQS queue in account B from a lambda function (written in Go) running in account A. I am getting an access denied error and do not understand why.
The lambda is running as an IAM role that has an inline policy that allows sqs:SendMessage to the queue in the other account, as verified in the AWS Lambda GUI, Configuration tab, Permissions tab, Resource summary "by resource" view:
The queue itself, in account B, allows any user or role in account A to call sendmessage. The queue does not have KMS enabled. I have opened up permissions quite wide for testing/troubleshooting:
The error I'm getting from the Golang SDK is:
AccessDenied: Access to the resource https://sqs.us-west-2.amazonaws.com/ is denied.\n\tstatus code: 403, request id: 27725068-xxxx-xxxx-xxxx-0cbc781c2526
My code is getting the SQS queue's URL from an environment variable, which is populated by Terraform from the resource's url attribute, so I'm comfortably certain that I'm sending my data to the correct URL. (I don't see a difference between what my code is calling and the queue's URL using stare-and-compare either.)
Can anyone suggest what else might be causing this, or how I could get a more detailed error message from AWS?
EDIT: The URL in the error message makes it appear as though I don't have the full queue URL. However, the sqs.SendMessageInput struct has the following data from my logs:
"DelaySeconds": null,
"MessageAttributes": null,
"MessageBody": "{\"CreatedTime\":1683599412006493,\"FooID\":\"1bec4d4a-336d-4a7c-bb0e-e73b6eb23c55\",\"S3Bucket\":\"myredactedbucketname\",\"S3Key\":\"b9f01b2f-4043-4e6b-b9e8-f47ea630a053/b992fee7-0181-4a0f-8cc3-e29c54747135\"}",
"MessageDeduplicationId": null,
"MessageGroupId": null,
"MessageSystemAttributes": null,
"QueueUrl": "https://sqs.us-west-2.amazonaws.com/<my-aws-account-id>/asset_xxxxxxx_queue_us-west-2"
Your situation is:
To grant permission for the Lambda function to send a message to the SQS queue, two things are required:
Both elements are required because the IAM Role and SQS queue are in different AWS Accounts. Merely giving permission on the IAM Role in one account is not sufficient to use resources in a different account.
To explain, let's say you have an AWS Account with the Lambda function and IAM Role. Also, I have an SQS queue in my own AWS Account. I don't know you, so I don't want you to be able to send a message to my queue. Thus, it should not be possible for you (in your Account) to give sufficient permission to the Lambda function to use my SQS queue. If I wanted to allow you to access my SQS queue, I would need to tell my SQS queue that I am willing for your Lambda function and IAM Role to write to my SQS queue.
This can be done via an Access Policy on the SQS queue:
{
"Version": "2012-10-17",
"Id": "__default_policy_ID",
"Statement": [
{
"Sid": "__owner_statement",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::222:root"
},
"Action": "SQS:*",
"Resource": "arn:aws:sqs:ap-southeast-2:222:my-queue"
},
{
"Sid": "__sender_statement",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111:role/your-iam-role"
},
"Action": "SQS:SendMessage",
"Resource": "arn:aws:sqs:ap-southeast-2:222:my-queue"
}
]
}
The first part of the policy grants permission for resources in my Account (222) to use the SQS queue.
The second part of the policy grants permission for the IAM Role in your Account (111) to send a message to the queue.
This policy was actually created by the Amazon SQS console when I created the queue, but you can add it manually after the queue is created by going to the Access policy tab.