X.509 인증서를 사용하여 디바이스를 IoT Central 애플리케이션에 연결하는 방법

IoT Central은 SAS(공유 액세스 서명) 및 X.509 인증서를 모두 지원하여 디바이스와 애플리케이션 간의 통신을 보호합니다. 클라이언트 애플리케이션 만들기 및 Azure IoT Central 애플리케이션에 연결 자습서에서는 SAS를 사용합니다. 이 문서에서는 X.509 인증서를 사용하도록 코드 샘플을 수정하는 방법에 대해 알아봅니다. X.509 인증서는 프로덕션 환경에서 사용하는 것이 좋습니다. 자세한 내용은 디바이스 인증 개념을 참조하세요.

이 가이드에서는 X.509 인증서를 사용하는 두 가지 방법 - 일반적으로 프로덕션 환경에서 사용되는 그룹 등록 및 테스트에 유용한 개별 등록을 보여 줍니다. 이 문서에서는 인증서가 만료될 때 기본 연결을 기본 디바이스 인증서를 롤하는 방법에 대해서도 설명합니다.

이 가이드는 C#, 자바, 자바스크립트 및 Python을 사용하는 클라이언트 애플리케이션을 만들고 Azure IoT Central 애플리케이션에 연결 자습서에 표시된 샘플을 기반으로 합니다. C 프로그래밍 언어를 사용하는 예제는 등록 그룹을 사용하여 여러 X.509 디바이스 프로비저닝을 참조하세요.

필수 조건

이 방법 가이드의 단계를 완료하려면 먼저 클라이언트 응용 프로그램을 만들어 Azure IoT Central 애플리케이션에 연결 자습서를 완료해야 합니다. 이 가이드의 단계를 따를 때 자습서에서 사용한 코드를 수정합니다.

이 방법 가이드에서는 일부 테스트 X.509 인증서를 생성합니다. 이러한 인증서를 생성하려면 다음이 필요합니다.

  • Node.js 버전 6 이상이 설치된 개발 머신. 명령줄에서 node --version 명령을 실행하여 버전을 확인할 수 있습니다. 이 자습서의 지침에서는 Windows 명령 프롬프트에서 node 명령을 실행한다고 가정합니다. 하지만 여러 운영 체제에서 Node.js를 사용할 수 있습니다.
  • 테스트 X.509 인증서를 생성하는 스크립트가 포함된 Node.js GitHub 리포지토리용 Microsoft Azure IoT SDK의 로컬 복사본입니다. 다음 링크를 사용하여 리포지토리의 복사본을 다운로드합니다. ZIP 다운로드 그런 다음, 로컬 머신의 적절한 위치에 파일의 압축을 풉니다.

그룹 등록 사용

프로덕션 환경에서 그룹 등록과 함께 X.509 인증서를 사용합니다. 그룹 등록에서 루트 또는 중간 X.509 인증서를 IoT Central 애플리케이션에 추가합니다. 루트 또는 중간 인증서에서 파생된 리프 인증서가 있는 디바이스는 애플리케이션에 연결할 수 있습니다.

루트 및 디바이스 인증서 생성

이 섹션에서는 X.509 인증서를 사용하여 디바이스를 IoT Central 등록 그룹의 인증서에서 파생된 인증서와 연결합니다.

Warning

X.509 인증서를 생성하는 이 방법은 테스트용으로만 사용할 수 있습니다. 프로덕션 환경의 경우 인증서를 생성하는 데 공식, 보안 메커니즘을 사용해야 합니다.

  1. 다운로드한 Node.js용 Microsoft Azure IoT SDK에서 인증서 생성기 스크립트로 이동합니다. 필요한 패키지를 설치합니다.

    cd azure-iot-sdk-node/provisioning/tools
    npm install
    
  2. 루트 인증서를 만든 다음, 스크립트를 실행하여 디바이스 인증서를 파생합니다.

    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 파일입니다.

이러한 파일의 위치를 기록해 두세요. 나중에 필요합니다.

그룹 등록 만들기

  1. IoT Central 애플리케이션을 열고 왼쪽 창에서 권한으로 이동한 다음, 디바이스 연결 그룹을 선택합니다.

  2. + 새로 만들기를 선택하여 증명 유형의 인증서(X.509)가 있는 MyX509Group이라는 새 등록 그룹을 만듭니다. IoT 디바이스 또는 IoT Edge 디바이스에 대한 등록 그룹을 만들 수 있습니다.

  3. 만든 등록 그룹에서 기본 관리를 선택합니다.

  4. 기본 인증서 패널에서 인증서 추가를 선택합니다.

  5. 이전에 생성한 mytestrootcert_cert.pem이라는 루트 인증서 파일을 업로드합니다.

  6. 신뢰할 수 있는 중간 또는 루트 인증 기관을 사용하고 인증서의 전체 소유권이 있음을 알고 있는 경우 On에 업로드할 때 인증서 상태 확인하도록 설정하여 인증서를 확인했음을 스스로 증명할 수 있습니다. 그렇지 않으면 업로드 시 확인된 인증서 상태를 끄기로 설정합니다.

  7. 업로드 시 확인된 인증서 상태를 끄기로 설정한 경우 확인 코드 생성을 선택합니다.

  8. 확인 코드를 복사하고 복사한 다음, X.509 확인 인증서를 만듭니다. 예를 들어, 명령 프롬프트에서 다음을 수행합니다.

    node create_test_cert.js verification --ca mytestrootcert_cert.pem --key mytestrootcert_key.pem --nonce  {verification-code}
    
  9. 확인을 선택하여 서명된 확인 인증서 verification_cert.pem을 업로드하고 확인을 완료합니다.

  10. 기본 인증서의 상태는 이제 확인됨입니다.

    Screenshot that shows a verified X509 certificate.

이제 이 기본 루트 인증서에서 파생된 X.509 인증서가 있는 디바이스를 연결할 수 있습니다.

등록 그룹을 저장한 후에는 ID 범위를 기록해 둡니다. 나중에 필요합니다.

샘플 디바이스 코드 실행

Windows를 사용하는 경우 샘플이 작동하려면 X.509 인증서가 Windows 인증서 저장소에 있어야 합니다. Windows 탐색기에서 이전에 생성한 PFX 파일(mytestrootcert.pfxsampleDevice01.pfx)을 두 번 클릭합니다. 인증서 가져오기 마법사에서 저장소 위치로 현재 사용자를 선택하고 암호로 1234를 입력하면 마법사가 인증서 저장소를 자동으로 선택하도록 합니다. 마법사는 인증서를 현재 사용자의 개인 저장소로 가져옵니다.

X.509 인증서를 사용하도록 샘플 코드를 수정하려면 다음을 수행합니다.

  1. IoTHubDeviceSamples Visual Studio 솔루션의 TemperatureController 프로젝트에서 Parameter.cs 파일을 엽니다.

  2. 클래스에 다음 두 매개 변수 정의를 추가합니다.

    [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");
    

    변경 내용을 저장합니다.

  3. IoTHubDeviceSamples Visual Studio 솔루션에서 TemperatureController 프로젝트의 Program.cs 파일을 엽니다.

  4. 다음 using 문을 추가합니다.

    using System.Security.Cryptography.X509Certificates;
    using System.IO;
    
  5. 클래스에 다음 메서드를 추가합니다.

    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;
    }
    
  6. 메서드에서 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;
    
  7. 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);
    }
    

    변경 내용을 저장합니다.

샘플을 실행하려면:

  1. 프로젝트에 다음 환경 변수를 추가합니다.

    • IOTHUB_DEVICE_X509_CERT: <full path to folder that contains PFX files>sampleDevice01.pfx
    • IOTHUB_DEVICE_X509_PASSWORD: 1234.
  2. 애플리케이션을 빌드 및 실행합니다. 디바이스 프로비저닝을 성공적으로 확인합니다.

