The Internet of Things on AWS – Official Blog

Deploy Fleets Easily with AWS IoT Device Management Services

Introduction

The Internet of Things (IoT) offers the potential for data acquisition and digital interaction in areas previously inaccessible at an unprecedented scale. The magnitude of this opportunity affects individuals, organizations, and governments in many different ways. In manufacturing, for example, many makers of existing products are racing to integrate connected features into their offerings and deliver these products to the market in substantial quantities. Startups and other organizations are creating completely new product lines built around connectability and cloud-based service integration.

In order to address the complexity of provisioning and managing connected things manufacturers need ways to simplify and automate tasks like provisioning device identities and providing those identities to the devices as they are being manufactured in a secure and repeatable fashion. Enabling this formidable task is a new feature from the AWS IoT Device Management service that enables bulk provisioning of connected things.

This new feature allows customers to register large number of devices at once. Certificates, things, and policy resources make up the principal and permissions configuration for each thing within AWS IoT Core. Regardless of the specific nature of your business, when developing a solution using AWS IoT Services, you will need to create a ‘thing’ to store information about each device, create a certificate to provide secure credentials for the ‘thing’, and set up permissions by attaching the certificate to an appropriate policy for the ‘thing’. AWS IoT bulk provisioning feature simplifies and automates the registration process.

Here’s a real world example from an AWS customer, Trimble. Best known for its GPS technology, Trimble integrates a wide range of positioning technologies including GPS, laser, optical, and inertial technologies with application software, wireless communications, and services to provide complete commercial solutions. “AWS IoT Device Management has helped streamline our device onboarding, which has enabled us to meet our planned production throughput for connected devices.” said Jim Coleman, Senior Engineer, Trimble. [1] Mr. Coleman also shared during his talk at AWS reInvent 2017 that his team achieved a 4x increase in device provisioning throughput using AWS IoT bulk provisioning feature. [2]

For more detail about AWS IoT certificates, things, policies and the rest of the AWS IoT security model have a look here in this article.

Use Cases for IoT Fleet Provisioning

Here at AWS we start with the customer and work backwards when we design services. When considering use cases for provisioning it is only natural that we should do the same. How will our customers interact with the connected device? Will it have a user interface? Will customers need to pair it with a mobile device? Might it have a WiFi access point that they can connect to and configure with a browser? Will it require any configuration at all? Will there be a service subscription associated with the device?

While we won’t attempt to answer all these questions in this blog post, we will use their influence to guide how we explore solution design for bulk provisioning. Let us consider this scenario: our customer obtains a device from a retail outlet and Bluetooth pairs it with a mobile device running an application used to configure the device. Once the device is configured, the mobile app is no longer required for general operations of the device. The device essentially operates stand-alone and has its own “identity.”

When the device was manufactured in the factory, the device was provisioned with a set of certificates, a thing name, and one or more AWS IoT policies. When the device is powered on and configured with Internet access by the mobile application, the device can then connect directly to the AWS IoT Core service, supply its credentials, and be authenticated by presenting valid certificates. The connected device is authorized to interact with the AWS IoT Core service based on provisioned policies.

Reviewing Options

While this post focuses on the AWS IoT Device Management bulk provisioning feature, there are other available options within AWS IoT Core for use in provisioning devices at scale. AWS IoT Core includes a feature set called Just in Time Registration (JITR) that allows for pre-provisioned and device deployed certificates signed by a customer-provided certificate authority (CA) to be registered with AWS IoT Core the first time a device connects. More detail can be found on the AWS IoT JITR feature in this article.

Exploring AWS IoT Device Management Bulk Provisioning Features

In order to make productive use of the AWS IoT Device Management bulk provisioning feature you’ll need to prepare a few AWS resources prior to starting the provisioning task. Those resources include a provisioning template, an S3 bucket location, a service role and a data file. Additionally, you will need to create X.509 certificates and generate certificate signing requests (CSRs). We’ll go over each of those resources in greater detail next.

Create Provisioning Template

A provisioning template contains variables that are replaced when the template is used to provision a device. A dictionary (map) is used to provide values for the variables used in a template. The bulk provisioning task will use the JSON data file as the replacement variable values when the task is run.

The following is a minimally complete example of a provisioning template. More detail on building these templates can be found in the AWS IoT Core documentation located here.

Paste the contents below into a file and save it as provisioning-template.json.

