moscajs / aedes-server-factory

Aedes server factory. Supports tcp, tls, http, https, http2, ws, wss and proxy decoders
MIT License
8 stars 6 forks source link

Request client certificate behind a proxy [question] #20

Open rosenvivanov opened 1 year ago

rosenvivanov commented 1 year ago

When we start an instance of aedes with TLS object passed to createServer function, then we are able to request the client certificate info - when we work with self-signed certs and want to authenticate with them. The property is requestCert = true. But in this case, aedes provides a secured connection and it should define ca, cert, key etc.

The question is: Is there a way to request the client certificate, without passing a TLS object to the createServer function? In this case, the proxy server behind a backend provides a server certificate.

robertsLando commented 1 year ago

I don't know how this could be done but maybe @getlarge knows

getlarge commented 1 year ago

@rosenvivanov sorry for the late reply. @robertsLando long time no speak!

I hardly see how this could be achieve with "plain" socket server... but i would be curious to know how if someone finds a way. Maybe by setting rejectUnauthorized:false and requestCert:true ? Still you have to know that you would get information about the proxy itself and the not original client.. In other word the proxy is the client of Aedes in that setup. Or maybe the proxy you use can be tweaked to add some extra information on the TCP layer ?

Still i suppose that with an HTTP proxy (when using Aedes with a websocket stream), you could add extra headers containing information about the client certificates and retrieve them in Aedes. Of course that would mean providing your own protocolDecoder in the options.

rosenvivanov commented 1 year ago

@getlarge

Thank you for your reply. Actually, I've tried every possible combination, unfortunately without success. I'm gonna try to explain them. The main idea is to have a MQTT client authentication with a self-signed certificate, so we will need the certificate's info. Every client is going to have its own generated certificate. As well as, we need for real client IP address - not a proxy IP :)

I've also tried using haproxy, as well as nginx, but the result is the same.

TEST 1:

RESULT: In that case Aedes successfully retrieves CERT info, and we have the original certificate's subject, issuer etc. But we don't have the real client IP, just ipAddress: '127.0.0.1' in my case, or what the proxy address is. The 'isProxy' property is also 0.

TEST 2:

RESULT: Now we manage to get a real client IP address, but the CERT info is missing. Perhaps we don't have 'requestCert'. Just:

{
  isProxy: 1,
  isWebsocket: false,
  ipFamily: 4,
  ipAddress: '<real_client_ip_address>',
  port: 39778,
  serverIpAddress: '<server_ip>',
  data: ....
}

TEST 3: I tried to make a combination between 1 and 2. To send a proxy protocol from the proxy server and provide a TLS connection by aedes, but get an error:

'Error: Client network socket disconnected before secure TLS connection was established'

robertsLando commented 1 year ago

@rosenvivanov What about use test 1 and simply make the proxy to set the ip of the client in a header?

Nginx example: https://www.nginx.com/resources/wiki/start/topics/examples/forwarded/

@getlarge nice to see you :)

rosenvivanov commented 1 year ago

@rosenvivanov What about use test 1 and simply make the proxy to set the ip of the client in a header?

Nginx example: https://www.nginx.com/resources/wiki/start/topics/examples/forwarded/

@getlarge nice to see you :)

As far as I understood, custom headers work only in HTTP mode, whereas we have a TCP connection.

robertsLando commented 1 year ago

unfortunately I'm not an expert in this field, I still didn't 100% understand what you are trying to archieve.

I think you want to use MQTTS (mqtt over tls) with self signed certs but this would require to create a certificate/key for each client and you just want to have a TLS connection without the need of this, right?

If I understood you correctly I can say I always use WSS for this purposes without any problems

getlarge commented 1 year ago

@rosenvivanov not sure i understood, do you need the TLS certificates in Aedes for specific values (subject, common name..) ?

test 1

As you might have figured, you can only retrieve the source IP address (the "real" client IP) with the current protocolDecoder implementation as long as you use the proxy_protocol in the Nginx config server directive. The 'isProxy' === 0 means that no proxy protocol was detected, whereas 'isProxy' === 1 means version 1 of proxy protocol is used and same logic for 'isProxy' === 2.

test 2

it's just a plain net socket used, so there is no option (in my knowledge) to requestCert from the client.

test 3

Did you ensure that the SSL config is correct in both Aedes and proxy side ? Few years ago i needed to achieve SSL termination on Nginx side, and i think this is the config i used in Nginx. I don't remember doing 2 way TLS between Aedes and Nginx so i can't really help, still i believe that if you manage to do it you would get the certificate information from the proxy as it is the client.

rosenvivanov commented 1 year ago

I think you want to use MQTTS (mqtt over tls) with self signed certs but this would require to create a certificate/key for each client and you just want to have a TLS connection without the need of this, right?

Every client has its own generated certificate, and it's signed by the server CA. So I want to authenticate not by username and password, but by values inside the certificate's subject (CN, OU, etc). In some of these fields, I will have the ID of the client and some other if I want. And I managed to do that by TEST 1, but I can't get the real client IP address.

rosenvivanov commented 1 year ago

Few years ago i needed to achieve SSL termination on Nginx side, and i think this is the config i used in Nginx.

Thank you. I will "dive" into this config and will try again with nginx, because I'm testing mainly with haproxy.