X.509 인증서를 사용하도록 샘플 코드를 수정하려면 다음을 수행합니다.

  1. 온도 컨트롤러 디바이스 샘플에 대한 pom.xml 파일 및 src 폴더가 포함된 azure-iot-sdk-java/device/iot-device-samples/pnp-device-sample/temperature-controller-device-sample 폴더로 이동합니다.

  2. 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>
    

    변경 내용을 저장합니다.

  3. 텍스트 편집기에서 src/기본/java/samples/com/microsoft/azure/sdk/iot/device/TemperatureController.java 파일을 엽니다.

  4. 가져오기를 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;
    
  5. 다음 가져오기를 추가합니다.

    import java.nio.file.*;
    
  6. 메서드가 throw하는 main 예외 목록에 추가 SecurityProviderException 합니다.

    public static void main(String[] args) throws IOException, URISyntaxException, ProvisioningDeviceClientException, InterruptedException, SecurityProviderException {
    
  7. 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();
        }
    }
    

    변경 내용을 저장합니다.

샘플을 실행하려면:

  1. 셸 환경에서 다음 두 환경 변수를 추가합니다. 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 애플리케이션에 연결 자습서를 완료할 때 다른 필수 환경 변수를 설정합니다.

  2. 애플리케이션을 빌드 및 실행합니다. 디바이스 프로비저닝을 성공적으로 확인합니다.

X.509 인증서를 사용하도록 샘플 코드를 수정하려면 다음을 수행합니다.

  1. pnp_temperature_controller.js 애플리케이션이 포함된 azure-iot-sdk-node/device/samples/javascript 폴더로 이동하고 다음 명령을 실행하여 X.509 패키지를 설치합니다.

    npm install azure-iot-security-x509 --save
    
  2. 텍스트 편집기에서 pnp_temperature_controller.js 파일을 엽니다.

  3. require 다음 코드를 포함하도록 문을 편집합니다.

    const fs = require('fs');
    const X509Security = require('azure-iot-security-x509').X509Security;
    
  4. "DPS 연결 정보" 섹션에 다음 네 줄을 추가하여 변수를 초기화합니다 deviceCert .

    const deviceCert = {
      cert: fs.readFileSync(process.env.IOTHUB_DEVICE_X509_CERT).toString(),
      key: fs.readFileSync(process.env.IOTHUB_DEVICE_X509_KEY).toString()
    };
    
  5. provisionDevice 첫 번째 줄을 다음 코드로 바꿔 클라이언트를 만드는 함수를 편집합니다.

    var provSecurityClient = new X509Security(registrationId, deviceCert);
    
  6. 동일한 함수에서 다음과 같이 변수를 deviceConnectionString 설정하는 줄을 수정합니다.

    deviceConnectionString = 'HostName=' + result.assignedHub + ';DeviceId=' + result.deviceId + ';x509=true';
    
  7. 함수에서 main 다음 줄을 호출 Client.fromConnectionString하는 줄 다음에 추가합니다.

    client.setOptions(deviceCert);
    

    변경 내용을 저장합니다.

샘플을 실행하려면:

  1. 셸 환경에서 다음 두 환경 변수를 추가합니다. 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 애플리케이션에 연결 자습서를 완료할 때 다른 필수 환경 변수를 설정합니다.

  2. 스크립트를 실행하고 디바이스가 성공적으로 프로비전되었는지 확인합니다.

    node pnp_temperature_controller.js
    

X.509 인증서를 사용하도록 샘플 코드를 수정하려면 다음을 수행합니다.

  1. azure-iot-device/samples/pnp 폴더로 이동하고 텍스트 편집기에서 temp_controller_with_thermostats.py 파일을 엽니다.

  2. 다음 from 문을 추가하여 X.509 기능을 가져옵니다.

    from azure.iot.device import X509
    
  3. 함수의 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,
        )
    
  4. 함수에서 main 변수를 설정하는 symmetric_key 줄을 다음 코드로 바꿉다.

    x509 = X509(
        cert_file=os.getenv("IOTHUB_DEVICE_X509_CERT"),
        key_file=os.getenv("IOTHUB_DEVICE_X509_KEY"),
    )
    
  5. main 함수에서 provision_device 함수에 대한 호출을 다음 코드로 바꿉니다.

    registration_result = await provision_device(
        provisioning_host, id_scope, registration_id, x509, model_id
    )
    
  6. 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,
    )
    

    변경 내용을 저장합니다.

샘플을 실행하려면:

  1. 셸 환경에서 다음 두 환경 변수를 추가합니다. 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 애플리케이션에 연결 자습서를 완료할 때 다른 필수 환경 변수를 설정합니다.

  2. 스크립트를 실행하고 디바이스가 성공적으로 프로비전되었는지 확인합니다.

    python temp_controller_with_thermostats.py
    

IoT Central 애플리케이션의 디바이스 보기에 원격 분석이 나타나는지 확인합니다.

Screenshot showing telemetry from a device that connected using X.509.

개별 등록 사용

개별 등록에 X.509 인증서를 사용하여 디바이스와 솔루션을 테스트합니다. 개별 등록에는 IoT Central 애플리케이션에 루트 또는 중간 X.509 인증서가 없습니다. 디바이스는 자체 서명된 X.509 인증서를 사용하여 애플리케이션에 연결합니다.

자체 서명된 디바이스 인증서 생성

이 섹션에서는 자체 서명된 X.509 인증서를 사용하여 개별 등록을 위해 디바이스를 연결합니다. 이는 단일 디바이스를 등록하는 데 사용됩니다. 자체 서명된 인증서는 테스트 전용입니다.

Warning

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 파일.

개별 등록 만들기

  1. Azure IoT Central 애플리케이션에서 디바이스를 선택하고 자동 온도 조절기 디바이스 템플릿에서 디바이스 ID를 mytestselfcertprimary사용하여 새 디바이스를 만듭니다. 나중에 사용하기 위해 ID 범위를 기록해 둡니다.

  2. 만든 디바이스를 열고 커넥트 선택합니다.

  3. 인증 유형으로 개별 등록을 선택하고 인증 방법으로 인증서(X.509)를 선택합니다.

  4. 이전에 기본 인증서로 생성한 mytestselfcertprimary_cert.pem 파일을 업로드합니다.

  5. 이전에 보조 인증서로 생성한 mytestselfcertsecondary_cert.pem 파일을 업로드합니다. 그런 다음 저장을 선택합니다.

  6. 이제 디바이스에 X.509 인증서가 있는 개별 등록이 있습니다.

    Screenshot that shows how to connect a device using an X.509 individual enrollment.

샘플 개별 등록 디바이스 실행

Windows를 사용하는 경우 샘플이 작동하려면 X.509 인증서가 Windows 인증서 저장소에 있어야 합니다. Windows 탐색기에서 이전에 생성한 PFX 파일(mytestselfcertprimary.pfxmytestselfcertsecondary.pfx)을 두 번 클릭합니다. 인증서 가져오기 마법사에서 저장소 위치로 현재 사용자를 선택하고 암호로 1234를 입력하면 마법사가 인증서 저장소를 자동으로 선택하도록 합니다. 마법사는 인증서를 현재 사용자의 개인 저장소로 가져옵니다.

X.509 인증서를 사용하도록 샘플 코드를 수정하려면 다음을 수행합니다.

  1. IoTHubDeviceSamples Visual Studio 솔루션의 TemperatureController 프로젝트에서 Parameter.cs 파일을 엽니다.

  2. 클래스에 다음 두 매개 변수 정의를 추가합니다.

    [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");
    

    변경 내용을 저장합니다.

  3. IoTHubDeviceSamples Visual Studio 솔루션에서 TemperatureController 프로젝트의 Program.cs 파일을 엽니다.

  4. 다음 using 문을 추가합니다.

    using System.Security.Cryptography.X509Certificates;
    using System.IO;
    
  5. 클래스에 다음 메서드를 추가합니다.

    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;
    }
    
  6. 메서드에서 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;
    
  7. 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);
    }
    

    변경 내용을 저장합니다.

