[英]Azure IoT Hub Device x509 Self-Signed Certificate (Python MQTT)
[英]Issues with Azure IoT Hub Python SDK using self-signed x509 Certs where protocol != MQTT_WS
有一些很奇怪的問題,與我的Python腳本,但我可以用包括在他們的Python SDK微軟的示例腳本復制它在這里 。
基本上,當我使用MQTT_WS以外的任何方式運行此代碼時,它將失敗並顯示各種錯誤。 這是代碼:(注意,我刪除了實際的證書/密鑰,因此這對您不起作用)。
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for
# full license information.
import random
import time
import sys
import iothub_client
from iothub_client import IoTHubClient, IoTHubClientError, IoTHubTransportProvider, IoTHubClientResult
from iothub_client import IoTHubMessage, IoTHubMessageDispositionResult, IoTHubError
from iothub_client_args import get_iothub_opt, OptionError
# HTTP options
# Because it can poll "after 9 seconds" polls will happen effectively
# at ~10 seconds.
# Note that for scalabilty, the default value of minimumPollingTime
# is 25 minutes. For more information, see:
# https://azure.microsoft.com/documentation/articles/iot-hub-devguide/#messaging
TIMEOUT = 241000
MINIMUM_POLLING_TIME = 9
# messageTimeout - the maximum time in milliseconds until a message times out.
# The timeout period starts at IoTHubClient.send_event_async.
# By default, messages do not expire.
MESSAGE_TIMEOUT = 10000
RECEIVE_CONTEXT = 0
AVG_WIND_SPEED = 10.0
MIN_TEMPERATURE = 20.0
MIN_HUMIDITY = 60.0
MESSAGE_COUNT = 5
RECEIVED_COUNT = 0
# global counters
RECEIVE_CALLBACKS = 0
SEND_CALLBACKS = 0
PROTOCOL = IoTHubTransportProvider.MQTT_WS
# String containing Hostname, Device Id in the format:
# "HostName=<host_name>;DeviceId=<device_id>;x509=true"
CONNECTION_STRING = "HostName=hub.azure-devices.net;DeviceId=device;x509=true"
MSG_TXT = "{\"deviceId\": \"device\",\"windSpeed\": %.2f,\"temperature\": %.2f,\"humidity\": %.2f}"
X509_CERTIFICATE = (
'''-----BEGIN CERTIFICATE-----
MIIFtTCCA52gAwIBAgIBAzANBgkqhkiG9w0BAQsFADA0MTIwMAYDVQQDDClBenVy
...
T4kySzeQghCYqpkF06hER0KXTP8shMZedg==
-----END CERTIFICATE-----'''
)
X509_PRIVATEKEY = (
'''-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEAnEOzMmctBZke/1kD+5g/soUTucJ28odMTW2RIlfj4kAhT1gW
...
UOBMkQUpHEBNWtBbQIyJbgrb26P1oec7dk5f2xvg7tHjSZLDOZprdEp8gxU=
-----END RSA PRIVATE KEY-----'''
)
# some embedded platforms need certificate information
def receive_message_callback(message, counter):
global RECEIVE_CALLBACKS
message_buffer = message.get_bytearray()
size = len(message_buffer)
print("Received Message [%d]:" % counter)
print(" Data: <<<%s>>> & Size=%d" % (message_buffer[:size].decode('utf-8'), size))
map_properties = message.properties()
key_value_pair = map_properties.get_internals()
print(" Properties: %s" % key_value_pair)
counter += 1
RECEIVE_CALLBACKS += 1
print(" Total calls received: %d" % RECEIVE_CALLBACKS)
return IoTHubMessageDispositionResult.ACCEPTED
def send_confirmation_callback(message, result, user_context):
global SEND_CALLBACKS
print("Confirmation[%d] received for message with result = %s" % (user_context, result))
map_properties = message.properties()
print(" message_id: %s" % message.message_id)
print(" correlation_id: %s" % message.correlation_id)
key_value_pair = map_properties.get_internals()
print(" Properties: %s" % key_value_pair)
SEND_CALLBACKS += 1
print(" Total calls confirmed: %d" % SEND_CALLBACKS)
def iothub_client_init():
# prepare iothub client
client = IoTHubClient(CONNECTION_STRING, PROTOCOL)
# HTTP specific settings
if client.protocol == IoTHubTransportProvider.HTTP:
client.set_option("timeout", TIMEOUT)
client.set_option("MinimumPollingTime", MINIMUM_POLLING_TIME)
# set the time until a message times out
client.set_option("messageTimeout", MESSAGE_TIMEOUT)
# this brings in x509 privateKey and certificate
client.set_option("x509certificate", X509_CERTIFICATE)
client.set_option("x509privatekey", X509_PRIVATEKEY)
# to enable MQTT logging set to 1
if client.protocol == IoTHubTransportProvider.MQTT:
client.set_option("logtrace", 0)
client.set_message_callback(
receive_message_callback, RECEIVE_CONTEXT)
return client
def print_last_message_time(client):
try:
last_message = client.get_last_message_receive_time()
print("Last Message: %s" % time.asctime(time.localtime(last_message)))
print("Actual time : %s" % time.asctime())
except IoTHubClientError as iothub_client_error:
if iothub_client_error.args[0].result == IoTHubClientResult.INDEFINITE_TIME:
print("No message received")
else:
print(iothub_client_error)
def iothub_client_sample_x509_run():
try:
client = iothub_client_init()
while True:
# send a few messages every minute
print("IoTHubClient sending %d messages" % MESSAGE_COUNT)
for message_counter in range(0, MESSAGE_COUNT):
temperature = MIN_TEMPERATURE + (random.random() * 10)
humidity = MIN_HUMIDITY + (random.random() * 20)
msg_txt_formatted = MSG_TXT % (
AVG_WIND_SPEED + (random.random() * 4 + 2),
temperature,
humidity)
# messages can be encoded as string or bytearray
if (message_counter & 1) == 1:
message = IoTHubMessage(bytearray(msg_txt_formatted, 'utf8'))
else:
message = IoTHubMessage(msg_txt_formatted)
# optional: assign ids
message.message_id = "message_%d" % message_counter
message.correlation_id = "correlation_%d" % message_counter
# optional: assign properties
prop_map = message.properties()
prop_map.add("temperatureAlert", 'true' if temperature > 28 else 'false')
client.send_event_async(message, send_confirmation_callback, message_counter)
print(
"IoTHubClient.send_event_async accepted message [%d] for transmission to IoT Hub." % message_counter)
# Wait for Commands or exit
print("IoTHubClient waiting for commands, press Ctrl-C to exit")
status_counter = 0
while status_counter <= MESSAGE_COUNT:
status = client.get_send_status()
print("Send status: %s" % status)
time.sleep(10)
status_counter += 1
except IoTHubError as iothub_error:
print("Unexpected error %s from IoTHub" % iothub_error)
return
except KeyboardInterrupt:
print("IoTHubClient sample stopped")
print_last_message_time(client)
def usage():
print("Usage: iothub_client_sample.py -p <protocol> -c <connectionstring>")
print(" protocol : <amqp, http, mqtt>")
print(" connectionstring: <HostName=<host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>>")
if __name__ == '__main__':
print("\nPython %s" % sys.version)
# print ( "IoT Hub for Python SDK Version: %s" % iothub_client.__version__ )
try:
(CONNECTION_STRING, PROTOCOL) = get_iothub_opt(sys.argv[1:], CONNECTION_STRING, PROTOCOL)
except OptionError as option_error:
print(option_error)
usage()
sys.exit(1)
print("Starting the IoT Hub Python sample...")
print(" Protocol %s" % PROTOCOL)
print(" Connection string=%s" % CONNECTION_STRING)
iothub_client_sample_x509_run()
成功運行: MQTT_WS(端口443)
IoTHubClient.send_event_async accepted message [0] for transmission to IoT Hub.
Confirmation[0] received for message with result = OK
message_id: message_0
correlation_id: correlation_0
Properties: {'temperatureAlert': 'false'}
Total calls confirmed: 1
運行不成功: MQTT(端口8883)-檢索期間消息超時
IoTHubClient.send_event_async accepted message [0] for transmission to IoT Hub.
Confirmation[0] received for message with result = MESSAGE_TIMEOUT
message_id: message_0
correlation_id: correlation_0
Properties: {'temperatureAlert': 'false'}
Total calls confirmed: 1
運行不成功: AMQP(端口5671)-嘗試連接時出錯,然后出現消息超時
IoTHubClient.send_event_async accepted message [0] for transmission to IoT Hub.
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\iothub_client\src\iothubtransport_amqp_common.c Func:on_amqp_connection_state_changed Line:772 amqp_connection was closed unexpectedly; connection retry will be triggered.
Info: Preparing transport for re-connection
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\iothub_client\src\iothubtransportamqp_methods.c Func:iothubtransportamqp_methods_unsubscribe Line:891 unsubscribe called while not subscribed
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\c-utility\adapters\tlsio_schannel.c Func:send_chunk Line:430 invalid tls_io_instance->tlsio_state: TLSIO_STATE_NOT_OPEN
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\c-utility\adapters\tlsio_schannel.c Func:internal_send Line:525 send_chunk failed
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\c-utility\adapters\tlsio_schannel.c Func:tlsio_schannel_send Line:1263 send failed
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\uamqp\src\connection.c Func:on_bytes_encoded Line:268 Cannot send encoded bytes
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\c-utility\adapters\tlsio_schannel.c Func:tlsio_schannel_close Line:1195 invalid tls_io_instance->tlsio_state = TLSIO_STATE_NOT_OPEN
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\uamqp\src\connection.c Func:on_bytes_encoded Line:272 xio_close failed
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\c-utility\adapters\tlsio_schannel.c Func:tlsio_schannel_close Line:1195 invalid tls_io_instance->tlsio_state = TLSIO_STATE_NOT_OPEN
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\uamqp\src\connection.c Func:connection_close Line:1437 xio_close failed
Error: Time:Tue Aug 21 17:14:37 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\iothub_client\src\iothubtransport_amqp_common.c Func:on_amqp_connection_state_changed Line:772 amqp_connection was closed unexpectedly; connection retry will be triggered.
Info: Preparing transport for re-connection
Confirmation[0] received for message with result = MESSAGE_TIMEOUT
message_id: message_0
correlation_id: correlation_0
Properties: {'temperatureAlert': 'false'}
Total calls confirmed: 1
運行不成功: AMQP_WS(端口443)-嘗試連接時出錯,然后出現消息超時
Same as regular AMQP
運行不成功: HTTP(端口443)-嘗試連接時出錯
IoTHubClient.send_event_async accepted message [0] for transmission to IoT Hub.
Error: Time:Tue Aug 21 17:20:18 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\iothub_client\src\iothubtransporthttp.c Func:DoEvent Line:1700 unexpected HTTP status code (401)
Error: Time:Tue Aug 21 17:20:18 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\iothub_client\src\iothubtransporthttp.c Func:DoMessages Line:2102 expected status code was 200, but actually was received 401... moving on
IoTHubClient.send_event_async accepted message [4] for transmission to IoT Hub.
Error: Time:Tue Aug 21 17:20:18 2018 File:C:\Release\iot-sdks-internals\release\python\automation\aziotsdk_pytools\src\c\iothub_client\src\iothubtransporthttp.c Func:DoEvent Line:1700 unexpected HTTP status code (401)
我在Windows 10計算機上安裝了Python版本3.6.6。
老實說,我不確定是什么導致了此問題。 我不認為這是證書,因為當我將它們與MQTT_WS結合使用時,它們就可以工作。 在測試期間,我嘗試短暫禁用Windows上的防火牆,但這也無濟於事。
此外,這以前工作。 我構建了一個單獨的腳本,該腳本將連接到用戶傳入的協議,並且我的測試腳本將循環遍歷以確保所有功能正常。 我休息了一段時間,努力使這些腳本適用於Mac / Linux。 我遇到了那些平台上的障礙,當我切換回Windows時,意識到它也遇到了同樣的問題。 我沒有更改Azure Hub上的任何內容以阻止某種類型的連接,因此不確定是什么原因導致了此問題。
我嘗試生成新證書並創建新的x509自簽名設備,但是它也遇到了相同的問題:(
希望有人可以提供幫助!
編輯:我能夠通過為IoTHub創建新證書來解決我的問題。 看來我那里的腳本是用測試腳本生成的,所以只用了30天就可以了。 盡管我不了解MQTT_WS協議如何仍然能夠解決並通過它,但這完全是一個單獨的問題。
感謝那些試圖提供幫助的人!
我正在嘗試重現此問題,但是失敗了。 使用最新版本的Python SDK,您提到的所有協議HTTP,MQTT,MQTT_WS,AMQP,AMQP_WS對我來說都很好。
為了縮小此問題的范圍,建議您創建一個新的Azure IoT中心以查看問題是否與Azure IoT中心的特定實例有關。 您可以為測試目的創建一個免費的。
如果該問題與特定的Azure IoT中心無關,則該問題也可能與網絡問題有關。 請檢查端口是否未阻塞,如果您在組織環境中工作,可能需要與IT部門確認。 或者,您可以在另一個網絡環境中進行測試以確認此問題。
以下是測試步驟,可能也對您有所幫助:
通過PowerShell創建X.509自簽名證書
New-SelfSignedCertificate -DnsName“ www.fabrikam.com”,“ www.contoso.com” -CertStoreLocation“ cert:\\ LocalMachine \\ My”
使用下面的命令導出證書和密鑰
openssl pkcs12 -in yourpfxfile.pfx -nokeys -out publiccert.pem -nodes
openssl pkcs12 -in x.pfx -nocerts -nodes -pass pass:123456 | openssl rsa -out privkey.pem
在Azure門戶上添加X.509自簽名證書設備
安裝最新的Azure IoT設備SDK
python -m pip安裝azure-iothub-device-client
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.