Field Notes: Integrating IoT and ITSM using AWS IoT Greengrass and AWS Secrets Manager – Part 2
AWS Architecture BlogField Notes: Integrating IoT and ITSM using AWS IoT Greengrass and AWS Secrets Manager – Part 2by Gary Emmerton | on29 OCT 2020| inArchitecture,AWS IoT Greengrass,AWS Lambda,AWS Secrets Manager,Internet of Things,Technical How-to|Permalink|ShareInpart 1 of this blogI introduced the need for organizations to securely connect thousands of IoT devices with many different systems in the hyperconnected world that exists today, and how that can be addressed usingAWS IoT GreengrassandAWS Secrets Manager.  We walked through the creation of ServiceNow credentials in AWS Secrets Manager, the creation of IAM roles and the Lambda functions that will run on our edge device (a Raspberry Pi).In this second part of the blog, we will setup AWS IoT Greengrass, on our Raspberry Pi, and AWS IoT Core so that we can run the AWS Lambda functions and access our ServiceNow credentials, retrieved securely from AWS Secrets Manager.Setting up AWS IoT Core and AWS IoT GreengrassThe overall sequence for configuring AWS IoT Core and AWS IoT Greengrass is:Create a certificate, and IoT Thing and link themCreate AWS IoT Greengrass groupAssociate IAM role to the AWS IoT Greengrass groupCreate and attach a policy to the certificateCreate an AWS IoT Greengrass Resource Definition for our ‘Secret’Create an AWS IoT Greengrass Function Definition for our Lambda functionsCreate an AWS IoT Greengrass Subscription Definition for IoT Topics to be usedFinally associate our Resource, Function and Subscription Definitions with our AWS IoT Greengrass CoreStepsFor this walkthrough, I have selected the AWS region “eu-west-1”, however, feel free to useother Regionswhere AWS IoT Core and AWS IoT Greengrass are available.First, let’s install Greengrass on the Raspberry Pi:Follow theinstructionsto configure the pre-requisites on the Raspberry PiThen we download theAWS IoT Greengrass softwareAnd then we unzip the AWS IoT Greengrass software using the following command (note, this command is for version 1.10.0 of Greengrass and will change as later versions are released):sudo tar -xzvf greengrass-linux-armv6l-1.10.0.tar.gz -C /Note that AWS IoT Greengrass must be compatible with the version of theAWS Greengrass SDK installedto identify what versions are compatible and usesudo pip3 install greengrasssdk==<version_number>to install the SDK compatible with the version of AWS IoT Greengrass that we installed.Our AWS IoT Greengrass core will authenticate with AWS IoT Core in AWS using certificates, so we need to generate these first using the following command:aws iot create-keys-and-certificate --set-as-active --certificate-pem-outfile "iot-ge.cert.pem" --public-key-outfile "iot-ge.public.key" --private-key-outfile "iot-ge.private.key"This command will generate three files containing the private key, public key and certificate.  All of these files need to be copied to the/greengrass/certsfolder on the Raspberry Pi.  Also, the output of the preceding command will give the ARN of the certificate – we need to make a note of this ARN as we will use it in the next steps.We also need to download a copy of the Amazon Root CA into the/greegrass/certsfolder using the command below:sudo wget -O root.ca.pem https://www.amazontrust.com/repository/AmazonRootCA1.pemFor the next step we need our AWS account number and IoT Host address unique to our account – we get the IoT Host address using the command:aws iot describe-endpoint --endpoint-type iot:Data-ATSNow we need to create aconfig.jsonfile on the Raspberry Pi in the/greengrass/configfolder, with the account number and IoT Host address obtained in the previous step;{
  "coreThing" : {
    "caPath" : "root.ca.pem",
    "certPath" : "iot-ge.cert.pem",
    "keyPath" : "iot-ge.private.key",
    "thingArn" : "arn:aws:iot:eu-west-1:<aws_account_number>:thing/IoT-blog_Core",
    "iotHost" : "<endpoint_address>",
    "ggHost" : "greengrass-ats.iot.eu-west-1.amazonaws.com",
    "keepAlive" : 600
  },
  "runtime" : {
    "cgroup" : {
      "useSystemd" : "yes"
    },
    "allowFunctionsToRunAsRoot" : "yes"
  },
  "managedRespawn" : false,
  "crypto" : {
    "principals" : {
      "SecretsManager" : {
        "privateKeyPath" : "file:///greengrass/certs/iot-ge.private.key"
      },
      "IoTCertificate" : {
        "privateKeyPath" : "file:///greengrass/certs/iot-ge.private.key",
        "certificatePath" : "file:///greengrass/certs/iot-ge.cert.pem"
      }
    },
    "caPath" : "file:///greengrass/certs/root.ca.pem"
  }
}Note that the line"allowFunctionsToRunAsRoot" : "yes"allows the Lambda functions to easily access the SenseHat on the Raspberry Pi. This configuration should normally be avoided in Production environments for security reasons but has been used here for simplicity.Next we create the IoT Thing to represent our Raspberry Pi to match the entry we added into theconfig.jsonfile previously:aws iot create-thing --thing-name IoT-blog_CoreNow that ourconfig.jsonfile is in place and our IoT ‘thing’ created we can start the AWS IoT Greengrass software using the following commands:cd /greengrass/ggc/core/
sudo ./greengrassd startThen we attach the certificate to our new Thing – we need the ARN of the certificate that was noted in the earlier steps when we created the certificates:aws iot attach-thing-principal --thing-name "IoT-blog_Core" --principal "<certificate_arn>"Now we create the AWS IoT Greengrass group – make a note of the Group ID in the output of this command as we use it later:aws greengrass create-group --name IoT-blog-groupNext we create the AWS IoT Greengrass Core definition file – create this using a text editor and save ascore-def.json{
  "Cores": [
    {
      "CertificateArn": "<certificate_arn>",
      "Id": "<IoT Thing Name>",
      "SyncShadow": true,
      "ThingArn": "<thing_arn>"
    }
  ]
}Then, using the preceding file we just created, we create the core definition using the following command:aws greengrass create-core-definition --name "IoT-blog_Core" --initial-version file://core-def.jsonNow we associate the AWS IoT Greengrass core with the AWS IoT Greengrass group – we need theLatestVersionARNfrom the output of the command above and thegroup IDof your existing AWS IoT Greengrass group (in the output from the command for creation of the group in previous steps):aws greengrass create-group-version --group-id "<greengrass_group_id>" --core-definition-version-arn "<core_definition_version_arn>"Then we associate the IAM role (created earlier) to the AWS IoT Greengrass group;aws greengrass associate-role-to-group --group-id "<greengrass_group_id>" --role-arn "arn:aws:iam::<aws_account_number>:role/IoTGGRole"We need to create a policy to associate with the certificate so that our AWS IoT Greengrass Core (authenticated/authorized by our certificates) has rights to interact with AWS IoT Core.  To do this we create thepolicy.jsonfile:{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iot:Publish",
        "iot:Subscribe",
        "iot:Connect",
        "iot:Receive"
      ],
      "Resource": [
        "*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "iot:GetThingShadow",
        "iot:UpdateThingShadow",
        "iot:DeleteThingShadow"
      ],
      "Resource": [
        "*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "greengrass:*"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}Then create the policy using the policy file using the command below:aws iot create-policy --policy-name myGGPolicy --policy-document file://policy.jsonAnd finally attach our new policy to the certificate – as the certificate is attached to our AWS IoT Greengrass Core, this gives the rights defined in the policy to our AWS IoT Greengrass Core;aws iot attach-policy --target "<certificate_arn>" --policy-name "myGGPolicy"Now we have the AWS IoT Greengrass Core and permissions in place, it’s time to add our Secret as a resource for AWS IoT Greengrass.First, we need to create a resource definition that refers to the ARN of the secret we created earlier.  Get the ARN of the secret using the following command:aws secretsmanager describe-secret --secret-id "greengrass-snow-creds"And then we create a text file containing the following and save it asresource.json:{
"Resources": [
    {
      "Id": "SNOW-Credentials",
      "Name": "SNOW-Credentials",
      "ResourceDataContainer": {
        "SecretsManagerSecretResourceData": {
          "ARN": "<secret_arn>"
        }
      }
    }
  ]
}Now we command to create the resource reference in IoT to the Secret:aws greengrass create-resource-definition --name "MySNOWSecret" --initial-version file://resource.jsonNote the Resource ID from the output as it is needed as it has to be added to the Lambda definition json file in the next steps.  The function definition file contains the details of the Lambda function(s) that we will attach to our AWS IoT Greengrass group.  We create a text file with the content below and save aslambda-def.json.We also specify a couple of variables in the definition file; these are the same as the environment variables that can be specified for Lambda, but they make the variables available in AWS IoT Greengrass.Note, if we specify environment variables for the functions in the Lambda console then these will NOT be available when the function is running under AWS IoT Greengrass.  We will need our ServiceNow API URL to add to the configuration below, and this will be in the form ofhttps://devXXXXX.service-now.com/api/now/table/incident, where XXXXX is the developer instance number assigned by ServiceNow when our instance is created.We need the ARNs of the Lambda functions that we created in part 1 of the blog – these appear in the output after successfully creating the functions from the command line, or can be obtained using theaws lambda list-functionscommand – we need to have the ‘:1’ at the end of the ARN as AWS IoT Greengrass needs to reference published function versions.{
  "DefaultConfig": {
    "Execution": {
      "IsolationMode": "NoContainer",
      "RunAs": {
        "Gid": 0,
        "Uid": 0
      }
    }
  },
  "Functions": [
    {
      "FunctionArn": "<lambda_function1_arn>:1",
      "FunctionConfiguration": {
        "EncodingType": "json",
        "Environment": {
          "Execution": {
            "IsolationMode": "NoContainer"
          },
          "Variables": { 
            "tempLimit": "30",
            "humidLimit": "50"
          }
        },
        "ExecArgs": "string",
        "Executable": "lambda_function.lambda_handler",
        "Pinned": true,
        "Timeout": 10
      },
    "Id": "sensorLambda"
    },
    {
      "FunctionArn": "<lambda_function2_arn>:1",
      "FunctionConfiguration": {
        "EncodingType": "json",
        "Environment": {
          "Execution": {
            "IsolationMode": "NoContainer"
          },
          "ResourceAccessPolicies": [
            {
              "Permission": "ro",
              "ResourceId": "SNOW-Credentials"
            }
          ],
          "Variables": { 
            "snowUrl": "<service_now_api_url>"
          }
        },
        "ExecArgs": "string",
        "Executable": "lambda_function.lambda_handler",
        "Pinned": false,
        "Timeout": 10
      },
    "Id": "anomalyLambda"
    }
  ]
}The Lambda function now needs to be registered within our AWS IoT Greengrass core using the definition file just created, using the following command:aws greengrass create-function-definition --name "IoT-blog-lambda" --initial-version file://lambda-def.jsonCreate SubscriptionsWe now need to create some IoT Topics to pass data between the two Lambda functions and also to submit all sensor data to AWS IoT Core, which gives us visibility of the successful collection of sensor data.cd.First, let’s create a subscription configuration file (subscriptions.json) for sensor data and anomaly data:{
  "Subscriptions": [
    {
      "Id": "SensorData",
      "Source": "<lambda_function1_arn>:1",
      "Subject": "IoTBlog/sensorData",
      "Target": "cloud"
    },
    {
      "Id": "AnomalyData",
      "Source": "<lambda_function1_arn>:1",
      "Subject": "IoTBlog/anomaly",
      "Target": "<lambda_function2_arn>:1"
    },
    {
      "Id": "AnomalyDataB",
      "Source": "<lambda_function1_arn>:1",
      "Subject": "IoTBlog/anomaly",
      "Target": "cloud"
    }
  ]
}And next, we run the command to create the subscription from this configuration:aws greengrass create-subscription-definition --name "IoT-sensor-subs" --initial-version file://subscriptions.jsonUpdate AWS IoT Greengrass Group Associations and DeployNow that the functions, subscriptions and resources have been defined, we run the following command to update our AWS IoT Greengrass group to the new version with those components included:aws greengrass create-group-version --group-id <gg_group_id> --core-definition-version-arn "<core_def_version_arn>" --function-definition-version-arn "<function_def_version_arn>" --resource-definition-version-arn "<resource_def_version_arn>" --subscription-definition-version-arn "<subscription_def_version_arn>"And finally, we can deploy our configuration.  Use the following command to deploy the Greengrass group to our device, using the group-version-id from the output of the previous command and also the group-id:aws greengrass create-deployment --deployment-type NewDeployment --group-id <gg_group_id> --group-version-id <gg_group_version_id>Summarized below is the integration between the different functions and components that we have now deployed to get from our sensor data through to an incident being raised in ServiceNow:Create an IncidentEverything is setup now from an IoT perspective, so we can attempt to trigger a threshold breach on the sensors to trigger the creation of an incident in ServiceNow.  In order to trigger the incident creation, let’s raise the humidity around the sensor so that it breaches the threshold defined in the environment variables of the Lambda function.Under normal conditions we will just see the data published by the first Lambda function in theIoTBlog/sensorDatatopic:However, when a threshold is breached (in our example, humidity above 50%), the data is published to theIoTBlog/anomalytopic as shown below:Via the AWS IoT Greengrass subscriptions created earlier, this message arriving in the anomaly topic also triggers the second Lambda function to create the ticket in ServiceNow.The log for the second Lambda function on AWS IoT Greengrass (stored in/greengrass/ggc/var/log/user/<region>/<aws_account_number>/on the Raspberry Pi) will show a ‘201’ return code if the incident is successfully created in ServiceNow.Now let’s log on to ServiceNow and check out our new incident.  Good news, our new incident appears correctly:And when we click on our incident we can see the detail, including the full data from the IoT topic in the Activities section;This is only a basic use of the ServiceNow API and there are many other parameters that you can use to increase the richness of the incident, refer to theServiceNow API documentationfor more details.Cleaning upTo avoid incurring future charges, delete the resources that you created in the walkthrough.ConclusionWe have built an IoT device (Raspberry Pi), running AWS IoT Greengrass, AWS Lambda, and using ServiceNow credentials managed in AWS Secrets Manager.  Using this we have triggered an anomaly event that has created an incident automatically in ServiceNow, directly from the Lambda function running on our Pi.  You can use this architecture as the foundation to integrate your edge devices and ITSM solution to automate ticket generation in your organization.Look out for follow-up blogs that will extend this solution to provide a real-time dashboard for the sensor data and store the sensor data in a Data Lake for historical visualization.Find out more aboutdeploying Secrets to AWS IoT Greengrass Core.Check out theAWS IoT Blogfor more examples of how to use AWS to integrate your edge devices with the AWS Cloud.Field Notes provides hands-on technical guidance from AWS Solutions Architects, consultants, and technical account managers, based on their experiences in the field solving real-world business problems for customers.TAGS:Field NotesGary EmmertonGary Emmerton is a Solutions Architect based in the UK who has been working in IT for over 25 years designing and implementing global solutions for enterprise customers. Working with IoT gives Gary a convenient excuse to experiment with and add to his collection of Raspberry Pis.
In part 1 of this blog I introduced the need for organizations to securely connect thousands of IoT devices with many different systems in the hyperconnected world that exists today, and how that can be addressed using AWS IoT Greengrass and AWS Secrets Manager.  We walked through the creation of ServiceNow credentials in AWS Secrets […]
Gary Emmerton
Architecture AWS IoT Greengrass AWS Lambda AWS Secrets Manager Internet of Things Technical How-to