or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

device-shadow.mdfleet-provisioning.mdgreengrass-discovery.mdgreengrass-ipc.mdindex.mdiot-jobs.mdmqtt-connections.md

fleet-provisioning.mddocs/

0

# Fleet Provisioning

1

2

Device certificate provisioning and thing registration capabilities for automated fleet provisioning workflows including certificate creation from CSR, keys and certificate generation, and device thing registration through both V1 (callback-based) and V2 (Future-based) client interfaces.

3

4

## Capabilities

5

6

### V1 Identity Client (Callback-Based)

7

8

The V1 client provides callback-based operations following the traditional publish/subscribe pattern.

9

10

#### Client Creation

11

12

```python { .api }

13

class IotIdentityClient(MqttServiceClient):

14

"""

15

V1 client for AWS IoT Identity/Fleet Provisioning service with callback-based operations.

16

17

Parameters:

18

- mqtt_connection: MQTT connection (mqtt.Connection or mqtt5.Client)

19

"""

20

def __init__(self, mqtt_connection): ...

21

```

22

23

Usage example:

24

25

```python

26

from awsiot import mqtt_connection_builder, iotidentity

27

28

# Create MQTT connection with provisioning claim certificates

29

connection = mqtt_connection_builder.mtls_from_path(

30

endpoint="your-endpoint.iot.us-east-1.amazonaws.com",

31

cert_filepath="/path/to/provisioning-claim.pem.crt",

32

pri_key_filepath="/path/to/provisioning-claim.pem.key",

33

client_id="provisioning-client-123"

34

)

35

36

# Create identity client

37

identity_client = iotidentity.IotIdentityClient(connection)

38

```

39

40

#### Certificate Operations

41

42

##### Create Certificate from CSR

43

44

```python { .api }

45

def publish_create_certificate_from_csr(self, request, qos):

46

"""

47

Publish request to create certificate from Certificate Signing Request.

48

49

Parameters:

50

- request (CreateCertificateFromCsrRequest): CSR certificate request

51

- qos (awscrt.mqtt.QoS): Quality of service

52

53

Returns:

54

Future: Future that completes when request is published

55

"""

56

57

def subscribe_to_create_certificate_from_csr_accepted(self, request, qos, callback):

58

"""

59

Subscribe to successful create certificate from CSR responses.

60

61

Parameters:

62

- request (CreateCertificateFromCsrSubscriptionRequest): Subscription request

63

- qos (awscrt.mqtt.QoS): Quality of service

64

- callback: Function called with certificate response

65

66

Returns:

67

Tuple[Future, str]: Future for subscription, topic string

68

"""

69

70

def subscribe_to_create_certificate_from_csr_rejected(self, request, qos, callback):

71

"""

72

Subscribe to rejected create certificate from CSR responses.

73

74

Parameters:

75

- request (CreateCertificateFromCsrSubscriptionRequest): Subscription request

76

- qos (awscrt.mqtt.QoS): Quality of service

77

- callback: Function called when request is rejected

78

79

Returns:

80

Tuple[Future, str]: Future for subscription, topic string

81

"""

82

```

83

84

##### Create Keys and Certificate

85

86

```python { .api }

87

def publish_create_keys_and_certificate(self, request, qos):

88

"""

89

Publish request to create new private key and certificate.

90

91

Parameters:

92

- request (CreateKeysAndCertificateRequest): Keys and certificate request

93

- qos (awscrt.mqtt.QoS): Quality of service

94

95

Returns:

96

Future: Future that completes when request is published

97

"""

98

99

def subscribe_to_create_keys_and_certificate_accepted(self, request, qos, callback):

100

"""

101

Subscribe to successful create keys and certificate responses.

102

103

Parameters:

104

- request (CreateKeysAndCertificateSubscriptionRequest): Subscription request

105

- qos (awscrt.mqtt.QoS): Quality of service

106

- callback: Function called with keys and certificate response

107

108

Returns:

109

Tuple[Future, str]: Future for subscription, topic string

110

"""

111

112

def subscribe_to_create_keys_and_certificate_rejected(self, request, qos, callback):

113

"""

114

Subscribe to rejected create keys and certificate responses.

115

"""

116

```

