以编程方式为 X.509 证书证明创建设备预配服务注册组

本文介绍如何以编程方式创建使用中间或根 CA X.509 证书的注册组。 注册组是使用 Azure IoT 中心 DPS 服务 SDK 和示例应用程序创建的。 注册组可以控制对设备的预配服务的访问,此类设备在其证书链中共享常用签名证书。 若要了解详细信息,请参阅使用 X.509 证书控制设备对预配服务的访问。 若要详细了解如何将基于 X.509 证书的公钥基础结构 (PKI) 与 Azure IoT 中心和设备预配服务配合使用,请参阅 X.509 CA 证书安全概述

先决条件

注意

本文使用 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 证书添加到设备预配服务并验证该证书,请执行以下操作:

  1. 登录 Azure 门户

  2. 在门户页面的左侧菜单中,选择“所有资源”。

  3. 选择你的设备预配服务。

  4. 在“设置”菜单中,选择“证书”。

  5. 在顶部菜单中,选择“+ 添加:”。

  6. 输入根 CA 证书或中间 CA 证书的名称,并上传 .pem 或 .cer 文件。

  7. 选择“在上传时将证书状态设置为已验证”。

    Screenshot that shows adding the root CA certificate to a DPS instance.

  8. 选择“保存”。

获取适用于预配服务的连接字符串

对于本文中的示例,需要预配服务的连接字符串。 使用以下步骤检索它。

  1. 登录 Azure 门户

  2. 在门户页面的左侧菜单中,选择“所有资源”。

  3. 选择你的设备预配服务。

  4. 在“设置”菜单中,选择“共享访问策略” 。

  5. 选择要使用的访问策略。

  6. 在“访问策略”面板中,复制并保存主密钥连接字符串。

    Screenshot that shows the location of the provisioning service connection string in the portal.

创建注册组示例

本部分介绍如何创建一个 .NET Core 控制台应用程序,用于将注册组添加到预配服务。

  1. 打开 Windows 命令提示符并导航到要在其中创建应用的文件夹。

  2. 若要创建控制台项目,请运行以下命令:

    dotnet new console --framework net6.0 --use-program-main 
    
  3. 若要添加对 DPS 服务 SDK 的引用,请运行以下命令:

    dotnet add package Microsoft.Azure.Devices.Provisioning.Service 
    

    此步骤将下载、安装 Azure IoT DPS 服务客户端 NuGet 包及其依赖项,并添加对其的引用。 此包包含 .NET 服务 SDK 的二进制文件。

  4. 在编辑器中打开 Program.cs 文件。

  5. 将文件顶部的命名空间语句替换为以下行:

    namespace CreateEnrollmentGroup;
    
  6. 在文件顶部(namespace 语句之上)添加以下 using 语句:

    using System.Security.Cryptography.X509Certificates;
    using System.Threading.Tasks;
    using Microsoft.Azure.Devices.Provisioning.Service;
    
  7. 将以下字段添加到 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 文件上传到预配服务。
  8. 将以下方法添加到 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
    
        }
    }
    
  9. 最后,将 Main 方法替换为以下行:

    static async Task Main(string[] args)
    {
        await RunSample();
        Console.WriteLine("\nHit <Enter> to exit ...");
        Console.ReadLine();
    }
    
  10. 保存所做更改。