{
  "Parameters": {
    "ThingName": {
      "Type": "String"
    },
    "SerialNumber": {
      "Type": "String"
    },
    "CSR": {
      "Type": "String"
    }
  },
  "Resources": {
    "thing": {
      "Type": "AWS::IoT::Thing",
      "Properties": {
        "ThingName": {
          "Ref": "ThingName"
        },
        "AttributePayload": {
          "version": "v1",
          "serialNumber": {
            "Ref": "SerialNumber"
          }
        }
      }
    },
    "certificate": {
      "Type": "AWS::IoT::Certificate",
      "Properties": {
        "CertificateSigningRequest": {
          "Ref": "CSR"
        },
        "Status": "ACTIVE"
      }
    },
    "policy": {
      "Type": "AWS::IoT::Policy",
      "Properties": {
        "PolicyDocument": "{\"Version\": \"2012-10-17\",\"Statement\": [{\"Effect\": \"Allow\",\"Action\": [\"iot:Publish\"],\"Resource\": [\"*\"]}]}"
      }
    }
  }
}

 

Create Certificates and Certificate Signing Requests (CSRs)

Next, we’ll create certificates and signing requests for our devices. For the purpose of this example we will provision 3 devices which will use individually unique certificates. In this example, we’ll be using the openssl command on an AWS EC2 instance running Amazon Linux to create the certificates. The commands below will create the certificate private key file and the CSR file for each of the 3 devices.

openssl req -new -newkey rsa:2048 -nodes -keyout device_one.key -out device_one.csr -subj "/C=US/ST=WA/L=Seattle/O=MyOrg/CN=MyDept"

openssl req -new -newkey rsa:2048 -nodes -keyout device_two.key -out device_two.csr -subj "/C=US/ST=WA/L=Seattle/O=MyOrg/CN=MyDept"

openssl req -new -newkey rsa:2048 -nodes -keyout device_three.key -out device_three.csr -subj "/C=US/ST=WA/L=Seattle/O=MyOrg/CN=MyDept"

Generate JSON data file and copy to S3 bucket

With the provisioning template and CSR files created, we can now build our JSON data file. The data file must be a newline-delimited JSON file. Each line contains all of the parameter values for provisioning a single device. For this example, our data file should appear as follows:

{"ThingName": "device-one", "SerialNumber": "001", "CSR": "*** CSR FILE CONTENT ***"}
{"ThingName": "device-two", "SerialNumber": "002", "CSR": "*** CSR FILE CONTENT ***"}
{"ThingName": "device-three", "SerialNumber": "003", "CSR": "*** CSR FILE CONTENT ***"}

 

Note that the CSR file content above was omitted in the above example. The CSR file contents should be formatted into a single line and included as the value for the CSR parameter. A properly formatted CSR file content string has the —–BEGIN CERTIFICATE REQUEST—– and —–END CERTIFICATE REQUEST—– lines removed and the line breaks, or carriage returns, converted into the escape sequence \n so that the content fits into a single string.

Here is an example of how to convert CSR file contents into a single string. Below we have an unmodified example CSR file content:

-----BEGIN CERTIFICATE REQUEST-----
MIICkjCCAXoCAQAwTTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQH
EwdTZWF0dGxlMQ4wDAYDVQQKEwVNeU9yZzEPMA0GA1UEAxMGTXlEZXB0MIIBIjAN
BgkqhkiG9w0BAQEFAAZCAQ8AMIIBCgKCAQEA5F5erQEDXqR0QgwDPlAE8u36c6Xr
pxA080KyaW8BQl0ZOwrxwZwtO/hpcg86d97DfY1gpw8RqftPEaVJe3451CWoc8a5
AKpJg82LQroQI8DNkdHl+wgdkaf9GvYzFiDLIQ3oNGa27Zx58Ve8qh+ymAo6g3+d
kdCfbcJhW/XqaJZeF5+lXGDXdrNotRealnm6kVJxMAqxEcJGpxDIRCaTjAES
yLcZPyOnEGBuUs68eKT6P2Wiyv8rTaO9E59FaSNcl8AMiK23AJt5sql1ZybBV8o+
WCQ3L2+nZnJVK9TME0ZZ+18AnfVKFhZYcoV2/UxXMAa3T6LFzw6DAhrH3QIDAQAB
oAAwDQYJKoZIhvcNAQEFBQADggEBAKCaWAvRargxBa9k1zZ2nI7y1mpuzTcgoOMj
IDR/9DxGjS913AtDfpYm/cM+1x38lNfe3qRQHTmw3UnPUlNJSLTA6rCepllpMQSe
XgaG60PTJ6/h0zvPwdUg1JOEE3lxlSJz4pHiT2Sdmyleg1hp7jezFqGEelKd+Xfd
bfp7rNBESIq1ymWdagXnsyWjN34JqvWiS6J4NWzO2zlFkHghkbMOwOZJRrZuyOVs
cjDZVgqYHt9xJD4Rm6U4L6uFQabHElw2IwT6izSCzU50Ahjj89snBCKnLWCe0XTb
ojVkIg5RofqzP1VwYtx5ORq93/YOxHqrpWDTa7q64BFzp1v7LlQ=
-----END CERTIFICATE REQUEST-----

 

With the content above contained in a file named device-one.csr, you can run the following commands to process the file into a properly formatted string.

grep -v REQUEST device-one.csr | awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' > single-string-file.out

The file single-string-file.out contains the CSR file formatted as a single string for use in the bulk-provisioning-data.json file.

An example output of the command above is as follows. Notice that the line feeds have become “\n” and that the BEGIN and END lines have been removed. Include the single string CSR content for each device specified in your data file.


MIICkjCCAXoCAQAwTTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQH\nEwdTZWF0dGxlMQ4wDAYDVQQKEwVNeU9yZzEPMA0GA1UEAxMGTXlEZXB0MIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5F5erQEDXqR0QgwDPlAE8u36c6Xr\npxA080KyaW8BQl0ZOwrxwZwtO/hpcg86d97CfY1gpw8RqftPEaVJe3451CWoc8a5\nAKpJg82LQroQI8DNkdHl+wgdkaf9GvYzFiDLIQ3oNGa27Zx58Ve8qh+ymAo6g3+d\nkdCfbcJhW/XqaJZeF5+lXGDXdrPccioASwybogusVJxMAqxEcJGpxDIRCaTjAES\nyLcZPyOnEGBuUs68eKT6P2Wiyv8rTaO9E59FaSNcl8ASillYAJt5sql1ZybBV8o+\nWCQ3L2+nZnJVK9TME0ZZ+18AnfVGFhZYcoV2/UxXMAa3T6LFzw6DAhrH3QIDAQAB\noAAwDQYJKoZIhvcNAQEFBQADNotRealAKCaWAvRargxBa9k1zZ2nI7y1mpuzTwooOMj\nIDR/9DxGjS913AtDfpYm/cM+1x38lNfe3qRQHTmw3UnPUlNJSLTA6rCepllpMQSe\nXgaG60PTJ6/h0zvLwdUg1JOEE3lxlSJz4pHiT2Sdmyleg1hp7jezFqGEelKd+Xfd\nbfp7rNBESIq1ymWdagXnsyWjN34JqvWiS6J4NWzO2zlFkHghkbMOwOZJRrZuyOVs\ncjDZVgqYHt9x

Save this JSON file as bulk-provisioning-data.json and copy this file to a location in an S3 bucket located in the region where you will be running the provisioning task.

Create Service Role

When the provisioning task is executed, the IoT service will need to locate the data file in an S3 bucket. You can use an existing bucket or create a new one specifically for use in provisioning a device in the AWS IoT Core service. With either choice, you will need to create a role that allows AWS IoT Core to access the bucket to retrieve the data file.

When creating the role, the trust policy should appear like this example:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "iot.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

 

Create a policy to provide permissions to your S3 bucket. Be sure that your bucket name is properly entered.

Use the example below as a guide:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject"
      ],
      "Resource": [
        "arn:aws:s3:::replace_with_your_bucket_name/*"
      ]
    }
  ]
}

 

Attach the policy to the role.

Next you can attach an AWS managed policy to the role to provide the AWS IoT Core Service permissions necessary to successfully execute the provisioning steps. In the IAM console, you can search for ‘AWSIoTThings’ to find the ‘AWSIoTThingsRegistration’ AWS managed policy. Attach this policy to your role in addition to the S3 permissions policy created in the previous steps.

Now that you’ve created the role, note the role ARN as you will require it in later steps.

Run the Bulk Provisioning Task

Now to the part you’ve been waiting for, running the bulk provisioning task! All the steps prior to this created data or configuration used for this activity. In order to run the bulk provisioning, you will need to have the AWS CLI installed and configured for a AWS IoT Core supported region with a user that has the proper permissions. For this example, an IAM user with the AWS managed policy arn:aws:iam::aws:policy/AWSIoTFullAccess attached was used. In addition to this policy, ensure that the IAM user executing the commands has the IAM:PassRole permission.

The IAM:PassRole permission can be added to the IAM user via an inline policy. An example policy is as follows:

{
   "Version": "2012-10-17",
     "Statement": [
     {
       "Effect": "Allow",
       "Action": "iam:PassRole",
       "Resource": "*"
     }
  ]
}

 

Remember to replace the values in the example command below with your values for the template file, data file, data file bucket and role ARN.

aws iot start-thing-registration-task --template-body file:///home/ec2-user/provisioning-template.json --input-file-bucket replace_with_your_bucket_name --input-file-key bulk-provisioning-data.json --role-arn arn:aws:iam::123456789012:role/iot-bulk-provisioning-role

