Give API Gateway permission to invoke Lambda function

356 Views Asked by At

I have an API Gateway with the following API proxy endpoint that calls a Lambda function for retrieving data from a dynamodb table:

API Gateway proxy endpoint

This is the policy associated to the IAM role attached to the Lambda function "connect_api" that calls the DynamoDB table:

{
    "Statement": [
        {
            "Action": [
                "connect:ListRoutingProfiles",
                "connect:*"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:connect:eu-west-2:xxxxxxxxxxxx:instance/xxxxxxxxxxxx/contact-flow/*/*",
                "arn:aws:connect:eu-west-2:xxxxxxxxxxxx:instance/xxxxxxxxxxxx/contact-flow/*",
                "arn:aws:connect:eu-west-2:xxxxxxxxxxxx:instance/xxxxxxxxxxxx/*",
                "arn:aws:connect:eu-west-2:xxxxxxxxxxxx:instance/xxxxxxxxxxxx"
            ],
            "Sid": ""
        },
        {
            "Effect": "Allow",
            "Action": "lambda:InvokeFunction",
            "Resource": "arn:aws:lambda:eu-west-2:xxxxxxxxxxxx:function:connect_api"
        },
        {
            "Action": "dynamodb:Query",
            "Effect": "Allow",
            "Resource": [
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/contactlens/index/timestamp",
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/contactlens"
            ],
            "Sid": ""
        },
        {
            "Action": [
                "dynamodb:Scan",
                "dynamodb:GetItem"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/ctr",
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/agent_status"
            ],
            "Sid": ""
        },
        {
            "Action": "dynamodb:UpdateItem",
            "Effect": "Allow",
            "Resource": "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/agent_status",
            "Sid": ""
        },
        {
            "Action": [
                "logs:PutLogEvents",
                "logs:CreateLogStream",
                "logs:CreateLogGroup"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:logs:*:*:*",
            "Sid": ""
        }
    ],
    "Version": "2012-10-17"
}

This is the trust relationship entity associated to the previous role:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "Service": "lambda.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

This is the policy associated to the IAM role attached to the API Gateway that calls the Lambda function "connect_api":

{
    "Statement": [
        {
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:DescribeLogGroups",
                "logs:DescribeLogStreams",
                "logs:PutLogEvents",
                "logs:GetLogEvents",
                "logs:FilterLogEvents"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:logs:*:*:*"
            ]
        },
        {
            "Action": [
                "dynamodb:PutItem",
                "dynamodb:UpdateItem",
                "dynamodb:DeleteItem",
                "dynamodb:GetItem",
                "dynamodb:Scan"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/customers",
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/accounts",
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/cards",
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/sinistres",
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/email",
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/appointment_slots",
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/agencies",
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/intent_history",
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/authorization_requests",
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/ctr",
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/agent_status",
                "arn:aws:dynamodb:eu-west-2:xxxxxxxxxxxx:table/missed_calls"
            ]
        },
        {
            "Action": [
                "lambda:InvokeFunction"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:lambda:eu-west-2:xxxxxxxxxxxx:function:*"
            ]
        }
    ],
    "Version": "2012-10-17"
}

This is the trust relationship entity associated to the previous role (the one attached to the API Gateway):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "Service": "apigateway.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Now, if I test the Lambda function from the Lambda console, everything works fine:

Lambda function test console

But if I test the proxy API linked to the Lambda function:

proxy API test console

It doesn't work and I get the following Internal Server Error:

Request: /connect/list_users
Status: 500
Latency: 29 ms
Response Body
{"message": "Internal server error"}
Response Headers
{"x-amzn-ErrorType":["InternalServerErrorException"]}
Logs
Execution log for request 3ff47544-2f03-4e52-a52c-ce76e397aee7
Wed May 31 15:52:55 UTC 2023 : Starting execution for request: 3ff47544-2f03-4e52-a52c-ce76e397aee7
Wed May 31 15:52:55 UTC 2023 : HTTP Method: GET, Resource Path: /connect/list_users
Wed May 31 15:52:55 UTC 2023 : Method request path: {proxy=list_users}
Wed May 31 15:52:55 UTC 2023 : Method request query string: {}
Wed May 31 15:52:55 UTC 2023 : Method request headers: {}
Wed May 31 15:52:55 UTC 2023 : Method request body before transformations: 
Wed May 31 15:52:55 UTC 2023 : Endpoint request URI: https://lambda.eu-west-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:eu-west-2:xxxxxxxxxxxx:function:connect_api/invocations
Wed May 31 15:52:55 UTC 2023 : Endpoint request headers: {X-Amz-Date=20230531T155255Z, x-amzn-apigateway-api-id=xxxxxxxxxxxx, Accept=application/json, User-Agent=AmazonAPIGateway_xxxxxxxxxxxx, Host=lambda.eu-west-2.amazonaws.com, X-Amz-Content-Sha256=xxxxxxxxxxxx, X-Amzn-Trace-Id=Root=1-64776d57-xxxxxxxxxxxx, x-amzn-lambda-integration-tag=xxxxxxxxxxxx, Authorization=*********************************************************************************************************************************************************************************************************************************************************************************************************************************************ca4e12, X-Amz-Source-Arn=arn:aws:execute-api:eu-west-2:xxxxxxxxxxxx:xxxxxxxxxxxx/test-invoke-stage/GET/connect/{proxy+}, X-Amz-Security-Token=xxxxxxxxxxxx/xxxxxxxxxxxx [TRUNCATED]
Wed May 31 15:52:55 UTC 2023 : Endpoint request body after transformations: {"resource":"/connect/{proxy+}","path":"/connect/list_users","httpMethod":"GET","headers":null,"multiValueHeaders":null,"queryStringParameters":null,"multiValueQueryStringParameters":null,"pathParameters":{"proxy":"list_users"},"stageVariables":null,"requestContext":{"resourceId":"xxxxxxxxxxxx","resourcePath":"/connect/{proxy+}","httpMethod":"GET","extendedRequestId":"xxxxxxxxxxxx=","requestTime":"31/May/2023:15:52:55 +0000","path":"/connect/{proxy+}","accountId":"xxxxxxxxxxxx","protocol":"HTTP/1.1","stage":"test-invoke-stage","domainPrefix":"testPrefix","requestTimeEpoch":xxxxxxxxxxxx,"requestId":"xxxxxxxxxxxx","identity":{"cognitoIdentityPoolId":null,"cognitoIdentityId":null,"apiKey":"test-invoke-api-key","principalOrgId":null,"cognitoAuthenticationType":null,"userArn":"arn:aws:iam::xxxxxxxxxxxx:user/[email protected]","apiKeyId":"test-invoke-api-key-id","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, li [TRUNCATED]
Wed May 31 15:52:55 UTC 2023 : Sending request to https://lambda.eu-west-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:eu-west-2:xxxxxxxxxxxx:function:connect_api/invocations
Wed May 31 15:52:55 UTC 2023 : Execution failed due to configuration error: Invalid permissions on Lambda function
Wed May 31 15:52:55 UTC 2023 : Method completed with status: 500

But if I go to the "Integration request" page of the proxy API:

proxy API Integration request page

Then I simply click in Lambda Function (the pencil symbol) like I want to modify the selected function and I try to save the selected function keeping the same one (connect_api), a new window will pop up before saving it:

Add permission to Lambda function

then I click "ok" and finally the API works fine.

Now the question is, how should I change the policy in order to avoid to add the permission to the API Gateway from the API Gateway Console?

1

There are 1 best solutions below

0
Paul Waldo On

If you are using Terraform to define your IaC, use aws_api_gateway_rest_api to create the permission aws_lambda_permission | Resources | hashicorp/aws | Terraform | Terraform Registry

resource "aws_api_gateway_rest_api" "MyDemoAPI" {
  name        = "MyDemoAPI"
  description = "This is my API for demonstration purposes"
}

resource "aws_lambda_permission" "lambda_permission" {
  statement_id  = "AllowMyDemoAPIInvoke"
  action        = "lambda:InvokeFunction"
  function_name = "MyDemoFunction"
  principal     = "apigateway.amazonaws.com"

  # The /* part allows invocation from any stage, method and resource path
  # within API Gateway.
  source_arn = "${aws_api_gateway_rest_api.MyDemoAPI.execution_arn}/*"
}