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 tonull
using Cloudformation. My CF method instead just has an empty object here. - My CF method has
"responseParameters": {},
, while the working configuration does not haveresponseParameters
at all - My CF method has
"requestModels": {},
, while the working configuration does not haverequestModels
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?