Node.js模块与Azure IoT Edge通信报自签名证书链错误如何解决?
问题描述
我正尝试在Azure IoT Edge设备上部署使用Node.js开发的温度数据模拟设备,已按流程生成证书并添加到Node.js模块中,导入证书后模块日志出现如下报错:
Could not connect: mqtt.js returned Failure on first connection (Not authorized): self signed certificate in certificate chain error
我的config.toml配置如下,为排除DNS问题,我先后尝试使用主机名和IP地址配置,得到的报错完全一致:
hostname = "10.90.27.150" trust_bundle_cert = "file:///home/edge/certificates/certs/azure-iot-test-only.root.ca.cert.pem" [edge_ca] cert = "file:///home/edge/certificates/certs/iot-edge-device-ca-10.90.27.150-full-chain.cert.pem" pk = "file:///home/edge/certificates/private/iot-edge-device-ca-10.90.27.150.key.pem"
我使用的模块代码如下:
// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. 'use strict'; var fs = require('fs'); var Protocol = require('azure-iot-device-mqtt').Mqtt; // 取消下方某一传输协议的注释,并在fromConnectionString中修改对应参数即可测试其他传输方式 // var Protocol = require('azure-iot-device-http').Http; // var Protocol = require('azure-iot-device-amqp').Amqp; var Client = require('azure-iot-device').Client; var Message = require('azure-iot-device').Message; // 1) 获取下游设备的连接字符串,并追加字符串GatewayHostName=<edge设备主机名>; // 2) Azure IoT Edge设备主机名是部署本示例的Azure IoT Edge设备config.yaml中设置的主机名 // // 最终生成的连接字符串格式如下: // "HostName=<iothub主机名>;DeviceId=<设备ID>;SharedAccessKey=<设备密钥>;GatewayHostName=<edge设备主机名>" var deviceConnectionString = "HostName=*removed*-devices.net;DeviceId=Virtual_Humidity_Simulator;SharedAccessKey=*removed*;GatewayHostName=10.90.27.150" //process.env.DEVICE_CONNECTION_STRING; // Edge "所有者"根CA证书路径 var edge_ca_cert_path = "./azure-iot-test-only.root.ca.cert.pem"; // fromConnectionString必须指定来自任意传输协议包的传输构造函数 var client = Client.fromConnectionString(deviceConnectionString, Protocol); var connectCallback = function (err) { if (err) { console.error('Could not connect: ' + err.message); } else { console.log('Client connected'); client.on('message', function (msg) { console.log('Id: ' + msg.messageId + ' Body: ' + msg.data); // 使用MQTT时下方代码无操作 client.complete(msg, printResultFor('completed')); // AMQP和HTTP传输协议支持完成、拒绝或放弃消息 // 完成消息时,发送C2D消息的服务会收到消息已处理的通知 // 拒绝消息时,服务会收到消息不会被设备处理的通知,对应方法为client.reject(msg, callback) // 放弃消息时,IoT Hub会立即尝试重发该消息,对应方法为client.abandon(msg, callback) // MQTT逻辑更简单:默认接收消息,不支持拒绝或放弃消息 }); // 每2秒创建一条消息并发送到IoT Hub var sendInterval = setInterval(function () { var windSpeed = 10 + (Math.random() * 4); // 范围: [10, 14] var temperature = 20 + (Math.random() * 10); // 范围: [20, 30] var humidity = 60 + (Math.random() * 20); // 范围: [60, 80] var data = JSON.stringify({ deviceId: 'myFirstDownstreamDevice', windSpeed: windSpeed, temperature: temperature, humidity: humidity }); var message = new Message(data); message.properties.add('temperatureAlert', (temperature > 28) ? 'true' : 'false'); console.log('Sending message: ' + message.getData()); client.sendEvent(message, printResultFor('send')); }, 2000); client.on('error', function (err) { console.error(err.message); }); client.on('disconnect', function () { clearInterval(sendInterval); client.removeAllListeners(); client.open(connectCallback); }); } }; // 通过setOptions方法为Azure IoT设备客户端提供用于设置Edge运行时的X509 Edge根CA证书 var options = { ca : fs.readFileSync(edge_ca_cert_path, 'utf-8'), }; client.setOptions(options, function(err) { if (err) { console.log('SetOptions Error: ' + err); } else { client.open(connectCallback); } }); // 控制台打印结果的辅助函数 function printResultFor(op) { return function printResult(err, res) { if (err) console.log(op + ' error: ' + err.toString()); if (res) console.log(op + ' status: ' + res.constructor.name); }; }
我已尝试按照官方文档生成测试证书、创建设备CA证书的步骤操作,问题仍未解决,请问操作存在什么问题?有没有更清晰的指导方案?
故障排查与解决方案
问题根因
该自签名证书链报错核心是Node.js客户端未正确信任Edge设备的CA证书,或证书本身配置不符合要求,按以下步骤逐一排查即可解决:
排查步骤
- 证书路径与读取校验
- 先在模块运行目录下执行
ls ./azure-iot-test-only.root.ca.cert.pem,确认证书文件存在且有可读权限,不要用相对路径,改为证书的绝对路径,比如你主机上的/home/edge/certificates/certs/azure-iot-test-only.root.ca.cert.pem,避免模块工作目录变化导致读不到证书。 - 读取证书内容校验合法性:执行
openssl x509 -in 证书路径 -text -noout,确认证书的有效期、CN字段无异常,且是你生成的根CA证书。
- Edge设备CA证书配置校验
- 你配置的
iot-edge-device-ca-10.90.27.150-full-chain.cert.pem必须包含完整的证书链:设备CA证书 + 根CA证书,不要只放单独的设备CA证书。 - 配置完
config.toml后要重启IoT Edge服务:sudo systemctl restart iotedge,执行sudo iotedge check确认所有证书相关的检查项都是绿色通过状态,没有警告或报错。
- Node.js客户端额外配置
- Node.js的TLS栈默认会拒绝不在系统信任库的自签名证书,你除了配置
ca参数外,可以先在代码最开头加一行环境变量配置:process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";测试是否是证书信任逻辑的问题(注意仅测试用,生产环境不要开启),如果加了之后能连通,就确定是证书信任的问题。 - 如果你用的是Azure IoT Node.js SDK v1.18以上版本,需要额外配置MQTT的传输选项,将options修改为:
var options = { ca : fs.readFileSync(edge_ca_cert_path, 'utf-8'), mqtt: { rejectUnauthorized: true } };
- 连接字符串与设备注册校验
- 确认IoT Hub上注册的
Virtual_Humidity_Simulator设备的父设备已经设置为你当前的IoT Edge设备,且设备是启用状态。 - 确认连接字符串里的GatewayHostName的值,和你Edge设备config.toml里的hostname完全一致,你这里用的是IP就保持两边都是相同的IP。
验证步骤
所有配置修改完成后,先在主机上用MQTT客户端工具测试连接:
mosquitto_pub -h 10.90.27.150 -p 8883 --cafile /home/edge/certificates/certs/azure-iot-test-only.root.ca.cert.pem -u "你的IoT Hub名称.azure-devices.net/Virtual_Humidity_Simulator/?api-version=2021-04-12" -P "你的设备SAS密钥" -t "devices/Virtual_Humidity_Simulator/messages/events/" -m "test"
如果能成功发送消息,再重新打包Node.js模块部署即可。
内容的提问来源于stack exchange,提问作者Alovantous
相关产品推荐
相关产品推荐

