I created a API gateway with websocket. And I added request/response integration to my lambda in $connect route. Then I deploy the API to staging and I can see there is a wss and https URL generated on staging page.
Then I am using wscat command to test the websocket connection:
wscat -c wss://xxxx.execute-api.ap-southeast-2.amazonaws.com/dev
But I get an error response: error: Unexpected server response: 500.
I don't have any authentication on the API. And I have checked my lambda log, it is not called. That means the request failed on API gateway. What could be the error in my API Gateway?
The lambda you're integrating the $connect route to needs permission to be invoked by apigateway.
Add the following permission:
Principal: apigateway.amazonaws.com
Effect: Allow
Action: lambda:InvokeFunction
Also enable Cloudwatch logs for API Gateway to get a better idea what's going on if it's failing before hitting your lambda.
Stages -> Logs/Tracing -> CloudWatch Settings -> Enable CloudWatch Logs
Related
I created a REST API with AWS API Gateway. I have a GET method that triggers a Lambda function, but I cannot get the response I need. I properly configured query params etc. but in Lambda logs I see this.
com.amazonaws.serverless.exceptions.InvalidRequestEventException: The incoming event is not a valid request from Amazon API Gateway or an Application Load Balancer
2021-05-19T15:37:38.003+04:00 at com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequestReader.readRequest(AwsProxyHttpServletRequestReader.java:48)
2021-05-19T15:37:38.003+04:00 at com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequestReader.readRequest(AwsProxyHttpServletRequestReader.java:30)
2021-05-19T15:37:38.003+04:00 at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxy(LambdaContainerHandler.java:201)
What am I missing ? Thank you in advance.
When running lambdas locally, you need to define the event that trigger it.
For example:
sam local invoke --event tst\event.json where the event.json is basically the http parameters you are passing.
{
"httpMethod": "GET",
"path": "/",
}
For creating an event json template file for http requests, you can use: sam local generate-event apigateway aws-proxy.
Original Requirement:
Create a route/path on AWS Api Gateway which connects API Gateway directly to AWS Event Bridge (Cloudwatch Events) and puts/pushes event on an event bus of it.
Was able to create it and executes just fine when done from AWS Console.
Actual Problem:
When writing the AWS Cloudformation script for this API Gateway, it looks like this:
EventsPostMethod:
Type: AWS::ApiGateway::Method
Properties:
ResourceId:
Ref: EventsResource
RestApiId:
Ref: RestAPI
HttpMethod: POST
AuthorizationType: NONE
Integration:
Type: AWS
IntegrationHttpMethod: POST
Uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:cloudwatchEvents:action/PutEvents
RequestParameters:
integration.request.header.X-Amz-Target: "'AWSEvents.PutEvents'"
RequestTemplate:
some-script-here...
Notice the Uri value:
"arn:aws:apigateway:${AWS::Region}:cloudwatchEvents:action/PutEvents"
arn:aws:apigateway:{region}:{subdomain.service|service}:path|action/{service_api}
According to AWS Docs the value of uri should be following:
For AWS or AWS_PROXY integrations, the URI is of the form arn:aws:apigateway:{region}:{subdomain.service|service}:path|action/{service_api}. Here, {Region} is the API Gateway region (e.g., us-east-1); {service} is the name of the integrated AWS service (e.g., s3); and {subdomain} is a designated subdomain supported by certain AWS service for fast host-name lookup. action can be used for an AWS service action-based API, using an Action={name}&{p1}={v1}&p2={v2}... query string. The ensuing {service_api} refers to a supported action {name} plus any required input parameters. Alternatively, path can be used for an AWS service path-based API. The ensuing service_api refers to the path to an AWS service resource, including the region of the integrated AWS service, if applicable. For example, for integration with the S3 API of GetObject, the uri can be either arn:aws:apigateway:us-west-2:s3:action/GetObject&Bucket={bucket}&Key={key} or arn:aws:apigateway:us-west-2:s3:path/{bucket}/{key}
You must have noticed that I replaced the service with cloudwatchEvents in the above mentioned uri.
Now, error Given by AWS Cloudformation Console during Publish of API Gateway:
AWS Service of type cloudwatchEvents not supported (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: 07bae22c-d198-4595-8de9-6ea23763eff5; Proxy: null)
Now I have tried replacing service with
cloudwatch
eventBridge
cloudwatchEvent
event-bus
This is the real problem. What should I place in service in uri so that it accepts ?
Based on the comments,
The URI should be something like below for events:
arn:aws:apigateway:${AWS::Region}:events:action/PutEvents
I have an API Gateway endpoint with IAM authentication, no Custom Domain Names, no API Key, API is deployed to Prod and no AWS WAF enabled (TBMK) and VPC proxy integration request method.
I am calling this endpoint from a Lambda (with attached execute-api:Invoke permission to call the API), however I am getting a 403 error with message Forbidden. Notice that if I remove the IAM authentication method, the call from Lambda works fine.
I've already seen this and this SO questions + AWS Doc on the topic but I've already tried these solutions (as explained before).
Sample code for calling API Gateway inside Lambda:
final HttpURLConnection connection = (HttpURLConnection) new URL(postApiUrl).openConnection();
connection.setRequestMethod("POST");
final int responseCode = connection.getResponseCode();
//...
How I attach API Gateway ARN to Lambda role in CDK:
this.addToRolePolicy(
new PolicyStatement({
actions: [execute-api:Invoke],
effect: Effect.ALLOW,
resources: [postMethod.methodArn],
}),
);
You have set up IAM authentication for your API GW method, but your Lambda function code does not sign the request made to API GW. Note: Simply adding the execute-api:Invoke permission to the Lambda function execution role does not sign the request.
You need to use the AWS SigV4 signing process to add the authentication information which is then verified on the API GW end. This doc lists the steps involved which basically are:
Create a canonical request.
Use the canonical request and additional metadata to create a string for signing.
Derive a signing key from your AWS secret access key. Then use the signing key, and the string from the previous step, to create a signature.
Add the resulting signature to the HTTP request in a header or as a query string parameter.
Since you're using Java, this blog post also provides some sample code which you can refer to.
APIG has a authorizer cache, check this out.
https://aws.amazon.com/premiumsupport/knowledge-center/api-gateway-403-error-lambda-authorizer/
If you could have a read and perhaps elaborate a little I'll include the proper solution.
How to setup cross account custom authorizer with serverless framework? Custom authorizer configured with sls framework works fine if it is in the same AWS account as function that needs authorization.
What I have now is organization root account where authorizer function has been deployed. On the second account, which is organization member, I have a serverless service deployed with the endpoints that needs to be authorized from the root account.
Is it possible to configure something like this inside serverless.yml that will be deployed on the member account (111111111111 is root account number):
hello:
handler: api/hello.handler
events:
- http:
path: hello
method: get
cors: true
authorizer: arn:aws:lambda:eu-west-1:111111111111:function:authorizer
I have tried this and received following error:
An error occurred: AuthorizerApiGatewayAuthorizer - The policy of
Lambda function must explicitly authorize the method or custom
authorizer with a SourceArn condition for cross account integration
(Service: AmazonApiGateway; Status Code: 400; Error Code:
BadRequestException;
... which makes sense according to the AWS docs. These docs explains how to manually do it using API Gateway console which is exactly what I did for now (authorizer in the root, authorizer in the member account - manually connected through API gateway, same as described in the docs).
I need a better solution as the number of services and organization member accounts is going to grow.
Is it possible to configure and make this work with serverless framework?
As with a lot of the Serverless Framework, there's a plug-in for those times that CloudFormation hasn't yet offered an option:
https://github.com/rschick/serverless-plugin-lambda-account-access
The custom authorizer's serverless.yml should then include:
plugins:
- serverless-plugin-lambda-account-access
provider:
allowAccess:
- 111111111111 # account id of invoking account
So i've got a scenario that i want to use an endpoint and map the provided requests directly into Kinesis stream.
I was able to do that manually in the aws console.
But is there a way to do change the integration to aws service using serverless or serverless plugin?
I tried to find a way to deploy an endpoint that communicates directly with an aws service, without lambdas, and could not find it.
It's been a while but recently i noticed that there's a plugin now that helps setup this exact configuration, https://github.com/horike37/serverless-apigateway-service-proxy
custom:
apiGatewayServiceProxies:
- kinesis:
path: /kinesis
method: post
streamName: { Ref: 'YourStream' }
cors:
origin: '*'
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- X-Amz-User-Agent
allowCredentials: false
Hope this helps others that are still having this problem