117

118

##### Register Thing

119

120

```python { .api }

121

def publish_register_thing(self, request, qos):

122

"""

123

Publish request to register device thing with provisioning template.

124

125

Parameters:

126

- request (RegisterThingRequest): Thing registration request

127

- qos (awscrt.mqtt.QoS): Quality of service

128

129

Returns:

130

Future: Future that completes when request is published

131

"""

132

133

def subscribe_to_register_thing_accepted(self, request, qos, callback):

134

"""

135

Subscribe to successful register thing responses.

136

137

Parameters:

138

- request (RegisterThingSubscriptionRequest): Subscription request

139

- qos (awscrt.mqtt.QoS): Quality of service

140

- callback: Function called with thing registration response

141

142

Returns:

143

Tuple[Future, str]: Future for subscription, topic string

144

"""

145

146

def subscribe_to_register_thing_rejected(self, request, qos, callback):

147

"""

148

Subscribe to rejected register thing responses.

149

"""

150

```

151

152

### V2 Identity Client (Future-Based)

153

154

The V2 client provides Future-based operations with request-response semantics.

155

156

#### Client Creation

157

158

```python { .api }

159

class IotIdentityClientV2:

160

"""

161

V2 client for AWS IoT Identity/Fleet Provisioning service with Future-based operations.

162

"""

163

def __init__(self, connection): ...

164

```

165

166

#### Certificate Operations

167

168

```python { .api }

169

def create_certificate_from_csr(self, request):

170

"""

171

Create certificate from CSR using request-response pattern.

172

173

Parameters:

174

- request (CreateCertificateFromCsrRequest): CSR certificate request

175

176

Returns:

177

Future[CreateCertificateFromCsrResponse]: Future containing certificate response

178

"""

179

180

def create_keys_and_certificate(self, request):

181

"""

182

Create private key and certificate using request-response pattern.

183

184

Parameters:

185

- request (CreateKeysAndCertificateRequest): Keys and certificate request

186

187

Returns:

188

Future[CreateKeysAndCertificateResponse]: Future containing keys and certificate

189

"""

190

191

def register_thing(self, request):

192

"""

193

Register device thing using request-response pattern.

194

195

Parameters:

196

- request (RegisterThingRequest): Thing registration request

197

198

Returns:

199

Future[RegisterThingResponse]: Future containing registration response

200

"""

201

```

202

203

### Data Model Classes

204

205

#### Request Classes

206

207

```python { .api }

208

@dataclass

209

class CreateCertificateFromCsrRequest:

210

"""Request to create certificate from CSR."""

211

certificate_signing_request: str

212

213

@dataclass

214

class CreateKeysAndCertificateRequest:

215

"""Request to create private key and certificate."""

216

pass # No additional parameters required

217

218

@dataclass

219

class RegisterThingRequest:

220

"""Request to register device thing."""

221

template_name: str

222

certificate_ownership_token: str

223

parameters: Optional[Dict[str, str]] = None

224

```

225

226

#### Response Classes

227

228

```python { .api }

229

@dataclass

230

class CreateCertificateFromCsrResponse:

231

"""Response from create certificate from CSR operation."""

232

certificate_pem: Optional[str] = None

233

certificate_arn: Optional[str] = None

234

certificate_id: Optional[str] = None

235

certificate_ownership_token: Optional[str] = None

236

237

@dataclass

238

class CreateKeysAndCertificateResponse:

239

"""Response from create keys and certificate operation."""

240

certificate_pem: Optional[str] = None

241

private_key: Optional[str] = None

242

certificate_arn: Optional[str] = None

243

certificate_id: Optional[str] = None

244

certificate_ownership_token: Optional[str] = None

245

246

@dataclass

247

class RegisterThingResponse:

248

"""Response from register thing operation."""

249

device_configuration: Optional[Dict[str, str]] = None

250

thing_name: Optional[str] = None

251

```

252

253

#### Subscription Request Classes

254

255

```python { .api }

256

@dataclass

257

class CreateCertificateFromCsrSubscriptionRequest:

258

"""Subscription request for create certificate from CSR responses."""

259

pass

260

261

@dataclass

262

class CreateKeysAndCertificateSubscriptionRequest:

263

"""Subscription request for create keys and certificate responses."""

264

pass

265

266

@dataclass

267

class RegisterThingSubscriptionRequest:

268

"""Subscription request for register thing responses."""

269

template_name: str

270

```

271

272

#### Error Response Classes

273

274

```python { .api }

275

@dataclass

276

class ErrorResponse:

277

"""Error response from identity operations."""

278

error_code: Optional[str] = None

279

error_message: Optional[str] = None

280

status_code: Optional[int] = None

281

```

282

283

## Usage Examples

284

285

### V1 Client - Complete Fleet Provisioning Workflow

286

287

```python

288

from awsiot import mqtt_connection_builder, iotidentity

289

from awscrt import mqtt

290

import json

291

import os

292

293

# Step 1: Connect with provisioning claim certificate

294

connection = mqtt_connection_builder.mtls_from_path(

295

endpoint="your-endpoint.iot.us-east-1.amazonaws.com",

296

cert_filepath="/path/to/provisioning-claim.pem.crt",

297

pri_key_filepath="/path/to/provisioning-claim.pem.key",

298

client_id="fleet-provisioning-123"

299

)

300

301

identity_client = iotidentity.IotIdentityClient(connection)

302

connection.connect().result()

303

304

# Global variables to store provisioning results

305

device_certificate = None

306

device_private_key = None

307

thing_name = None

308

certificate_ownership_token = None

309

310

def on_create_keys_accepted(response):

311

"""Handle successful keys and certificate creation."""

312

global device_certificate, device_private_key, certificate_ownership_token

313

314

print("Keys and certificate created successfully!")

315

device_certificate = response.certificate_pem

316

device_private_key = response.private_key

317

certificate_ownership_token = response.certificate_ownership_token

318

319

# Save certificate and key to files

320

with open("/tmp/device-certificate.pem.crt", "w") as f:

321

f.write(device_certificate)

322

with open("/tmp/device-private.pem.key", "w") as f:

323

f.write(device_private_key)

324

325

print(f"Certificate ID: {response.certificate_id}")

326

print(f"Certificate ARN: {response.certificate_arn}")

327

328

# Step 2: Register the thing using the certificate ownership token

329

register_request = iotidentity.RegisterThingRequest(

330

template_name="MyFleetProvisioningTemplate",

331

certificate_ownership_token=certificate_ownership_token,

332

parameters={

333

"DeviceLocation": "Building-A-Floor-2",

334

"DeviceType": "TemperatureSensor"

335

}

336

)

337

identity_client.publish_register_thing(register_request, mqtt.QoS.AT_LEAST_ONCE)

338

339

def on_create_keys_rejected(error):

340

"""Handle keys and certificate creation rejection."""

341

print(f"Keys and certificate creation rejected: {error}")

342

343

def on_register_thing_accepted(response):

344

"""Handle successful thing registration."""

345

global thing_name

346

347

print("Thing registered successfully!")

348

thing_name = response.thing_name

349

350

print(f"Thing name: {thing_name}")

351

print(f"Device configuration: {response.device_configuration}")

352

353

# Save device configuration

354

if response.device_configuration:

355

with open("/tmp/device-config.json", "w") as f:

356

json.dump(response.device_configuration, f, indent=2)

357

358

print("Fleet provisioning completed successfully!")

359

360

# Now you can disconnect from the provisioning endpoint

361

# and connect using the new device certificate

362

setup_device_connection()

363

364

def on_register_thing_rejected(error):

365

"""Handle thing registration rejection."""

366

print(f"Thing registration rejected: {error}")

367

368

def setup_device_connection():

369

"""Setup permanent device connection with new certificate."""

370

print("Setting up device connection with new certificate...")

371

372

# Disconnect from provisioning connection

373

connection.disconnect().result()

374

375

# Create new connection with device certificate

376

device_connection = mqtt_connection_builder.mtls_from_path(

377

endpoint="your-endpoint.iot.us-east-1.amazonaws.com",

378

cert_filepath="/tmp/device-certificate.pem.crt",

379

pri_key_filepath="/tmp/device-private.pem.key",

380

client_id=thing_name,

381

clean_session=False,

382

keep_alive_secs=30

383

)

384

385

device_connection.connect().result()

386

print(f"Device {thing_name} connected successfully!")

387

388

# Your device application logic starts here

389

# ...

390

391

device_connection.disconnect().result()

392

393

# Subscribe to provisioning responses

394

identity_client.subscribe_to_create_keys_and_certificate_accepted(

395

iotidentity.CreateKeysAndCertificateSubscriptionRequest(),

396

mqtt.QoS.AT_LEAST_ONCE,

397

on_create_keys_accepted

398

).result()

399

400

identity_client.subscribe_to_create_keys_and_certificate_rejected(

401

iotidentity.CreateKeysAndCertificateSubscriptionRequest(),

402

mqtt.QoS.AT_LEAST_ONCE,

403

on_create_keys_rejected

404

).result()

405

406

identity_client.subscribe_to_register_thing_accepted(

407

iotidentity.RegisterThingSubscriptionRequest(template_name="MyFleetProvisioningTemplate"),

408

mqtt.QoS.AT_LEAST_ONCE,

409

on_register_thing_accepted

410

).result()

411

412

identity_client.subscribe_to_register_thing_rejected(

413

iotidentity.RegisterThingSubscriptionRequest(template_name="MyFleetProvisioningTemplate"),

414

mqtt.QoS.AT_LEAST_ONCE,

415

on_register_thing_rejected

416

).result()

417

418

# Step 1: Request keys and certificate creation

419

create_keys_request = iotidentity.CreateKeysAndCertificateRequest()

420

identity_client.publish_create_keys_and_certificate(create_keys_request, mqtt.QoS.AT_LEAST_ONCE)

421

422

print("Fleet provisioning started. Waiting for responses...")

423

```