샘플을 실행하려면:

  1. 프로젝트에 다음 환경 변수를 추가합니다.

    • 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.
  2. 애플리케이션을 빌드 및 실행합니다. 디바이스 프로비저닝을 성공적으로 확인합니다.

X.509 인증서를 사용하도록 샘플 코드를 수정하려면 다음을 수행합니다.

  1. 온도 컨트롤러 디바이스 샘플에 대한 pom.xml 파일 및 src 폴더가 포함된 azure-iot-sdk-java/device/iot-device-samples/pnp-device-sample/temperature-controller-device-sample 폴더로 이동합니다.

  2. 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>
    

    변경 내용을 저장합니다.

  3. 텍스트 편집기에서 src/기본/java/samples/com/microsoft/azure/sdk/iot/device/TemperatureController.java 파일을 엽니다.

  4. 가져오기를 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;
    
  5. 다음 가져오기를 추가합니다.

    import java.nio.file.*;
    
  6. 메서드가 throw하는 main 예외 목록에 추가 SecurityProviderException 합니다.

    public static void main(String[] args) throws IOException, URISyntaxException, ProvisioningDeviceClientException, InterruptedException, SecurityProviderException {
    
  7. 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();
        }
    }
    

    변경 내용을 저장합니다.

샘플을 실행하려면:

  1. 셸 환경에서 다음 두 환경 변수를 추가합니다. 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 애플리케이션에 연결 자습서를 완료할 때 다른 필수 환경 변수를 설정합니다.

  2. 애플리케이션을 빌드 및 실행합니다. 디바이스 프로비저닝을 성공적으로 확인합니다.

mytestselfcertsecondary 인증서에 대해서도 위의 단계를 반복할 수 있습니다.

X.509 인증서를 사용하도록 샘플 코드를 수정하려면 다음을 수행합니다.

  1. pnp_temperature_controller.js 애플리케이션이 포함된 azure-iot-sdk-node/device/samples/javascript 폴더로 이동하고 다음 명령을 실행하여 X.509 패키지를 설치합니다.

    npm install azure-iot-security-x509 --save
    
  2. 텍스트 편집기에서 pnp_temperature_controller.js 파일을 엽니다.

  3. require 다음 코드를 포함하도록 문을 편집합니다.

    const fs = require('fs');
    const X509Security = require('azure-iot-security-x509').X509Security;
    
  4. "DPS 연결 정보" 섹션에 다음 네 줄을 추가하여 변수를 초기화합니다 deviceCert .

    const deviceCert = {
      cert: fs.readFileSync(process.env.IOTHUB_DEVICE_X509_CERT).toString(),
      key: fs.readFileSync(process.env.IOTHUB_DEVICE_X509_KEY).toString()
    };
    
  5. provisionDevice 첫 번째 줄을 다음 코드로 바꿔 클라이언트를 만드는 함수를 편집합니다.

    var provSecurityClient = new X509Security(registrationId, deviceCert);
    
  6. 동일한 함수에서 다음과 같이 변수를 deviceConnectionString 설정하는 줄을 수정합니다.

    deviceConnectionString = 'HostName=' + result.assignedHub + ';DeviceId=' + result.deviceId + ';x509=true';
    
  7. 함수에서 main 다음 줄을 호출 Client.fromConnectionString하는 줄 다음에 추가합니다.

    client.setOptions(deviceCert);
    

    변경 내용을 저장합니다.

샘플을 실행하려면:

  1. 셸 환경에서 다음 두 환경 변수를 추가합니다. 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 애플리케이션에 연결 자습서를 완료할 때 다른 필수 환경 변수를 설정합니다.

  2. 스크립트를 실행하고 디바이스가 성공적으로 프로비전되었는지 확인합니다.

    node pnp_temperature_controller.js
    

