Skip to main content

API Gateway Research Notes

Overview

AWS API Gateways are used to define access to a service.

Implementation Details

  • Requires several components in Terraform.
    • aws_api_gateway_rest_api
      resource "aws_api_gateway_rest_api" "[name]_api" {
      name = "${var.prefix}_[name]_api"
      }
    • aws_api_gateway_resource
      resource "aws_api_gateway_resource" "[name]_api_resource" {
      path_part = "{proxy+}" # This acts as a "catch all"
      parent_id = aws_api_gateway_rest_api.[name]_api.root_resource_id
      rest_api_id = aws_api_gateway_rest_api.[name]_api.id
      }
    • aws_api_gateway_method
      resource "aws_api_gateway_method" "[name]_api_method" {
      rest_api_id = aws_api_gateway_rest_api.[name]_api.id
      resource_id = aws_api_gateway_resource.[name]_api_resource.id
      http_method = "ANY"
      # todo: Make sure this is locked down against external access.
      authorization = "NONE"
      }
    • aws_api_gateway_integration
      resource "aws_api_gateway_integration" "integration" {
      rest_api_id = aws_api_gateway_rest_api.[name]_api.id
      resource_id = aws_api_gateway_resource.[name]_api_resource.id
      http_method = aws_api_gateway_method.[name]_api_method.http_method
      integration_http_method = "POST"
      type = "AWS"
      uri = aws_lambda_function.[name].invoke_arn
      }
    • aws_api_gateway_method_response
      resource "aws_api_gateway_method_response" "[name]_response_200" {
      rest_api_id = aws_api_gateway_rest_api.[name]_api.id
      resource_id = aws_api_gateway_resource.[name]_api_resource.id
      http_method = aws_api_gateway_method.[name]_api_method.http_method
      status_code = "200"
      }
    • aws_api_gateway_integration_response
      resource "aws_api_gateway_integration_response" "[name]_api_response" {
      depends_on = [aws_api_gateway_integration.[name]_api_integration]
      rest_api_id = aws_api_gateway_rest_api.[name]_api.id
      resource_id = aws_api_gateway_resource.[name]_api_resource.id
      http_method = aws_api_gateway_method.[name]_api_method.http_method
      status_code = aws_api_gateway_method_response.[name]_response_200.status_code

      # Transforms the backend JSON response to XML
      # "stackTrace" being present in the returned dictionary will cause a return code of 500
      # This will happen automatically if your Python raises an unhandled exception.
      # You can return a dictionary with a manually set "httpStatus" key with an int value to set the return code of the HTTP request.
      response_templates = {
      "application/json" = <<EOF
      #set($inputRoot = $input.path('$'))
      $input.json("$")

      #if($input.path("stackTrace") != '')
      #set($context.responseOverride.status = 500)
      #elseif($input.path("httpStatus") != '')
      #set($context.responseOverride.status = $input.path('httpStatus'))
      #end
      EOF
      }
      }
    • aws_api_gateway_deployment
      resource "aws_api_gateway_deployment" "[name]_api_deployment" {
    rest_api_id = aws_api_gateway_rest_api.[name]_api.id
    stage_name = "orca" #add your stage name
    }
    • aws_lambda_permission
      resource "aws_lambda_permission" "[name]_api_permission" {
      statement_id = "AllowExecutionFromAPIGateway"
      action = "lambda:InvokeFunction"
      function_name = aws_lambda_function.[name].function_name
      principal = "apigateway.amazonaws.com"

      # More: http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-control-access-using-iam-policies-to-invoke-api.html
      # Alternate potential source_arn: "${aws_api_gateway_rest_api.[name]_api.execution_arn}/*/$ {aws_api_gateway_method.request_status[name]api_method.http_method}${aws_api_gateway_resource.[name]_api_resource.path}"
      # source_arn = "${aws_api_gateway_rest_api.[name]_api.execution_arn}/*/${aws_api_gateway_method.[name]_api_method.http_method}${aws_api_gateway_resource.[name]_api_resource.path}"
      }
    • aws_api_gateway_rest_api_policy
      resource "aws_lambda_permission" "[name]_api_resource_policy" {

      rest_api_id = aws_api_gateway_rest_api.[name]_api.id
      policy = <<EOF
      {
      "Version": "2012-10-17",
      "Statement": [
      {
      "Effect": "Allow",
      "Principal": {
      "AWS": "*"
      },
      "Action": "execute-api:Invoke",
      "Resource": "${aws_api_gateway_rest_api.[name]_api.execution_arn}"
      }
      ]
      }
      EOF
      }
  • Proper HTTP error codes can be returned from a Lambda to the gateway via a dictionary, as shown in Handle Lambda errors in API Gateway
  • In order to access a private API, a VPC endpoint has to be created in VPC. Secondly, a resource policy needs to be created and attached to the API.

Future Direction

Sources