本部分介绍如何创建一个 Node.js 脚本,用于将注册组添加到预配服务。

  1. 在工作文件夹的命令窗口中,运行以下命令:

    npm install azure-iot-provisioning-service
    

    此步骤将下载、安装 Azure IoT DPS 服务客户端包及其依赖项,并添加对其的引用。 此包包含 Node.js 服务 SDK 的二进制文件。

  2. 使用文本编辑器,在工作文件夹中创建 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));
              }
            });
          }
        });
    

  1. 打开 Windows 命令提示符。

  2. 使用 Java 服务 SDK 克隆设备注册代码示例的 GitHub 存储库:

    git clone https://github.com/Azure/azure-iot-sdk-java.git --recursive
    
  3. 从下载存储库的位置转到示例文件夹:

    cd azure-iot-sdk-java\provisioning\provisioning-service-client-samples\service-enrollment-group-sample 
    
  4. 在所选的编辑器中打开文件“/src/main/java/samples/com/microsoft/azure/sdk/iot/ServiceEnrollmentGroupSample.java”。

  5. [Provisioning Connection String] 替换为在获取适用于预配服务的连接字符串中复制的连接字符串。

  6. 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 文件上传到预配服务。
  7. 可以通过此示例在注册组中设置 IoT 中心以在其中预配设备。 设置的 IoT 中心必须是以前链接到预配服务的 IoT 中心。 在本文中,我们让 DPS 根据默认的分配策略(均匀加权分布),从链接中心中进行选择。 注释禁止文件中的以下语句:

    enrollmentGroup.setIotHubHostName(IOTHUB_HOST_NAME);                // Optional parameter.
    
  8. 示例代码为 X.509 设备创建、更新、查询和删除注册组。 若要验证是否在 Azure 门户中成功创建注册组,请注释禁止文件末尾附近的以下代码行:

    // ************************************** Delete info of enrollmentGroup ***************************************
    System.out.println("\nDelete the enrollmentGroup...");
    provisioningServiceClient.deleteEnrollmentGroup(enrollmentGroupId);
    
  9. 保存 ServiceEnrollmentGroupSample.java 文件。

运行注册组示例

  1. 运行示例:

    dotnet run
    
  2. 成功创建后,该命令窗口将显示新注册组的属性。

  1. 在命令提示符下,运行以下命令。 包括命令参数两侧的引号,并将 <connection string> 替换为在上一部分复制的连接字符串,将 <certificate .pem file> 替换为证书 .pem 文件的路径。 此文件表示根 CA X.509 证书的公共部分,该证书之前已通过预配服务上传和验证,或者表示中间证书的公共部分,该证书本身已上传和验证或其签名链中的证书已上传和验证。

    node create_enrollment_group.js "<connection string>" "<certificate .pem file>"
    
  2. 成功创建后,该命令窗口将显示新注册组的属性。

  1. 在命令提示符的 azure-iot-sdk-java\provisioning\provisioning-service-client-samples\service-enrollment-group-sample 文件夹中,运行以下命令以生成示例:

    mvn install -DskipTests
    

    此命令将 Azure IoT DPS 服务客户端 Maven 包下载到计算机并生成示例。 此包包含 Java 服务 SDK 的二进制文件。

  2. 切换到 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
    
  3. 成功创建后,该命令窗口将显示新注册组的属性。

若要验证注册组是否已创建,请执行以下操作:

  1. Azure 门户中导航到设备预配服务实例。

  2. 在“设置”菜单中,选择“管理注册” 。

  3. 选择“注册组”选项卡。此时应会看到一个对应于示例中使用的注册组 ID 的新注册项。

Screenshot that shows the newly created enrollment group in the portal.

Screenshot that shows the newly created enrollment group in the portal.

Screenshot that shows the newly created enrollment group in the portal.

清理资源

如果你打算继续学习 Azure IoT 中心设备预配服务教程,请不要清理本文中创建的资源。 否则,请执行以下步骤删除本文中创建的所有资源。

  1. 关闭计算机上的示例输出窗口。

  2. 在 Azure 门户的左侧菜单中,选择“所有资源”。

  3. 选择你的设备预配服务。

  4. 在左侧菜单的“设置”下,选择“管理注册”。

  5. 选择“注册组”选项卡。

  6. 选中本文中创建的注册组的组名称旁边的复选框。

  7. 在页面顶部,选择“删除”。

  8. 在 Azure 门户的“设备预配服务”中,选择左侧菜单中“设置”下的“证书”。

  9. 选择为本文上传的证书。

  10. 在“证书详细信息”顶部,选择“删除”。

证书工具

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 证书创建注册组。 若要进一步探索,请查看以下链接: