rabbitmq / discussions

Please use RabbitMQ mailing list for questions. Issues that are questions, discussions or lack details necessary to investigate them are moved to this repository.
3 stars 4 forks source link

Peer verification on WS connecitons #159

Closed creising closed 4 years ago

creising commented 4 years ago

I apologize if I missed something obvious in the documentation that answers this question, but I was curious if it is possible to enable peer verification on web MQTT connections.

My SSL options are set as follows:

ssl_options.certfile   = /var/certs/server_certificate.pem
ssl_options.keyfile    = /var/certs/server_key.pem
ssl_options.verify     = verify_peer
# Set to true if the client must have a valid cert in order to proceed
ssl_options.fail_if_no_peer_cert = true

and my web mqtt options are

web_mqtt.ws_opts.idle_timeout = 90000
web_mqtt.ssl.port       = XXXX
web_mqtt.ssl.backlog    = 1024
web_mqtt.ssl.certfile   = /var/certs/server_certificate.pem
web_mqtt.ssl.keyfile    = /var/certs/server_key.pem
web_mqtt.ssl.cacertfile = /var/certs/ca_certificate.pem

I am using a test client written in Python that uses Paho. When I setup the client to not include client certificates I am still able to connect, and I would expect that connection to be rejected.

I am running official Docker container version 3.7.16, Erlang 22.0.7.

Thank you!

michaelklishin commented 4 years ago

Paho Python is an MQTT client, not an MQTT-over-WebSockets client to my knowledge. Consider providing an example that can be run to reproduce. The settings look reasonable.

creising commented 4 years ago

Thank you for your quick response. Paho does have support for WebSockets if you set the transport arg in the constructor to "websockets" so it should be enough to test this. I also can see via the management UI that this connection lists Web MQTT 3.1.1 as its protocol and when I set the client to MQTT, the protocol shows up as MQTT so I am fairly sure I have it setup correctly.

The test client is:

import paho.mqtt.client as mqtt
import uuid
import sys
import ssl

if len(sys.argv) != 2:
    print("You must pass in the client ID!")
    sys.exit(1)
name = sys.argv[1]

subscribe_topic = "my/test/topic"

# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
    print("I am connected with result code "+str(rc) + " to topic: " + subscribe_topic)

    # Subscribing in on_connect() means that if we lose the connection and
    # reconnect then subscriptions will be renewed.
    client.subscribe(subscribe_topic, qos=1)

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    print(msg.topic+" "+str(msg.payload) + " on topic " + msg.topic)

# Note the transport arg is set to websockets, for MQTT set to "tcp" and update the port
client = mqtt.Client(client_id=name, clean_session=False, transport="websockets")
client.username_pw_set(name, "somepassword")
client.on_connect = on_connect
client.on_message = on_message

# If you comment out certfile and keyfile I would expect this connection to be rejected
client.tls_set(
    ca_certs="./cert/ca_certificate.pem",
    certfile="./cert/client_certificate.pem",
    keyfile="./cert/client_key.pem",
    tls_version=ssl.PROTOCOL_TLS,
    ciphers=None)

client.ws_set_options(path="/ws", headers=None)

client.connect("somehost", 19443, 60)
client.loop_forever()
michaelklishin commented 4 years ago

My reading of the fail_if_no_peer_cert setting is not really different from yours. So my best guess is that the Web MQTT plugin requires all settings to be listed under web_mqtt.ssl.*. The core settings are not merged because WebSocket acceptors are separate from "regular" TCP listener acceptors. That's what a quick reading of the code suggests.

The easiest option would be to compare this to how the MQTT plugin behaves first, then to openssl s_client as demonstrated in our Troubleshooting TLS guide.

I'm afraid inspecting these settings for a specific connection is currently fairly involved. @essen is there a Cowboy/Ranch-specific function that we can run to see the actual TLS socket settings?

essen commented 4 years ago

There's https://ninenines.eu/docs/en/ranch/2.0/manual/ranch.get_transport_options/ but no functions that give you the full options including the default values that you didn't set.