After running the command successfully, you should receive a task id output like the following:

{
"taskId": "5d111206-093c-4ab3-1234-b2f14b0c208d"
}

You can inspect your recently executed tasks using the list-thing-registration-tasks command as shown below.

aws iot list-thing-registration-tasks
{
"taskIds": [
"d62ded50-1ac6-4424-5678-84fed7b9f916",
"5d111206-093c-4ab3-1234-b2f14b0c208d"
]
}

Next, you can see the details and check the status of the registration task using the describe-thing-registration-task command as shown below.

aws iot describe-thing-registration-task --task-id 5d111206-093c-4ab3-1234-b2f14b0c208d
{
"status": "Completed",
"successCount": 3,
"creationDate": 1511202602.898,
"templateBody": “** removed for readability **",
"lastModifiedDate": 1511202604.694,
"roleArn": "arn:aws:iam::123456789012:role/iot-bulk-provisioning-role",
"inputFileKey": "bulk-provisioning-data.json",
"inputFileBucket": "my_bucket",
"taskId": "5d111206-093c-4ab3-1234-b2f14b0c208d",
"failureCount": 0,
"percentageProgress": 100
}

Lastly, you can also get a more detailed report using the list-thing-registration-task-reports command as shown below.

aws iot list-thing-registration-task-reports --task-id eacb0860-e99a-1234-5678-f7a976fc2408 --report-type RESULTS
{
"resourceLinks": [
"https://aws-iot-btp-prod-us-east-1.s3.amazonaws.com/123456789012/a779514e-51f1-4027-beef-73447cafebaca/successful/a779514e-51f1-4027-bd2e-73447efcbaca-1?X-Amz-Security-Token=FQoDYXdzEE4aDOjiGWbWwt7xASULzSLYAb37lzpZBsW7HPpYS0ko8MtWntXCed0QhYKZ0i4hBJZ6JAoqvBE58LcytLTgmxUwg3NS2ZnbYEzH%2FH%2Fxd1XalbertMZCpYg2lF0fpbAjt2B%2FJog%2Fj0FtyflWztC9s0NdaolhFuEj3XNQpL3qHK41jKhITYA3imKdX75Z6x2%2BHRSjCpvvTrQllDLHS3dC1nFOXYXGd1ChjxnkjKkhQGPQlrAoGPR3TMMCpi73fDAtR72yQ0mTF%2FJHEZ4g6umLj%2FAbHlBeiA%2BQ99QhCaUQ3Sco1xL7BpJ7jkuYmCj%2B5ZbRBQ%3D%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20171204T204440Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86400&X-Amz-Credential=ASIAIOE5MA3ZIRF7WHAT%2F20171204%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=600b27c36c484cb8b3bfa707beefde0fe279d92ccb9f2a4848a13e95442b854"
],
"reportType": "RESULTS"
}

Navigate to the link returned in “resourceLinks” for a JSON file containing the signed certificate values, the thing ARNs and the policy ARNs for the newly provisioned things.

If the list-thing-registration-task-reports with report type RESULTS returns an empty list then there may have been errors processing the data file. Details on the errors can be retrieved by issuing the list-thing-registration-task-reports command with the —report-type parameter value as ERRORS. The link returned will be a link to an error report which is helpful for troubleshooting.

With our IoT things now fully provisioned, we can provide the certificate files to manufacturing to be copied to the devices as they come off of our assembly line. Then our products can be packed and shipped to retailers where they can be purchased and enjoyed by customers.

Wrapping Up

Using AWS IoT bulk provisioning feature, device manufacturers and suppliers can simplify and automate tasks like provisioning device identities in a secure and repeatable fashion as demonstrated by the examples. While the examples here are a start, there is much more that AWS IoT Device Management offers organizations for deploying and managing large fleets of connected things. I hope you found the blog useful and informative, and I encourage you to learn more about the new features of the AWS IoT Core to help your organization make the most of these and other enabling new technologies from AWS.

Learning More

More on AWS IoT Device Management
https://aws.amazon.com/iot-device-management

AWS IoT Device Management – Features
https://aws.amazon.com/iot-device-management/features/

AWS IoT Device Provisioning
http://docs.aws.amazon.com/iot/latest/developerguide/iot-provision.html

Citations

[1] AWS Announces a Slew of New IoT Services; Brings Machine Learning to the Edge
http://www.businesswire.com/news/home/20171129006079/en/AWS-Announces-Slew-New-IoT-Services-Brings

[2] AWS re:Invent 2017: AWS IoT Device Management (IOT330)
https://youtu.be/Qi1FVPXDPQc?t=1065