By using AWS re:Post, you agree to the AWS re:Post Terms of Use

AccessDenied Error with AWS API Gateway and SQS when Using Custom Mapping Template for Sending Messages

0

Hello AWS Community,

I am facing an issue when using AWS API Gateway with a REST API connected to a Standard Queue (SQS). Specifically, I am trying to send messages to the queue using a custom mapping template, but I encounter an "AccessDenied" error when using a new mapping template. The error message I receive is:

{
    "Error": {
        "Code": "AccessDenied",
        "Message": "Access to the resource https://sqs.us-east-1.amazonaws.com/72XX89XX8XX4/QAXXRealtimeData is denied.",
        "Type": "Sender"
    },
    "RequestId": "e4caf06e-7985-5eca-a59d-afd8b2bb6850"
}

Setup:

API Gateway: I am using a REST API in API Gateway with the integration type set to SQS.

SQS Queue: The SQS queue is located in the us-east-1 region, and the queue URL is https://sqs.us-east-1.amazonaws.com/72XX89XX8XX4/QAXXRealtimeData.

Mapping Template 1 (which works fine):

Action=SendMessage&MessageBody={ "data": $input.json('$'), "api-key": "$input.params('api-key')", "apiType": "POST", "headers": { #foreach($param in $input.params().header.keySet()) "$param": "$util.escapeJavaScript($input.params().header.get($param))" #if($foreach.hasNext),#end #end } }

This template successfully sends messages to the SQS queue.

Mapping Template 2 (the problematic one):

#set($inputRoot = $input.path('$'))

#set($messageBody = "")
#foreach($elem in $inputRoot)
    #set($description = "Item ${elem.id} is a ${elem.type}.")
    #set($askingPrice = ${elem.price})
    #set($itemJson = "{\"description\":\"$description\",\"askingPrice\":$askingPrice}")
    #if($foreach.hasNext)
        #set($messageBody = "$messageBody$itemJson,")
    #else
        #set($messageBody = "$messageBody$itemJson")
    #end
#end

#set($finalMessageBody = "[$messageBody]")
Action=SendMessage&MessageBody=$util.urlEncode($finalMessageBody)

The mapping transformation appears to be successful, but when this template is used, the message fails to be sent, and I encounter the AccessDenied error.

The Data I am Trying to Send:

I am sending data in the following format:

{ "dailies": [ { "somethingElse": "value", "steps": 70, "stepsCounts": 503, "someRandomArray": ["00000", "11111"], "userId": "3234222" }, { "somethingElse": "avalue", "steps": 30, "stepsCounts": 5033, "someRandomArray": ["00000", "11111"], "userId": "2342223" } ] }

I want to extract only the required properties, such as steps and userId, and send the transformed data like this:

{ "dailies": [ { "steps": 70, "userId": "3234222" }, { "steps": 5033, "userId": "2342223" } ] }

Issue:

The transformation works fine when using the first template, but when using the second template (with foreach and nested $inputRoot), I receive the AccessDenied error. I am trying to understand why the message cannot be sent when using the second mapping template and what might be causing this issue. What I Have Tried:

IAM Permissions: I have double-checked that the IAM role for the API Gateway has the required permissions to send messages to the SQS queue. It has full access
Message Format: I verified that the message format output by both mapping templates is correct and appropriately formatted for SQS.
SQS Queue Policy: The SQS queue's access policy allows API Gateway to send messages, as confirmed by the working first template.

Question:

What might be causing this AccessDenied error with the second mapping template, and how can I resolve it? Could the issue be related to the way the message body is being constructed in the second template, or is there something else in the configuration that I may be missing?

Any help or insight into this issue would be greatly appreciated. Thank you in advance!

1 Answer
-1

The AccessDenied error you're encountering with the second mapping template is likely due to how the message body is being constructed and encoded. There are a few potential issues to consider:

  1. Message Body Encoding: In the second template, you're using $util.urlEncode() to encode the entire message body. This might be causing issues with the message format that SQS expects. Instead of URL encoding the entire message, try encoding only the necessary parts.

  2. Message Size: If the transformed message is larger than 256KB (the maximum size for an SQS message), it will be rejected. Ensure that your transformed message doesn't exceed this limit.

  3. Special Characters: The way you're constructing the JSON in the second template might introduce unexpected characters or formatting issues. Consider using $util.escapeJavaScript() for individual values to ensure proper escaping.

  4. Permissions: Although you mentioned that the IAM role has full access, double-check that the permissions include both sqs:SendMessage and sqs:SendMessageBatch actions.

To resolve this issue, try modifying your second template as follows:

  1. Use $util.toJson() to convert the entire message body to a properly formatted JSON string.
  2. Use $util.urlEncode() only on the resulting JSON string.
  3. Ensure that you're properly accessing the 'dailies' array in your input.

Here's a revised version of your second template that might work:

#set($inputRoot = $input.path('$.dailies'))

#set($items = [])
#foreach($elem in $inputRoot)
    $util.qr($items.add({
        "steps": $elem.steps,
        "userId": $elem.userId
    }))
#end

#set($messageBody = $util.toJson({"dailies": $items}))
Action=SendMessage&MessageBody=$util.urlEncode($messageBody)

This template should create a properly formatted JSON string for your message body, which is then URL encoded before being sent to SQS.

If you're still encountering issues after these changes, you may want to:

  1. Enable CloudWatch Logs for your API Gateway and examine the logs for any additional error information.
  2. Test the SQS queue directly using the AWS CLI or SDK to ensure there are no issues with the queue itself.
  3. Verify that the API Gateway's execution role has the necessary permissions to access the specific SQS queue you're trying to send messages to.

Remember, when working with custom mapping templates, it's crucial to ensure that the resulting message adheres to SQS's requirements and that all necessary permissions are in place.
Sources
Amazon SQS Features | Message Queuing Service | AWS
Amazon SQS Key management - Amazon Simple Queue Service

profile picture
answered 18 days ago
  • The revised map still gives me { "Error": { "Code": "AccessDenied", "Message": "Access to the resource https://sqs.us-east-1.amazonaws.com/XX53890XXXX4/QAXXRealtimeData is denied.", "Type": "Sender" }, "RequestId": "fb9b26f4-bfd0-57ef-bea5-7943e767d9ad" } 2) I dont think the response size exceeds 256 kb , input i tried was { "dailies": [ { "somethingElse": "value", "steps": 70, "stepsCounts": 503, "someRandomArray":["00000","11111"], "userId": "3234222" },{ "somethingElse": "avalue", "steps": 30, "stepsCounts": 5033, "someRandomArray":["00000","11111"], "userId": "2342223" } ] } 3) i have given necessary permisons to api gateway since i can send messages when mapping template is like Action=SendMessage&MessageBody={ "data" : $input.json('$'), "api-key": "$input.params('api-key')", "apiType" : "POST", "headers": { #foreach($param in $input.params().header.keySet()) "$param": "$util.escapeJavaScript($input.params().header.get($param))" #if($foreach.hasNext),#end #end }}

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions