I am trying to connect my python paho mqtt client to my broker through tls using my own certificate authority. I generated necessary files and configured my RabbitMQ broker to use them. My idea is that the client authenticates the server but client itself doesn't need to be authenticated.
ca.cert.pem
cert.pem
key.pem
I know these should work correctly because I also have a scala paho mqtt client that works correctly.
Currently I am running the file directly from the terminal on my mac. I am using an virtuanenv created by python 3.5.2 and I have a file subscribe.py
import paho.mqtt.client as paho
import ssl
def on_message(clnt, userdata, msg):
print(msg.topic+" "+str(msg.payload))
def on_connect(client, userdata, rc):
print("Connected with result code "+str(rc))
mqttc.subscribe("foo")
mqttc = paho.Client()
mqttc.on_message = on_message
mqttc.on_message = on_message
mqttc.tls_set("ca.cert.pem", tls_version=ssl.PROTOCOL_TLSv1_2)
mqttc.connect("address", 8883, 60)
mqttc.loop_forever()
When I run the file I receive the following error
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:645)
I have also tried changing the tls_version to TLSv1_1, TLSv1 and leaving it out completely. ca.cert.pem is in the same folder as the subscribe.py file
The example on paho website seems very simple so what am I missing here? Why do I receive the error on my python client?
Have you tried mosquitto clients? There are lots of possibility for the problem you have encountered, so best way to figured it out is trying another way.
mosquitto_sub -h address -p 8883 --cafile ca.cert.pem -t "#" -d -v
d flag is for debug messages, v flag is verbose mode.
If mosquitto client cannot connect with ca, you can try:
mosquitto_sub -h address -p 8883 --cafile ca.cert.pem -t "#" -d -v --insecure
The insecure flag will ignore CA checking for server. If add the insecure flag can make you connected, then maybe the CA is wrong. You can use openssl to debug it then.
Related
I am running a docker container for mosquitto mqtt broker like this:
$ docker run -it -p 1883:1883 -p 9001:9001 -v mosquitto.conf:/mosquitto/config/mosquitto.conf eclipse-mosquitto
Next I try to connect to this using a python mqtt client like this:
import paho.mqtt.client as mqtt
mqtt_broker = 'localhost'
client = mqtt.Client("Temperature inside")
client.connect(mqtt_broker, 1883)
I get a ConnectionRefusedError [Errno 61] Connection refused error
What am I doing wrong on the docker side (presumably) or otherwise?
I'm currently following a rabbitmq tutorial and running into an issue. No matter how close I follow the tutorial I keep getting this error when trying to run my send.py and receive.py:
pika.exceptions.ConnectionClosed: Connection to 127.0.0.1:5672 failed: [Errno 61] Connection refused
This is the send.py:
#!/usr/bin/env python
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.queue_declare(queue='hello')
channel.basic_publish(exchange='',
routing_key='hello',
body='Hello World!')
print(" [x] Sent 'Hello World!'")
connection.close()
This is the receive.py:
#!/usr/bin/env python
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.queue_declare(queue='hello')
def callback(ch, method, properties, body):
print(" [x] Received %r" % body)
channel.basic_consume(callback,
queue='hello',
no_ack=True)
print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()
I can't for the life of me figure out what I'm doing wrong. I've looked at other post on here that ask a similar question but still no dice.
I used the same tutorial it seems, and they did miss the dependency to install and run rabbitmq
After doing brew install rabbitmq and then brew services start rabbitmq the connection to localhost on Pika then works
If you are using docker to run rabbitmq and followed instructions in the tutorial and the docker page (https://github.com/docker-library/docs/tree/master/rabbitmq), you might run into this problem. When you run the container without specifying the port mapping option ("-p"), the port binding will be valid only within the container. You can verify by doing a "docker exec" into the container and then running netstat.
So what you would want to do is to restart the rabbitmq container and specify a port mapping. Example:
docker run -d --hostname my-rabbit --name some-rabbit -p 5672:5672 rabbitmq:latest
Are you using docker to run your rabbitmq? If yes, I suggest you to double check ports binding. For example: -p 5672:5672
I set up a Mosquitto server a few days ago using https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-the-mosquitto-mqtt-messaging-broker-on-debian-8.
Playing around with it, everything seemd to be working like I wanted. I am able to connect an android client and MQTTSpy to my own server.
Yesterday I had the great idea of looking for a Kodi plugin that would push status and info to MQTT: https://github.com/owagner/kodi2mqtt
It is able to find the server as I see changes in the Mosquitto log file, however I keep getting the same error:
1492549927: New connection from 81.240.134.64 on port 8883.
1492549927: OpenSSL Error: error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol
1492549927: Socket error on client <unknown>, disconnecting.
1492549932: New connection from 81.240.134.64 on port 8883.
1492549933: OpenSSL Error: error:140780E5:SSL routines:SSL23_READ:ssl handshake failure
1492549933: Socket error on client <unknown>, disconnecting.
1492549934: New connection from 81.240.134.64 on port 8883.
1492549934: OpenSSL Error: error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol
1492549934: Socket error on client <unknown>, disconnecting.
1492549939: New connection from 81.240.134.64 on port 8883.
1492549939: OpenSSL Error: error:140780E5:SSL routines:SSL23_READ:ssl handshake failure
1492549939: Socket error on client <unknown>, disconnecting.
From what I understand there are some issues with certificates but I am not 100% sure what is missing. In the other applications I do not need to provide my own certificates, so I don't see what is missing. I tried using the generated certificates in the Kodi addon, however they seem not to work and I get a different error:
1492541859: New connection from 81.240.134.64 on port 8883.
1492541860: OpenSSL Error: error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca
1492541860: OpenSSL Error: error:140940E5:SSL routines:SSL3_READ_BYTES:ssl handshake failure
1492541860: Socket error on client <unknown>, disconnecting.
1492541862: New connection from 81.240.134.64 on port 8883.
1492541862: OpenSSL Error: error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca
1492541862: OpenSSL Error: error:140940E5:SSL routines:SSL3_READ_BYTES:ssl handshake failure
1492541862: Socket error on client <unknown>, disconnecting.
I'm not sure in what direction I should check. Is something wrong with my server/certificates (seems unlikely since other clients are working) or is something wrong with the python code of the Kodi addon? If so, could anyone shed some light on what is missing (I know my way around coding, just not really around certificate things).
Thanks for the help!
Joren C.
Your python client will need access to the trusted certificate authority. Copy the signed public certificate The browser clients don't need that because they already come loaded with trusted certificate authorities.
If the kodi addon is using the paho mqtt client library , then the following should fix it..
client.tls_set('$your server's public cert$.crt')
Try ssl connection:
openssl s_client -connect 81.240.134.xxx:8883 -CAfile /etc/certs/file.crt -debug
At the moment I am trying to figure out how to do an MQTT publish using the .crt and .pem files for our application.
below is some pseudo code for what I am trying to do:
connect to an existing topic over tls
publish a message
import paho.mqtt.publish as mqtt
import paho.mqtt.client as mqttclient
topic = "Some/Topic/Goes/Here"
my_ca_cert = open("<path_to_cert>\ca.crt", 'rb').read()
my_pri_cert = open("<path_to_cert>\private.pem", 'rb').read()
my_key_cert = open("<path_to_cert>\certificate.pem", 'rb').read()
mqttc = mqttclient.Client("Python_Ex_Pub")
mqttc.tls_set(my_ca_cert, certfile=my_pri_cert, keyfile=my_key_cert)
mqttc.connect("<gateway_address>", 8883)
mqttc.publish(topic_name, "This is a test pub from Python.")
mqttc.loop(timeout=2.0, max_packets=1)
When I run the script the following error is thrown:
Traceback (most recent call last):
File "mqtt_pub_test.py", line 9, in <module>
mqttc.tls_set(my_ca_cert, certfile=my_pri_cert, keyfile=my_key_cert)
File "C:\Python27\lib\site-packages\paho\mqtt\client.py", line 557, in tls_set
raise IOError(ca_certs+": "+err.strerror)
IOError: -----BEGIN CERTIFICATE-----
<cert_info_here>
-----END CERTIFICATE-----: No such file or directory
I read through the TLS example on the paho doc page, but just do not understand how I should be passing the crt / pem files in my code.
At one point I was only pointing to the folder containing the files, and even went as far as to chmod 777 the folder but at that point I was getting access denied from python at run time.
Any help is appreshiated
Do you want to do TLS client authentication (that is, your Python script needs to authenticate to the server / MQTT broker)? Or do you want your Python script to behave like a web browser, and just validate the server certificate?
If you only want the latter, I have had success using the tls_set() method in the Paho Python client when I point it to a PEM file containing the server's certificate. And that's the only argument you need to pass on tls_set() to have the Paho client validate the server certificate, and connect to the broker using TLS. For example:
mqttc.tls_set("/home/bob/certificates/mqttbrokercertificate.pem")
How do you obtain the mqtt broker's certificate in PEM format? The easiest way is with openssl:
openssl s_client -host mqtt.broker.hostname.com -port 8883 -showcerts
Redirect the output to a file, and delete every line in the file except what is between the "BEGIN CERTIFICATE" and "END CERTIFICATE" lines (inclusive -- be sure to include these lines as well). This is a good article here on StackOverflow about how to save a server's SSL certificate using openssl:
How to save server SSL certificate to a file
Lastly, you need to be sure of what version of TLS your broker supports, and make sure your Python client also supports it. For example, the IBM Watson IoT Platform requires TLS 1.2. The ssl module in Python 2.7 (which is built on openssl) does not support TLS 1.2. Generally, you need Python 3.X, and openssl of at least 1.0.1. Here is how you can set the TLS version on the Paho client (don't forget to import ssl):
mqttc.tls_set("/home/bob/certificates/mqttbrokercertificate.pem", tls_version=ssl.PROTOCOL_TLSv1_2)
If you want TLS client authentication, that's probably better handled in an entirely separate article. But I hope this helps with TLS server authentication using the Paho Python client.
Looking at the error it would suggest that the tls_set function is expecting paths to the files not the contents of the file to be passed in.
When I run the command:
fab -H localhost host_type
I receive the following error:
[localhost] Executing task 'host_type'
[localhost] run: uname -s
Fatal error: Low level socket error connecting to host localhost: Connection refused
Aborting.
Any thoughts as to why? Thanks.
Fabfile.py
from fabric.api import run
def host_type():
run('uname -s')
Configuration
Fabric 1.0a0 (installed from the most recent Github commit---b8e1b6a)
Paramiko 1.7.4
PyCrypto 2.0.1
Virtualenv ver 1.3.3
Python 2.6.2+ (release26-maint:74924, Sep 18 2009, 16:03:18)
Mac OS X 10.6.1
The important part isn't the "low level error" part of the message - the important part is the "Connection refused" part. You'll get a "connection refused" message when trying to connect to a closed port.
The most likely scenario is that you are not running an ssh server on your machine at the time that Fabric is running. If you do
ssh localhost
you'll probably get a message similar to
ssh: connect to host localhost: Connection refused
So you'll have to go out and set up an SSH server on your computer before you can proceed with Fabric from there.
I had the same problem, but the reason was different: While I could easily log in to the server via SSH (default port 22), fabric tried to connect on a closed port 9090.
Finally I recognized that I had defined "env.port=9090" in my old fabfile for some WSGI server setup; while that was never a problem, I updated my Python installation some weeks before, and fabric now uses env.port for its SSH connection.
I just renamed that config, and all is well again.
This can also happen in OS X 10.11.4 and Fabric 1.10.1, in the case where you are ssh'ing to a VM using Vagrant, which does port forwarding from localhost. In this case, localhost was resolving to the IPv6 ::1 address (not due to /etc/hosts file), and giving this error.
The fix was to force use of IPv4 by using the 127.0.0.1 address in the fabfile instead of the hostname. Using a hostname in /etc/hosts with this address didn't work.
You might also want to try these useful tips for debugging connection issues in Fabric.
env.roledefs = {
'role1': env.hosts[0:5],
'role2':[env.hosts[5],]
}
I encountered the same error if "role" value IS NOT A LIST. for example, the above code works but the following doesn't.
env.roledefs = {
'role1': env.hosts[0:5],
'role2':env.hosts[5],
}