A couple of days ago I asked AWS lambda basic-authentication without custom authorizer. I got the answer which was enough for me, I implemented the custom authorizer which works properly.
I have a very similar problem right now because we decided to change API Gateway to Application Load Balancer which will trigger the lambda function on an appropriate path.
I would like to prepare the basic authentication for this endpoint also (exact the same as before).
So, the same problem:
AWS lambda function which is a proxy for an additional service. This function only forwards the whole request and give the user the whole response. That's why I need to force the usage of the Authentication header and I would like to have the prompt window for passing the credentials: Authentication.
The response which should be sent from the lambda function is a little bit different than for the API Gateway: Using AWS Lambda with an Application Load Balancer - AWS Lambda
About the authentication with the usage of ALB, I found only Authenticate Users Using an Application Load Balancer - Elastic Load Balancing.
I can't find anything connected with Basic Authentication and the prompt window.
Has anyone ever tried to setup basic auth with ALB for the lambda function? Where to look for the information?
To answer my own question:
I started my search for an answer in the wrong places. I thought that it should be connected with the ALB but in the end, it was not that hard as I thought at the beginning. It can work as a simple Basic Authentication.
So, it is enough to return that response from the asynchronous function/handler to do that in the simplest way:
{
statusCode: 401,
statusDescription: "401 Unauthorized",
isBase64Encoded: false,
headers: { "content-type": "application/json", "WWW-Authenticate": "Basic" },
body: "",
};
Of course, there is a possibility to return anything that you want in the body of this response.
Related
I have node/express APIs running in Lambda function.
The API endpoint is {domain}/api/user/{username} where I pass username in URL itself.
example: to get userA detail, endpoint will be xxx.com/api/user/userA
also sending user_id:xxx in header.
Hitting above endpoint using API gateway/Lambda returns the data without any error.
Problem occurs when I use % in username.
Assume I have username as userA% .
Endpoint would become: xxx.com/api/user/userA%
Now, the problem is when I run this in my local machine with node/express/mysql api with endpoint localhost:2000/api/user/userA%, it returns the data.
But the same API using API gateway/Lambda : xxx.com/api/user/userA% throws
CORS: PreflightMissionAllowOriginHeader.
I have configured some CORS policies as shown in below image but can't seem to figure out what should I configure more to allow this type of requests.
We have an authenticated HTTP cloud function (CF). The endpoint for this CF is public but because it is authenticated, it requires a valid identity token (id_token) to be added to the Authorization header.
We have another Node JS application that is deployed in the same Google Cloud. What we want is to call the CF from the Node application, for which we will be needing a valid id token.
The GCP documentation for authentication is too generic and does not have anything for such kind of scenario.
So what is the best way to achieve this?
Note
Like every google Kubernetes deployment, the node application has a service account attached to it which already has cloud function invoker access.
Follow Up
Before posting the question here I had already followed the same approach as #guillaume mentioned in his answer.
In my current code, I am hitting the metadata server from the Node JS application to get an id_token, and then I am sending the id_token in a header Authorization: 'Bearer [id_token]' to the CF HTTP request.
However, I am getting a 403 forbidden when I do that. I am not sure why??
I can verify the id_token fetched from the metadata server with the following endpoint.
https://www.googleapis.com/oauth2/v1/tokeninfo?id_token=[id_token]
It's a valid one.
And it has the following fields.
Decoding the id_token in https://jwt.io/ shows the same field in the payload.
{
"issued_to": "XXX",
"audience": "[CLOUD_FUNTION_URL]",
"user_id": "XXX",
"expires_in": 3570,
"issuer": "https://accounts.google.com",
"issued_at": 1610010647
}
There is no service account email field!
You have what you need in the documentation but I agree, it's not clear. It's named function-to-function authentication.
In fact, because the metadata server is deployed on each computes element on Google Cloud, you can reuse this solution everywhere (or almost everywhere! You can't generate an id_token on Cloud Build, I wrote an article and a workaround on this)
This article provides also a great workaround for local testing (because you don't have metadata server on your computer!)
My setup currently looks like:
API Gateway --- ALB --- ECS Cluster --- NodeJS Applications
|
-- Lambda
I also have a custom domain name set on API Gateway (UPDATE: I used the default API gateway link and got the same problem, I don't think this is a custom domain issue)
When 1 service in ECS cluster calls another service via API gateway, I get
Hostname/IP doesn't match certificate's altnames: "Host: someid.ap-southeast-1.elb.amazonaws.com. is not in the cert's altnames: DNS:*.execute-api.ap-southeast-1.amazonaws.com"
Why is this?
UPDATE
I notice when I start a local server that calls the API gateway I get a similar error:
{
"error": "Hostname/IP doesn't match certificate's altnames: \"Host: localhost. is not in the cert's altnames: DNS:*.execute-api.ap-southeast-1.amazonaws.com\""
}
And if I try to disable the HTTPS check:
const response = await axios({
method: req.method,
url,
baseURL,
params: req.params,
query: req.query,
data: body || req.body,
headers: req.headers,
httpsAgent: new https.Agent({
: false // <<=== HERE!
})
})
I get this instead ...
{
"message": "Forbidden"
}
When I call the underlying API gateway URL directly on Postman it works ... somehow it reminds me of CORS, where the server seems to be blocking my server either localhost or ECS/ELB from accessing my API gateway?
It maybe quite confusing so a summary of what I tried:
In the existing setup, services inside ECS may call another via API gateway. When that happens it fails because of the HTTPS error
To resolve it, I set rejectUnauthorized: false, but API gateway returns HTTP 403
When running on localhost, the error is similar
I tried calling ELB instead of API gateway, it works ...
There are various workarounds, which introduce security implications, instead of providing a proper solution. in order to fix it, you need to add a CNAME entry for someid.ap-southeast-1.elb.amazonaws.com. to the DNS (this entry might already exists) and also to one SSL certificate, alike it is being described in the AWS documentation for Adding an Alternate Domain Name. this can be done with the CloudFront console & ACM. the point is, that with the current certificate, that alternate (internal !!) host-name will never match the certificate, which only can cover a single IP - therefore it's much more of an infrastructural problem, than it would be a code problem.
When reviewing it once again... instead of extending the SSL certificate of the public-facing interface - a better solution might be to use a separate SSL certificate, for the communication in between the API Gateway and the ALB, according to this guide; even self-signed is possible in this case, because the certificate would never been accessed by any external client.
Concerning that HTTP403 the docs read:
You configured an AWS WAF web access control list (web ACL) to monitor requests to your Application Load Balancer and it blocked a request.
I hope this helps setting up end-to-end encryption, while only the one public-facing interface of the API gateway needs a CA certificate, for whatever internal communication, self-signed should suffice.
This article is about the difference in between ELB and ALB - while it might be worth a consideration, if indeed the most suitable load-balancer for the given scenario had been chosen. in case no content-based routing is required, cutting down on useless complexity might be helpful. this would eliminate the need to define the routing rules ...which you should also review once, in case sticking to ALB. I mean, the questions only shows the basic scenario and some code which fails, but not the routing rules.
I have NodeJS service which is protected and exposed using a load balancer. Need to call the drill Query.JSON API which is projected using j_secuirty_check.
Existing logic:
First hit the j_security_check URL with the credentials and receive the cookie.
Hit the query.JSON URL with the received cookie in the above step.
Code Snippet:
var options1 = {
url: 'http://<HOSTNAME>:8047/query.json',
method: 'POST',
json: JSON.parse('{ "queryType":"SQL", "query": "show schemas"}'),
headers : {
cookie : setcookie
}
};
The above method is working without the load balancer.
Example:
backend service running on http://localhost:3000
Drill URL: http://<SOMEIP:PORT>/query.JSON
Issue:
The second request is redirecting to login page thought we set cookie received in the previous step.
Example:
backend service running on https://<LOADBALANCER_URL>
Drill URL: http://<SOMEIP:PORT>/query.JSON
Is this because of https & http protocols or diff domain?
Please share your suggestion.
In case of load balancer the request might be going to another Drillbit WebServer which doesn't issued the cookie in first step. In which case it will not work, your load balancer should have some concept of sticky session or send the request from a client to same WebServer every time.
I have created one API endpoint for lambda function, as - https://XXXXXXXXX.execute-api.us-east-1.amazonaws.com/XXXX/XXXXXXXXXXXX/ which is GET method.
While calling that endpoint from postman it is giving me
{
"message": "'XXXXXXXXX3LPDGPBF33Q:XXXXXXXXXXBLh219REWwTsNMyyyfbucW8MuM7' not a valid key=value pair (missing equal-sign) in Authorization header: 'AWS XXXXXXXXX3LPDGPBF33Q:XXXXXXXXXXBLh219REWwTsNMyyyfbucW8MuM7'."
}
This is a screenshot of the Amazon Lambda Upload Site: http://i.stack.imgur.com/mwJ3w.png
I have Access Key Id & Secret Access Key for IAM user. I used it all but no luck. Can anyone suggest tweak about this.
If you're using the latest version of Postman, you can generate the SigV4 signature automatically. The region should correspond to your API region (i.e. "us-east-1") and the service name should be "execute-api"
This is not a solution but it has helped me more than once:
Double-check that you are actually hitting an existing endpoint! Especially if you're working with AWS. AWS will return this error if you don't have the correct handler set up in your Lambda or if your API Gateway is not configured to serve this resource/verb/etc.