SQS access policy which denies receiving messages except one lambda

Yesterday, I had a task to setup SQS access policy to allow reading messages from queue only by one lambda. Another part of this task was to allow sending messages only by Api Gateway.

I tried following access policies with Deny + Principal to restrict SQS:ReceiveMessage action only to my lambda.

{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "Only my lambda is allowed to read messages",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "SQS:ReceiveMessage",
      "Resource": "arn:aws:sqs:eu-west-1:XXX:my_sqs_queue",
      "Condition": {
        "StringNotLike": {
          "aws:SourceArn": "arn:aws:lambda:eu-west-1:XXX:function:my_lambda"
        }
      }
    }
  ]
}
{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "Only my lambda is allowed to read messages",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "SQS:ReceiveMessage",
      "Resource": "arn:aws:sqs:eu-west-1:XXX:my_sqs_queue",
      "Condition": {
        "ArnNotLike": {
          "aws:SourceArn": "arn:aws:lambda:eu-west-1:XXX:function:*"
        }
      }
    }
  ]
}

Or Deny + NotPrincipal

{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "Only my lambda is allowed to read messages",
      "Effect": "Deny",
      "NotPrincipal": {
        "AWS": [
          "arn:aws:iam::XXX:root",
          "arn:aws:iam::XXX:role/my_lambda_role",
          "arn:aws:sts::XXX:assumed-role/my_lambda_role /my_lambda"
        ]
      },
      "Action": "SQS:ReceiveMessage",
      "Resource": "arn:aws:sqs:eu-west-1:XXX:my_sqs_queue"
    }
  ]
}

But such access policies prevented anyone (also my lambda) from reading messages from queue. Sample policies from AWS documentation also do not cover such case. Finally, I found working policy.

{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "Only my lambda is allowed to read messages",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "SQS:ReceiveMessage",
      "Resource": "arn:aws:sqs:eu-west-1:XXX:my_sqs_queue",
      "Condition": {
        "StringNotLike": {
          "aws:userid": [
            "AROA4XB7NRHNWU35SVABC:*"
          ]
        }
      }
    }
  ]
}

It turns out that if we specify the lambda role ARN and assumed role ARN used by the Lambda in NotPrincipal section, it does not work since Lambda assumes the role and appends a suffix at the end of the assumed role while polling the SQS queue. But since the suffix cannot be pre-determined before and since NotPrincipal section can contain only the defined role ARNs (not something like arn:aws:sts::XXX:assumed-role/my_lambda_role /my_lambda*), therefore as a workaround we can use the wildcard Principal * with condition key aws:userid for the role id. Following things need to be specified in the condition clause

<USER ID of the Role being used by the Lambda:*>

User id of the role can be retrieved using the following CLI command
aws iam get-role --role-name my_lambda_role

{
    "Role": {
       "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": "sts:AssumeRole",
                    "Principal": {
                        "Service": "lambda.amazonaws.com"
                    },
                    "Effect": "Allow",
                    "Sid": ""
                }
            ]
        },
        "RoleId": "AROA4XB7NRHNWU35SVABC",
        "CreateDate": "2020-01-21T11:40:55Z",
        "RoleName": "my_lambda_role",
        "Path": "/",
        "Arn": "arn:aws:iam::XXX:role/my_lambda_role"
    }
}

Similarly for ApiGateway endpoint

I added policy which does not deny sending SQS messages by execution role my_gateway_role.

{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "Only my lambda is allowed to read messages",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "SQS:ReceiveMessage",
      "Resource": "arn:aws:sqs:eu-west-1:XXX:my_sqs_queue",
      "Condition": {
        "StringNotLike": {
          "aws:userid": [
            "AROA4XB7NRHNWU35SVABC:*"
          ]
        }
      }
    },
    {
      "Sid": "Only API Gateway is allowed to send messages",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "SQS:SendMessage",
      "Resource": "arn:aws:sqs:eu-west-1:XXX:my_sqs_queue",
      "Condition": {
        "StringNotLike": {
          "aws:userid": [
            "AROA4XB7NRHNVE2XY7ABC:*"
          ]
        }
      }
    }
  ]
}

AROA4XB7NRHNVE2XY7ABC is a role id of my_gateway_role

Leave a Comment