Skip to content

Commit bbdec61

Browse files
committed
reinstate service client samples
1 parent 428df09 commit bbdec61

File tree

16 files changed

+2020
-0
lines changed

16 files changed

+2020
-0
lines changed
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
# Node: Fleet provisioning
2+
3+
[**Return to main sample list**](../../README.md)
4+
5+
This sample uses the AWS IoT [Fleet provisioning service](https://docs.aws.amazon.com/iot/latest/developerguide/provision-wo-cert.html) to provision devices using the CreateKeysAndCertificate and RegisterThing APIs. This allows you to create new AWS IoT Core thing resources using a Fleet Provisioning Template.
6+
7+
The [IAM Policy](https://docs.aws.amazon.com/iot/latest/developerguide/iot-policies.html) attached to your provisioning certificate must provide privileges for this sample to connect, subscribe, publish, and receive. Below is a sample policy that can be used that will allow this sample to run as intended.
8+
9+
<details>
10+
<summary>(see sample policy)</summary>
11+
<pre>
12+
{
13+
"Version": "2012-10-17",
14+
"Statement": [
15+
{
16+
"Effect": "Allow",
17+
"Action": "iot:Publish",
18+
"Resource": [
19+
"arn:aws:iot:<b>region</b>:<b>account</b>:topic/$aws/certificates/create/json",
20+
"arn:aws:iot:<b>region</b>:<b>account</b>:topic/$aws/provisioning-templates/<b>templatename</b>/provision/json"
21+
]
22+
},
23+
{
24+
"Effect": "Allow",
25+
"Action": [
26+
"iot:Receive"
27+
],
28+
"Resource": [
29+
"arn:aws:iot:<b>region</b>:<b>account</b>:topic/$aws/certificates/create/json/accepted",
30+
"arn:aws:iot:<b>region</b>:<b>account</b>:topic/$aws/certificates/create/json/rejected",
31+
"arn:aws:iot:<b>region</b>:<b>account</b>:topic/$aws/provisioning-templates/<b>templatename</b>/provision/json/accepted",
32+
"arn:aws:iot:<b>region</b>:<b>account</b>:topic/$aws/provisioning-templates/<b>templatename</b>/provision/json/rejected"
33+
]
34+
},
35+
{
36+
"Effect": "Allow",
37+
"Action": [
38+
"iot:Subscribe"
39+
],
40+
"Resource": [
41+
"arn:aws:iot:<b>region</b>:<b>account</b>:topicfilter/$aws/certificates/create/json/accepted",
42+
"arn:aws:iot:<b>region</b>:<b>account</b>:topicfilter/$aws/certificates/create/json/rejected",
43+
"arn:aws:iot:<b>region</b>:<b>account</b>:topicfilter/$aws/provisioning-templates/<b>templatename</b>/provision/json/accepted",
44+
"arn:aws:iot:<b>region</b>:<b>account</b>:topicfilter/$aws/provisioning-templates/<b>templatename</b>/provision/json/rejected"
45+
]
46+
},
47+
{
48+
"Effect": "Allow",
49+
"Action": "iot:Connect",
50+
"Resource": "arn:aws:iot:<b>region</b>:<b>account</b>:client/test-*"
51+
}
52+
]
53+
}
54+
</pre>
55+
56+
Replace with the following with the data from your AWS account:
57+
* `<region>`: The AWS IoT Core region where you created your AWS IoT Core thing you wish to use with this sample. For example `us-east-1`.
58+
* `<account>`: Your AWS IoT Core account ID. This is the set of numbers in the top right next to your AWS account name when using the AWS IoT Core website.
59+
* `<templatename>`: The name of your AWS Fleet Provisioning template you want to use to create new AWS IoT Core Things.
60+
61+
Note that in a real application, you may want to avoid the use of wildcards in your ClientID or use them selectively. Please follow best practices when working with AWS on production applications using the SDK. Also, for the purposes of this sample, please make sure your policy allows a client ID of `test-*` to connect or use `--client_id <client ID here>` to send the client ID your policy supports.
62+
63+
</details>
64+
65+
### How to run
66+
67+
There are many different ways to run the Fleet Provisioning sample because of how many different ways there are to setup a Fleet Provisioning template in AWS IoT Core. **The easiest and most common way is to run the sample with the following**:
68+
69+
``` sh
70+
# from the node/fleet_provisioning folder
71+
npm install
72+
node ./index.js --endpoint <endpoint> --cert <file> --key <file> --template_name <template name> --template_parameters <template parameters>
73+
```
74+
75+
### Fleet Provisioning Detailed Instructions
76+
77+
#### Aws Resource Setup
78+
79+
Fleet provisioning requires some additional AWS resources be set up first. These steps assume you have the [AWS CLI](https://aws.amazon.com/cli/) installed and have your AWS credentials for the AWS CLI setup and with sufficient permissions to perform all of the operations in this guide. For instructions on how to setup AWS CLI, see the following: [Configuring the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html).
80+
81+
You will also need Python version 3 installed to be able to run the `parse_cert_set_result.py` file, which is a helper script to make running this sample easier. You can find Python3 installers for your platform on the [Python website](https://www.python.org/).
82+
83+
These steps are based on the provisioning setup steps
84+
that can be found at [Embedded C SDK Setup](https://docs.aws.amazon.com/freertos/latest/lib-ref/c-sdk/provisioning/provisioning_tests.html#provisioning_system_tests_setup).
85+
86+
87+
First, create the IAM role that will be needed by the fleet provisioning template. Replace `<RoleName>` with a name of the role you want to create.
88+
89+
``` sh
90+
aws iam create-role \
91+
--role-name <RoleName> \
92+
--assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"iot.amazonaws.com"}}]}'
93+
```
94+
95+
This is the IAM role the Fleet Provisioning template will use to create the new AWS IoT things. However, before it can do so, it will need to have a policy attached to it to give the new role permission to perform the operations it needs. To do this, run the following command and replace `<RoleName>` with the name of the role you created in the previous step.
96+
97+
``` sh
98+
aws iam attach-role-policy \
99+
--role-name <RoleName> \
100+
--policy-arn arn:aws:iam::aws:policy/service-role/AWSIoTThingsRegistration
101+
```
102+
103+
The next step is to make a template resource that will be used for provisioning the new AWS IoT Core things. This template tells AWS IoT Core how to setup the new AWS IoT Core Things you create when your Fleet Provisioning role is invoked, setting up material such as the name and tags, for example.
104+
105+
To create a new Fleet Provisioning template, you can use the following AWS CLI command, replacing `<TemplateName>` with the name of the template you wish to create, `<RoleName>` with the name of the role you created two steps prior, and `<Account>` with your AWS IoT Core account number. Finally, make sure to replace `<TemplateJSON>` with a valid JSON document as a single line. An example JSON document is provided further below.
106+
107+
``` sh
108+
aws iot create-provisioning-template \
109+
--template-name <TemplateName> \
110+
--provisioning-role-arn arn:aws:iam::<Account>:role/<RoleName> \
111+
--template-body "<TemplateJSON>" \
112+
--enabled
113+
```
114+
115+
For the purposes of this sample, the following template JSON document is presumed to be used:
116+
117+
<details>
118+
<summary>(see template body)</summary>
119+
120+
```json
121+
{
122+
"Parameters": {
123+
"DeviceLocation": {
124+
"Type": "String"
125+
},
126+
"AWS::IoT::Certificate::Id": {
127+
"Type": "String"
128+
},
129+
"SerialNumber": {
130+
"Type": "String"
131+
}
132+
},
133+
"Mappings": {
134+
"LocationTable": {
135+
"Seattle": {
136+
"LocationUrl": "https://example.aws"
137+
}
138+
}
139+
},
140+
"Resources": {
141+
"thing": {
142+
"Type": "AWS::IoT::Thing",
143+
"Properties": {
144+
"ThingName": {
145+
"Fn::Join": [
146+
"",
147+
[
148+
"ThingPrefix_",
149+
{
150+
"Ref": "SerialNumber"
151+
}
152+
]
153+
]
154+
},
155+
"AttributePayload": {
156+
"version": "v1",
157+
"serialNumber": "serialNumber"
158+
}
159+
},
160+
"OverrideSettings": {
161+
"AttributePayload": "MERGE",
162+
"ThingTypeName": "REPLACE",
163+
"ThingGroups": "DO_NOTHING"
164+
}
165+
},
166+
"certificate": {
167+
"Type": "AWS::IoT::Certificate",
168+
"Properties": {
169+
"CertificateId": {
170+
"Ref": "AWS::IoT::Certificate::Id"
171+
},
172+
"Status": "Active"
173+
},
174+
"OverrideSettings": {
175+
"Status": "REPLACE"
176+
}
177+
},
178+
"policy": {
179+
"Type": "AWS::IoT::Policy",
180+
"Properties": {
181+
"PolicyDocument": {
182+
"Version": "2012-10-17",
183+
"Statement": [
184+
{
185+
"Effect": "Allow",
186+
"Action": [
187+
"iot:Connect",
188+
"iot:Subscribe",
189+
"iot:Publish",
190+
"iot:Receive"
191+
],
192+
"Resource": "*"
193+
}
194+
]
195+
}
196+
}
197+
}
198+
},
199+
"DeviceConfiguration": {
200+
"FallbackUrl": "https://www.example.com/test-site",
201+
"LocationUrl": {
202+
"Fn::FindInMap": [
203+
"LocationTable",
204+
{
205+
"Ref": "DeviceLocation"
206+
},
207+
"LocationUrl"
208+
]
209+
}
210+
}
211+
}
212+
```
213+
214+
</details>
215+
216+
And here is the same JSON document, but as a single line for easier copy-pasting:
217+
218+
<details>
219+
<summary>(see template body)</summary>
220+
221+
``` json
222+
{"Parameters": {"DeviceLocation": {"Type": "String"},"AWS::IoT::Certificate::Id": {"Type": "String"},"SerialNumber": {"Type": "String"}},"Mappings": {"LocationTable": {"Seattle": {"LocationUrl": "https://example.aws"}}},"Resources": {"thing": {"Type": "AWS::IoT::Thing","Properties": {"ThingName": {"Fn::Join": ["",["ThingPrefix_",{"Ref": "SerialNumber"}]]},"AttributePayload": {"version": "v1","serialNumber": "serialNumber"}},"OverrideSettings": {"AttributePayload": "MERGE","ThingTypeName": "REPLACE","ThingGroups": "DO_NOTHING"}},"certificate": {"Type": "AWS::IoT::Certificate","Properties": {"CertificateId": {"Ref": "AWS::IoT::Certificate::Id"},"Status": "Active"},"OverrideSettings": {"Status": "REPLACE"}},"policy": {"Type": "AWS::IoT::Policy","Properties": {"PolicyDocument": {"Version": "2012-10-17","Statement": [{"Effect": "Allow","Action": ["iot:Connect","iot:Subscribe","iot:Publish","iot:Receive"],"Resource": "*"}]}}}},"DeviceConfiguration": {"FallbackUrl": "https://www.example.com/test-site","LocationUrl": {"Fn::FindInMap": ["LocationTable",{"Ref": "DeviceLocation"},"LocationUrl"]}}}
223+
```
224+
225+
</details>
226+
227+
You can use this JSON document as the `<TemplateJSON>` in the AWS CLI command. This sample will assume you have used the template JSON above, so you may need to adjust if you are using a different template JSON. Thankfully, all of these steps need to only be done and, now that they are complete, you will need not perform them again.
228+
229+
#### Creating a certificate-key set from a provisioning claim
230+
231+
To run the provisioning sample, you'll need a certificate and key set with sufficient permissions. Provisioning certificates are normally created ahead of time and placed on your device, but for this sample, we will just create them on the fly. This is primarily done for example purposes.
232+
233+
You can also use any certificate set you've already created if it has sufficient IoT permissions. If you wish to do this, you can skip the step that calls `create-provisioning-claim` below and move right to the next step: [Running the sample using a certificate-key set](#running-the-sample-using-a-certificate-key-set)
234+
235+
We've included a script in the utils folder that creates certificate and key files from the response of calling
236+
`create-provisioning-claim`. These dynamically sourced certificates are **only valid for five minutes**. When running the command,
237+
you'll need to substitute the name of the template you previously created. If on Windows, replace the paths with something appropriate.
238+
239+
**Note**: The following assumes you are running this command from the `aws-iot-device-sdk-js-v2` folder, which is the main GitHub folder. If you are running this from another folder then you will need to adjust the filepaths accordingly.
240+
241+
```sh
242+
aws iot create-provisioning-claim \
243+
--template-name <TemplateName> \
244+
| python3 ./utils/parse_cert_set_result.py \
245+
--path /tmp \
246+
--filename provision
247+
```
248+
* Replace `<TemplateName>` with the name of the Fleet Provisioning template you created earlier.
249+
250+
This will create a certificate and key in the `tmp` folder with file names starting with `provision`. You can now use these temporary keys
251+
to perform the actual provisioning in the section below.
252+
253+
#### Running the sample using a certificate-key set
254+
255+
To run the sample with your certificate and private key, use the following command:
256+
257+
``` sh
258+
# from the node/fleet_provisioning/basic folder
259+
npm install
260+
node ./dist/index.js --endpoint <endpoint> --cert <file> --key <file> --template_name <template name> --template_parameters '{"SerialNumber":"1","DeviceLocation":"Seattle"}'
261+
```
262+
263+
As per normal, replace the `<>` parameters with the proper values. Notice that we provided substitution values for the two parameters in the template body, `DeviceLocation` and `SerialNumber`.
264+
265+
With that, the sample should run and work as expected! You should then find you have a new AWS IoT Core thing!
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
6+
import { iotidentity } from 'aws-iot-device-sdk-v2';
7+
import { once } from "events"
8+
9+
type Args = { [index: string]: any };
10+
const yargs = require('yargs');
11+
12+
// The relative path is '../../../util/cli_args' from here, but the compiled javascript file gets put one level
13+
// deeper inside the 'dist' folder
14+
const common_args = require('../../../../util/cli_args');
15+
16+
yargs.command('*', false, (yargs: any) => {
17+
common_args.add_direct_connection_establishment_arguments(yargs);
18+
yargs
19+
.option('template_name', {
20+
alias: 't',
21+
description: 'Template Name.',
22+
type: 'string',
23+
required: true
24+
})
25+
.option('template_parameters', {
26+
alias: 'tp',
27+
description: '<json>: Template parameters json.',
28+
type: 'string',
29+
required: false
30+
})
31+
}, main).parse();
32+
33+
async function main(argv: Args) {
34+
common_args.apply_sample_arguments(argv);
35+
36+
console.log("Connecting...");
37+
let protocolClient = common_args.build_mqtt5_client_from_cli_args(argv);
38+
let identityClient = iotidentity.IotIdentityClientv2.newFromMqtt5(protocolClient, {
39+
maxRequestResponseSubscriptions: 2,
40+
maxStreamingSubscriptions: 0,
41+
operationTimeoutInSeconds: 60
42+
});
43+
44+
const connectionSuccess = once(protocolClient, "connectionSuccess");
45+
protocolClient.start();
46+
47+
await connectionSuccess;
48+
console.log("Connected!");
49+
50+
let createKeysResponse = await identityClient.createKeysAndCertificate({});
51+
console.log(`CreateKeysAndCertificate Response: ${JSON.stringify(createKeysResponse)}`);
52+
53+
let registerThingRequest : iotidentity.model.RegisterThingRequest = {
54+
templateName: argv.template_name,
55+
certificateOwnershipToken: createKeysResponse.certificateOwnershipToken,
56+
};
57+
58+
if (argv.template_parameters) {
59+
registerThingRequest.parameters = JSON.parse(argv.template_parameters);
60+
}
61+
62+
let registerThingResponse = await identityClient.registerThing(registerThingRequest);
63+
console.log(`RegisterThing Response: ${JSON.stringify(registerThingResponse)}`);
64+
65+
identityClient.close();
66+
67+
console.log("Disconnecting...");
68+
69+
let stopped = once(protocolClient, "stopped");
70+
protocolClient.stop();
71+
await stopped;
72+
73+
console.log("Disconnected");
74+
process.exit(0);
75+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "fleet-provisioning-basic",
3+
"version": "1.0.0",
4+
"description": "NodeJS IoT SDK v2 Fleet Provisioning Sample",
5+
"homepage": "https://github.com/awslabs/aws-iot-device-sdk-js-v2",
6+
"repository": {
7+
"type": "git",
8+
"url": "git+https://github.com/aws/aws-iot-device-sdk-js-v2.git"
9+
},
10+
"contributors": [
11+
"AWS SDK Common Runtime Team <[email protected]>"
12+
],
13+
"license": "Apache-2.0",
14+
"main": "./dist/index.js",
15+
"scripts": {
16+
"tsc": "tsc",
17+
"prepare": "npm run tsc"
18+
},
19+
"devDependencies": {
20+
"@types/node": "^10.17.50",
21+
"typescript": "^4.7.4"
22+
},
23+
"dependencies": {
24+
"aws-iot-device-sdk-v2": "file:../../../..",
25+
"yargs": "^16.2.0"
26+
}
27+
}

0 commit comments

Comments
 (0)