Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS Api Gateway proxy resource using Cloudformation?

I'm trying to proxy an S3 bucket configured as a website from an API Gateway endpoint. I configured an endpoint successfully using the console, but I am unable to recreate the configuration using Cloudformation.

After lots of trial and error and guessing, I've come up with the following CF stack template that gets me pretty close:

Resources:
  Api:
    Type: 'AWS::ApiGateway::RestApi'
    Properties:
      Name: ApiDocs

  Resource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      ParentId: !GetAtt Api.RootResourceId
      RestApiId: !Ref Api
      PathPart: '{proxy+}'

  RootMethod:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      HttpMethod: ANY
      ResourceId: !GetAtt Api.RootResourceId
      RestApiId: !Ref Api
      AuthorizationType: NONE
      Integration:
        IntegrationHttpMethod: ANY
        Type: HTTP_PROXY
        Uri: 'http://my-bucket.s3-website-${AWS::Region}.amazonaws.com/'
        PassthroughBehavior: WHEN_NO_MATCH
        IntegrationResponses:
          - StatusCode: 200

  ProxyMethod:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      HttpMethod: ANY
      ResourceId: !Ref Resource
      RestApiId: !Ref Api
      AuthorizationType: NONE
      RequestParameters:
        method.request.path.proxy: true
      Integration:
        CacheKeyParameters:
          - 'method.request.path.proxy'
        RequestParameters:
          integration.request.path.proxy: 'method.request.path.proxy'
        IntegrationHttpMethod: ANY
        Type: HTTP_PROXY
        Uri: 'http://my-bucket.s3-website-${AWS::Region}.amazonaws.com/{proxy}'
        PassthroughBehavior: WHEN_NO_MATCH
        IntegrationResponses:
          - StatusCode: 200

  Deployment:
    DependsOn:
      - RootMethod
      - ProxyMethod
    Type: 'AWS::ApiGateway::Deployment'
    Properties:
      RestApiId: !Ref Api
      StageName: dev

Using this template I can successfully get the root of the bucket website, but the proxy resource gives me a 500:

curl -i https://abcdef.execute-api.eu-west-1.amazonaws.com/dev/index.html
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
Content-Length: 36
Connection: keep-alive
Date: Mon, 11 Dec 2017 16:36:02 GMT
x-amzn-RequestId: 6014a809-de91-11e7-95e4-dda6e24d156a
X-Cache: Error from cloudfront
Via: 1.1 8f6f9aba914cc74bcbbf3c57e10df26a.cloudfront.net (CloudFront)
X-Amz-Cf-Id: TlOCX3eemHfY0aiVk9MLCp4qFzUEn5I0QUTIPkh14o6-nh7YAfUn5Q==

{"message": "Internal server error"}

I have no idea how to debug that 500.

To track down what may be wrong, I've compared the output of aws apigateway get-resource on the resource I created manually in the console (which is working) with the one Cloudformation made (which isn't). The resources look exactly alike. The output of get-method however, is subtly different, and I'm not sure it's possible to make them exactly the same using Cloudformation.

Working method configuration:

{
  "apiKeyRequired": false,
  "httpMethod": "ANY",
  "methodIntegration": {
    "integrationResponses": {
      "200": {
        "responseTemplates": {
          "application/json": null
        },
        "statusCode": "200"
      }
    },
    "passthroughBehavior": "WHEN_NO_MATCH",
    "cacheKeyParameters": [
      "method.request.path.proxy"
    ],
    "requestParameters": {
      "integration.request.path.proxy": "method.request.path.proxy"
    },
    "uri": "http://muybucket.s3-website-eu-west-1.amazonaws.com/{proxy}",
    "httpMethod": "ANY",
    "cacheNamespace": "abcdefg",
    "type": "HTTP_PROXY"
  },
  "requestParameters": {
    "method.request.path.proxy": true
  },
  "authorizationType": "NONE"
}

Configuration that doesn't work:

{
    "apiKeyRequired": false,
    "httpMethod": "ANY",
    "methodIntegration": {
        "integrationResponses": {
            "200": {
                "responseParameters": {},
                "responseTemplates": {},
                "statusCode": "200"
            }
        },
        "passthroughBehavior": "WHEN_NO_MATCH",
        "cacheKeyParameters": [
            "method.request.path.proxy"
        ],
        "requestParameters": {
            "integration.request.path.proxy": "method.request.path.proxy"
        },
        "uri": "http://mybucket.s3-website-eu-west-1.amazonaws.com/{proxy}",
        "httpMethod": "ANY",
        "requestTemplates": {},
        "cacheNamespace": "abcdef",
        "type": "HTTP_PROXY"
    },
    "requestParameters": {
        "method.request.path.proxy": true
    },
    "requestModels": {},
    "authorizationType": "NONE"
}

The differences:

  • The working configuration has responseTemplates set to "application/json": null. As far as I can tell, there's no way to set a mapping explicitly to null using Cloudformation. My CF method instead just has an empty object here.
  • My CF method has "responseParameters": {},, while the working configuration does not have responseParameters at all
  • My CF method has "requestModels": {},, while the working configuration does not have requestModels at all

Comparing the two in the console, they are seemingly exactly the same.

I'm at my wits end here: what am I doing wrong? Is this possible to achieve using Cloudformation?

like image 769
Christian Johansen Avatar asked Dec 11 '17 16:12

Christian Johansen


People also ask

How do I create a proxy resource in API Gateway?

To set up a proxy integration in an API Gateway API with a proxy resource, you perform the following tasks: Create a proxy resource with a greedy path variable of { proxy +} . Set the ANY method on the proxy resource. Integrate the resource and method with a backend using the HTTP or Lambda integration type.

How do I create AWS resources using CloudFormation template?

Create a stack from existing resources using the AWS Management Console. Sign in to the AWS Management Console and open the AWS CloudFormation console at https://console.aws.amazon.com/cloudformation . On the Stacks page, choose Create stack, and then choose With existing resources (import resources).


1 Answers

Answer: The above is correct. I had arrived at this solution through a series of steps, and re-applied the template over and over. Deleting the stack and deploying it anew with this configuration had the desired effect.

like image 76
Christian Johansen Avatar answered Oct 24 '22 12:10

Christian Johansen