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