Skip to content

AWS IoT Greengrass Installation with Hardware Security Integration

Note

Prerequisited: follow the previous AWS IoT Greengrass Installation guide.

Create the AWS IoT Thing

Get the AWS IoT data endpoint for your AWS account.

aws iot describe-endpoint --endpoint-type iot:Data-ATS
{
    "endpointAddress": "a1rm1gogglx99n-ats.iot.us-east-1.amazonaws.com"
}

Get the AWS IoT credentials endpoint for your AWS account.

aws iot describe-endpoint --endpoint-type iot:CredentialProvider
{
    "endpointAddress": "c3s9r3bwgw6exe.credentials.iot.us-east-1.amazonaws.com"
}

Create an AWS IoT thing.

aws iot create-thing --thing-name REGATE-10-14-GreengrassCoreHSM
{
    "thingName": "REGATE-10-14-GreengrassCoreHSM",
    "thingArn": "arn:aws:iot:us-east-1:332696098873:thing/REGATE-10-14-GreengrassCoreHSM",
    "thingId": "dc732ab7-6b3f-44d9-8575-21d9fc1732d0"
}

Add the AWS IoT thing to a thing group.

aws iot add-thing-to-thing-group --thing-name REGATE-10-14-GreengrassCoreHSM --thing-group-name EurotechGreengrassCoreGroup

Create the certificate from a private key in an HSM

On the device, create the certificate from a private key in an HSM. Eurotech gateways use a TPM 2.0 hardware security module. The AWS IoT Greengrass certificate will be loaded in the TPM Owner Hierarchy.

Initialize TPM 2.0 Storage Root Key

If the TPM has not been initialized, create a Storage Root Key (SRK) and persist it with the following command.

sudo mkdir -p /opt/aws/tpm2/
sudo chmod 777 /opt/aws/tpm2/
cd /opt/aws/tpm2/
tpm2_createprimary -C o -G rsa -g sha256 \
    -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|restricted|decrypt" \
    -c srk.ctx
tpm2_evictcontrol -C o -c srk.ctx 0x81000001

Create a private key for the AWS IoT Thing

Create a private key for the AWS IoT Thing under the Storage Root Key. We will call that key Local Device ID (LDevID) and we will make it persistent at 0x81000002.

tpm2_create -C 0x81000001 \
    -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|sign|decrypt|noda" \
    -G rsa2048:null:null -g sha256 \
    -u ldevid.pub -r ldevid.priv 
tpm2_load -C 0x81000001 -u ldevid.pub -r ldevid.priv -c ldevid.ctx
tpm2_evictcontrol -C o -c ldevid.ctx 0x81000002

Create a CSR and a Certificate for the AWS IoT Thing

Create a certificate signing request (CSR) from the private key. AWS IoT uses this CSR to create a thing certificate for the private key that you generated in the HSM.

openssl req -new -engine tpm2tss -keyform engine -key 0x81000002 \
    -config openssl-devids.conf -reqexts ldevid \
    -out ldevid.csr

Copy the CSR from the device to your development computer.

scp ldevid.csr host-ip-address:~/ldevid.csr 

On the host, use the CSR file to create and download the certificate for the AWS IoT thing to your development computer.