mytestselfcertsecondary 인증서에 대해서도 위의 단계를 반복할 수 있습니다.

X.509 인증서를 사용하도록 샘플 코드를 수정하려면 다음을 수행합니다.

  1. azure-iot-device/samples/pnp 폴더로 이동하고 텍스트 편집기에서 temp_controller_with_thermostats.py 파일을 엽니다.

  2. 다음 from 문을 추가하여 X.509 기능을 가져옵니다.

    from azure.iot.device import X509
    
  3. 함수의 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,
        )
    
  4. 함수에서 main 변수를 설정하는 symmetric_key 줄을 다음 코드로 바꿉다.

    x509 = X509(
        cert_file=os.getenv("IOTHUB_DEVICE_X509_CERT"),
        key_file=os.getenv("IOTHUB_DEVICE_X509_KEY"),
    )
    
  5. main 함수에서 provision_device 함수에 대한 호출을 다음 코드로 바꿉니다.

    registration_result = await provision_device(
        provisioning_host, id_scope, registration_id, x509, model_id
    )
    
  6. 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,
    )
    

    변경 내용을 저장합니다.

샘플을 실행하려면:

  1. 셸 환경에서 다음 두 환경 변수를 추가합니다. 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 애플리케이션에 연결 자습서를 완료할 때 다른 필수 환경 변수를 설정합니다.

  2. 스크립트를 실행하고 디바이스가 성공적으로 프로비전되었는지 확인합니다.

    python temp_controller_with_thermostats.py
    

mytestselfcertsecondary 인증서에 대해서도 위의 단계를 반복할 수 있습니다.

IoT Edge 디바이스 연결

이 섹션에서는 그룹 등록을 사용하여 IoT Edge 디바이스를 연결하고 있다고 가정합니다. 이전 섹션의 단계에 따라 다음을 수행합니다.

X.509 디바이스 인증서를 사용하여 IoT Edge 디바이스를 IoT Central에 연결하려면:

  • 디바이스 인증서 및 키 파일을 IoT Edge 디바이스에 복사합니다. 이전 그룹 등록 예에서 이러한 파일의 이름은 sampleDevice01_key.pemsampleDevice01_cert.pem입니다.

  • IoT Edge 디바이스에서 다음과 같이 /etc/aziot/config.toml 구성 파일의 섹션을 편집 provisioning 합니다.

    # 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
    

자세한 내용은 Linux에서 X.509 인증서를 사용하여 대규모로 IoT Edge 디바이스 만들기 및 프로비저닝을 참조하세요.

다운스트림 디바이스를 IoT Edge에 연결

IoT Edge는 X.509 인증서를 사용하여 다운스트림 디바이스와 투명 게이트웨이 역할을 하는 IoT Edge 디바이스 간의 연결을 보호합니다. 이 시나리오를 구성하는 방법에 대한 자세한 내용은 다운스트림 디바이스를 Azure IoT Edge 게이트웨이에 커넥트 참조하세요.

X.509 디바이스 인증서 롤

IoT Central 애플리케이션의 수명 주기 동안 X.509 인증서를 롤해야 할 수 있습니다. 예시:

  • 보안 위반이 있는 경우 인증서를 롤링하는 것이 시스템을 보호할 수 있는 보안 모범 사례입니다.
  • X.509 인증서에는 만료 날짜가 있습니다. 인증서를 롤링하는 빈도는 솔루션의 보안 요구 사항에 따라 다릅니다. 매우 중요한 데이터가 포함된 솔루션을 사용하는 고객은 매일 인증서를 배포할 수 있고, 다른 고객은 2년마다 인증서를 배포할 수 있습니다.

중단 없는 연결을 위해 IoT Central을 사용하면 기본 및 보조 X.509 인증서를 구성할 수 있습니다. 주 인증서와 보조 인증서의 만료 날짜가 다른 경우 디바이스가 다른 인증서와 계속 연결하는 동안 만료된 인증서를 롤할 수 있습니다.

