API Gateway - Pass through proxy and AWS_IAM, not passing identity - amazon-web-services

I'm trying to create an API Gateway, which uses an AWS_IAM Authorizer, and using Amplify to sign in to my app using Federated Identities.
This all works fine, however I'm not getting an identity in my backend service.
What I want is to be able to access the identity of the user in my backend service. Eg a header with a user-id or something like that.
I've been looking at this example: https://github.com/matsev/cloudformation-api-gateway/blob/master/cloudformation.template to try to map the $context, however it seems it doesn't work with HTTP_PROXY?
RefreshProxy:
Type: AWS::ApiGateway::Resource
Properties:
ParentId:
Ref: SomeOtherHandler
PathPart: '{proxy+}'
RestApiId:
Ref: ApiGatewayRestApi
RefreshProxyMethod:
Type: AWS::ApiGateway::Method
Properties:
ResourceId:
Ref: RefreshProxy
RestApiId:
Ref: ApiGatewayRestApi
AuthorizationType: AWS_IAM
HttpMethod: POST
RequestParameters:
method.request.path.proxy: true
Integration:
IntegrationHttpMethod: POST
Type: HTTP_PROXY
Uri: url/{proxy}
IntegrationResponses:
- StatusCode: 200
RequestParameters:
integration.request.path.proxy: method.request.path.proxy
integration.request.header.Accept-Encoding: "'identity'"
PassthroughBehavior: WHEN_NO_MATCH

You need to add a header with the cognitoIdentityId from the context. So in the integration section you need:
integration.request.header.Identity: context.identity.cognitoIdentityId

Related

APIGateway Proxy resource doesn't get path parameter into Lambda

I need to create an API endpoint, which will trigger a Lambda function and return an image from an S3 bucket.
Example URL: https://abc.execute-api.eu-west-1.amazonaws.com/dev/xyz/00/01/23911414.jpeg
I created an APIGateway instance manually using the web console and it’s working fine.
And I created the same (I guess) using CloudFormation and it’s not working.
The Lambda gets triggered, but it doesn't get the path parameter in the event.
But I want the Lambda function to get /xyz/00/01/23911414.jpeg as the event['path'].
Here is a part of my CloudFormation Template:
RestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Description: Example API Gateway
EndpointConfiguration:
Types:
- REGIONAL
Name: imaginary-api
ProxyResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref RestApi
ParentId: !GetAtt
- RestApi
- RootResourceId
PathPart: '{proxy+}'
ProxyResourceANY:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref RestApi
ResourceId: !Ref ProxyResource
HttpMethod: ANY
AuthorizationType: NONE
MethodResponses:
- StatusCode: 200
Integration:
Type: AWS
IntegrationHttpMethod: POST
Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImaginaryLambda.Arn}/invocations
Credentials: !GetAtt ApiGatewayIamRole.Arn
PassthroughBehavior: WHEN_NO_TEMPLATES
RequestTemplates:
"image/jpeg": ""
"image/jpg": ""
IntegrationResponses:
- StatusCode: 200
RestAPIDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn:
- ProxyResource
Properties:
RestApiId: !Ref RestApi
StageName: dev
ImaginaryInvoke:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !GetAtt ImaginaryLambda.Arn
Principal: apigateway.amazonaws.com
SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:abc/dev
This is the first time I'm using APIGateway and I might have done something wrong here. Any help would be highly appreciated.
UPDATE:
Adding RequestParameters to the Method won't work either.
RequestParameters:
method.request.path.proxy: true
You have different possible integrations:
aws (requires data mapping)
aws_proxy
mock
http
http_proxy
The AWS integration type requires data mapping to get the required attributes (check https://docs.aws.amazon.com/apigateway/latest/developerguide/request-response-data-mappings.html).
You can use AWS_PROXY to get the complete event (check: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format) including the path attribute.
You can return binary file (be careful with content length) or return a s3 presigned url (thru a redirection for example).
Let me answer my own question.
I was able to fix this with the following values.
RestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Description: Example API Gateway
BinaryMediaTypes:
- "*/*" # <-- Important
EndpointConfiguration:
Types:
- REGIONAL
Name: imaginary-api
ProxyResourceANY:
Type: AWS::ApiGateway::Method
DependsOn:
ProxyResource
Properties:
RestApiId: !Ref RestApi
ResourceId: !Ref ProxyResource
HttpMethod: ANY
AuthorizationType: NONE
RequestParameters:
method.request.path.proxy: true # <-- Important
MethodResponses:
- StatusCode: 200
Integration:
Type: AWS_PROXY # <-- Important
IntegrationHttpMethod: POST
ContentHandling: CONVERT_TO_TEXT # <-- Important, depends on your code
PassthroughBehavior: WHEN_NO_MATCH
Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImaginaryLambda.Arn}/invocations
Credentials: !GetAtt ApiGatewayIamRole.Arn
Something strange I noticed is, even though the manually created one showed as AWS in the web console, it showed as AWS_PROXY when I exported the stage as a Swagger definition.
Comparing the two Swagger definitions helped me a lot comparing the YAMLs taken out from Export as Swagger + API Gateway Extensions option.

Creating an API Gateway AWS Integration with S3

I would like to set up API Gateway to retrieve files from a specific bucket on S3.
The GET method for the resource in the Cloudformation template looks like this:
GetMethod:
Type: "AWS::ApiGateway::Method"
Properties:
HttpMethod: GET
ApiKeyRequired: true
AuthorizationType: NONE
RequestParameters:
'method.request.path.listId': true
RestApiId:
Ref: ApiGatewayRestApi
ResourceId:
Ref: Lists
Integration:
Type: aws
Credentials:
Ref: S3ReadAccessRole
IntegrationHttpMethod: GET
PassthroughBehavior: WHEN_NO_MATCH
RequestParameters:
'integration.request.path.key': 'method.request.path.listId'
I am having trouble specifying the S3 URI to integrate with. I've done the following with no success:
The S3 URI: arn:aws:s3:::lists/groceries/{key}
The API Gateway based uri based on this article. arn:aws:apigateway:us-west-2:s3:lists/groceries/{key}
Please help me figure out the correct URI to allow objects on S3 to be retrieved using API Gateway directly.

not a valid key=value pair (missing equal-sign) in Authorization header

While hitting an API from Postman I am getting this error.
API details:
URL:
https://account-perf.myglobal.com/v1/users/00uk0khprrME7gZOU0h7/credentials/change_password
Header:
Content-Type:application/json Authorization:Bearer
n7mbkw74jsubd7rauhptdnre
Type:
POST
Body:
{"password":"Baddy125#","token":"eyJhbGci...."}
Edit 1:
Web-service call to generate token-
URL-
https://api-perf.myglobal.com/rest/oauth2/v1/token
Type-
POST
Body-
client_id:abcd client_secret:xyz grant_type:client_credentials
I had this whenever any unhandled endpoint method or resource was called. My setup is an API Gateway with defined resources (e.g. /myendpoint) and defined methods for those endpoints (e.g. GET).
To fix it, I created a Node.js Lambda function that just returned a 404. Then I added any ANY method at the root of the endpoints / and pointed it as a Lambda proxy function to the ANY methods.
Then I added a proxy resource, e.g. /{proxy} -- there's a checkbox you can click when creating a resource to tell it to proxy. An ANY method on that resource pointing to the same Lambda function, deploy the API, and I'm done.
Now instead of the auth bearer token error, I get a proper HTTP 404 error.
#Matt H - That's pretty good idea this gave me an inspiration of another one.
Assuming all of the other paths within the API are explicitly specified, I created a default path /{proxy+} which would return a http 404, message resource not found. Instead of using lambda, I was able to create a mock response, so there isn't even any cost incurred for getting Lambda to return the response.
I created my APIs via Open API spec. This is how my YAML for the implementation would like
/{proxy+}:
x-amazon-apigateway-any-method:
responses:
404:
description: "404 response"
content: {}
x-amazon-apigateway-integration:
responses:
404:
statusCode: "404"
responseTemplates:
application/json: "{\"message\":\"resource not available\"}"
requestTemplates:
application/json: "{\"statusCode\": 404}"
passthroughBehavior: "when_no_templates"
type: "mock"
Serverless also has the ability to specify inline mock response. Below can be a sample:
functions:
default:
handler: handler.default
events:
- http:
path: hello
cors: true
method: get
integration: mock
request:
template:
application/json: '{"statusCode": 404}'
response:
template: $input.path('$')
statusCodes:
404:
pattern: '' #default method
template:
application/json: '{"statusCode": 404, "message":"resource not found"}'
serverless doc: https://www.serverless.com/framework/docs/providers/aws/events/apigateway/#custom-response-templates
Analyze and validate the request path, in case the request is incorrect this error is thrown at API Gateway. I stepped on the same error, when corrected the request parameters it worked well.
Let me know.
I managed to do it by proxying the ANY /{proxy+} route to a lambda which will always respond with an HTTP 404
Since all other routes are precisely configured, this ANY /{proxy+} route acts as the default one and will catch any unmatched request
Here is how I did it with CloudFormation :
Parameters:
RestAPI:
Type: String
RestApiRootResourceId:
Type: String
LambdaName:
Type: String
Path:
Type: String
RootResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref RestAPI
ParentId: !Ref RestApiRootResourceId
PathPart: !Ref Path
ProxyResource:
Type: 'AWS::ApiGateway::Resource'
Properties:
RestApiId: !Ref RestAPI
ParentId: !Ref RestApiRootResourceId
PathPart: "{proxy+}"
AnyMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
RestApiId: !Ref RestAPI
ResourceId: !Ref ProxyResource
HttpMethod: ANY
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
PassthroughBehavior: WHEN_NO_MATCH
Uri:
Fn::Join:
- ":"
- - !Sub "arn:aws:apigateway:${AWS::Region}:lambda"
- !Sub "path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function"
- !Sub "${LambdaName}/invocations"
ApiGatewayInvokeLambdaPermissionAny:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName:
Fn::Join:
- ":"
- - !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function"
- !Ref LambdaName
Principal: apigateway.amazonaws.com
SourceArn:
Fn::Join:
- ":"
- - !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}"
- !Sub "${RestAPI}/*/ANY/*"
Paramters :
RestAPI is your API ID
RestApiRootResourceId is the ID of the root resource (!GetAtt "RestApi.RootResourceId")
LambdaName is the name of your proxy lambda
Path is something I have bewteen the stage and the root (for mty specific usage)