mkdir greengrass-v2-certs
aws iot create-certificate-from-csr --set-as-active --certificate-signing-request=file://ldevid.csr --certificate-pem-outfile greengrass-v2-certs/ldevid.pem.crt
{
    "certificateArn": "arn:aws:iot:us-east-1:332696098873:cert/162a88d1009eb6b0f257ed8e0163d5cb3ad4b570eeb0a8e45f160ac8894ed03d",
    "certificateId": "162a88d1009eb6b0f257ed8e0163d5cb3ad4b570eeb0a8e45f160ac8894ed03d",
    "certificatePem": "-----BEGIN CERTIFICATE-----\nMIIDfDCCAmSgAwIBAgIVAJHaEri69bhONajM7gb3g8Kenm6qMA0GCSqGSIb3DQEB\nCwUAME0xSzBJBgNVBAsMQkFtYXpvbiBXZWIgU2VydmljZXMgTz1BbWF6b24uY29t\nIEluYy4gTD1TZWF0dGxlIFNUPVdhc2hpbmd0b24gQz1VUzAeFw0yMjAyMTUyMTEx\nNTJaFw00OTEyMzEyMzU5NTlaMEAxETAPBgNVBAoMCEV1cm90ZWNoMRgwFgYDVQQD\nDA9SRUdBVEUtMTAtMTQtMzYxETAPBgNVBAUTCDAxMDIwMzA0MIIBIjANBgkqhkiG\n9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt1iJp5z0d7eiwFZf+J/epxX6xeDr7iZ9eUwS\n65fwBRGaTLNMjD6NdV1zH/8ClWrYN/gnKosjzji6AHb2cyDj9b8tnQCEakJfLSh6\nwpID0wdJyM7RHqqQw4ZNKn2JDXqam2XGZCZBt3UDeOKxTm5mS2A4LgmkNpoEdqof\nNJJmNYsckowN8j/SIKD9b5FouI4//qF1zUmmzeidqS2HFno0FZnrdIcUZdJfTLYf\n6zn1g3hCFkpa1xE2k3vidrP36HStbjzcj9PNaFzbTdwpUx+7gzsxl2kC8AoZygoO\n0g1kN6GrCYPSHTASAWbQXQJzJw/RSnjlIj3QvnB2ce10XH6+DQIDAQABo2AwXjAf\nBgNVHSMEGDAWgBTSuW1XP6mpLBsdpakikv5OXfq7XzAdBgNVHQ4EFgQUZsEqsvf9\nfiov7or3EnzTYvoHOnEwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwDQYJ\nKoZIhvcNAQELBQADggEBAAOGtPIu3C1UIwUYenfWyGJkPXlAIWc/C2enbQ17LH9J\nvvMptXumiPUsuk4gSbfgI639YkD70nkvUO2uFvwtFC4We//jmx2E+Oe4xJQ457Yo\nrn/Yftt5RTcyFq9ggsXhylps4ae0WbR7bYOg+JBOeaoi9R0hhf4k3qB44kMz1Hc1\nE+JcFbwPqh+80oz7cd6V5oaKz1rT5Lle7R8FTUMuC1wXMHMb5n4QjFgSvnzKdko3\nAvfdOTB2dicIJ2qKeMsu0COchZFVNSzxGA2KKuyKtarg/S+A4xn3dc6bHQ9LlHXQ\niUAt+TLCcO72BcErkYYEST8sje3CLur2a++n4uoWLCo=\n-----END CERTIFICATE-----\n"
}

Copy the certificate to the device.

scp greengrass-v2-certs/ldevid.pem.crt guest@device-ip:/opt/aws/tpm2/

Attach the certificate to the AWS IoT thing.

aws iot attach-thing-principal --thing-name REGATE-10-14-GreengrassCoreHSM --principal arn:aws:iot:us-east-1:332696098873:cert/162a88d1009eb6b0f257ed8e0163d5cb3ad4b570eeb0a8e45f160ac8894ed03d

Create and attach an AWS IoT policy that defines the AWS IoT permissions for your Greengrass core device.

nano greengrass-v2-iot-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iot:Publish",
        "iot:Subscribe",
        "iot:Receive",
        "iot:Connect",
        "greengrass:*"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

aws iot create-policy --policy-name EthGreengrassV2IoTThingPolicy --policy-document file://greengrass-v2-iot-policy.json
{
    "policyName": "EthGreengrassV2IoTThingPolicy",
    "policyArn": "arn:aws:iot:us-east-1:332696098873:policy/EthGreengrassV2IoTThingPolicy",
    "policyDocument": "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"iot:Publish\",\n        \"iot:Subscribe\",\n        \"iot:Receive\",\n        \"iot:Connect\",\n        \"greengrass:*\"\n      ],\n      \"Resource\": [\n        \"*\"\n      ]\n    }\n  ]\n}\n",
    "policyVersionId": "1"
}

Attach the AWS IoT policy to the AWS IoT thing's certificate.

aws iot attach-policy --policy-name EthGreengrassV2IoTThingPolicy --target arn:aws:iot:us-east-1:332696098873:cert/162a88d1009eb6b0f257ed8e0163d5cb3ad4b570eeb0a8e45f160ac8894ed03d

Create a token exchange IAM role.

nano device-role-trust-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "credentials.iot.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

aws iam create-role --role-name EthGreengrassV2TokenExchangeRole --assume-role-policy-document file://device-role-trust-policy.json
{
    "Role": {
        "Path": "/",
        "RoleName": "EthGreengrassV2TokenExchangeRole",
        "RoleId": "AROAU25R3TA4QZW5HN3HB",
        "Arn": "arn:aws:iam::332696098873:role/EthGreengrassV2TokenExchangeRole",
        "CreateDate": "2022-02-15T21:44:59+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "Service": "credentials.iot.amazonaws.com"
                    },
                    "Action": "sts:AssumeRole"
                }
            ]
        }
    }
}

Create a file that contains the access policy document that the token exchange role requires.

nano device-role-access-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iot:DescribeCertificate",
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents",
        "logs:DescribeLogStreams",
        "s3:GetBucketLocation"
      ],
      "Resource": "*"
    }
  ]
}

aws iam create-policy --policy-name EthGreengrassV2TokenExchangeRoleAccess --policy-document file://device-role-access-policy.json
{
    "Policy": {
        "PolicyName": "EthGreengrassV2TokenExchangeRoleAccess",
        "PolicyId": "ANPAU25R3TA4UJAMA4QXI",
        "Arn": "arn:aws:iam::332696098873:policy/EthGreengrassV2TokenExchangeRoleAccess",
        "Path": "/",
        "DefaultVersionId": "v1",
        "AttachmentCount": 0,
        "PermissionsBoundaryUsageCount": 0,
        "IsAttachable": true,
        "CreateDate": "2022-02-15T21:46:42+00:00",
        "UpdateDate": "2022-02-15T21:46:42+00:00"
    }
}

Attach the IAM policy to the token exchange role.

aws iam attach-role-policy --role-name EthGreengrassV2TokenExchangeRole --policy-arn arn:aws:iam::332696098873:policy/EthGreengrassV2TokenExchangeRoleAccess

Create an AWS IoT role alias that points to the token exchange role.

aws iot create-role-alias --role-alias EthGreengrassCoreTokenExchangeRoleAlias --role-arn arn:aws:iam::332696098873:role/EthGreengrassV2TokenExchangeRole
{
    "roleAlias": "EthGreengrassCoreTokenExchangeRoleAlias",
    "roleAliasArn": "arn:aws:iot:us-east-1:332696098873:rolealias/EthGreengrassCoreTokenExchangeRoleAlias"
}

Create and attach an AWS IoT policy that allows your Greengrass core device to use the role alias to assume the token exchange role.

nano greengrass-v2-iot-role-alias-policy.json
{
  "Version":"2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:AssumeRoleWithCertificate",
      "Resource": "arn:aws:iot:us-east-1:332696098873:rolealias/EthGreengrassCoreTokenExchangeRoleAlias"
    }
  ]
}

aws iot create-policy --policy-name EthGreengrassCoreTokenExchangeRoleAliasPolicy --policy-document file://greengrass-v2-iot-role-alias-policy.json
{
    "policyName": "EthGreengrassCoreTokenExchangeRoleAliasPolicy",
    "policyArn": "arn:aws:iot:us-east-1:332696098873:policy/EthGreengrassCoreTokenExchangeRoleAliasPolicy",
    "policyDocument": "{\n  \"Version\":\"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": \"iot:AssumeRoleWithCertificate\",\n      \"Resource\": \"arn:aws:iot:us-east-1:332696098873:rolealias/EthGreengrassCoreTokenExchangeRoleAlias\"\n    }\n  ]\n}\n",
    "policyVersionId": "1"
}

Attach the AWS IoT policy to the AWS IoT thing's certificate.

aws iot attach-policy --policy-name EthGreengrassCoreTokenExchangeRoleAliasPolicy --target arn:aws:iot:us-east-1:332696098873:cert/162a88d1009eb6b0f257ed8e0163d5cb3ad4b570eeb0a8e45f160ac8894ed03d

Import the AWS IoT Thing Certificate into the HSM

If not already done, initialize a PKCS11 store in the TPM 2. A store creates a primary object under the owner hierarchy and each primary object is mapped to a slot. Make sure to define the /etc/tpm2_pkcs11/ directory to store the PKCS11 supporting information for the tpm2_tools, tpm2_ptool, and the libpcks11 library.

sudo mkdir /etc/tpm2_pkcs11/
tpm2_ptool init --primary-handle 0x81000001

After creating a slot, now one needs to create a token. This is accomplished with the addtoken command for tpm2-ptool, using the primary object ID from previous step. A token is created and a unique name called a label is provided. The label is used in subsequent commands to reference the token.

tpm2_ptool addtoken --pid '1' --label 'aws' --userpin '1234' --sopin '1234' 

Now link private key for the AWS IoT Thing to PKCS#11 'aws' token with ldevid key-label. Then, install the AWS IoT Thing device certificate in the same slot with the same key-label.

cd /opt/aws/tpm2/
tpm2_ptool link --label='aws' --userpin='1234' --key-label="ldevid" ldevid.pub ldevid.priv
tpm2_ptool addcert --label='aws' --key-label='ldevid' ldevid.pem.crt
tpm2_ptool listobjects --label 'aws'

Install the AWS IoT Greengrass Core software

Install the AWS IoT Greengrass Core software.

Download the Amazon root certificate authority (CA) certificate. AWS IoT certificates are associated with Amazon's root CA certificate by default.

sudo mkdir -p /opt/aws/greengrass/v2
sudo chmod 755 /opt/aws/greengrass
sudo curl -o /opt/aws/greengrass/v2/AmazonRootCA1.pem https://www.amazontrust.com/repository/AmazonRootCA1.pem

Download the AWS IoT Greengrass Core software.

curl -s https://d2s8p88vqu9w66.cloudfront.net/releases/greengrass-nucleus-latest.zip > greengrass-nucleus-latest.zip
unzip greengrass-nucleus-latest.zip -d GreengrassInstaller && rm greengrass-nucleus-latest.zip
java -jar ./GreengrassInstaller/lib/Greengrass.jar --version

Download the PKCS#11 provider plugin to a file named aws.greengrass.crypto.Pkcs11Provider.jar.

curl -s https://d2s8p88vqu9w66.cloudfront.net/releases/Pkcs11Provider/aws.greengrass.crypto.Pkcs11Provider-latest.jar > GreengrassInstaller/aws.greengrass.crypto.Pkcs11Provider.jar

Create a configuration file named config.yaml to provide to the installer.

nano GreengrassInstaller/config.yaml
---
system:
  certificateFilePath: "pkcs11:object=ldevid;type=cert"
  privateKeyPath: "pkcs11:object=ldevid;type=private"
  rootCaPath: "/opt/aws/greengrass/v2/AmazonRootCA1.pem"
  rootpath: "/opt/aws/greengrass/v2"
  thingName: "REGATE-10-14-GreengrassCoreHSM"
services:
  aws.greengrass.Nucleus:
    componentType: "NUCLEUS"
    version: "2.5.3"
    configuration:
      awsRegion: "us-east-1"
      iotRoleAlias: "EthGreengrassCoreTokenExchangeRoleAlias"
      iotDataEndpoint: "a1rm1gogglx99n-ats.iot.us-east-1.amazonaws.com"
      iotCredEndpoint: "c3s9r3bwgw6exe.credentials.iot.us-east-1.amazonaws.com"
  aws.greengrass.crypto.Pkcs11Provider:
    configuration:
      name: "tpm2_pkcs11"
      library: "/usr/lib/pkcs11/libtpm2_pkcs11.so.0.0.0"
      slot: 2
      userPin: 1234

Run the installer.

sudo -E java -Droot="/opt/aws/greengrass/v2" -Dlog.store=FILE \
  -jar ./GreengrassInstaller/lib/Greengrass.jar \
  --trusted-plugin ./GreengrassInstaller/aws.greengrass.crypto.Pkcs11Provider.jar \
  --init-config ./GreengrassInstaller/config.yaml \
  --component-default-user ggc_user:ggc_group \
  --setup-system-service true

If needed, the Greengrass configuration can be updated as follows.

sudo systemctl stop greengrass.service
sudo nano /opt/aws/greengrass/v2/config/effectiveConfig.yaml
sudo java -Droot="/opt/aws/greengrass/v2" \
  -jar /opt/aws/greengrass/v2/alts/current/distro/lib/Greengrass.jar \
  --start false \
  --init-config /opt/aws/greengrass/v2/config/effectiveConfig.yaml
sudo systemctl start greengrass.service
sudo journalctl -u greengrass.service -f
sudo tail -100f /opt/aws/greengrass/v2/