简体   繁体   中英

Mutual Authentication in Cloud Foundry Application with NodeJS+express

I have developed a NodeJs+express application deployed as Cloud Foundry application in IBM Cloud. I want to perform mutual authentication (client and server certificates) in order to control incoming traffic and requests to my application. My certificates are generated by Secure Gateway as described here with my application configured as a cloud destination (to be reached from on-premises clients).

The Secure Gateway has generated the following pem files: primary, intermediate and root certificate of the server and destination cert and key. In the documentation there is a pretty clear Nodejs example using tls.createServer.

In my scenario there are some differences: first of all I am in the opposite scenario (with on-prem clients connecting to a cloud application through Secure Gateway creating the tunnel). Second, and this is the main reason of this post, my app is deployed as a CF application.

Reading CF documentation about HTTP routing I figured out that IBM cloud only uses ports 80 and 443 and then forwards the requests via HTTP to the ports the app is listening to (for example if my NodeJs is running on port 6001 and I call the cloud endpoint on port 443, the GoRouter will forward the request via HTTP to the correct port, adding the X-Forwarded-Proto header to pass the application the information of the original protocol used for the request.

Having this in mind (assuming this is correct), in my NodeJs code I cannot use something like https.createServer(opts, app) giving that all the requests coming to the App Container will be via HTTP.

Reading CF docs here I understand that is possible to tell CF to forward certificates up to my application but there is something I cannot truly understand.

First of all what is the difference between terminating TLS at Load Balancer or at GoRouter? What are the reasons behind this choice?

My second question is which is the correct way of handling the certificates once they are forwarded to my application as HTTP headers? This is due to the fact the my NodeJs server will be an http server, created with express in the standard way http.createServer(app) .

Thanks to all those who will help me figuring this out. Obviously, if you have any examples or advices it would be very helpful.

Reading CF documentation about HTTP routing I figured out that IBM cloud only uses ports 80 and 443 and then forwards the requests via HTTP to the ports the app is listening to (for example if my NodeJs is running on port 6001 and I call the cloud endpoint on port 443, the GoRouter will forward the request via HTTP to the correct port, adding the X-Forwarded-Proto header to pass the application the information of the original protocol used for the request.

Having this in mind (assuming this is correct), in my NodeJs code I cannot use something like https.createServer(opts, app) giving that all the requests coming to the App Container will be via HTTP.

That is correct.

First of all what is the difference between terminating TLS at Load Balancer or at GoRouter? What are the reasons behind this choice?

This only applies if you are operating your own Cloud Foundry platform. If you are deploying apps to a Cloud Foundry platform operated by someone else, they will make this decision and it won't affect you as a user.

As an operator, this is a choice you need to make. There are some trade-offs depending on what you choose to do.

  1. You can terminate at the LB. This is typically the fastest as LB's are very efficient at handling TLS/SSL. The LB can then forward traffic onto the Gorouter unencrypted, which puts less work on the Gorouter, but comes at the cost of not encrypting traffic between the two (may not be OK, depending on security requirements). In this scenario, it is the responsibility of the LB to add the x-forwarded-* headers.

    browser -> HTTPS -> LB -> HTTP -> Gorouters -> HTTP -> Your App

  2. You can use a layer-4 LB and have connections balanced across your Gorouters. This enables the Gorouters to terminate TLS/SSL. They are pretty efficient at doing this, but less so than most LBs. This also gets you encryption in the request path up to the Gorouter. In this scenario, it is the responsibility of the Gorouters to add the x-forwarded-* headers.

    browser -> HTTPS -> LB -> HTTPS -> Gorouters -> HTTP -> Your App

  3. You can terminate at the LB, but open a new TLS/SSL session between the LB & the Gorouters. This is the least efficient option as it requires terminating two TLS/SSL sessions, but it provides for encryption in the request path up to the Gorouter. It also tends to be the most flexible working with non-layer-4 LBs and it can allow your LB to inspect the HTTP traffic, because you're terminating the session at the LB. In this scenario, it is the responsibility of the LB to add the x-forwarded-* headers.

    browser -> HTTPS (session A) -> LB -> HTTPS (session B) -> Gorouters -> HTTP -> Your App

Again, if you're not operating a Cloud Foundry platform, then you can ignore this.

My second question is which is the correct way of handling the certificates once they are forwarded to my application as HTTP headers? This is due to the fact the my NodeJs server will be an http server, created with express in the standard way http.createServer(app).

You don't need to do anything fancy with the way you create your server. All you need to do is look at the x-forwarded-* headers & use those to make your decisions.

  1. Did the request come in over HTTPS? Look at either x-forwarded-proto , which should be set to https for HTTPS requests or look at x-forwarded-port , which should be set to 443 for HTTPS requests.

  2. Was a client cert provided with the request? Look at X-Forwarded-Client-Cert . If it contains a cert, then the client provided the cert.

  3. Is the client's cert valid? If your app gets the request, then the client's cert is valid. You know this because the platform handles that part for you. Since the platform (either LB or Gorouter) is terminating the TLS/SSL connection, it's the responsibility of it to validate the cert. If your app receives a request & x-forwarded-client-cert is set, then the cert is valid.

  4. How do I make authorization decisions based on a client cert? This is a little trickier, but typically you'd pull the cert out of x-forwarded-client-cert , read/parse it and make decisions based on the cert content (which we know is valid thanks to the platform). Most likely you're going to look at the subject name and treat that like a user name. Then look up roles or permissions for that user. However, how you handle that is up to you as the developer.

Hope that helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM