TABLE OF CONTENTS

Create an AWS IOT Signed Certificate Using Boto3

Author Sagi Liba
Sagi Liba on Nov 23, 2022
12 min šŸ•

Recently, I've been reseaching a lot about AWS IOT as part of few tasks I've been given at work. AWS IOT gives you the ability to communicate with your remote devices using a publish/subscribe protocol called MQTT, which uses certificates to identify the remote devices communicating with the IOT service.

As part of the research I've done, I've had the need to generate an AWS IOT signed certificate using a Certificate Signing Request (CSR), that will be used to identify the device I'm using for communication with the AWS IOT service.

Certificate Signing Request

A certificate signing request (CSR) is a file with encoded information used to identify the server it is created on during the process of applying for a TLS/SSL certificate from a certificate authority (CA).

This certificate will hold information such as the Domain Name of the server, it's Organization Name, Country, etc...

Example of a CSR file:

Copy
-----BEGIN NEW CERTIFICATE REQUEST-----
MIIDVDCCAr0CAQAweTEeMBwGA1UEAxMV4uY29tMQ8w
dt3mE2CiHYZnIAMgNVBAcMCEJyb2MA4GA1UdDwEB2d
...
...
NF7oU/xz0YCKOy9Zc4wddPUxETAPBgNVBAcMCzSwRf
ZSZTusPFTLKaqValdnS9Uw+6Vq7/I4ouDA8Q+8HQ==
-----END NEW CERTIFICATE REQUEST-----

Creating CSR using openSSL

Let's create a CSR using the openSSL toolkit, we have to make sure that it is at least 2048-bit RSA encoded, and it has our relevant information.

Copy
openssl req -newkey rsa:2048 -nodes -keyout private.key -out cert.csr -subj "/C=US/ST=Client/L=Brooklyn/O=IRYL/CN=example.com`

Breakdown:

  • req, tell openSSL to generate a CSR.
  • -keyout, outputs the private key.
  • -out, outputs the CSR, it acts as our public key.
  • -subj, it fills the CSR information programmatically.
  • -nodes, the private key should not be encrypted with a passphrase (you can decide otherwise, but Iā€™ve not tested the connection to IOT with a passphrase).

We have now created a public key (cert.csr) and a private key (private.key) for our CSR.

Generate IOT Certificate

When applying for a TLS certificate signed by Amazon Certificate Authority we send the Certificate Authority our CSR as a public key, and in return we receive the signed TLS certificate.

Note: The Certificate Authority should only use the public key, and the private key should be saved and kept secret.

Because we have created an RSA key pair of public and private keys, you cannot decrypt the messages without the private key.

To create an IOT certificate, certified by AWS CA, we will have to pass our previously generated public key file ā€œcert.csrā€ contents as a string to the following command:

Copy
aws iot create-certificate-from-csr --set-as-active --certificate-signing-request "cert.csr file contents as a string"

Iā€™ve passed the certificate as a string programmatically, the code is found at the bottom.

Upon success, you will receive the following response:

Copy
{
"certificateArn": "arn:aws:iot:....",
"certificateId": "....",
"certificatePem": "...."
}

The response holds all the relevant details for the created certificate.

You then need to save the created IOT certificate as a file, Iā€™ve called it ā€œiot-cert.pemā€, it will be used to connect to AWS IOT through MQTT requests.

You can save thecertificateId andcertificateArn as well, in another file.

Python Boto3 Example

The following code does all of the above mentioned steps:

  1. Create a CSR using openSSL toolkit.
  2. Apply for an AWS IOT certificate.
  3. Save that certificate information locally, to be used for communication using MQTT.
Copy
import subprocess
import json
import boto3
# Definitions
iot = boto3.client("iot")
certificateInfo = '/C=US/ST=Client Two/L=Brooklyn/O=IRYL/CN=examplebrooklyn.com'
def generate_csr(certificateInfo):
# -nodes - private key should not be encrypted with a passphrase
subprocess.run(["openssl", "req","-newkey","rsa:2048","-nodes","-keyout", "private.key","-out","cert.csr","-subj", certificateInfo])
def read_csr(fileName):
certificateString = ''
# read certificate file to certificateString
with open(fileName, 'r') as file:
certificateString = file.read().replace('\n', '')
return certificateString
def generate_iot_certificate(certificateString):
return iot.create_certificate_from_csr(certificateSigningRequest=certificateString, setAsActive=True)
# 1. Saves iot certificate to file
# 2. Save iot certificate arn and id to "latest-cert-info.txt"
def handle_iot_certificate_generation_response(response):
response_json = json.loads(response)
certificateId = response_json["certificateId"]
certificateArn = response_json["certificateArn"]
certificatePem = response_json["certificatePem"]
# Save iot certificate for connection
f = open("iot-cert.pem", "w")
f.write(certificatePem)
f.close()
print("@@@ Saved IOT certificate for connection as 'iot-cert.pem'")
# Save iot certificate Id + Arn
f = open("latest-cert-info.txt", "w")
f.write("Certificate Id: " + certificateId + "\n")
f.write("Certificate Arn: " + certificateArn + "\n")
f.close()
print("@@@ Saved IOT certificate generation response to 'latest-cert-info.txt'")
# Usage
generate_csr(certificateInfo)
# read created csr to string
certificateString = read_csr("cert.csr")
# create iot certificate
response = generate_iot_certificate(certificateString)
# save certificate information, create connection iot-cert.pem
handle_iot_certificate_generation_response(response)

Send a Message With MQTT

The MQTT protocol, is an extremely light-weight publish/subscribe protocol designed for messaging with remote devices and minimal network bandwidth usage.

AWS IOT uses it for its messaging transactions viaAWSIOTPythonSDK.

I've not used boto3 here because it relies on the permissions of the AWS account you have configured locally. We need to rely on our generated IOT certificate for communication.

* Ā * Ā *
Download the Amazon Root CA from:

https://docs.aws.amazon.com/iot/latest/developerguide/server-authentication.html

Go to:

  1. CA certificates for server authentication
  2. RSA 2048 bit key
  3. Amazon Root CA 1
  4. Save it as AmazonRootCA1.pem.

The following code uses the created TLS certificate, private key and root CA of Amazon to send the messages.

Copy
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient
import time
import json
# Fill the following details correctly:
host = '<iot-unique-id>.iot.us-west-2.amazonaws.com'
rootCAPath = 'AmazonRootCA1.pem'
certificatePath = 'iot-cert.pem'
privateKeyPath = 'private.key'
port = 8883
clientId = 'your_client_id'
topic = 'your_topic'
# Init AWSIoTMQTTClient
myAWSIoTMQTTClient = AWSIoTMQTTClient(clientId)
myAWSIoTMQTTClient.configureEndpoint(host, port)
myAWSIoTMQTTClient.configureCredentials(rootCAPath, privateKeyPath, certificatePath)
# AWSIoTMQTTClient connection configuration
myAWSIoTMQTTClient.configureAutoReconnectBackoffTime(1, 32, 20)
myAWSIoTMQTTClient.configureOfflinePublishQueueing(-1) # Infinite offline Publish queueing
myAWSIoTMQTTClient.configureDrainingFrequency(2) # Draining: 2 Hz
myAWSIoTMQTTClient.configureConnectDisconnectTimeout(10) # 10 sec
myAWSIoTMQTTClient.configureMQTTOperationTimeout(5) # 5 sec
# Connect and subscribe to AWS IoT
myAWSIoTMQTTClient.connect()
# Send 20 messages
loopCount = 0
while loopCount < 20:
messageJson = json.dumps({"message": "{} - Client: {}".format(loopCount, clientId)})
myAWSIoTMQTTClient.publish(topic, messageJson, 1)
loopCount += 1
time.sleep(1)

That's it, your devices can now communicate with AWS IOT through a certificate generated programmatically.

Ā© 2020-present Sagi Liba. All Rights Reserved