以编程方式为 X.509 证书证明创建设备预配服务注册组
本文介绍如何以编程方式创建使用中间或根 CA X.509 证书的注册组。 注册组是使用 Azure IoT 中心 DPS 服务 SDK 和示例应用程序创建的。 注册组可以控制对设备的预配服务的访问,此类设备在其证书链中共享常用签名证书。 若要了解详细信息,请参阅将 X.509 证书与 DPS 配合使用。 若要详细了解如何将基于 X.509 证书的公钥基础结构 (PKI) 与 Azure IoT 中心和设备预配服务配合使用,请参阅 X.509 CA 证书安全概述。
先决条件
如果没有 Azure 订阅,请在开始前创建一个试用版订阅。
完成通过 Azure 门户设置 IoT 中心设备预配服务中的步骤。
在基于 Windows 的计算机上安装 .NET 6.0 SDK 或更高版本。 可使用以下命令来检查你的版本。
dotnet --info
- 在计算机上安装 Node.js v4.0 或更高版本。
Java SE 开发工具包 8。 本文使用适用于 Java 的 Azure IoT SDK,它在 Windows 和 Linux 上都可以工作。 本文使用 Windows。
- 安装最新版本的 Git。 确保将 Git 添加到可供命令窗口访问的环境变量。 请参阅软件自由保护组织提供的 Git 客户端工具,了解要安装的最新版
git
工具,其中包括 Git Bash,这是一个命令行应用,可以用来与本地 Git 存储库交互。
注意
本文使用 Windows 开发计算机,不过,本文中的步骤在 Windows 和 Linux 计算机上均适用。
创建测试证书
可以将使用 X.509 证书证明的注册组配置为使用根 CA 证书或中间证书。 更常见的情况是使用中间证书配置注册组。 使用中间证书提供了更大的灵活性,因为同一根 CA 证书可以生成或撤销多个中间证书。
在本文中,需要根 CA 证书文件或中间 CA 证书文件,或者两者都是 .pem 或 .cer 格式。 一个文件包含根 CA X.509 证书的公共部分,另一个文件包含中间 CA X.509 证书的公共部分。
如果已有根 CA 文件和/或中间 CA 文件,则可以继续添加和验证根或中间 CA 证书。
添加并验证根或中间 CA 证书
通过使用 X.509 证书的注册组预配的设备在使用 DPS 进行身份验证时会显示整个证书链。 为了使 DPS 能够验证证书链,注册组中配置的根证书或中间证书必须是经过验证的证书,或者在向服务进行身份验证时,必须汇总到设备提供的证书链中的经过验证的证书。
本文假设你有根 CA 证书和由根 CA 签名的中间 CA 证书:
如果打算使用根 CA 证书创建注册组,则需要上传并验证根 CA 证书。
如果打算使用中间 CA 证书创建注册组,可以上传并验证根 CA 证书或中间 CA 证书。 (如果证书链中有多个中间 CA 证书,也可以上传并验证根 CA 证书和用于创建注册组的中间证书之间的任何中间证书。)
若要将根 CA 证书或中间 CA 证书添加到设备预配服务并验证该证书,请执行以下操作:
登录 Azure 门户。
在门户页面的左侧菜单中,选择“所有资源”。
选择你的设备预配服务。
在“设置”菜单中,选择“证书”。
在顶部菜单中,选择“+ 添加:”。
输入根 CA 证书或中间 CA 证书的名称,并上传 .pem 或 .cer 文件。
选择“在上传时将证书状态设置为已验证”。
选择“保存” 。
获取适用于预配服务的连接字符串
对于本文中的示例,需要预配服务的连接字符串。 使用以下步骤检索它。
登录 Azure 门户。
在门户页面的左侧菜单中,选择“所有资源”。
选择你的设备预配服务。
在“设置”菜单中,选择“共享访问策略” 。
选择要使用的访问策略。
在“访问策略”面板中,复制并保存主密钥连接字符串。
创建注册组示例
本部分介绍如何创建一个 .NET Core 控制台应用程序,用于将注册组添加到预配服务。
打开 Windows 命令提示符并导航到要在其中创建应用的文件夹。
若要创建控制台项目,请运行以下命令:
dotnet new console --framework net6.0 --use-program-main
若要添加对 DPS 服务 SDK 的引用,请运行以下命令:
dotnet add package Microsoft.Azure.Devices.Provisioning.Service
此步骤将下载、安装 Azure IoT DPS 服务客户端 NuGet 包及其依赖项,并添加对其的引用。 此包包含 .NET 服务 SDK 的二进制文件。
在编辑器中打开 Program.cs 文件。
将文件顶部的命名空间语句替换为以下行:
namespace CreateEnrollmentGroup;
在文件顶部(
namespace
语句之上)添加以下using
语句:using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; using Microsoft.Azure.Devices.Provisioning.Service;
将以下字段添加到
Program
类,并按指示进行更改。private static string ProvisioningConnectionString = "{ProvisioningServiceConnectionString}"; private static string EnrollmentGroupId = "enrollmentgrouptest"; private static string X509RootCertPath = @"{Path to a .cer or .pem file for a verified root CA or intermediate CA X.509 certificate}";
将
ProvisioningServiceConnectionString
占位符值替换为在上一部分复制的预配服务连接字符串。将
X509RootCertPath
占位符值替换为 .pem 或 .cer 文件的路径。 此文件表示根 CA X.509 证书的公共部分,该证书之前已通过预配服务上传和验证,或者表示中间证书的公共部分,该证书本身已上传和验证或其签名链中的证书已上传和验证。可以选择性地更改
EnrollmentGroupId
值。 字符串只能包含小写字符和连字符。
重要
在生产代码中,请注意以下安全注意事项:
- 为预配服务管理员硬编码连接字符串不符合安全最佳做法。 与硬编码相反,连接字符串应采用安全方式进行存储,例如存储在安全配置文件或注册表中。
- 确保只上传签名证书的公用部分。 不要将包含私钥的 .pfx (PKCS12) 或 .pem 文件上传到预配服务。
将以下方法添加到
Program
类。 此代码创建一个EnrollmentGroup
条目,然后调用ProvisioningServiceClient.CreateOrUpdateEnrollmentGroupAsync
方法,将注册组添加到预配服务。public static async Task RunSample() { Console.WriteLine("Starting sample..."); using (ProvisioningServiceClient provisioningServiceClient = ProvisioningServiceClient.CreateFromConnectionString(ProvisioningConnectionString)) { #region Create a new enrollmentGroup config Console.WriteLine("\nCreating a new enrollmentGroup..."); var certificate = new X509Certificate2(X509RootCertPath); Attestation attestation = X509Attestation.CreateFromRootCertificates(certificate); EnrollmentGroup enrollmentGroup = new EnrollmentGroup( EnrollmentGroupId, attestation) { ProvisioningStatus = ProvisioningStatus.Enabled }; Console.WriteLine(enrollmentGroup); #endregion #region Create the enrollmentGroup Console.WriteLine("\nAdding new enrollmentGroup..."); EnrollmentGroup enrollmentGroupResult = await provisioningServiceClient.CreateOrUpdateEnrollmentGroupAsync(enrollmentGroup).ConfigureAwait(false); Console.WriteLine("\nEnrollmentGroup created with success."); Console.WriteLine(enrollmentGroupResult); #endregion } }
最后,将
Main
方法替换为以下行:static async Task Main(string[] args) { await RunSample(); Console.WriteLine("\nHit <Enter> to exit ..."); Console.ReadLine(); }
保存所做更改。
本部分介绍如何创建一个 Node.js 脚本,用于将注册组添加到预配服务。
在工作文件夹的命令窗口中,运行以下命令:
npm install azure-iot-provisioning-service
此步骤将下载、安装 Azure IoT DPS 服务客户端包及其依赖项,并添加对其的引用。 此包包含 Node.js 服务 SDK 的二进制文件。
使用文本编辑器,在工作文件夹中创建 create_enrollment_group.js 文件。 将以下代码添加到文件并进行保存:
'use strict'; var fs = require('fs'); var provisioningServiceClient = require('azure-iot-provisioning-service').ProvisioningServiceClient; var serviceClient = provisioningServiceClient.fromConnectionString(process.argv[2]); var enrollment = { enrollmentGroupId: 'first', attestation: { type: 'x509', x509: { signingCertificates: { primary: { certificate: fs.readFileSync(process.argv[3], 'utf-8').toString() } } } }, provisioningStatus: 'disabled' }; serviceClient.createOrUpdateEnrollmentGroup(enrollment, function(err, enrollmentResponse) { if (err) { console.log('error creating the group enrollment: ' + err); } else { console.log("enrollment record returned: " + JSON.stringify(enrollmentResponse, null, 2)); enrollmentResponse.provisioningStatus = 'enabled'; serviceClient.createOrUpdateEnrollmentGroup(enrollmentResponse, function(err, enrollmentResponse) { if (err) { console.log('error updating the group enrollment: ' + err); } else { console.log("updated enrollment record returned: " + JSON.stringify(enrollmentResponse, null, 2)); } }); } });
打开 Windows 命令提示符。
使用 Java 服务 SDK 克隆设备注册代码示例的 GitHub 存储库:
git clone https://github.com/Azure/azure-iot-sdk-java.git --recursive
从下载存储库的位置转到示例文件夹:
cd azure-iot-sdk-java\provisioning\provisioning-service-client-samples\service-enrollment-group-sample
在所选的编辑器中打开文件“/src/main/java/samples/com/microsoft/azure/sdk/iot/ServiceEnrollmentGroupSample.java”。
将
[Provisioning Connection String]
替换为在获取适用于预配服务的连接字符串中复制的连接字符串。将
PUBLIC_KEY_CERTIFICATE_STRING
常量字符串替换为根 CA 证书或中间 CA 证书.pem
文件的值。 此文件表示根 CA X.509 证书的公共部分,该证书之前已通过预配服务上传和验证,或者表示中间证书的公共部分,该证书本身已上传和验证或其签名链中的证书已上传和验证。证书文本的语法必须遵循以下模式,其中不包含额外的空格或字符。
private static final String PUBLIC_KEY_CERTIFICATE_STRING = "-----BEGIN CERTIFICATE-----\n" + "MIIFOjCCAyKgAwIBAgIJAPzMa6s7mj7+MA0GCSqGSIb3DQEBCwUAMCoxKDAmBgNV\n" + ... "MDMwWhcNMjAxMTIyMjEzMDMwWjAqMSgwJgYDVQQDDB9BenVyZSBJb1QgSHViIENB\n" + "-----END CERTIFICATE-----";
手动更新此字符串值可能容易出错。 若要生成正确的语法,可以复制以下命令并并粘贴到 Git Bash 提示符中,将
your-cert.pem
替换为证书文件的位置,然后按 ENTER。 此命令将生成PUBLIC_KEY_CERTIFICATE_STRING
字符串常量值的语法并将其写入到输出。sed 's/^/"/;$ !s/$/\\n" +/;$ s/$/"/' your-cert.pem
复制并粘贴常量值的输出证书文本。
重要
在生产代码中,请注意以下安全注意事项:
- 为预配服务管理员硬编码连接字符串不符合安全最佳做法。 与硬编码相反,连接字符串应采用安全方式进行存储,例如存储在安全配置文件或注册表中。
- 确保只上传签名证书的公用部分。 不要将包含私钥的 .pfx (PKCS12) 或 .pem 文件上传到预配服务。
可以通过此示例在注册组中设置 IoT 中心以在其中预配设备。 设置的 IoT 中心必须是以前链接到预配服务的 IoT 中心。 在本文中,我们让 DPS 根据默认的分配策略(均匀加权分布),从链接中心中进行选择。 注释禁止文件中的以下语句:
enrollmentGroup.setIotHubHostName(IOTHUB_HOST_NAME); // Optional parameter.
示例代码为 X.509 设备创建、更新、查询和删除注册组。 若要验证是否在 Azure 门户中成功创建注册组,请注释禁止文件末尾附近的以下代码行:
// ************************************** Delete info of enrollmentGroup *************************************** System.out.println("\nDelete the enrollmentGroup..."); provisioningServiceClient.deleteEnrollmentGroup(enrollmentGroupId);
保存 ServiceEnrollmentGroupSample.java 文件。
运行注册组示例
运行示例:
dotnet run
成功创建后,该命令窗口将显示新注册组的属性。
在命令提示符下,运行以下命令。 包括命令参数两侧的引号,并将
<connection string>
替换为在上一部分复制的连接字符串,将<certificate .pem file>
替换为证书.pem
文件的路径。 此文件表示根 CA X.509 证书的公共部分,该证书之前已通过预配服务上传和验证,或者表示中间证书的公共部分,该证书本身已上传和验证或其签名链中的证书已上传和验证。node create_enrollment_group.js "<connection string>" "<certificate .pem file>"
成功创建后,该命令窗口将显示新注册组的属性。
在命令提示符的 azure-iot-sdk-java\provisioning\provisioning-service-client-samples\service-enrollment-group-sample 文件夹中,运行以下命令以生成示例:
mvn install -DskipTests
此命令将 Azure IoT DPS 服务客户端 Maven 包下载到计算机并生成示例。 此包包含 Java 服务 SDK 的二进制文件。
切换到 target 文件夹并运行示例。 上一步中的生成会在 target 文件夹中输出使用以下文件格式的 .jar 文件:
provisioning-x509-sample-{version}-with-deps.jar
;例如:provisioning-x509-sample-1.8.1-with-deps.jar
。 可能需要替换以下命令中的版本。cd target java -jar ./service-enrollment-group-sample-1.8.1-with-deps.jar
成功创建后,该命令窗口将显示新注册组的属性。
若要验证注册组是否已创建,请执行以下操作:
在 Azure 门户中导航到设备预配服务实例。
在“设置”菜单中,选择“管理注册” 。
选择“注册组”选项卡。此时应会看到一个对应于示例中使用的注册组 ID 的新注册项。
清理资源
如果你打算继续学习 Azure IoT 中心设备预配服务教程,请不要清理本文中创建的资源。 否则,请执行以下步骤删除本文中创建的所有资源。
关闭计算机上的示例输出窗口。
在 Azure 门户的左侧菜单中,选择“所有资源”。
选择你的设备预配服务。
在左侧菜单的“设置”下,选择“管理注册”。
选择“注册组”选项卡。
选中本文中创建的注册组的组名称旁边的复选框。
在页面顶部,选择“删除”。
在 Azure 门户的“设备预配服务”中,选择左侧菜单中“设置”下的“证书”。
选择为本文上传的证书。
在“证书详细信息”顶部,选择“删除”。
证书工具
Azure IoT C SDK 具有可以帮助创建和管理证书的脚本。 若要了解详细信息,请参阅管理用于示例和教程的测试 CA 证书。
Azure IoT Node.js SDK 具有可以帮助创建和管理证书的脚本。 若要了解详细信息,请参阅 适用于 Node.js 的 Azure IoT 设备预配设备 SDK 工具。
还可以使用 Azure IoT C SDK 中提供的工具。 若要了解详细信息,请参阅管理用于示例和教程的测试 CA 证书。
Azure IoT Java SDK 包含测试工具,可以帮助创建和管理证书。 若要了解详细信息,请参阅使用 DICE 模拟器的 X509 证书生成器。
后续步骤
在本文中,你已使用 Azure IoT 中心设备预配服务为 X.509 中间或根 CA 证书创建注册组。 若要进一步探索,请查看以下链接:
有关使用 DPS 进行 X.509 证书证明的详细信息,请参阅 X.509 证书证明。
若要了解如何使用 Azure 门户管理单个注册和注册组,请参阅如何通过 Azure 门户管理设备注册。