How to create an API Gateway HTTP Proxy without any lambda function

i use the serverless framework and would like to deploy an API Gateway HTTP Proxy but i don't have a Lambda function connected with API Gateway.
I found this in the internet, but this example require one lambda function connected to API Gateway
# ProxyResource:
# Type: AWS::ApiGateway::Resource
# Properties:
# ParentId:
# Fn::GetAtt:
# - ApiGatewayRestApi # our default Rest API logical ID
# - RootResourceId
# PathPart: serverless # the endpoint in your API that is set as proxy
# RestApiId:
# Ref: ApiGatewayRestApi
# ProxyMethod:
# Type: AWS::ApiGateway::Method
# Properties:
# ResourceId:
# Ref: ProxyResource
# RestApiId:
# Ref: ApiGatewayRestApi
# HttpMethod: GET # the method of your proxy. Is it GET or POST or ... ?
# MethodResponses:
# - StatusCode: 200
# Integration:
# IntegrationHttpMethod: POST
# Type: HTTP
# Uri: http://serverless.com # the URL you want to set a proxy to
# IntegrationResponses:
# - StatusCode: 200
If i deploy this i got the error:
The CloudFormation template is invalid: Template format error: Unresolved resource dependencies [ApiGatewayRestApi] in the Resources block of the template
It is possible to deploy just an API Gateway HTTP Proxy ?
Thanks
I figure out how to create an API Gateway if i don't have any lambda function in serverless. I just need to add this to resources and change Ref: ApiGatewayRestApi to Ref: ProxyApi
resources:
Resources:
ProxyApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: ApiGateway
To fulfill my requirement to use AppSync without any ApiKey - it's possible with these lines:
ProxyApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: AppSync Graph Proxy
ProxyResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId:
Fn::GetAtt:
- ProxyApi # our default Rest API logical ID
- RootResourceId
PathPart: graphql # the endpoint in your API that is set as proxy
RestApiId:
Ref: ProxyApi
ProxyMethod:
Type: AWS::ApiGateway::Method
Properties:
ResourceId:
Ref: ProxyResource
RestApiId:
Ref: ProxyApi
AuthorizationType: NONE
HttpMethod: ANY # the method of your proxy. Is it GET or POST or ... ?
MethodResponses:
- StatusCode: 200
Integration:
IntegrationHttpMethod: POST
Type: HTTP
Uri: { Fn::GetAtt: [GraphQlApi, GraphQLUrl] } # the URL you want to set a proxy to
IntegrationResponses:
- StatusCode: 200
RequestParameters:
"integration.request.header.x-api-key": "stageVariables.API_KEY"
ProxyDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn: "ProxyMethod"
Properties:
RestApiId:
Ref: ProxyApi
ProxyStage:
Type: AWS::ApiGateway::Stage
Properties:
StageName: ${opt:stage, self:provider.stage}
RestApiId:
Ref: ProxyApi
DeploymentId:
Ref: ProxyDeployment
Variables:
API_KEY: { Fn::GetAtt: [GraphQlApiKeyDefault, ApiKey] }
For this, you need an working and configured serverless-appsync-plugin in your serverless config

AWS Api Gateway with Lambda integration only works via console

I have a CloudFormation template which sets up an API Gateway with a Lambda integration. When testing the integration via the AWS console it works.
When I attempt to use the HTTP method via Postman or Chrome, the response is null.
The full template can be seen here:
https://github.com/mattcanty/musicdown/blob/07b899d5924ab2fcc675cc521706b0c217e4e07e/cloudformation.yaml
I think something is not quite right here:
MusicdownsGet:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref ApiGateway
ResourceId: !Ref MusicdownResource
HttpMethod: GET
RequestParameters:
method.request.querystring.filter: true
AuthorizationType: NONE
RequestModels:
application/json: !Ref MusicdownModel
Integration:
Type: AWS
IntegrationHttpMethod: POST
Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Lambda.Arn}/invocations
IntegrationResponses:
- StatusCode: 200
RequestTemplates:
application/json: "{ \"filter\": \"$input.params('filter')\" }"
MethodResponses:
- StatusCode: 200