424

425

### V1 Client - Certificate from CSR Workflow

426

427

```python

428

from awsiot import mqtt_connection_builder, iotidentity

429

from awscrt import mqtt

430

from cryptography import x509

431

from cryptography.x509.oid import NameOID

432

from cryptography.hazmat.primitives import hashes, serialization

433

from cryptography.hazmat.primitives.asymmetric import rsa

434

435

def generate_csr():

436

"""Generate a Certificate Signing Request."""

437

# Generate private key

438

private_key = rsa.generate_private_key(

439

public_exponent=65537,

440

key_size=2048

441

)

442

443

# Create CSR

444

subject = x509.Name([

445

x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),

446

x509.NameAttribute(NameOID.LOCALITY_NAME, "Seattle"),

447

x509.NameAttribute(NameOID.ORGANIZATION_NAME, "MyCompany"),

448

x509.NameAttribute(NameOID.COMMON_NAME, "my-iot-device"),

449

])

450

451

csr = x509.CertificateSigningRequestBuilder().subject_name(

452

subject

453

).sign(private_key, hashes.SHA256())

454

455

# Serialize CSR and private key

456

csr_pem = csr.public_bytes(serialization.Encoding.PEM).decode()

457

private_key_pem = private_key.private_bytes(

458

encoding=serialization.Encoding.PEM,

459

format=serialization.PrivateFormat.PKCS8,

460

encryption_algorithm=serialization.NoEncryption()

461

).decode()

462

463

return csr_pem, private_key_pem

464

465

# Generate CSR and private key

466

csr_pem, device_private_key = generate_csr()

467

468

# Save private key (you'll need this with the certificate)

469

with open("/tmp/device-private.pem.key", "w") as f:

470

f.write(device_private_key)

471

472

# Connect with provisioning claim certificate

473

connection = mqtt_connection_builder.mtls_from_path(

474

endpoint="your-endpoint.iot.us-east-1.amazonaws.com",

475

cert_filepath="/path/to/provisioning-claim.pem.crt",

476

pri_key_filepath="/path/to/provisioning-claim.pem.key",

477

client_id="csr-provisioning-123"

478

)

479

480

identity_client = iotidentity.IotIdentityClient(connection)

481

connection.connect().result()

482

483

def on_create_cert_from_csr_accepted(response):

484

"""Handle successful certificate creation from CSR."""

485

print("Certificate created from CSR successfully!")

486

487

# Save certificate

488

with open("/tmp/device-certificate.pem.crt", "w") as f:

489

f.write(response.certificate_pem)

490

491

print(f"Certificate ID: {response.certificate_id}")

492

print(f"Certificate ARN: {response.certificate_arn}")

493

494

# Register thing with certificate ownership token

495

register_request = iotidentity.RegisterThingRequest(

496

template_name="MyFleetProvisioningTemplate",

497

certificate_ownership_token=response.certificate_ownership_token,

498

parameters={"SerialNumber": "ABC123456"}

499

)

500

identity_client.publish_register_thing(register_request, mqtt.QoS.AT_LEAST_ONCE)

501

502

def on_create_cert_from_csr_rejected(error):

503

"""Handle certificate creation rejection."""

504

print(f"Certificate creation from CSR rejected: {error}")

505

506

# Subscribe to responses

507

identity_client.subscribe_to_create_certificate_from_csr_accepted(

508

iotidentity.CreateCertificateFromCsrSubscriptionRequest(),

509

mqtt.QoS.AT_LEAST_ONCE,

510

on_create_cert_from_csr_accepted

511

).result()

512

513

identity_client.subscribe_to_create_certificate_from_csr_rejected(

514

iotidentity.CreateCertificateFromCsrSubscriptionRequest(),

515

mqtt.QoS.AT_LEAST_ONCE,

516

on_create_cert_from_csr_rejected

517

).result()

518

519

# Request certificate creation from CSR

520

csr_request = iotidentity.CreateCertificateFromCsrRequest(

521

certificate_signing_request=csr_pem

522

)

523

identity_client.publish_create_certificate_from_csr(csr_request, mqtt.QoS.AT_LEAST_ONCE)

524

525

print("CSR provisioning started. Waiting for certificate...")

526

```

