The Internet of Things on AWS – Official Blog

Setting Up Just-in-Time Provisioning with AWS IoT Core

In an earlier blog post about just-in-time registration of device certificates, we discussed how just-in-time registration (JITR) can be used to activate device certificates and attach policies to the certificates immediately after the device is auto-registered. JITR triggers a registration event. You must create an AWS IoT Core rule to listen for the registration event topic and, when the registration event is identified, your Lambda code is executed to onboard devices.

In this blog post, I will show you how a new feature, just-in-time provisioning (JITP), can be used to provision resources. JITP makes it possible for you to onboard your devices without creating the AWS IoT Core rule and Lambda function. You need to attach a provisioning template to the CA certificate together with an IAM role. JITP will create, update, and attach resources based on the provisioning template. The role is passed in to grant AWS IoT permission to call APIs required for provisioning on your behalf.

The following figure shows the difference between JITR and JITP.

The JITP flow has fewer steps than JITR

Create a CA certificate

Just like JITR, you start by creating a CA certificate. We are using OpenSSL in a terminal to create a sample CA certificate.

$ openssl genrsa -out rootCA.key 2048
$ openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem

After we execute these commands, we get two files, rootCA.key and rootCA.pem, which we will use later as our sample CA certificate.

Create a service role

Because JITP needs the permissions to call AWS IoT Core APIs, we will create a role and associate it with the CA certificate. It is easier to create this role through the IAM console than the CLI. We already have a policy, AWSIoTThingsRegistration, that can be used to create the service role specific to JITP.

In the IAM console, choose Roles, and then choose the Create role button.

Create a role for JITP

 

Under Choose the service that will use this role, choose IoT.

Choose IoT as the trusted service

 

Review the policy. Type a name and description for the role.

Review the policy

Provide Role name and Role description

 

We now have a role named JITPRole, which we will use in the registrationConfig field when we register or update a CA certificate.

Create a provisioning template

A provisioning template must be attached to the CA certificate so that the JITP workflow will provision resources specified in the template when the device first connects to AWS IoT Core. For JITP, we can use the following parameters in our template.

  • AWS::IoT::Certificate::Country
  • AWS::IoT::Certificate::Organization
  • AWS::IoT::Certificate::OrganizationalUnit
  • AWS::IoT::Certificate::DistinguishedNameQualifier
  • AWS::IoT::Certificate::StateName
  • AWS::IoT::Certificate::CommonName
  • AWS::IoT::Certificate::SerialNumber
  • AWS::IoT::Certificate::Id

The values for the first 7 provisioning template parameters are extracted from the subject field in the certificate of the device that is being provisioned. The AWS::IoT::Certificate::Id parameter refers to an internally generated ID, not an ID that is contained in the certificate. You can get the value of this ID using the principle() function inside an AWS IoT rule.

We are using the following sample template. We need to escape the JSON string of templateBody value in the template.

{
 "templateBody":"{ \"Parameters\" : { \"AWS::IoT::Certificate::Country\" : { \"Type\" : \"String\" }, \"AWS::IoT::Certificate::Id\" : { \"Type\" : \"String\" } }, \"Resources\" : { \"thing\" : { \"Type\" : \"AWS::IoT::Thing\", \"Properties\" : { \"ThingName\" : {\"Ref\" : \"AWS::IoT::Certificate::Id\"}, \"AttributePayload\" : { \"version\" : \"v1\", \"country\" : {\"Ref\" : \"AWS::IoT::Certificate::Country\"}} } }, \"certificate\" : { \"Type\" : \"AWS::IoT::Certificate\", \"Properties\" : { \"CertificateId\": {\"Ref\" : \"AWS::IoT::Certificate::Id\"}, \"Status\" : \"ACTIVE\" } }, \"policy\" : {\"Type\" : \"AWS::IoT::Policy\", \"Properties\" : { \"PolicyDocument\" : \"{\\\"Version\\\": \\\"2012-10-17\\\",\\\"Statement\\\": [{\\\"Effect\\\":\\\"Allow\\\",\\\"Action\\\": [\\\"iot:Connect\\\",\\\"iot:Publish\\\"],\\\"Resource\\\" : [\\\"*\\\"]}]}\" } } } }",
 "roleArn":"arn:aws:iam::123456789012:role/JITPRole"
}

We declare we are using two provisioning parameters, AWS::IoT::Certificate::Country and AWS::IoT::Certificate::Id, and we will use them in the Resource section. The JITP workflow will substitute the references with the values extracted from the certificate and provision the resources specified in the template.

More specifically, the JITP workflow will create:

  • One thing resource.
  • One policy resource.

It will then:

  • Attach the policy to the certificate.
  • Attach the certificate to the thing.
  • Update the certificate status to ACTIVE.

Now we will put the whole template together with the role ARN we got from the previous step into a local file, provisioning-template.json.

For more information about the provisioning template, see Provisioning Templates in the AWS IoT Core Developer Guide.

Register a CA certificate

Now that we have created a sample CA certificate, we will register it with AWS IoT Core. To use JITP, we need to associate a template and a role with the CA certificate. This can be done at the time we register the CA certificate or later when we update the CA certificate. In this example, we will register the CA certificate with the template and the role ARN. You can also call UpdateCACertificate API or update-ca-certificate CLI command to change the status of the CA certificate, enable auto-registration status and set the registration configuration by providing a template and a role ARN.

Follow these steps to register the CA certificate.

First, we get a registration code from AWS IoT Core. This code will be used as the Common Name of the private key verification certificate.

$ aws iot get-registration-code

Then we generate a key pair for the private key verification certificate. We will get a file called verificationCert.key.

$ openssl genrsa -out verificationCert.key 2048

Now we execute the following command to create a CSR for the private key verification certificate. We will get a file called verificationCert.csr.

$ openssl req -new -key verificationCert.key -out verificationCert.csr

Now we need to set the Common Name field of the certificate with the registration code:

Country Name (2 letter code) [AU]:

State or Province Name (full name) []:

Locality Name (for example, city) []:

Organization Name (for example, company) []:

Organizational Unit Name (for example, section) []:

Common Name (e.g. server FQDN or YOUR name) []: XXXXXXXREGISTRATION-CODEXXXXXXX

Email Address []:

We use the CSR to create a private key verification certificate. The verificationCert.pem file we get from this step will be used when we register the CA certificate.

$ openssl x509 -req -in verificationCert.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out verificationCert.pem -days 500 -sha256

Lastly, we call the register-ca-certificate CLI command to register the CA certificate.

$ aws iot register-ca-certificate --ca-certificate file://rootCA.pem --verification-cert file://verificationCert.pem --set-as-active --allow-auto-registration --registration-config file://provisioning-template.json

We get an HTTP 200 response back with the registered CA certificateArn and certificateId. After registering the CA certificate, we can still call UpdateCACertificate API or the update-ca-certificate CLI command to update the registered CA certificate, if needed.

Auto-provision a device with a certificate signed by a CA certificate

Now that we have registered a sample CA certificate with auto-registration-status enabled and associated it with a provisioning template, we can try using the CA certificate to create a device certificate. The device certificate is provisioned automatically when it first connects to AWS IoT Core.

To create a device certificate, we run the following commands in our terminal:

$ openssl genrsa -out deviceCert.key 2048
$ openssl req -new -key deviceCert.key -out deviceCert.csr

After we run these commands, we can set the subject fields of the certificate, such as country name, common name, and so on and pass them to JITP.

Now we connect to AWS IoT Core using the device certificate. At the time of connection, we need to send the device certificate and its registered CA certificate (the sample CA certificate).

$ openssl x509 -req -in deviceCert.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out deviceCert.crt -days 365 -sha256

Then we create a file that contains the device certificate and its registered CA certificate.

$ cat deviceCert.crt rootCA.pem > deviceCertAndCACert.crt

Lastly, we need the MQTT Mosquitto client to connect and publish to AWS IoT Core using the device certificate:

$ mosquitto_pub --cafile root.cert --cert deviceCertAndCACert.crt --key deviceCert.key -h <prefix>.iot.us-east-1.amazonaws.com -p 8883 -q 1 -t foo/bar -I anyclientID --tls-version tlsv1.2 -m "Hello" -d

Note: The root.cert is the AWS IoT root certificate. To download it, click here. Save it in your current directory as “root.cert.” Because the <prefix> of the endpoint varies, we need to run the describe-endpoint command to retrieve it.

$ aws iot describe-endpoint

After connecting and publishing to AWS IoT Core, the provisioning workflow will auto-provision the resource specified in the template during the TLS handshake. In our example:

  • A thing resource is created for the device.
  • A certificate signed by the sample CA certificate is created, and its status is set to ACTIVE.
  • A policy resource is created and attached to the certificate, and the certificate is attached to the thing resource.

The device now is full provisioned. You can use the AWS IoT console to verify these resources are provisioned as expected.

Conclusion

In this post, we’ve shown how JITP can simplify the work required for provisioning an IoT device. AWS IoT Core now provides a stand-alone and secure provisioning system to help manufactures save time while onboarding devices. We hope you’ll try this new feature. Feel free to leave questions and other feedback in the comments.

Learning more

AWS IoT Core

https://thinkwithwp.com/iot-core/
AWS IoT Core Features
https://thinkwithwp.com/iot-core/features/
AWS IoT Device Provisioning
http://docs.thinkwithwp.com/iot/latest/developerguide/iot-provision.html