자세한 내용은 위반 방법론 가정(Assume Breach Methodology)을 참조 하세요.

이 섹션에서는 IoT Central에서 인증서를 롤링하는 방법을 설명합니다. IoT Central에서 인증서를 롤하는 경우 새 디바이스 인증서도 디바이스에 복사해야 합니다.

새 X.509 인증서 가져오기

인증서 공급자로부터 새 X.509 인증서를 가져옵니다. OpenSSL과 같은 도구를 사용하여 고유한 X.509 인증서를 만들 수 있습니다. 이 방법은 X.509 인증서를 테스트하는 데 유용하지만 몇 가지 보안 보장을 제공합니다. 사용자 고유의 CA 공급자 역할을 할 준비가 되어 있지 않은 경우 테스트에만 이 방법을 사용합니다.

등록 그룹 및 보안 위반

보안 위반에 대응하여 그룹 등록을 업데이트하려면 다음 방법을 사용하여 현재 인증서를 즉시 업데이트해야 합니다. 둘 다 손상된 경우 기본 및 보조 인증서에 대해 다음 단계를 완료합니다.

  1. 왼쪽 창에서 권한으로 이동하여 디바이스 연결 그룹을 선택합니다.

  2. 등록 그룹 아래 목록에서 그룹 이름을 선택합니다.

  3. 인증서 업데이트의 경우 기본 관리 또는 보조 관리를 선택합니다.

  4. 등록 그룹에서 루트 X.509 인증서를 추가하고 확인합니다.

개별 등록 및 보안 위반

보안 위반에 대응하여 인증서를 롤링하는 경우 다음 방식을 사용하여 현재 인증서를 즉시 업데이트합니다. 기본 인증서와 보조 인증서가 모두 손상된 경우 이러한 단계를 완료합니다.

  1. 디바이스를 선택하고 디바이스를 선택합니다.

  2. 커넥트 선택하고 개별 등록으로 연결 방법을 선택합니다.

  3. 메커니즘으로 인증서(X.509)를 선택합니다.

  4. 인증서 업데이트의 경우 폴더 아이콘을 선택하여 등록 항목에 대해 업로드할 새 인증서를 선택합니다. 저장을 선택합니다.

등록 그룹 및 인증서 만료

인증서 만료를 처리하려면 다음 방식을 사용하여 현재 인증서를 즉시 업데이트합니다.

  1. 왼쪽 창에서 권한으로 이동하여 디바이스 연결 그룹을 선택합니다.

  2. 등록 그룹 아래 목록에서 그룹 이름을 선택합니다.

  3. 인증서 업데이트의 경우 기본 관리를 선택합니다.

  4. 등록 그룹에서 루트 X.509 인증서를 추가하고 확인합니다.

  5. 나중에 보조 인증서가 만료되면 돌아와서 보조 인증서를 업데이트합니다.

개별 등록 및 인증서 만료

인증서 만료를 처리하기 위해 인증서를 롤링하는 경우 다음과 같이 보조 인증서 구성을 사용하여 애플리케이션에서 프로비전을 시도하는 디바이스의 가동 중지 시간을 줄여야 합니다.

보조 인증서가 만료에 가까워지고 롤아웃해야 하는 경우 기본 구성을 사용하도록 회전할 수 있습니다. 이러한 방식으로 기본 인증서와 보조 인증서 간에 순환하면 애플리케이션에서 프로비전을 시도하는 디바이스의 가동 중지 시간이 줄어듭니다.

  1. 디바이스를 선택하고 디바이스를 선택합니다.

  2. 커넥트 선택하고 개별 등록으로 연결 방법을 선택합니다.

  3. 메커니즘으로 인증서(X.509)를 선택합니다.

  4. 보조 인증서 업데이트의 경우 폴더 아이콘을 선택하여 등록 항목에 대해 업로드할 새 인증서를 선택합니다. 저장을 선택합니다.

  5. 나중에 기본 인증서가 만료되면 돌아와서 기본 인증서를 업데이트합니다.