527

528

### V2 Client - Request-Response Pattern

529

530

```python

531

from awsiot import mqtt_connection_builder, iotidentity

532

import asyncio

533

534

async def fleet_provisioning_v2():

535

# Create connection with provisioning claim certificate

536

connection = mqtt_connection_builder.mtls_from_path(

537

endpoint="your-endpoint.iot.us-east-1.amazonaws.com",

538

cert_filepath="/path/to/provisioning-claim.pem.crt",

539

pri_key_filepath="/path/to/provisioning-claim.pem.key",

540

client_id="fleet-v2-client"

541

)

542

543

# Create V2 identity client

544

identity_client = iotidentity.IotIdentityClientV2(connection)

545

await connection.connect()

546

547

try:

548

# Step 1: Create keys and certificate

549

print("Creating keys and certificate...")

550

keys_request = iotidentity.CreateKeysAndCertificateRequest()

551

keys_response = await identity_client.create_keys_and_certificate(keys_request)

552

553

print(f"Certificate created: {keys_response.certificate_id}")

554

555

# Save certificate and private key

556

with open("/tmp/device-certificate.pem.crt", "w") as f:

557

f.write(keys_response.certificate_pem)

558

with open("/tmp/device-private.pem.key", "w") as f:

559

f.write(keys_response.private_key)

560

561

# Step 2: Register thing

562

print("Registering thing...")

563

register_request = iotidentity.RegisterThingRequest(

564

template_name="MyFleetProvisioningTemplate",

565

certificate_ownership_token=keys_response.certificate_ownership_token,

566

parameters={

567

"DeviceSerial": "DEV123456789",

568

"DeviceModel": "TempSensor-v2"

569

}

570

)

571

572

register_response = await identity_client.register_thing(register_request)

573

574

print(f"Thing registered: {register_response.thing_name}")

575

print(f"Device configuration: {register_response.device_configuration}")

576

577

# Save device configuration

578

if register_response.device_configuration:

579

import json

580

with open("/tmp/device-config.json", "w") as f:

581

json.dump(register_response.device_configuration, f, indent=2)

582

583

print("Fleet provisioning completed successfully!")

584

585

return {

586

"thing_name": register_response.thing_name,

587

"certificate_path": "/tmp/device-certificate.pem.crt",

588

"private_key_path": "/tmp/device-private.pem.key",

589

"device_config": register_response.device_configuration

590

}

591

592

except iotidentity.V2ServiceException as e:

593

print(f"Provisioning failed: {e.message}")

594

if e.modeled_error:

595

print(f"Error details: {e.modeled_error}")

596

return None

597

598

finally:

599

await connection.disconnect()

600

601

# Run async provisioning

602

provisioning_result = asyncio.run(fleet_provisioning_v2())

603

604

if provisioning_result:

605

print(f"Device {provisioning_result['thing_name']} provisioned successfully!")

606

607

# Connect with new device certificate

608

device_connection = mqtt_connection_builder.mtls_from_path(

609

endpoint="your-endpoint.iot.us-east-1.amazonaws.com",

610

cert_filepath=provisioning_result["certificate_path"],

611

pri_key_filepath=provisioning_result["private_key_path"],

612

client_id=provisioning_result["thing_name"]

613

)

614

615

device_connection.connect().result()

616

print("Device connected with new certificate!")

617

device_connection.disconnect().result()

618

```

619

620

### Provisioning Template Setup

621

622

Before using fleet provisioning, you need to create a provisioning template in AWS IoT Core:

623

624

```json

625

{

626

"templateName": "MyFleetProvisioningTemplate",

627

"description": "Template for provisioning temperature sensors",

628

"templateBody": {

629

"Parameters": {

630

"DeviceLocation": {

631

"Type": "String"

632

},

633

"DeviceType": {

634

"Type": "String"

635

},

636

"SerialNumber": {

637

"Type": "String"

638

}

639

},

640

"Resources": {

641

"certificate": {

642

"Properties": {

643

"CertificateId": {

644

"Ref": "AWS::IoT::Certificate::Id"

645

},

646

"Status": "Active"

647

},

648

"Type": "AWS::IoT::Certificate"

649

},

650

"policy": {

651

"Properties": {

652

"PolicyName": "TemperatureSensorPolicy"

653

},

654

"Type": "AWS::IoT::Policy"

655

},

656

"thing": {

657

"OverrideSettings": {

658

"AttributePayload": "MERGE",

659

"ThingGroups": "DO_NOTHING",

660

"ThingTypeName": "REPLACE"

661

},

662

"Properties": {

663

"AttributePayload": {

664

"location": {

665

"Ref": "DeviceLocation"

666

},

667

"deviceType": {

668

"Ref": "DeviceType"

669

},

670

"serialNumber": {

671

"Ref": "SerialNumber"

672

}

673

},

674

"ThingName": {

675

"Fn::Join": [

676

"",

677

[

678

"TempSensor-",

679

{

680

"Ref": "SerialNumber"

681

}

682

]

683

]

684

},

685

"ThingTypeName": "TemperatureSensor"

686

},

687

"Type": "AWS::IoT::Thing"

688

}

689

}

690

},

691

"enabled": true,

692

"provisioningRoleArn": "arn:aws:iam::123456789012:role/IoTFleetProvisioningRole"

693

}

694

```