Got legacy microservices running on EC2 instances accessed externally via API Gateway. Microservices return JSON responses with discoverability url options:
GET /api/accout/0001
{
id: "0001",
balance: 1000000,
currency: "BTC",
_links: [
{name: "close", method: "DELETE", url: "http://10.0.0.1:8080/api/account/0001" },
{name: "deposit", method: "POST", url: "http://10.0.0.1:8080/api/account/0001/deposit" }
]
}
API Gateway exposes the API via https and a custom domain name so links like "http://10.0.0.1:8080/api/account/0001" make no sense externally.
How do I configure AWS API Gateway to replace "http://10.0.0.1:8080/api/account/0001" with "https://api.mycompany.com/api/account/0001" before passing responses from microservices to external api clients?
API Gateway supports Response transformation and method mapping functionality.
You can define the response templates with required transformation:
API Gateway Response transformation
Based on this:
If needed, add body-mapping templates to transform given integration
response payloads into specified method response payloads.
Specifically Method Models which use JSON path expressions, which can be used for transformation.
Related
I have the following setup:
API Gateway with HTTP Protocol
It has integration to SQS (SendMessage action)
CORS is enabled on API
I am facing following error when I call the endpoint from browser:
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
In the documentation: https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html
For a Lambda proxy integration or HTTP proxy integration, you can still set up the required OPTIONS response headers in API Gateway. However, your backend is responsible for returning the Access-Control-Allow-Origin and Access-Control-Allow-Headers headers, because a proxy integration doesn't return an integration response.
Is it not clear how SQS can return headers, because the integration is between API Gateway -> SQS
The documentation you have linked to describes using CORS with REST API Gateways. If you are using HTTP API Gateways then the relevant documentation is https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html.
When using REST API Gateway to implement a service proxy to another AWS service like S3 / SQS / SNS you can set any headers you want on the method response - see https://docs.aws.amazon.com/apigateway/latest/developerguide/request-response-data-mappings.html#mapping-response-parameters.
If you're using OpenAPI specifications to define your REST APIs then these headers can be specified using (for example):
x-amazon-apigateway-integration:
type: "aws"
responses:
"200":
statusCode: "200"
responseParameters:
method.response.header.Access-Control-Allow-Origin: "'*'"
method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'"
method.response.header.Access-Control-Allow-Methods: "'OPTIONS,GET'"
If you're defining the REST API in the AWS Console then these values can be set in the Integration Response panel. Note the embedded single quotes are important here i.e. "'*'" to signify that you want the header to be the literal value * (or whatever you specify).
I am using an AWS Websocket API Gateway that has the following routes:
I've been able to connect to my websocket and send requests and receive responses from /SendMessage with the following json: {"action": "SendMessage", "message": "Hello, World"} however, when I tried adding a new route /Register. Sending the json {"action": "Register", "message": "Hello, World"} AWS API Gateway routes the request to $default.
The following request appears on CloudWatch:
The request should be routed to /Register and not /default. Do I need to do some kind of redeployment of the API Gateway when I add a new route?
First, make sure you have re-deployed your API Gateway.
Second, make sure you have re-deployed your Lambda functions
Last, you have to Stringify your request like this:
socket.send(JSON.stringify({
"action": "SendMessage",
"message": "Hello, World"
}))
I have Cloud Front distribution URL (https://abcdef.cloudfront.net/) backed by Route53 (https://example.com).
I need to set 'Access-Control-Allow-Origin' header - I am not allowed to put '*' here.
So the question is whether to put the Cloud Front distribution URL or the Route53 URL.
I am not sure which one will work, or either one will work?
A bit more context:
So I have a full-stack application - The UI part is build and copied to a S3 bucket which is then linked to the above Cloudfront Distribution (https://abcdef.cloudfront.net/).
This particular Cloudfront distribution is then backed by a hosted zone DNS via Route 53 (https://example.com).
I have multiple back-end AWS Lambdas hiding behind an AWS API Gateway which has an Integration Request as Type: LAMBDA_PROXY.
The headers are part of the response of the Lambdas, as below:
'Content-Type': 'application/json',
'X-Content-Type-Options': 'nosniff',
'X-XSS-Protection': '1',
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload',
'Access-Control-Allow-Origin': '*'
The Security scan is raising the below issue:
Risk Name
Overly Permissive CORS Access Policy
Vulnerability
Scan detected that the "Access-Control-Allow-Origin" header is too permissive.
Threat
It is possible to gather sensitive information about the web
application such as usernames, passwords, machine name and/or
sensitive file locations
It is possible to persuade a naive user to supply sensitive
information such as username, password, credit card number, social
security number etc.
Given the fact you use the LAMBDA_PROXY request type behind API Gateway, your lambda function is responsible for returning the correct headers. I suggest the following:
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Headers" : "Content-Type", // check API Gateway configuration which headers are allowed by default
"Access-Control-Allow-Origin": "https://www.example.com", // you add the domain which is used to make the request
"Access-Control-Allow-Methods": "OPTIONS,POST,GET"
},
body: JSON.stringify('Hello from Lambda!'),
};
References:
https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html
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.
I have setup a CloudFront Distribution with an API Gateway as one of the origins and this API Gateway is configured with an AWS IAM authorizer.
When CloudFront url is invoked with Authorization headers, it returns a 403 error.
{
"message": "Missing Authentication Token"
}
However, when the API Gateway url is invoked instead of CloudFront url with the same Authorization headers, it worked.
I've also tried invoking the endpoint without any authorizer via CloudFront url and it worked. Any idea on how to solve this issue.
When provisioning a CloudFront distribution, remember that CloudFront removes most headers from the request by default.
This is done to optimize the cache hit ratio while preventing your origin server from making decisions based on those headers that would not be appropriate for different requests based on other variations (or absence) of those headers, which CloudFront would then serve from cache, inappropriately.
You'll need to whitelist the Authorization header for forwarding to the origin.
Note also that when provisioning API Gateway behind a CloudFront distribution that you control, you'll probably want to deploy your API endpoint as regional and not edge-optimized.
Please see below, in case if anyone is facing this issue when using API Gateway as a secondary origin - behavior instead of default behavior for the Cloudfront Distribution i.e.
forwarding all paths like /api/* requests to API Gateway
serving the remaining paths with an s3 or other default resource like an Application load balancer
I was using AWS CDK to define and deploy AWS API Gateway as a secondary behavior and faced the same issue and I did everything including
forwarding headers and query params
enabling all http request methods
Setting the API gateway as regional
My configuration for the deployment is as follows:
originConfigs: [{
customOriginSource: {
domainName: clientAppBucket.bucketWebsiteDomainName,
originProtocolPolicy: cloudfront.OriginProtocolPolicy.HTTP_ONLY
},
behaviors: [{
isDefaultBehavior: true,
compress: true
}]
},
{
customOriginSource: { domainName: `${api.restApiId}.execute-api.${this.region}.amazonaws.com/prod` },
behaviors: [
{
pathPattern: "/api/*",
allowedMethods: cloudfront.CloudFrontAllowedMethods.ALL,
defaultTtl: cdk.Duration.seconds(0),
forwardedValues: {
queryString: true,
headers: ["Authorization"],
},
},
],
}]
The problem was that Cloudfront prepends the path that we are using as a custom behavior with each request i.e. when we call domain.com/api/something, It will not call ${api.restApiId}.execute-api.${this.region}.amazonaws.com/prod/something. Instead it will call ${api.restApiId}.execute-api.${this.region}.amazonaws.com/prod/api/something.
Therefore, either the stage name of the default API Gateway URL which is usually prod should be equal to the behavior path which we specify i.e /path/* or /api/* or /backend/* etc -> /prod/* or we should have a /path/ as a resource at the top level of RestApi and nest all the resources under it