你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
IoT Central 支持共享访问签名(SAS)和 X.509 证书,以保护设备与应用程序之间的通信。 创建客户端应用程序并将其连接到 Azure IoT Central 应用程序教程使用 SAS。 本文介绍如何修改代码示例以使用 X.509 证书。 建议在生产环境中使用 X.509 证书。 有关详细信息,请参阅 IoT Central 中的设备身份验证概念。
本指南介绍了使用 X.509 证书的两种方法 - 组注册 通常用于生产环境,以及 各个注册 适合用于测试。 本文还介绍如何 滚动更新设备证书 ,以在证书过期时保持连接。
本指南基于创建和将客户端应用程序连接到使用 C#、Java、JavaScript 和 Python 的 Azure IoT Central 应用程序 教程中所示的示例。 有关使用 C 编程语言的示例,请参阅 使用注册组教程预配多个 X.509 设备 。
先决条件
若要完成本作指南中的步骤,应首先完成 创建客户端应用程序并将客户端应用程序连接到 Azure IoT Central 应用程序 教程。 按照本指南中的步骤修改本教程中使用的代码。
本指南将在此过程中生成一些测试用的 X.509 证书。 若要生成这些证书,需要:
- 安装了 Node.js 版本 6 或更高版本的开发计算机。 可以在命令行中运行
node --version以检查版本。 本教程中的说明假定你在 Windows 命令提示符处运行 node 命令。 但是,可以在许多其他作系统上使用 Node.js。 - 用于 Node.jsGitHub 存储库Microsoft Azure IoT SDK 的本地副本,其中包含用于生成测试 X.509 证书的脚本。 使用此链接下载存储库的副本: 下载 ZIP。 然后将文件解压缩到本地计算机上的合适位置。
使用组注册
在生产环境中将 X.509 证书与组注册配合使用。 在组注册中,将根证书或中间 X.509 证书添加到 IoT Central 应用程序。 具有派生自根证书或中间证书的叶证书的设备可以连接到你的应用程序。
生成根证书和设备证书
在本部分中,您将使用 X.509 证书连接设备,该证书是从 IoT Central 注册组的证书派生的。
警告
生成 X.509 证书的这种方式仅用于测试。 对于生产环境,应使用官方的安全机制生成证书。
导航到已下载Microsoft Azure IoT SDK 中用于 Node.js 的证书生成器脚本。 安装所需的包:
cd azure-iot-sdk-node/provisioning/tools npm install创建根证书,然后通过运行脚本来派生设备证书:
node create_test_cert.js root mytestrootcert node create_test_cert.js device sample-device-01 mytestrootcert小窍门
设备 ID 可以包含字母、数字和
-字符。
这些命令生成以下根证书和设备证书:
| filename | 内容 |
|---|---|
| mytestrootcert_cert.pem | 根 X509 证书的公钥部分 |
| mytestrootcert_key.pem | 根 X509 证书的私钥 |
| mytestrootcert_fullchain.pem | 根 X509 证书的整个密钥链。 |
| mytestrootcert.pfx | 根 X509 证书的 PFX 文件。 |
| sampleDevice01_cert.pem | 设备 X509 证书的公用部分 |
| sampleDevice01_key.pem | 设备 X509 证书的私钥 |
| sampleDevice01_fullchain.pem | 设备 X509 证书的整个密钥链。 |
| sampleDevice01.pfx | 设备 X509 证书的 PFX 文件。 |
记下这些文件的位置。 稍后需要用到此信息。
创建小组注册
打开 IoT Central 应用程序并导航到左侧窗格中 的权限 ,然后选择 “设备连接组”。
选择“+ 新建”以创建名为 MyX509Group 的新注册组,其证明类型为“证书”(X.509)。 可以为 IoT 设备或 IoT Edge 设备创建注册组。
在创建的注册组中,选择“ 管理主数据库”。
在 “主证书 ”面板中,选择“ 添加证书”。
上传前面生成的 名为 mytestrootcert_cert.pem 的根证书文件。
如果您使用的是您信任的中间或根证书颁发机构,并且确信您拥有该证书的完全所有权,那么您可以通过将上传时的证书状态设置为On,自我声明您已验证了证书。 否则,将证书状态在上传时设置为Off。
如果将上传后验证的证书状态设置为 “关闭”,请选择“ 生成验证码”。
复制验证码,复制它,然后创建 X.509 验证证书。 例如,在命令提示符处:
node create_test_cert.js verification --ca mytestrootcert_cert.pem --key mytestrootcert_key.pem --nonce {verification-code}选择“验证”以上传已签名的验证证书verification_cert.pem以完成验证。
主证书的状态现已 验证:
现在可以连接具有派生自此主根证书的 X.509 证书的设备。
保存注册组后,记下 ID 范围。 稍后需要用到此信息。
运行示例设备代码
如果使用 Windows,X.509 证书必须位于 Windows 证书存储中,才能使示例正常工作。 在 Windows 资源管理器中,双击之前生成的 PFX 文件mytestrootcert.pfx 和 sampleDevice01.pfx。 在 “证书导入向导”中,选择 “当前用户 ”作为存储位置,输入 1234 为密码,让向导自动选择证书存储。 向导将证书导入当前用户的个人存储。
若要修改示例代码以使用 X.509 证书:
在 IoTHubDeviceSamples Visual Studio 解决方案中,打开 TemperatureController 项目中Parameter.cs文件。
将以下两个参数定义添加到类:
[Option( 'x', "CertificatePath", HelpText = "(Required if DeviceSecurityType is \"dps\"). \nThe device PFX file to use during device provisioning." + "\nDefaults to environment variable \"IOTHUB_DEVICE_X509_CERT\".")] public string CertificatePath { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_X509_CERT"); [Option( 'p', "CertificatePassword", HelpText = "(Required if DeviceSecurityType is \"dps\"). \nThe password of the PFX certificate file." + "\nDefaults to environment variable \"IOTHUB_DEVICE_X509_PASSWORD\".")] public string CertificatePassword { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_X509_PASSWORD");保存更改。
在 IoTHubDeviceSamples Visual Studio 解决方案中,打开 TemperatureController 项目中的Program.cs文件。
添加以下
using语句:using System.Security.Cryptography.X509Certificates; using System.IO;将以下方法添加到类:
private static X509Certificate2 LoadProvisioningCertificate(Parameters parameters) { var certificateCollection = new X509Certificate2Collection(); certificateCollection.Import( parameters.CertificatePath, parameters.CertificatePassword, X509KeyStorageFlags.UserKeySet); X509Certificate2 certificate = null; foreach (X509Certificate2 element in certificateCollection) { Console.WriteLine($"Found certificate: {element?.Thumbprint} {element?.Subject}; PrivateKey: {element?.HasPrivateKey}"); if (certificate == null && element.HasPrivateKey) { certificate = element; } else { element.Dispose(); } } if (certificate == null) { throw new FileNotFoundException($"{parameters.CertificatePath} did not contain any certificate with a private key."); } Console.WriteLine($"Using certificate {certificate.Thumbprint} {certificate.Subject}"); return certificate; }SetupDeviceClientAsync方法中,将case "dps"的代码块替换为以下代码:case "dps": s_logger.LogDebug($"Initializing via DPS"); Console.WriteLine($"Loading the certificate..."); X509Certificate2 certificate = LoadProvisioningCertificate(parameters); DeviceRegistrationResult dpsRegistrationResult = await ProvisionDeviceAsync(parameters, certificate, cancellationToken); var authMethod = new DeviceAuthenticationWithX509Certificate(dpsRegistrationResult.DeviceId, certificate); deviceClient = InitializeDeviceClient(dpsRegistrationResult.AssignedHub, authMethod); break;将
ProvisionDeviceAsync该方法替换为以下代码:private static async Task<DeviceRegistrationResult> ProvisionDeviceAsync(Parameters parameters, X509Certificate2 certificate, CancellationToken cancellationToken) { SecurityProvider security = new SecurityProviderX509Certificate(certificate); ProvisioningTransportHandler mqttTransportHandler = new ProvisioningTransportHandlerMqtt(); ProvisioningDeviceClient pdc = ProvisioningDeviceClient.Create(parameters.DpsEndpoint, parameters.DpsIdScope, security, mqttTransportHandler); var pnpPayload = new ProvisioningRegistrationAdditionalData { JsonData = PnpConvention.CreateDpsPayload(ModelId), }; return await pdc.RegisterAsync(pnpPayload, cancellationToken); }保存更改。
若要运行该示例:
将以下环境变量添加到项目:
-
IOTHUB_DEVICE_X509_CERT:<full path to folder that contains PFX files>sampleDevice01.pfx -
IOTHUB_DEVICE_X509_PASSWORD: 1234.
-
生成并运行应用程序。 验证设备预配是否成功。
若要修改示例代码以使用 X.509 证书:
导航到 azure-iot-sdk-java/device/iot-device-samples/pnp-device-sample/temperature-controller-device-sample 文件夹,其中包含温度控制器设备示例 的pom.xml 文件和 src 文件夹。
编辑 pom.xml 文件,在节点中添加以下依赖项配置
<dependencies>:<dependency> <groupId>com.microsoft.azure.sdk.iot.provisioning.security</groupId> <artifactId>${x509-provider-artifact-id}</artifactId> <version>${x509-provider-version}</version> </dependency>保存更改。
在文本编辑器中打开 src/main/java/samples/com/microsoft/azure/sdk/iot/device/TemperatureController.java 文件。
将
SecurityProviderSymmetricKey导入替换为以下导入:import com.microsoft.azure.sdk.iot.provisioning.security.SecurityProvider; import com.microsoft.azure.sdk.iot.provisioning.security.hsm.SecurityProviderX509Cert; import com.microsoft.azure.sdk.iot.provisioning.security.exceptions.SecurityProviderException;添加以下导入:
import java.nio.file.*;将
main添加到SecurityProviderException方法抛出的异常列表中:public static void main(String[] args) throws IOException, URISyntaxException, ProvisioningDeviceClientException, InterruptedException, SecurityProviderException {将
initializeAndProvisionDevice该方法替换为以下代码:private static void initializeAndProvisionDevice() throws ProvisioningDeviceClientException, IOException, URISyntaxException, InterruptedException, SecurityProviderException { String deviceX509Key = new String(Files.readAllBytes(Paths.get(System.getenv("IOTHUB_DEVICE_X509_KEY")))); String deviceX509Cert = new String(Files.readAllBytes(Paths.get(System.getenv("IOTHUB_DEVICE_X509_CERT")))); SecurityProvider securityProviderX509 = new SecurityProviderX509Cert(deviceX509Cert, deviceX509Key, null); ProvisioningDeviceClient provisioningDeviceClient; ProvisioningStatus provisioningStatus = new ProvisioningStatus(); provisioningDeviceClient = ProvisioningDeviceClient.create(globalEndpoint, scopeId, provisioningProtocol, securityProviderX509); AdditionalData additionalData = new AdditionalData(); additionalData.setProvisioningPayload(com.microsoft.azure.sdk.iot.provisioning.device.plugandplay.PnpHelper.createDpsPayload(MODEL_ID)); provisioningDeviceClient.registerDevice(new ProvisioningDeviceClientRegistrationCallbackImpl(), provisioningStatus, additionalData); while (provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getProvisioningDeviceClientStatus() != ProvisioningDeviceClientStatus.PROVISIONING_DEVICE_STATUS_ASSIGNED) { if (provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getProvisioningDeviceClientStatus() == ProvisioningDeviceClientStatus.PROVISIONING_DEVICE_STATUS_ERROR || provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getProvisioningDeviceClientStatus() == ProvisioningDeviceClientStatus.PROVISIONING_DEVICE_STATUS_DISABLED || provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getProvisioningDeviceClientStatus() == ProvisioningDeviceClientStatus.PROVISIONING_DEVICE_STATUS_FAILED) { provisioningStatus.exception.printStackTrace(); System.out.println("Registration error, bailing out"); break; } System.out.println("Waiting for Provisioning Service to register"); Thread.sleep(MAX_TIME_TO_WAIT_FOR_REGISTRATION); } ClientOptions options = new ClientOptions(); options.setModelId(MODEL_ID); if (provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getProvisioningDeviceClientStatus() == ProvisioningDeviceClientStatus.PROVISIONING_DEVICE_STATUS_ASSIGNED) { System.out.println("IotHUb Uri : " + provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getIothubUri()); System.out.println("Device ID : " + provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getDeviceId()); String iotHubUri = provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getIothubUri(); String deviceId = provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getDeviceId(); log.debug("Opening the device client."); deviceClient = DeviceClient.createFromSecurityProvider(iotHubUri, deviceId, securityProviderX509, IotHubClientProtocol.MQTT, options); deviceClient.open(); } }保存更改。
若要运行该示例:
在 shell 环境中,添加以下两个环境变量。 请确保提供 PEM 文件的完整路径,并为作系统使用正确的路径分隔符:
set IOTHUB_DEVICE_X509_CERT=<full path to folder that contains PEM files>sampleDevice01_cert.pem set IOTHUB_DEVICE_X509_KEY=<full path to folder that contains PEM files>sampleDevice01_key.pem小窍门
完成 创建并将客户端应用程序连接到 Azure IoT Central 应用程序 教程时,请设置其他必需的环境变量。
生成并运行应用程序。 验证设备预配是否成功。
若要修改示例代码以使用 X.509 证书:
导航到包含 pnp_temperature_controller.js 应用程序的 azure-iot-sdk-node/device/samples/javascript 文件夹,并运行以下命令安装 X.509 包:
npm install azure-iot-security-x509 --save在文本编辑器中打开 pnp_temperature_controller.js 文件。
编辑
require中的语句以包含以下代码:const fs = require('fs'); const X509Security = require('azure-iot-security-x509').X509Security;将以下四行添加到“DPS 连接信息”部分以初始化
deviceCert变量:const deviceCert = { cert: fs.readFileSync(process.env.IOTHUB_DEVICE_X509_CERT).toString(), key: fs.readFileSync(process.env.IOTHUB_DEVICE_X509_KEY).toString() };通过将
provisionDevice第一行替换为以下代码来编辑创建客户端的函数:var provSecurityClient = new X509Security(registrationId, deviceCert);在同一函数中,修改设置
deviceConnectionString变量的行,如下所示:deviceConnectionString = 'HostName=' + result.assignedHub + ';DeviceId=' + result.deviceId + ';x509=true';在函数中
main,在调用Client.fromConnectionString的行后面添加以下行:client.setOptions(deviceCert);保存更改。
若要运行该示例:
在 shell 环境中,添加以下两个环境变量。 请确保提供 PEM 文件的完整路径,并为作系统使用正确的路径分隔符:
set IOTHUB_DEVICE_X509_CERT=<full path to folder that contains PEM files>sampleDevice01_cert.pem set IOTHUB_DEVICE_X509_KEY=<full path to folder that contains PEM files>sampleDevice01_key.pem小窍门
完成 创建并将客户端应用程序连接到 Azure IoT Central 应用程序 教程时,请设置其他必需的环境变量。
执行脚本并验证设备预配是否成功:
node pnp_temperature_controller.js
若要修改示例代码以使用 X.509 证书:
导航到 azure-iot-device/samples/pnp 文件夹,并在文本编辑器中打开 temp_controller_with_thermostats.py 文件。
添加以下
from语句以导入 X.509 功能:from azure.iot.device import X509将函数
provision_device的第一部分修改如下:async def provision_device(provisioning_host, id_scope, registration_id, x509, model_id): provisioning_device_client = ProvisioningDeviceClient.create_from_x509_certificate( provisioning_host=provisioning_host, registration_id=registration_id, id_scope=id_scope, x509=x509, )在函数中
main,将设置symmetric_key变量的行替换为以下代码:x509 = X509( cert_file=os.getenv("IOTHUB_DEVICE_X509_CERT"), key_file=os.getenv("IOTHUB_DEVICE_X509_KEY"), )在
main函数中,将对函数的provision_device调用替换为以下代码:registration_result = await provision_device( provisioning_host, id_scope, registration_id, x509, model_id )在
main函数中,将对函数的IoTHubDeviceClient.create_from_symmetric_key调用替换为以下代码:device_client = IoTHubDeviceClient.create_from_x509_certificate( x509=x509, hostname=registration_result.registration_state.assigned_hub, device_id=registration_result.registration_state.device_id, product_info=model_id, )保存更改。
若要运行该示例:
在 shell 环境中,添加以下两个环境变量。 请确保提供 PEM 文件的完整路径,并为作系统使用正确的路径分隔符:
set IOTHUB_DEVICE_X509_CERT=<full path to folder that contains PEM files>sampleDevice01_cert.pem set IOTHUB_DEVICE_X509_KEY=<full path to folder that contains PEM files>sampleDevice01_key.pem小窍门
完成 创建并将客户端应用程序连接到 Azure IoT Central 应用程序 教程时,请设置其他必需的环境变量。
执行脚本并验证设备预配是否成功:
python temp_controller_with_thermostats.py
验证遥测是否显示在 IoT Central 应用程序中的设备视图中:
使用个人注册
将 X.509 证书与单个注册配合使用来测试设备和解决方案。 在单独注册中,IoT Central 应用程序中没有根或中间 X.509 证书。 设备使用自签名 X.509 证书连接到应用程序。
生成自签名设备证书
本部分将使用自签名的 X.509 证书连接用于单独注册的设备,单独注册用于注册单个设备。 自签名证书仅用于测试。
警告
生成 X.509 证书的这种方式仅用于测试。 对于生产环境,应使用官方的安全机制生成证书。
运行以下命令创建自签名 X.509 设备证书:
cd azure-iot-sdk-node/provisioning/tools
node create_test_cert.js device mytestselfcertprimary
node create_test_cert.js device mytestselfcertsecondary
小窍门
设备 ID 可以包含字母、数字和 - 字符。
这些命令生成以下设备证书:
| filename | 内容 |
|---|---|
| mytestselfcertprimary_cert.pem | 主设备 X509 证书的公共部分 |
| mytestselfcertprimary_key.pem | 主设备 X509 证书的私钥 |
| mytestselfcertprimary_fullchain.pem | 主设备 X509 证书的整个密钥链。 |
| mytestselfcertprimary.pfx | 主设备 X509 证书的 PFX 文件。 |
| mytestselfcertsecondary_cert.pem | 辅助设备 X509 证书的公开部分 |
| mytestselfcertsecondary_key.pem | 辅助设备 X509 证书的私钥 |
| mytestselfcertsecondary_fullchain.pem | 次要设备 X509 证书的整个密钥链。 |
| mytestselfcertsecondary.pfx | 辅助设备 X509 证书的 PFX 文件。 |
创建单个注册
在 Azure IoT Central 应用程序中,选择 “设备”,并从恒温器设备模板创建 设备 ID 作为 mytestselfcertprimary 的新设备。 记下 ID 范围,稍后使用。
打开创建的设备,然后选择 “连接”。
选择 “个人注册 ”作为 “身份验证类型 ”和 “证书”(X.509) 作为 身份验证方法。
上传之前作为主证书生成的 mytestselfcertprimary_cert.pem 文件。
将您之前生成的 mytestselfcertsecondary_cert.pem 文件上传为辅助证书。 然后,选择“保存”。
设备现在有一个使用 X.509 证书的单独注册。
运行示例单独注册设备
如果使用 Windows,X.509 证书必须位于 Windows 证书存储中,才能使示例正常工作。 在 Windows 资源管理器中,双击之前生成的 PFX 文件mytestselfcertprimary.pfx和mytestselfcertsecondary.pfx。 在 “证书导入向导”中,选择 “当前用户 ”作为存储位置,输入 1234 为密码,让向导自动选择证书存储。 向导将证书导入当前用户的个人存储。
若要修改示例代码以使用 X.509 证书:
在 IoTHubDeviceSamples Visual Studio 解决方案中,打开 TemperatureController 项目中Parameter.cs文件。
将以下两个参数定义添加到类:
[Option( 'x', "CertificatePath", HelpText = "(Required if DeviceSecurityType is \"dps\"). \nThe device PFX file to use during device provisioning." + "\nDefaults to environment variable \"IOTHUB_DEVICE_X509_CERT\".")] public string CertificatePath { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_X509_CERT"); [Option( 'p', "CertificatePassword", HelpText = "(Required if DeviceSecurityType is \"dps\"). \nThe password of the PFX certificate file." + "\nDefaults to environment variable \"IOTHUB_DEVICE_X509_PASSWORD\".")] public string CertificatePassword { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_X509_PASSWORD");保存更改。
在 IoTHubDeviceSamples Visual Studio 解决方案中,打开 TemperatureController 项目中的Program.cs文件。
添加以下
using语句:using System.Security.Cryptography.X509Certificates; using System.IO;将以下方法添加到类:
private static X509Certificate2 LoadProvisioningCertificate(Parameters parameters) { var certificateCollection = new X509Certificate2Collection(); certificateCollection.Import( parameters.CertificatePath, parameters.CertificatePassword, X509KeyStorageFlags.UserKeySet); X509Certificate2 certificate = null; foreach (X509Certificate2 element in certificateCollection) { Console.WriteLine($"Found certificate: {element?.Thumbprint} {element?.Subject}; PrivateKey: {element?.HasPrivateKey}"); if (certificate == null && element.HasPrivateKey) { certificate = element; } else { element.Dispose(); } } if (certificate == null) { throw new FileNotFoundException($"{parameters.CertificatePath} did not contain any certificate with a private key."); } Console.WriteLine($"Using certificate {certificate.Thumbprint} {certificate.Subject}"); return certificate; }在
SetupDeviceClientAsync方法中,将case "dps"代码块替换为以下代码:case "dps": s_logger.LogDebug($"Initializing via DPS"); Console.WriteLine($"Loading the certificate..."); X509Certificate2 certificate = LoadProvisioningCertificate(parameters); DeviceRegistrationResult dpsRegistrationResult = await ProvisionDeviceAsync(parameters, certificate, cancellationToken); var authMethod = new DeviceAuthenticationWithX509Certificate(dpsRegistrationResult.DeviceId, certificate); deviceClient = InitializeDeviceClient(dpsRegistrationResult.AssignedHub, authMethod); break;将
ProvisionDeviceAsync该方法替换为以下代码:private static async Task<DeviceRegistrationResult> ProvisionDeviceAsync(Parameters parameters, X509Certificate2 certificate, CancellationToken cancellationToken) { SecurityProvider security = new SecurityProviderX509Certificate(certificate); ProvisioningTransportHandler mqttTransportHandler = new ProvisioningTransportHandlerMqtt(); ProvisioningDeviceClient pdc = ProvisioningDeviceClient.Create(parameters.DpsEndpoint, parameters.DpsIdScope, security, mqttTransportHandler); var pnpPayload = new ProvisioningRegistrationAdditionalData { JsonData = PnpConvention.CreateDpsPayload(ModelId), }; return await pdc.RegisterAsync(pnpPayload, cancellationToken); }保存更改。
若要运行该示例:
将以下环境变量添加到项目:
-
IOTHUB_DEVICE_DPS_DEVICE_ID:mytestselfcertprimary -
IOTHUB_DEVICE_X509_CERT:<full path to folder that contains PFX files>mytestselfcertprimary.pfx -
IOTHUB_DEVICE_X509_PASSWORD: 1234.
-
生成并运行应用程序。 验证设备预配是否成功。
若要修改示例代码以使用 X.509 证书:
导航到 azure-iot-sdk-java/device/iot-device-samples/pnp-device-sample/temperature-controller-device-sample 文件夹,其中包含温度控制器设备示例 的pom.xml 文件和 src 文件夹。
编辑 pom.xml 文件,在节点中添加以下依赖项配置
<dependencies>:<dependency> <groupId>com.microsoft.azure.sdk.iot.provisioning.security</groupId> <artifactId>${x509-provider-artifact-id}</artifactId> <version>${x509-provider-version}</version> </dependency>保存更改。
在文本编辑器中打开 src/main/java/samples/com/microsoft/azure/sdk/iot/device/TemperatureController.java 文件。
将
SecurityProviderSymmetricKey导入替换为以下导入:import com.microsoft.azure.sdk.iot.provisioning.security.SecurityProvider; import com.microsoft.azure.sdk.iot.provisioning.security.hsm.SecurityProviderX509Cert; import com.microsoft.azure.sdk.iot.provisioning.security.exceptions.SecurityProviderException;添加以下导入:
import java.nio.file.*;将
SecurityProviderException添加到main方法引发的异常列表中。public static void main(String[] args) throws IOException, URISyntaxException, ProvisioningDeviceClientException, InterruptedException, SecurityProviderException {将
initializeAndProvisionDevice该方法替换为以下代码:private static void initializeAndProvisionDevice() throws ProvisioningDeviceClientException, IOException, URISyntaxException, InterruptedException, SecurityProviderException { String deviceX509Key = new String(Files.readAllBytes(Paths.get(System.getenv("IOTHUB_DEVICE_X509_KEY")))); String deviceX509Cert = new String(Files.readAllBytes(Paths.get(System.getenv("IOTHUB_DEVICE_X509_CERT")))); SecurityProvider securityProviderX509 = new SecurityProviderX509Cert(deviceX509Cert, deviceX509Key, null); ProvisioningDeviceClient provisioningDeviceClient; ProvisioningStatus provisioningStatus = new ProvisioningStatus(); provisioningDeviceClient = ProvisioningDeviceClient.create(globalEndpoint, scopeId, provisioningProtocol, securityProviderX509); AdditionalData additionalData = new AdditionalData(); additionalData.setProvisioningPayload(com.microsoft.azure.sdk.iot.provisioning.device.plugandplay.PnpHelper.createDpsPayload(MODEL_ID)); provisioningDeviceClient.registerDevice(new ProvisioningDeviceClientRegistrationCallbackImpl(), provisioningStatus, additionalData); while (provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getProvisioningDeviceClientStatus() != ProvisioningDeviceClientStatus.PROVISIONING_DEVICE_STATUS_ASSIGNED) { if (provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getProvisioningDeviceClientStatus() == ProvisioningDeviceClientStatus.PROVISIONING_DEVICE_STATUS_ERROR || provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getProvisioningDeviceClientStatus() == ProvisioningDeviceClientStatus.PROVISIONING_DEVICE_STATUS_DISABLED || provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getProvisioningDeviceClientStatus() == ProvisioningDeviceClientStatus.PROVISIONING_DEVICE_STATUS_FAILED) { provisioningStatus.exception.printStackTrace(); System.out.println("Registration error, bailing out"); break; } System.out.println("Waiting for Provisioning Service to register"); Thread.sleep(MAX_TIME_TO_WAIT_FOR_REGISTRATION); } ClientOptions options = new ClientOptions(); options.setModelId(MODEL_ID); if (provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getProvisioningDeviceClientStatus() == ProvisioningDeviceClientStatus.PROVISIONING_DEVICE_STATUS_ASSIGNED) { System.out.println("IotHUb Uri : " + provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getIothubUri()); System.out.println("Device ID : " + provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getDeviceId()); String iotHubUri = provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getIothubUri(); String deviceId = provisioningStatus.provisioningDeviceClientRegistrationInfoClient.getDeviceId(); log.debug("Opening the device client."); deviceClient = DeviceClient.createFromSecurityProvider(iotHubUri, deviceId, securityProviderX509, IotHubClientProtocol.MQTT, options); deviceClient.open(); } }保存更改。
若要运行该示例:
在 shell 环境中,添加以下两个环境变量。 请确保提供 PEM 文件的完整路径,并为作系统使用正确的路径分隔符:
set IOTHUB_DEVICE_DPS_DEVICE_ID=mytestselfcertprimary set IOTHUB_DEVICE_X509_CERT=<full path to folder that contains PEM files>mytestselfcertprimary_cert.pem set IOTHUB_DEVICE_X509_KEY=<full path to folder that contains PEM files>mytestselfcertprimary_key.pem小窍门
完成 创建并将客户端应用程序连接到 Azure IoT Central 应用程序 教程时,请设置其他必需的环境变量。
生成并运行应用程序。 验证设备预配是否成功。
也可以对 mytestselfcertsecondary 证书重复上述步骤。
若要修改示例代码以使用 X.509 证书:
导航到包含 pnp_temperature_controller.js 应用程序的 azure-iot-sdk-node/device/samples/javascript 文件夹,并运行以下命令安装 X.509 包:
npm install azure-iot-security-x509 --save在文本编辑器中打开 pnp_temperature_controller.js 文件。
编辑
require中的语句以包含以下代码:const fs = require('fs'); const X509Security = require('azure-iot-security-x509').X509Security;将以下四行添加到“DPS 连接信息”部分以初始化
deviceCert变量:const deviceCert = { cert: fs.readFileSync(process.env.IOTHUB_DEVICE_X509_CERT).toString(), key: fs.readFileSync(process.env.IOTHUB_DEVICE_X509_KEY).toString() };通过将
provisionDevice第一行替换为以下代码来编辑创建客户端的函数:var provSecurityClient = new X509Security(registrationId, deviceCert);在同一函数中,修改设置
deviceConnectionString变量的行,如下所示:deviceConnectionString = 'HostName=' + result.assignedHub + ';DeviceId=' + result.deviceId + ';x509=true';在函数中
main,在调用Client.fromConnectionString的行后面添加以下行:client.setOptions(deviceCert);保存更改。
若要运行该示例:
在 shell 环境中,添加以下两个环境变量。 请确保提供 PEM 文件的完整路径,并为作系统使用正确的路径分隔符:
set IOTHUB_DEVICE_DPS_DEVICE_ID=mytestselfcertprimary set IOTHUB_DEVICE_X509_CERT=<full path to folder that contains PEM files>mytestselfcertprimary_cert.pem set IOTHUB_DEVICE_X509_KEY=<full path to folder that contains PEM files>mytestselfcertprimary_key.pem小窍门
完成 创建并将客户端应用程序连接到 Azure IoT Central 应用程序 教程时,请设置其他必需的环境变量。
执行脚本并验证设备预配是否成功:
node pnp_temperature_controller.js
也可以对 mytestselfcertsecondary 证书重复上述步骤。
若要修改示例代码以使用 X.509 证书:
导航到 azure-iot-device/samples/pnp 文件夹,并在文本编辑器中打开 temp_controller_with_thermostats.py 文件。
添加以下
from语句以导入 X.509 功能:from azure.iot.device import X509将函数
provision_device的第一部分修改如下:async def provision_device(provisioning_host, id_scope, registration_id, x509, model_id): provisioning_device_client = ProvisioningDeviceClient.create_from_x509_certificate( provisioning_host=provisioning_host, registration_id=registration_id, id_scope=id_scope, x509=x509, )在函数中
main,将设置symmetric_key变量的行替换为以下代码:x509 = X509( cert_file=os.getenv("IOTHUB_DEVICE_X509_CERT"), key_file=os.getenv("IOTHUB_DEVICE_X509_KEY"), )在
main函数中,将对函数的provision_device调用替换为以下代码:registration_result = await provision_device( provisioning_host, id_scope, registration_id, x509, model_id )在
main函数中,将对函数的IoTHubDeviceClient.create_from_symmetric_key调用替换为以下代码:device_client = IoTHubDeviceClient.create_from_x509_certificate( x509=x509, hostname=registration_result.registration_state.assigned_hub, device_id=registration_result.registration_state.device_id, product_info=model_id, )保存更改。
若要运行该示例:
在 shell 环境中,添加以下两个环境变量。 请确保提供 PEM 文件的完整路径,并为作系统使用正确的路径分隔符:
set IOTHUB_DEVICE_DPS_DEVICE_ID=mytestselfcertprimary set IOTHUB_DEVICE_X509_CERT=<full path to folder that contains PEM files>mytestselfcertprimary_cert.pem set IOTHUB_DEVICE_X509_KEY=<full path to folder that contains PEM files>mytestselfcertprimary_key.pem小窍门
完成 创建并将客户端应用程序连接到 Azure IoT Central 应用程序 教程时,请设置其他必需的环境变量。
执行脚本并验证设备预配是否成功:
python temp_controller_with_thermostats.py
也可以对 mytestselfcertsecondary 证书重复上述步骤。
连接 IoT Edge 设备
本部分假定你正在使用组注册来连接 IoT Edge 设备。 请按照前面部分的步骤操作:
若要使用 X.509 设备证书将 IoT Edge 设备连接到 IoT Central,请执行以下作:
将设备证书和密钥文件复制到 IoT Edge 设备上。 在前面的组注册示例中,这些文件称为 sampleDevice01_key.pem 和 sampleDevice01_cert.pem。
在 IoT Edge 设备上,编辑
provisioning/etc/aziot/config.toml 配置文件中的部分,如下所示:# DPS X.509 provisioning configuration provisioning: source: "dps" global_endpoint: "https://global.azure-devices-provisioning.net" scope_id: "<SCOPE_ID>" attestation: method: "x509" # registration_id: "<OPTIONAL REGISTRATION ID. LEAVE COMMENTED OUT TO REGISTER WITH CN OF identity_cert>" identity_cert: "file:///<path>/sampleDevice01_cert.pem" identity_pk: "file:///<path>/sampleDevice01_key.pem" # always_reprovision_on_startup: true # dynamic_reprovisioning: false [provisioning] source = "dps" global_endpoint = "https://global.azure-devices-provisioning.net" id_scope = "<SCOPE_ID>" [provisioning.attestation] method = "x509" registration_id = "env-sens-001" identity_pk = "file:///<path>/envSens001_key.pem" identity_cert = "file:///<path>/envSens001_cert.pem"小窍门
无需为
registration_id.. 添加值。 IoT Edge 可以使用 X.509 证书中的 CN 值。运行以下命令以重启 IoT Edge 运行时:
sudo iotedge config apply
若要了解详细信息,请参阅 使用 X.509 证书在 Linux 上大规模创建和预配 IoT Edge 设备。
将下游设备连接到 IoT Edge
IoT Edge 使用 X.509 证书来保护下游设备与充当透明网关的 IoT Edge 设备之间的连接。 若要详细了解如何配置此方案,请参阅 将下游设备连接到 Azure IoT Edge 网关。
滚动更新 X.509 设备证书
在 IoT Central 应用程序的生命周期内,可能需要更新 X.509 证书。 例如:
- 如果存在安全漏洞,滚动证书是帮助保护系统的安全最佳做法。
- X.509 证书有到期日期。 滚动更新证书的频率取决于解决方案的安全需求。 具有涉及高度敏感数据的解决方案的客户可能会每天滚动更新证书,而其他客户则每隔几年滚动一次证书。
对于不间断的连接,IoT Central 允许你配置主要和辅助 X.509 证书。 如果主要证书和次要证书的过期日期不同,你可以滚动更新已过期的证书,而设备仍可使用另一个证书进行连接。
若要了解详细信息,请参阅 [Microsoft Enterprise Cloud Red Teaming] 的“假设违规方法”部分(https://download.microsoft.com/download/C/1/9/C1990DBA-502F-4C2A-848D-392B93D9B9C3/Microsoft_Enterprise_Cloud_Red_Teaming.pdf)。
本部分介绍如何在 IoT Central 中滚动更新证书。 在 IoT Central 中更新证书时,同时需要将新设备证书复制到你的设备上。
获取新的 X.509 证书
从证书提供程序获取新的 X.509 证书。 可以使用 OpenSSL 等工具创建自己的 X.509 证书。 此方法对测试 X.509 证书很有用,但几乎没有安全保证。 仅使用此方法进行测试,除非已准备好充当自己的 CA 提供商。
注册分组和安全漏洞
若要更新组注册以响应安全漏洞,应使用以下方法来立即更新当前证书。 如果两者都遭到泄露,请为主证书和副证书完成以下步骤:
导航到左窗格中 的权限 ,然后选择 “设备连接组”。
在“注册组”下的列表中选择组名称。
对于证书更新,请选择“ 管理主 数据库”或“ 管理辅助数据库”。
在注册组中添加和验证根 X.509 证书。
个人注册和安全漏洞
如果要滚动更新证书以响应安全漏洞,请使用以下方法来立即更新当前证书。 如果两者都受到损害,请为主要证书和辅助证书完成以下步骤:
选择 “设备”,然后选择设备。
选择 “连接”,然后选择“连接方法”为 “单个注册”
选择 证书(X.509) 作为机制。
对于证书更新,请选择文件夹图标以选择要为注册条目上传的新证书。 选择“保存”。
注册组和证书有效期
若要处理证书过期,请使用以下方法来立即更新当前证书:
导航到左窗格中 的权限 ,然后选择 “设备连接组”。
在“注册组”下的列表中选择组名称。
对于证书更新,请选择“ 管理主数据库”。
在注册组中添加和验证根 X.509 证书。
稍后,当辅助证书过期时,请返回并更新辅助证书。
个人注册和证书有效性过期
如果您要轮替使用证书以应对证书到期,建议按如下所示使用备用证书配置,以减少设备在尝试应用程序预配时的停机时间。
当辅助证书即将过期且需要更新时,可以转换为使用主要配置。 以这种方式在主要证书与次要证书之间轮换可以减少设备尝试在应用程序中进行预配时造成的停机时间。
选择 “设备”,然后选择设备。
选择连接,并将连接方法选择为个人注册
选择 证书(X.509) 作为机制。
对于辅助证书更新,请选择文件夹图标以选择要为注册条目上传的新证书。 选择“保存”。
稍后,当主证书过期时,请返回并更新主证书。