3
votes

I am attempting to use BOTO3 to create an Api Gateway method that invokes a lambda function. I have so far been unable to find how to grant the necessary permissions.

Curiously, setting the lambda method name manually through the AWS console sets up permissions automatically. I have been unable to replicate this in code.

This is the code I am using to set up the gateway:

# Create a rest api
self.rest_api = self.apigateway.create_rest_api(
    name='AWS_CMS_Operations'
)

# Get the rest api's root id
root_id = self.apigateway.get_resources(
    restApiId=self.rest_api['id']
)['items'][0]['id']

# Create an api resource
api_resource = self.apigateway.create_resource(
    restApiId=self.rest_api['id'],
    parentId=root_id,
    pathPart='AWS_CMS_Manager'
)

# Add a post method to the rest api resource
api_method = self.apigateway.put_method(
    restApiId=self.rest_api['id'],
    resourceId=api_resource['id'],
    httpMethod='POST',
    authorizationType='NONE'
)

# Add an integration method to the api resource
self.apigateway.put_integration(
    restApiId=self.rest_api['id'],
    resourceId=api_resource['id'],
    httpMethod='POST',
    type='AWS',
    integrationHttpMethod='POST',
    uri=self.create_api_invocation_uri()
)

# Set the put method response for the api resource
self.apigateway.put_method_response(
    restApiId=self.rest_api['id'],
    resourceId=api_resource['id'],
    httpMethod='POST',
    statusCode='200',
    responseModels={
        'application/json': 'Empty'
    }
)

# Set the put integration response for the api resource
self.apigateway.put_integration_response(
    restApiId=self.rest_api['id'],
    resourceId=api_resource['id'],
    httpMethod='POST',
    statusCode='200',
    responseTemplates={
        'application/json': ''
    }
)

# Create a deployment of the rest api
self.apigateway.create_deployment(
    restApiId=self.rest_api['id'],
    stageName='prod'
)

# Give the api deployment permission to trigger the lambda function
self.lmda.add_permission(
    FunctionName=self.lmda_function['FunctionName'],
    StatementId='apigateway-production-aws-cms',
    Action='lambda:InvokeFunction',
    Principal='apigateway.amazonaws.com',
    SourceArn=self.create_api_permission_uri(api_resource)
)

Everything works fine with the exception of the proper permission being set for the gateway to invoke lambda.

2

2 Answers

0
votes

From section 3.6 in this tutorial is a sample CLI command:

$ aws lambda add-permissionn \
--function-name <function-name> \
--statement-id apigateway-test-2 \
--action lambda:InvokeFunction \
--principal apigateway.amazonaws.com \
--source-arn "<method-arn">

Should be straight forward enough to translate to Boto3.

0
votes

I was able to get this working in Boto3 using this code:

source_arn = f'arn:aws:execute-api:{REGION}:{account_id}:{api_id}/*/*/{api_path}'
lambda_client.add_permission(FunctionName=lambda_function_arn, StatementId=f'invoke_{api_id}', 
        Action='lambda:InvokeFunction', Principal='apigateway.amazonaws.com',
        SourceArn=source_arn)

This doesn't use the conventions used in the original question, but there are three things I'd like to point that may help with anyone wrestling with this question:

  1. The FunctionName parameter can take the function name, the function's ARN, or the partial ARN according to the Boto3 Documentation.
  2. The StatementId must be unique in your account. To ensure uniqueness, I appended something to the API ID, since I'll only need one rule per API.
  3. The SourceARN is the "execute-api" ARN for your api/staging location. I haven't seen that ARN used elsewhere.