Skip to content

Instantly share code, notes, and snippets.

@DoumanAsh
Last active April 22, 2025 05:13
Show Gist options
  • Save DoumanAsh/13e71bd93ceab2d807e0b4b65c1e763d to your computer and use it in GitHub Desktop.
Save DoumanAsh/13e71bd93ceab2d807e0b4b65c1e763d to your computer and use it in GitHub Desktop.
AWS IoT Core Provisioning script
import { mqtt5, iot, iotidentity } from 'aws-iot-device-sdk-v2';
///Ensure at least once delivery should be enough most of the time
const QOS = mqtt5.QoS.AtLeastOnce;
///Environment config
const CONFIG = {
endpoint: process.env.IOT_CORE_ENDPOINT!,
cert: process.env.IOT_CORE_CERTIFICATE!,
priv_key: process.env.IOT_CORE_PKEY!,
client_id: process.env.IOT_CORE_CLIENT_ID,
//registration parameters should be JSON matching template
provisioning_template_name: process.env.IOT_CORE_PROVISIONING_TEMPLATE!,
provisioning_template_params: JSON.parse(process.env.IOT_CORE_PROVISIONING_PARAMS!),
};
function unexpected_error(error: any) {
console.error("Unexpected error: %s\n%s", error, error.stack);
}
///Creates MQTT config
//
//Following environment variables are used to infer config
//
//- IOT_CORE_ENDPOINT - required endpoint hostname
//- IOT_CORE_CERTIFICATE = required x509 certificate in PEM format
//- IOT_CORE_PKEY - required pirvate key corresponding to IOT_CORE_CERTIFICATE in order to establish TLS connection
//- IOT_CORE_CLIENT_ID - optional client id. If not specified, uses random `test-*`
function create_mqtt_config(): mqtt5.Mqtt5ClientConfig {
const properties = {
clientId: CONFIG.client_id || "test-" + Math.floor(Math.random() * 100000000),
keepAliveIntervalSeconds: 120
};
return iot.AwsIotMqtt5ClientConfigBuilder.newDirectMqttBuilderWithMtlsFromMemory(CONFIG.endpoint, CONFIG.cert, CONFIG.priv_key).withSessionBehavior(mqtt5.ClientSessionBehavior.Clean).withConnectProperties(properties).build();
}
///Performs finalization of device registration by submitting CSR response token with necessary template parameters
function initiate_iot_device_registration(csr_response: iotidentity.model.CreateKeysAndCertificateResponse, iot_identity: iotidentity.IotIdentityClient) {
const subscribe_register_thing = {
templateName: CONFIG.provisioning_template_name
}
function on_register_accepted(error?: iotidentity.IotIdentityError, response?: iotidentity.model.RegisterThingResponse) {
if (error) {
console.error("Unexpected error: %s", error);
} else if (response) {
console.log("#### Device registration complete:\n # name='%s'\n # certificate_id='%s'\n # private_key:\n%s\n # certificate:\n%s\n", response.thingName ? response.thingName : '', csr_response.certificateId, csr_response.privateKey, csr_response.certificatePem);
if (response.deviceConfiguration) {
console.log("Device configuration:", response.deviceConfiguration);
}
}
}
function on_register_rejected(error?: iotidentity.IotIdentityError, response?: iotidentity.model.ErrorResponse) {
if (response) {
console.error("CSR is rejected:\n statusCode=%s\n errorCode=%s\n errorMessage=%s", response.statusCode, response.errorCode, response.errorMessage);
}
if (error) {
console.error("Unexpected error: %s", error);
}
}
console.log("subscribeToRegisterThing(templateName='%s') SEND", subscribe_register_thing.templateName);
const subscription_ongoing = [
iot_identity.subscribeToRegisterThingAccepted(subscribe_register_thing, QOS, on_register_accepted),
iot_identity.subscribeToRegisterThingRejected(subscribe_register_thing, QOS, on_register_rejected),
];
Promise.all(subscription_ongoing).then(() => {
console.debug("subscribeToRegisterThing() DONE");
const register_thing_request = {
parameters: CONFIG.provisioning_template_params,
templateName: CONFIG.provisioning_template_name,
certificateOwnershipToken: csr_response.certificateOwnershipToken
};
iot_identity.publishRegisterThing(register_thing_request, QOS).then(() => {
console.debug("publishRegisterThing() SENT");
}).catch(unexpected_error)
}).catch(unexpected_error)
}
///Initiates provisioning using provided mqtt client
//
//Requires connection to be successfully established.
function initiate_iot_provisioning(client: mqtt5.Mqtt5Client) {
const iot_identity = iotidentity.IotIdentityClient.newFromMqtt5Client(client);
function on_csr_accepted(error?: iotidentity.IotIdentityError, response?: iotidentity.model.CreateKeysAndCertificateResponse) {
if (error) {
console.error("Unexpected error: %s", error);
} else if (response) {
console.log("publishCreateCertificateFromCsr() DONE")
initiate_iot_device_registration(response, iot_identity);
}
}
function on_csr_rejected(error?: iotidentity.IotIdentityError, response?: iotidentity.model.ErrorResponse) {
if (response) {
console.error("CSR is rejected:\n statusCode=%s\n errorCode=%s\n errorMessage=%s", response.statusCode, response.errorCode, response.errorMessage);
}
if (error) {
console.error("Unexpected error: %s", error);
}
}
const ongoing = [
iot_identity.subscribeToCreateKeysAndCertificateAccepted({}, QOS, on_csr_accepted),
iot_identity.subscribeToCreateKeysAndCertificateRejected({}, QOS, on_csr_rejected),
];
Promise.all(ongoing).then(() => {
console.debug("subscribeToCreateCertificateFromCsr() DONE");
iot_identity.publishCreateKeysAndCertificate({}, QOS).then(() => {
console.debug("publishCreateCertificateFromCsr() SENT");
}).catch(unexpected_error)
}).catch(unexpected_error)
}
function initiate_mqtt_connection(config: mqtt5.Mqtt5ClientConfig) {
const client = new mqtt5.Mqtt5Client(config);
client.once("connectionSuccess", (data) => {
console.log("Connection successful", data)
initiate_iot_provisioning(client)
});
client.on("connectionFailure", (data) => {
console.log("Connection failed", data)
});
console.log("Connecting...");
client.start();
}
function main() {
const config = create_mqtt_config();
initiate_mqtt_connection(config)
}
main()
{
"devDependencies": {
"@types/bun": "latest",
"typescript": "^5.8.3",
"typescript-language-server": "^4.3.4"
},
"dependencies": {
"aws-iot-device-sdk-v2": "^1.21.3"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment