Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request client certificate behind a proxy [question] #20

Open
rosenvivanov opened this issue Jan 2, 2023 · 9 comments
Open

Request client certificate behind a proxy [question] #20

rosenvivanov opened this issue Jan 2, 2023 · 9 comments
Labels
question Further information is requested

Comments

@rosenvivanov
Copy link

rosenvivanov commented Jan 2, 2023

  • aedes: 0.48.0
  • aedes-server-factory: 0.2.1
  • aedes-protocol-decoder: 2.1.0

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.

  • send-proxy is enabled on proxy side
  • trustProxy is enabled on aedes side
@robertsLando
Copy link
Member

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

@getlarge
Copy link
Member

@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
Copy link
Author

@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:

  • Aedes provides TLS connection: so I have TLS object defined in the aedes instance:
{
  tls: {
      ca: [...],
      cert: ...,
      key: ...,
      rejectUnauthorized: false,
      requestCert: true
  },
  trustProxy: true,
  extractSocketDetails,
  protocolDecoder
}
  • Proxy just listen on public port and send traffic to the aedes instance on local port. There is NO proxy protocol enabled as an option.

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:

  • Aedes doesn't provide TLS, just properties:
{
  trustProxy: true,
  extractSocketDetails,
  protocolDecoder
}
  • Proxy service provides the TLS connection with CA, cert and key and forward the connection to aedes. Protocol IS enabled in that case.

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
Copy link
Member

robertsLando commented Jan 23, 2023

@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
Copy link
Author

@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
Copy link
Member

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
Copy link
Member

getlarge commented Jan 23, 2023

@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
Copy link
Author

rosenvivanov commented Jan 23, 2023

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
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants