Create Fleet Provisioning Demo AWS Setup Script in Python (#778)

* Create CloudFormation template for demo setup

* Add CF_ prefix to CloudFormation-created resources to avoid collisions

* Update lexicon.txt

* Create initial python setup script

* Create separate demo_cleanup.py file

* Move setup items to DemoSetup folder

* Add demo_config.h setup to the demo_setup.py script

* Modify error logging on demo_setup.py

* Add file cleanup to demo_cleanup.py

* Rename convert_pem_to_der.py to convert_credentials_to_der.py

* Adjust comment wording on demo_cleanup.py

* added configUSE_TICKLESS_IDLE (#764)

* Fix tests needed for https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/435 (#766)

* Fix tests needed for https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/435

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>

* Add tests to cover https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/435 (#768)

Add tests to cover https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/435

This ensures that the coverage does not go down with the PR
https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/435.

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>

* Add tests to increase queue code coverage (#770)

These tests cover the following portion in the queue code:

static void prvUnlockQueue( Queue_t * const pxQueue )
{
    ...

    if( prvNotifyQueueSetContainer( pxQueue ) != pdFALSE )
    {
        /* The queue is a member of a queue set, and posting to
            * the queue set caused a higher priority task to unblock.
            * A context switch is required. */
        vTaskMissedYield();
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    ...
}

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>

* Update FreeRTOS-Kernel submodule pointer (#771)

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>

* Add new names to spell check dictionary (#772)

* Return error if invalid input detected in transport layer (Send/Recv) (#773)

* return error if invalid input detected in transport layer

* Create mqtt_pkcs11_demo_helpers for AWS demos (#769)

* Create mqtt_pkcs11_demo_helpers by modifying mqtt_demo_helpers

* Update formatting and variable naming

* Fix multi-line parameter formatting

* Update file headers to match latest release version

* GCC/Rx100 Demo project files update to e2 Studio v8 (#776)

* Upgrade GCC project files for e2 studio v7.8.0 in Demo/RX100-RSK_GCC_e2studio folder

* Update Demo project file to e2 Studio v8 and remove the .bat file.

* Update the choice of toolchain version.

* Update the link in file header.

Co-authored-by: NoMaY (a user of Japan.RenesasRulz.com) <NoMaY-jp@outlook.com>

* Update FreeRTOS-Cellular-Interface submodule pointer (#775)

* Update cellular sub-module pointer
* Add more log in cellular_setup.c to indicate error
* Adjust cellular transport timeout value for demo application
* Add default cellular module specific config in cellular_config.h

* Create separate demo_cleanup.py file

* Move setup items to DemoSetup folder

* Add demo_config.h setup to the demo_setup.py script

* Modify error logging on demo_setup.py

* Add file cleanup to demo_cleanup.py

* Rename convert_pem_to_der.py to convert_credentials_to_der.py

* Adjust comment wording on demo_cleanup.py

* Adjust comment wording on demo_config.h

* Format files and reduce code redundancy

* Update lexicon.txt

* Remove preconfigured fields from demo_config,h

* Update convert_credentials_to_der.py

Co-authored-by: Archit Gupta <71798289+archigup@users.noreply.github.com>

* Make python files executable

Co-authored-by: Joseph Julicher <jjulicher@mac.com>
Co-authored-by: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com>
Co-authored-by: Ravishankar Bhagavandas <bhagavar@amazon.com>
Co-authored-by: ActoryOu <jay2002824@gmail.com>
Co-authored-by: Ming Yue <mingyue86010@gmail.com>
Co-authored-by: NoMaY (a user of Japan.RenesasRulz.com) <NoMaY-jp@outlook.com>
Co-authored-by: chinglee-iot <61685396+chinglee-iot@users.noreply.github.com>
Co-authored-by: Archit Gupta <71798289+archigup@users.noreply.github.com>
This commit is contained in:
johnrhen 2022-07-20 13:35:59 -07:00 committed by GitHub
parent cfb32b4f62
commit f062becb34
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 998 additions and 64 deletions

View file

@ -0,0 +1,183 @@
{
"Resources": {
"FPDemoRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": "CF_FleetProvisioningDemoRole",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "iot.amazonaws.com"
}
}
]
},
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AWSIoTThingsRegistration"
]
}
},
"FPDemoThingPolicy": {
"Type": "AWS::IoT::Policy",
"Properties": {
"PolicyName": "CF_FleetProvisioningDemoThingPolicy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iot:Connect",
"Resource": {
"Fn::Join": [
":",
[
"arn:aws:iot",
{
"Ref": "AWS::Region"
},
{
"Ref": "AWS::AccountId"
},
"*"
]
]
}
}
]
}
}
},
"FPDemoTemplate": {
"Type": "AWS::IoT::ProvisioningTemplate",
"Properties": {
"TemplateName": "CF_FleetProvisioningDemoTemplate",
"Enabled": "true",
"ProvisioningRoleArn": {
"Fn::Join": [
"",
[
"arn:aws:iam::",
{
"Ref": "AWS::AccountId"
},
":role/",
{
"Ref": "FPDemoRole"
}
]
]
},
"TemplateBody": "{ \"Parameters\": { \"SerialNumber\": { \"Type\": \"String\" }, \"AWS::IoT::Certificate::Id\": { \"Type\": \"String\" } }, \"Resources\": { \"certificate\": { \"Properties\": { \"CertificateId\": { \"Ref\": \"AWS::IoT::Certificate::Id\" }, \"Status\": \"Active\" }, \"Type\": \"AWS::IoT::Certificate\" }, \"policy\": { \"Properties\": { \"PolicyName\": \"CF_FleetProvisioningDemoThingPolicy\" }, \"Type\": \"AWS::IoT::Policy\" }, \"thing\": { \"OverrideSettings\": { \"AttributePayload\": \"MERGE\", \"ThingGroups\": \"DO_NOTHING\" }, \"Properties\": { \"AttributePayload\": {}, \"ThingGroups\": [], \"ThingName\": { \"Fn::Join\": [ \"\", [ \"fp_demo_\", { \"Ref\": \"SerialNumber\" } ] ] } }, \"Type\": \"AWS::IoT::Thing\" } }, \"DeviceConfiguration\": { \"Foo\": \"Bar\" } }"
}
},
"FPDemoClaimPolicy": {
"Type": "AWS::IoT::Policy",
"Properties": {
"PolicyName": "CF_FleetProvisioningDemoClaimPolicy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:Connect"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"iot:Publish",
"iot:Receive"
],
"Resource": [
{
"Fn::Join": [
"",
[
"arn:aws:iot:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":topic/$aws/certificates/create-from-csr/*"
]
]
},
{
"Fn::Join": [
"",
[
"arn:aws:iot:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":topic/$aws/provisioning-templates/",
{
"Ref": "FPDemoTemplate"
},
"/provision/*"
]
]
}
]
},
{
"Effect": "Allow",
"Action": "iot:Subscribe",
"Resource": [
{
"Fn::Join": [
"",
[
"arn:aws:iot:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":topicfilter/$aws/certificates/create-from-csr/*"
]
]
},
{
"Fn::Join": [
"",
[
"arn:aws:iot:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":topicfilter/$aws/provisioning-templates/",
{
"Ref": "FPDemoTemplate"
},
"/provision/*"
]
]
}
]
}
]
}
}
}
}
}

View file

@ -0,0 +1,66 @@
#!/usr/bin/env python
import argparse
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
KEY_OUT_NAME = "corePKCS11_Claim_Key.dat"
CERT_OUT_NAME = "corePKCS11_Claim_Certificate.dat"
def convert_pem_to_der(cert_pem, key_pem):
# Convert certificate from PEM to DER
key = serialization.load_pem_private_key(
bytes(key_pem, "utf-8"), None, default_backend())
key_der = key.private_bytes(
serialization.Encoding.DER,
serialization.PrivateFormat.TraditionalOpenSSL,
serialization.NoEncryption(),
)
with open(f"../{KEY_OUT_NAME}", "wb") as key_out:
key_out.write(key_der)
print(
f"Successfully converted key PEM to DER. Output file named: {KEY_OUT_NAME}"
)
cert = x509.load_pem_x509_certificate(
bytes(cert_pem, "utf-8"), default_backend())
with open(f"../{CERT_OUT_NAME}", "wb") as cert_out:
cert_out.write(cert.public_bytes(serialization.Encoding.DER))
print(
f"Successfully converted certificate PEM to DER. Output file named: {CERT_OUT_NAME}"
)
def main(args):
with open(args.cert_file, "r") as cert:
cert_pem = cert.read()
with open(args.key_file, "r") as key:
key_pem = key.read()
convert_pem_to_der(cert_pem, key_pem)
if __name__ == "__main__":
arg_parser = argparse.ArgumentParser(
description="This script converts passed in PEM format certificates and keys into the binary DER format."
)
arg_parser.add_argument(
"-c",
"--cert_file",
type=str,
help="Specify the name of the generated certificate file.",
required=True,
)
arg_parser.add_argument(
"-k",
"--key_file",
type=str,
help="Specify the name of the generated key file.",
required=True,
)
args = arg_parser.parse_args()
main(args)

View file

@ -0,0 +1,165 @@
#!/usr/bin/env python
import os
import boto3
import botocore
KEY_OUT_NAME = "corePKCS11_Claim_Key.dat"
CERT_OUT_NAME = "corePKCS11_Claim_Certificate.dat"
THING_PRIVATE_KEY_NAME = "corePKCS11_Key.dat"
THING_PUBLIC_KEY_NAME = "corePKCS11_PubKey.dat"
THING_CERT_NAME = "corePKCS11_Certificate.dat"
RESOURCE_STACK_NAME = "FPDemoStack"
cf = boto3.client("cloudformation")
iot = boto3.client("iot")
# Convert a CloudFormation arn into a link to the resource
def convert_cf_arn_to_link(arn):
region = arn.split(":")[3]
return f"https://{region}.console.aws.amazon.com/cloudformation/home?region={region}#/stacks/stackinfo?stackId={arn}"
# Get the CloudFormation stack if it exists - "STACK_NOT_FOUND" otherwise
def get_stack():
try:
response = cf.describe_stacks(StackName=RESOURCE_STACK_NAME)
return response["Stacks"][0]
except botocore.exceptions.ClientError as e:
if e.response["Error"]["Code"] == "ValidationError":
return "STACK_NOT_FOUND"
raise
# Delete a Thing after clearing it of all certificates
def delete_thing(thing_name):
paginator = iot.get_paginator("list_thing_principals")
list_certificates_iterator = paginator.paginate(
thingName=thing_name
)
for response in list_certificates_iterator:
for certificate_arn in response["principals"]:
iot.detach_thing_principal(
thingName=thing_name,
principal=certificate_arn
)
iot.delete_thing(thingName=thing_name)
# Delete a certificate and all Things attached to it
def delete_certificate_and_things(certificate_arn, policy_name):
paginator = iot.get_paginator("list_principal_things")
list_things_iterator = paginator.paginate(
principal=certificate_arn
)
for response in list_things_iterator:
for thing_name in response["things"]:
delete_thing(thing_name)
iot.detach_policy(
policyName=policy_name,
target=certificate_arn
)
certificate_id = certificate_arn.split("/")[-1]
iot.update_certificate(
certificateId=certificate_id,
newStatus="INACTIVE"
)
iot.delete_certificate(certificateId=certificate_id)
# Delete all resources (including provisioned Things)
def delete_resources():
stack_response = get_stack()
if stack_response == "STACK_NOT_FOUND":
print("Nothing to delete - no Fleet Provisioning resources were found.")
return
# Find all certificates with "CF_FleetProvisioningDemoThingPolicy" attached
print("Deleting certificates and things...")
paginator = iot.get_paginator("list_targets_for_policy")
list_targets_things_iterator = paginator.paginate(
policyName="CF_FleetProvisioningDemoThingPolicy"
)
# Delete all certificates and Things created by this demo
for response in list_targets_things_iterator:
for certificate_arn in response["targets"]:
delete_certificate_and_things(
certificate_arn,
"CF_FleetProvisioningDemoThingPolicy"
)
# Find all certificates with "CF_FleetProvisioningDemoClaimPolicy" attached
paginator = iot.get_paginator("list_targets_for_policy")
list_targets_claim_iterator = paginator.paginate(
policyName="CF_FleetProvisioningDemoClaimPolicy"
)
# Delete all Fleet Provisioning Claim certificates
for response in list_targets_claim_iterator:
for certificate_arn in response["targets"]:
delete_certificate_and_things(
certificate_arn,
"CF_FleetProvisioningDemoClaimPolicy"
)
print("Done.")
print("Fleet Provisioning resource stack deletion started. View the stack in the CloudFormation console here:")
print(convert_cf_arn_to_link(stack_response["StackId"]))
delete_response = cf.delete_stack(
StackName=RESOURCE_STACK_NAME
)
print("Waiting...")
try:
create_waiter = cf.get_waiter("stack_delete_complete")
create_waiter.wait(StackName=RESOURCE_STACK_NAME)
print("Successfully deleted the resources stack.")
except botocore.exceptions.WaiterError as err:
print("Error: Stack deletion failed. Check the CloudFormation link for more information.")
raise
print("All Fleet Provisioning demo resources have been cleaned up.")
# Delete the files created by the demo and reset demo_config.h
def reset_files():
# Remove Claim credentials
if os.path.exists(f"../{KEY_OUT_NAME}"):
os.remove(f"../{KEY_OUT_NAME}")
if os.path.exists(f"../{CERT_OUT_NAME}"):
os.remove(f"../{CERT_OUT_NAME}")
# Remove demo-generated Thing credentials
if os.path.exists(f"../{THING_PRIVATE_KEY_NAME}"):
os.remove(f"../{THING_PRIVATE_KEY_NAME}")
if os.path.exists(f"../{THING_PUBLIC_KEY_NAME}"):
os.remove(f"../{THING_PUBLIC_KEY_NAME}")
if os.path.exists(f"../{THING_CERT_NAME}"):
os.remove(f"../{THING_CERT_NAME}")
# Reset demo_config.h
template_file = open("demo_config_empty.templ", 'r')
file_text = template_file.read()
header_file = open("../demo_config.h", "w")
header_file.write(file_text)
header_file.close()
template_file.close()
print("Credentials removed and demo_config.h reset.")
# Parse arguments and execute appropriate functions
def main():
# Check arguments and go appropriately
print("\nThis script will delete ALL Things, credentials, and resources which were created by demo_setup.py and the Fleet Provisioning demo.")
print("It may take several minutes for all of the resources to be deleted.")
if input("Are you sure you want to do this? (y/n) ") == "y":
print()
reset_files()
delete_resources()
if __name__ == "__main__":
main()

View file

@ -0,0 +1,239 @@
/*
* FreeRTOS V202112.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef DEMO_CONFIG_H
#define DEMO_CONFIG_H
/**************************************************/
/******* DO NOT CHANGE the following order ********/
/**************************************************/
/* Include logging header files and define logging macros in the following order:
* 1. Include the header file "logging_levels.h".
* 2. Define the LIBRARY_LOG_NAME and LIBRARY_LOG_LEVEL macros depending on
* the logging configuration for DEMO.
* 3. Include the header file "logging_stack.h", if logging is enabled for DEMO.
*/
#include "logging_levels.h"
/* Logging configuration for the Demo. */
#ifndef LIBRARY_LOG_NAME
#define LIBRARY_LOG_NAME "FLEET_PROVISIONING_DEMO"
#endif
#ifndef LIBRARY_LOG_LEVEL
#define LIBRARY_LOG_LEVEL LOG_INFO
#endif
/* Prototype for the function used to print to console on Windows simulator
* of FreeRTOS.
* The function prints to the console before the network is connected;
* then a UDP port after the network has connected. */
extern void vLoggingPrintf( const char * pcFormatString,
... );
/* Map the SdkLog macro to the logging function to enable logging
* on Windows simulator. */
#ifndef SdkLog
#define SdkLog( message ) vLoggingPrintf message
#endif
#include "logging_stack.h"
/************ End of logging configuration ****************/
/**
* @brief The unique ID used by the demo to differentiate instances.
*
*!!! Please note a #defined constant is used for convenience of demonstration
*!!! only. Production devices can use something unique to the device that can
*!!! be read by software, such as a production serial number, instead of a
*!!! hard coded constant.
*/
#define democonfigFP_DEMO_ID "FPDemoID"__TIME__
/**
* @brief The MQTT client identifier used in this example. Each client identifier
* must be unique so edit as required to ensure no two clients connecting to the
* same broker use the same client identifier.
*
* @note Appending __TIME__ to the client id string will reduce the possibility of a
* client id collision in the broker. Note that the appended time is the compilation
* time. This client id can cause collision, if more than one instance of the same
* binary is used at the same time to connect to the broker.
*/
#ifndef democonfigCLIENT_IDENTIFIER
#define democonfigCLIENT_IDENTIFIER "client"democonfigFP_DEMO_ID
#endif
/**
* @brief Details of the MQTT broker to connect to.
*
* This is the Claim's Rest API Endpoint for AWS IoT.
*
* @note Your AWS IoT Core endpoint can be found in the AWS IoT console under
* Settings/Custom Endpoint, or using the describe-endpoint API.
*
* #define democonfigMQTT_BROKER_ENDPOINT "...insert here..."
*/
#define democonfigMQTT_BROKER_ENDPOINT <IOTEndpoint>
/**
* @brief AWS IoT MQTT broker port number.
*
* In general, port 8883 is for secured MQTT connections.
*
* @note Port 443 requires use of the ALPN TLS extension with the ALPN protocol
* name. When using port 8883, ALPN is not required.
*/
#define democonfigMQTT_BROKER_PORT ( 8883 )
/**
* @brief Server's root CA certificate.
*
* For AWS IoT MQTT broker, this certificate is used to identify the AWS IoT
* server and is publicly available. Refer to the AWS documentation available
* in the link below.
* https://docs.aws.amazon.com/iot/latest/developerguide/server-authentication.html#server-authentication-certs
*
* @note This certificate should be PEM-encoded.
*
* Must include the PEM header and footer:
* "-----BEGIN CERTIFICATE-----\n"\
* "...base64 data...\n"\
* "-----END CERTIFICATE-----\n"
*
* #define democonfigROOT_CA_PEM "...insert here..."
*/
#define democonfigROOT_CA_PEM
"-----BEGIN CERTIFICATE-----\n" \
"MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n" \
"ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n" \
"b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\n" \
"MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n" \
"b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\n" \
"ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\n" \
"9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\n" \
"IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\n" \
"VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\n" \
"93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\n" \
"jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n" \
"AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\n" \
"A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\n" \
"U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\n" \
"N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\n" \
"o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\n" \
"5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\n" \
"rqXRfboQnoZsG4q5WTP468SQvvG5\n" \
"-----END CERTIFICATE-----\n"
/**
* @brief Name of the provisioning template to use for the RegisterThing
* portion of the Fleet Provisioning workflow.
*
* For information about provisioning templates, see the following AWS documentation:
* https://docs.aws.amazon.com/iot/latest/developerguide/provision-template.html#fleet-provision-template
*
* The example template used for this demo is available in the
* example_demo_template.json file in the DemoSetup directory. In the example,
* replace <provisioned-thing-policy> with the policy provisioned devices
* should have. The demo template uses Fn::Join to construct the Thing name by
* concatenating fp_demo_ and the serial number sent by the demo.
*
* @note The provisioning template MUST be created in AWS IoT before running the
* demo.
*
* @note If you followed the manual setup steps on https://freertos.org/iot-fleet-provisioning/demo.html,
* the provisioning template name is "FleetProvisioningDemoTemplate".
* However, if you used CloudFormation to set up the demo, the template name is "CF_FleetProvisioningDemoTemplate"
*
* #define democonfigPROVISIONING_TEMPLATE_NAME "...insert here..."
*/
#define democonfigPROVISIONING_TEMPLATE_NAME "CF_FleetProvisioningDemoTemplate"
/**
* @brief Subject name to use when creating the certificate signing request (CSR)
* for provisioning the demo client with using the Fleet Provisioning
* CreateCertificateFromCsr APIs.
*
* This is passed to MbedTLS; see https://tls.mbed.org/api/x509__csr_8h.html#a954eae166b125cea2115b7db8c896e90
*/
#ifndef democonfigCSR_SUBJECT_NAME
#define democonfigCSR_SUBJECT_NAME "CN="democonfigFP_DEMO_ID
#endif
/**
* @brief Set the stack size of the main demo task.
*
* In the Windows port, this stack only holds a structure. The actual
* stack is created by an operating system thread.
*
* @note This demo runs on WinSim and the minimal stack size is functional.
* However, if you are porting components of this demo to other platforms,
* the stack size may need to be increased to accommodate the size of the
* buffers used when generating new keys and certificates.
*
*/
#define democonfigDEMO_STACKSIZE configMINIMAL_STACK_SIZE
/**
* @brief Size of the network buffer for MQTT packets. Must be large enough to
* hold the GetCertificateFromCsr response, which, among other things, includes
* a PEM encoded certificate.
*/
#define democonfigNETWORK_BUFFER_SIZE ( 2048U )
/**
* @brief The name of the operating system that the application is running on.
* The current value is given as an example. Please update for your specific
* operating system.
*/
#define democonfigOS_NAME "FreeRTOS"
/**
* @brief The version of the operating system that the application is running
* on. The current value is given as an example. Please update for your specific
* operating system version.
*/
#define democonfigOS_VERSION tskKERNEL_VERSION_NUMBER
/**
* @brief The name of the hardware platform the application is running on. The
* current value is given as an example. Please update for your specific
* hardware platform.
*/
#define democonfigHARDWARE_PLATFORM_NAME "WinSim"
/**
* @brief The name of the MQTT library used and its version, following an "@"
* symbol.
*/
#include "core_mqtt.h" /* Include coreMQTT header for MQTT_LIBRARY_VERSION macro. */
#define democonfigMQTT_LIB "core-mqtt@"MQTT_LIBRARY_VERSION
#endif /* DEMO_CONFIG_H */

View file

@ -0,0 +1,215 @@
/*
* FreeRTOS V202112.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef DEMO_CONFIG_H
#define DEMO_CONFIG_H
/**************************************************/
/******* DO NOT CHANGE the following order ********/
/**************************************************/
/* Include logging header files and define logging macros in the following order:
* 1. Include the header file "logging_levels.h".
* 2. Define the LIBRARY_LOG_NAME and LIBRARY_LOG_LEVEL macros depending on
* the logging configuration for DEMO.
* 3. Include the header file "logging_stack.h", if logging is enabled for DEMO.
*/
#include "logging_levels.h"
/* Logging configuration for the Demo. */
#ifndef LIBRARY_LOG_NAME
#define LIBRARY_LOG_NAME "FLEET_PROVISIONING_DEMO"
#endif
#ifndef LIBRARY_LOG_LEVEL
#define LIBRARY_LOG_LEVEL LOG_INFO
#endif
/* Prototype for the function used to print to console on Windows simulator
* of FreeRTOS.
* The function prints to the console before the network is connected;
* then a UDP port after the network has connected. */
extern void vLoggingPrintf( const char * pcFormatString,
... );
/* Map the SdkLog macro to the logging function to enable logging
* on Windows simulator. */
#ifndef SdkLog
#define SdkLog( message ) vLoggingPrintf message
#endif
#include "logging_stack.h"
/************ End of logging configuration ****************/
/**
* @brief The unique ID used by the demo to differentiate instances.
*
*!!! Please note a #defined constant is used for convenience of demonstration
*!!! only. Production devices can use something unique to the device that can
*!!! be read by software, such as a production serial number, instead of a
*!!! hard coded constant.
*/
#define democonfigFP_DEMO_ID "FPDemoID"__TIME__
/**
* @brief The MQTT client identifier used in this example. Each client identifier
* must be unique so edit as required to ensure no two clients connecting to the
* same broker use the same client identifier.
*
* @note Appending __TIME__ to the client id string will reduce the possibility of a
* client id collision in the broker. Note that the appended time is the compilation
* time. This client id can cause collision, if more than one instance of the same
* binary is used at the same time to connect to the broker.
*/
#ifndef democonfigCLIENT_IDENTIFIER
#define democonfigCLIENT_IDENTIFIER "client"democonfigFP_DEMO_ID
#endif
/**
* @brief Details of the MQTT broker to connect to.
*
* This is the Claim's Rest API Endpoint for AWS IoT.
*
* @note Your AWS IoT Core endpoint can be found in the AWS IoT console under
* Settings/Custom Endpoint, or using the describe-endpoint API.
*
* #define democonfigMQTT_BROKER_ENDPOINT "...insert here..."
*/
/**
* @brief AWS IoT MQTT broker port number.
*
* In general, port 8883 is for secured MQTT connections.
*
* @note Port 443 requires use of the ALPN TLS extension with the ALPN protocol
* name. When using port 8883, ALPN is not required.
*/
#define democonfigMQTT_BROKER_PORT ( 8883 )
/**
* @brief Server's root CA certificate.
*
* For AWS IoT MQTT broker, this certificate is used to identify the AWS IoT
* server and is publicly available. Refer to the AWS documentation available
* in the link below.
* https://docs.aws.amazon.com/iot/latest/developerguide/server-authentication.html#server-authentication-certs
*
* @note This certificate should be PEM-encoded.
*
* Must include the PEM header and footer:
* "-----BEGIN CERTIFICATE-----\n"\
* "...base64 data...\n"\
* "-----END CERTIFICATE-----\n"
*
* #define democonfigROOT_CA_PEM "...insert here..."
*/
/**
* @brief Name of the provisioning template to use for the RegisterThing
* portion of the Fleet Provisioning workflow.
*
* For information about provisioning templates, see the following AWS documentation:
* https://docs.aws.amazon.com/iot/latest/developerguide/provision-template.html#fleet-provision-template
*
* The example template used for this demo is available in the
* example_demo_template.json file in the DemoSetup directory. In the example,
* replace <provisioned-thing-policy> with the policy provisioned devices
* should have. The demo template uses Fn::Join to construct the Thing name by
* concatenating fp_demo_ and the serial number sent by the demo.
*
* @note The provisioning template MUST be created in AWS IoT before running the
* demo.
*
* @note If you followed the manual setup steps on https://freertos.org/iot-fleet-provisioning/demo.html,
* the provisioning template name is "FleetProvisioningDemoTemplate".
* However, if you used CloudFormation to set up the demo, the template name is "CF_FleetProvisioningDemoTemplate"
*
* #define democonfigPROVISIONING_TEMPLATE_NAME "...insert here..."
*/
/**
* @brief Subject name to use when creating the certificate signing request (CSR)
* for provisioning the demo client with using the Fleet Provisioning
* CreateCertificateFromCsr APIs.
*
* This is passed to MbedTLS; see https://tls.mbed.org/api/x509__csr_8h.html#a954eae166b125cea2115b7db8c896e90
*/
#ifndef democonfigCSR_SUBJECT_NAME
#define democonfigCSR_SUBJECT_NAME "CN="democonfigFP_DEMO_ID
#endif
/**
* @brief Set the stack size of the main demo task.
*
* In the Windows port, this stack only holds a structure. The actual
* stack is created by an operating system thread.
*
* @note This demo runs on WinSim and the minimal stack size is functional.
* However, if you are porting components of this demo to other platforms,
* the stack size may need to be increased to accommodate the size of the
* buffers used when generating new keys and certificates.
*
*/
#define democonfigDEMO_STACKSIZE configMINIMAL_STACK_SIZE
/**
* @brief Size of the network buffer for MQTT packets. Must be large enough to
* hold the GetCertificateFromCsr response, which, among other things, includes
* a PEM encoded certificate.
*/
#define democonfigNETWORK_BUFFER_SIZE ( 2048U )
/**
* @brief The name of the operating system that the application is running on.
* The current value is given as an example. Please update for your specific
* operating system.
*/
#define democonfigOS_NAME "FreeRTOS"
/**
* @brief The version of the operating system that the application is running
* on. The current value is given as an example. Please update for your specific
* operating system version.
*/
#define democonfigOS_VERSION tskKERNEL_VERSION_NUMBER
/**
* @brief The name of the hardware platform the application is running on. The
* current value is given as an example. Please update for your specific
* hardware platform.
*/
#define democonfigHARDWARE_PLATFORM_NAME "WinSim"
/**
* @brief The name of the MQTT library used and its version, following an "@"
* symbol.
*/
#include "core_mqtt.h" /* Include coreMQTT header for MQTT_LIBRARY_VERSION macro. */
#define democonfigMQTT_LIB "core-mqtt@"MQTT_LIBRARY_VERSION
#endif /* DEMO_CONFIG_H */

View file

@ -0,0 +1,122 @@
#!/usr/bin/env python
import boto3
import botocore
from convert_credentials_to_der import convert_pem_to_der
KEY_OUT_NAME = "corePKCS11_Claim_Key.dat"
CERT_OUT_NAME = "corePKCS11_Claim_Certificate.dat"
RESOURCE_STACK_NAME = "FPDemoStack"
cf = boto3.client("cloudformation")
iot = boto3.client("iot")
# Convert a CloudFormation arn into a link to the resource
def convert_cf_arn_to_link(arn):
region = arn.split(":")[3]
return f"https://{region}.console.aws.amazon.com/cloudformation/home?region={region}#/stacks/stackinfo?stackId={arn}"
# Get the CloudFormation stack if it exists - "STACK_NOT_FOUND" otherwise
def get_stack():
try:
paginator = cf.get_paginator("describe_stacks")
response_iterator = paginator.paginate(StackName=RESOURCE_STACK_NAME)
for response in response_iterator:
return response["Stacks"][0]
response = cf.describe_stacks(StackName=RESOURCE_STACK_NAME)
return response["Stacks"][0]
except botocore.exceptions.ClientError as e:
if e.response["Error"]["Code"] == "ValidationError":
return "STACK_NOT_FOUND"
raise
# Create the required resources from the CloudFormation template
def create_resources():
stack_response = get_stack()
if stack_response != "STACK_NOT_FOUND":
print("Fleet Provisioning resource stack already exists with status: " +
stack_response["StackStatus"])
print()
if stack_response["StackStatus"] != "CREATE_COMPLETE":
raise Exception("Fleet Provisioning resource stack failed to create successfully. You may need to delete the stack and retry."
+ "\nView the stack in the CloudFormation console here:\n" + convert_cf_arn_to_link(stack_response["StackId"]))
else:
# Read the cloudformation template file contained in the same directory
cf_template_file = open("cloudformation_template.json", "r")
cf_template = cf_template_file.read()
cf_template_file.close()
create_response = cf.create_stack(
StackName=RESOURCE_STACK_NAME,
TemplateBody=cf_template,
Capabilities=["CAPABILITY_NAMED_IAM"],
OnFailure="ROLLBACK"
)
print("Stack creation started. View the stack in the CloudFormation console here:")
print(convert_cf_arn_to_link(create_response["StackId"]))
print("Waiting...")
try:
create_waiter = cf.get_waiter("stack_create_complete")
create_waiter.wait(StackName=RESOURCE_STACK_NAME)
print("Successfully created the resources stack.")
except botocore.exceptions.WaiterError as err:
print(
"Error: Stack creation failed. You may need to delete_all and try again.")
raise
# Generate IoT credentials in DER format and save them in the demo directory
def create_credentials():
# Verify that the stack exists (create_resources has been ran before somewhere)
stack_response = get_stack()
if stack_response == "STACK_NOT_FOUND":
raise Exception(
f"CloudFormation stack \"{RESOURCE_STACK_NAME}\" not found.")
elif stack_response["StackStatus"] != "CREATE_COMPLETE":
print("Error: Stack was not successfully created. View the stack in the CloudFormation console here:")
stack_link = convert_cf_arn_to_link(stack_response["StackId"])
raise Exception(
"Stack was not successfully created. View the stack in the CloudFormation console here:\n" + stack_link)
else:
credentials = iot.create_keys_and_certificate(setAsActive=True)
iot.attach_policy(policyName="CF_FleetProvisioningDemoClaimPolicy",
target=credentials["certificateArn"])
convert_pem_to_der(
credentials["certificatePem"], credentials["keyPair"]["PrivateKey"])
# Set the necessary fields in demo_config.h
def update_demo_config():
endpoint = iot.describe_endpoint(endpointType='iot:Data-ATS')
template_file = open("demo_config.templ", 'r')
file_text = template_file.read()
file_text = file_text.replace(
"<IOTEndpoint>", "\"" + endpoint["endpointAddress"] + "\"")
header_file = open("../demo_config.h", "w")
header_file.write(file_text)
header_file.close()
template_file.close()
print("Successfully updated demo_config.h")
# Parse arguments and execute appropriate functions
def main():
# Check arguments and go appropriately
print("\nThis script will set up the AWS resources required for the Fleet Provisioning demo.")
print("It may take several minutes for the resources to be provisioned.")
if input("Are you sure you want to do this? (y/n) ") == "y":
print()
create_resources()
create_credentials()
update_demo_config()
print("\nFleet Provisioning demo setup complete. Ensure that all generated files (key, certificate, demo_config.h) are in the same folder as \"fleet_provisioning_demo.sln\".")
if __name__ == "__main__":
main()

View file

@ -137,7 +137,7 @@ extern void vLoggingPrintf( const char * pcFormatString,
* https://docs.aws.amazon.com/iot/latest/developerguide/provision-template.html#fleet-provision-template * https://docs.aws.amazon.com/iot/latest/developerguide/provision-template.html#fleet-provision-template
* *
* The example template used for this demo is available in the * The example template used for this demo is available in the
* example_demo_template.json file in the demo directory. In the example, * example_demo_template.json file in the DemoSetup directory. In the example,
* replace <provisioned-thing-policy> with the policy provisioned devices * replace <provisioned-thing-policy> with the policy provisioned devices
* should have. The demo template uses Fn::Join to construct the Thing name by * should have. The demo template uses Fn::Join to construct the Thing name by
* concatenating fp_demo_ and the serial number sent by the demo. * concatenating fp_demo_ and the serial number sent by the demo.
@ -145,6 +145,10 @@ extern void vLoggingPrintf( const char * pcFormatString,
* @note The provisioning template MUST be created in AWS IoT before running the * @note The provisioning template MUST be created in AWS IoT before running the
* demo. * demo.
* *
* @note If you followed the manual setup steps on https://freertos.org/iot-fleet-provisioning/demo.html,
* the provisioning template name is "FleetProvisioningDemoTemplate".
* However, if you used CloudFormation to set up the demo, the template name is "CF_FleetProvisioningDemoTemplate"
*
* #define democonfigPROVISIONING_TEMPLATE_NAME "...insert here..." * #define democonfigPROVISIONING_TEMPLATE_NAME "...insert here..."
*/ */

View file

@ -1,63 +0,0 @@
#!/usr/bin/env python
import argparse
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
KEY_OUT_NAME = "corePKCS11_Claim_Key.dat"
CERT_OUT_NAME = "corePKCS11_Claim_Certificate.dat"
def convert_pem_to_der(cert_file, key_file):
# Convert certificate from PEM to DER
print("Converting format to DER format...")
with open(key_file, "rb") as key:
print("Starting key PEM to DER conversion.")
pemkey = serialization.load_pem_private_key(key.read(), None, default_backend())
key_der = pemkey.private_bytes(
serialization.Encoding.DER,
serialization.PrivateFormat.TraditionalOpenSSL,
serialization.NoEncryption(),
)
with open(KEY_OUT_NAME, "wb") as key_out:
key_out.write(key_der)
print(
f"Successfully converted key PEM to DER. Output file named: {KEY_OUT_NAME}"
)
print("Starting certificate pem conversion.")
with open(cert_file, "rb") as cert:
cert = x509.load_pem_x509_certificate(cert.read(), default_backend())
with open(CERT_OUT_NAME, "wb") as cert_out:
cert_out.write(cert.public_bytes(serialization.Encoding.DER))
print(
f"Successfully converted certificate PEM to DER. Output file named: {CERT_OUT_NAME}"
)
def main(args):
convert_pem_to_der(cert_file=args.cert_file, key_file=args.key_file)
if __name__ == "__main__":
arg_parser = argparse.ArgumentParser(
description="This script converts passed in PEM format certificates and keys into the binary DER format."
)
arg_parser.add_argument(
"-c",
"--cert_file",
type=str,
help="Specify the name of the generated certificate file.",
required=True,
)
arg_parser.add_argument(
"-k",
"--key_file",
type=str,
help="Specify the name of the generated key file.",
required=True,
)
args = arg_parser.parse_args()
main(args)

View file

@ -264,6 +264,7 @@ clienttoken
cligetoutputbuffer cligetoutputbuffer
clint clint
cliprocesscommand cliprocesscommand
cloudformation
clk clk
clkdiv clkdiv
clksel clksel
@ -522,6 +523,7 @@ democonfiguse
democonfiguser democonfiguser
demofiles demofiles
demoiptrace demoiptrace
demosetup
demotask demotask
demotimer demotimer
der der
@ -767,6 +769,7 @@ flasg
flashc flashc
flashlite flashlite
flashtimer flashtimer
fleetprovisioningdemotemplate
flexcomm flexcomm
flg flg
flopc flopc