Skip to content

Instantly share code, notes, and snippets.

@noahcoad
Last active September 27, 2023 10:56
Show Gist options
  • Save noahcoad/4701c6154a3c523c7d2b1b534947922b to your computer and use it in GitHub Desktop.
Save noahcoad/4701c6154a3c523c7d2b1b534947922b to your computer and use it in GitHub Desktop.
AWS IoT: Use a Custom Root CA

AWS IoT: Use a Custom Root CA

By default when creating new device certificates in AWS IoT Core, the root Amazon Certificate Authority (CA) is used. However, you can use your own CA, register it with AWS, and create device certificates with it. This is useful for example when you want to load device certificates onto a device without cloud connectivity, or want to control your own CA, or want to support multiple CAs, like a chip vendor and manufacture CAs.

The official doc on this topic is missing a piece about the CA:TRUE flag being required. And I like to be able to just copy/paste a bunch of commands and it works.

root ca

# prereqs
brew install jq

# create custom Root CA w keys w CA:TRUE flag
echo "[req]\ndistinguished_name=dn\nextensions=v3_ca\nreq_extensions=v3_ca\n[v3_ca]\nbasicConstraints=CA:TRUE\n[dn]" > rootCA_openssl.conf
openssl genrsa -out rootCA.key 2048
openssl req -new -sha256 -key rootCA.key -nodes -out rootCA.csr -config rootCA_openssl.conf -subj "/CN=my_root_ca"
openssl x509 -req -days 3650 -extfile rootCA_openssl.conf -extensions v3_ca -in rootCA.csr -signkey rootCA.key -out rootCA.pem

# get a registration code from AWS IoT
aws iot get-registration-code | tee get-registration-code.json

# create a verification CSR w AWS registration code
openssl req -nodes -newkey rsa:2048 -keyout verificationCert.key -out verificationCert.csr -subj "/CN=$(jq -r '.registrationCode' < get-registration-code.json)"

# sign CSR w new root CA
openssl x509 -req -in verificationCert.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out verificationCert.pem -days 500 -sha256

# upload signed CSR to AWS and activate it
aws iot register-ca-certificate --ca-certificate file://rootCA.pem --verification-cert file://verificationCert.pem | tee register-ca-certificate.json
CERT_ID=$(jq -r '.certificateId' < register-ca-certificate.json)
aws iot update-ca-certificate --certificate-id $CERT_ID --new-status ACTIVE

That's it, your custom Root CA is now registered in AWS.

You can now have new devices that connect to AWS IoT Core for the first time with a certificate signed by this root CA trigger Just-in-Time Registration. Or manually activate device certs and attach an IoT policy to them (like below).

device cert

Here's how to create a device certificate with your root CA and test it.

# create a device certificate from root CA
openssl genrsa -out deviceCert.key 2048
openssl req -new -key deviceCert.key -out deviceCert.csr -subj "/CN=my_device_cert"
openssl x509 -req -in deviceCert.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out deviceCert.pem -days 500 -sha256
aws iot register-certificate --certificate-pem file://deviceCert.pem --ca-certificate-pem file://rootCA.pem | tee register-certificate.json
CERT_ID=$(jq -r '.certificateId' < register-certificate.json)
aws iot update-certificate --certificate-id $CERT_ID --new-status ACTIVE

# create and attach a policy
RND=$(cat /dev/random | LC_CTYPE=C tr -dc "[:alpha:]" | head -c 8)
aws iot create-policy --policy-name demo_iot_all_access --policy-document '{"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Action": ["iot:*"], "Resource": ["*"]}]}'
CERT_ARN=$(jq -r '.certificateArn' < register-certificate.json)
aws iot attach-policy --policy-name demo_iot_all_access --target ${CERT_ARN}

# get endpoint
aws iot describe-endpoint --endpoint-type iot:Data-ATS | tee describe-endpoint.json

# test with AWS IoT Device SDK v2
pip3 show awsiotsdk > /dev/null || pip3 install --user awsiotsdk
[[ -r aws-iot-device-sdk-python-v2 ]] || git clone --depth 1 https://github.com/aws/aws-iot-device-sdk-python-v2.git
python3 aws-iot-device-sdk-python-v2/samples/pubsub.py --endpoint $(jq -r '.endpointAddress' < describe-endpoint.json) --root-ca rootCA.pem --cert deviceCert.pem --key deviceCert.key

cleanup

# cleanup device cert and demo policy
CERT_ARN=$(jq -r '.certificateArn' < register-certificate.json)
CERT_ID=$(jq -r '.certificateId' < register-certificate.json)
aws iot detach-policy --policy-name demo_iot_all_access --target ${CERT_ARN}
aws iot delete-policy --policy-name demo_iot_all_access
aws iot update-certificate --certificate-id $CERT_ID --new-status INACTIVE
aws iot delete-certificate --certificate-id $CERT_ID

# cleanup root ca
CERT_ID=$(jq -r '.certificateId' < register-ca-certificate.json)
aws iot update-ca-certificate --certificate-id $CERT_ID --new-status INACTIVE
aws iot delete-ca-certificate --certificate-id $CERT_ID

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment