The Internet of Things on AWS – Official Blog

Scaling authorization policies with AWS IoT Core

Introduction

Solutions architects, developers, and system designers building IoT solutions need ways to properly secure data and functions that operate on data across the entire solution landscape. In this post, we describe a few design options for scaling authorization policies focused on multi-user and multi-device use cases with AWS IoT Core. We cover several scenarios, including varying levels of device-to-user cardinality and scale. This information is helpful for making security design and architecture decisions for solutions built on AWS IoT services.

Security coverage is needed at each tier, including IoT devices, network paths, end-user devices, databases, backend systems, and other components that interact with the data. A common term in IT security when approaching a security architecture is “AAA” or “triple-A,” which represents the terms authentication, authorization, and accounting (or sometimes, auditing). AAA is a way to organize and view security requirements and map solution architecture onto those requirements. This way solution stakeholders, end users, and compliance professionals understand how a solution is designed to cover these important requirements.

The essential form of IoT solutions implies a distributed systems architecture as an inherent design element. With distributed systems architecture comes the need for complementary distributed security solutions. Many customers are using federation approaches for handling identity (authentication) requirements for distributed systems in the cloud and for hybrid architectures integrating cloud and on-premises enterprise systems. These federation approaches can be integrated into securing data and functions for IoT as well. To learn more about AWS identity federation options, view this identity federation in AWS page.

With a solid solution for identity in place, we can focus on dealing with the requirements of authorization, the second “A.” We are going to focus on options for common authorization use cases IoT solution builders face. Customers have indicated that the most common user-to-device configurations are 1:1 and 1:many, so this post covers some examples for those cases.

Simple use case: 1 user to 1 device (1:1)

Starting with the 1 user to 1 device (1:1) use case makes sense because it is the most simple to understand and configure using out-of-the-box AWS IoT Core features. Additionally, the description of the use case as 1:1 leads directly to the scenarios relevant to its selection and application.

Scenarios where the 1:1 use case is appropriate include prototype development and personal devices. Many prototyping activities map well onto the 1:1 configuration to support rapid changes and configuration simplicity associated with prototype development. Another scenario is for an end user with a personal device. The end user, using potentially multiple end-user interfaces, such as web and mobile, wants to interact with a single personal device.

The qualifier personal is used to help clarify the intention of the device as one designed to be used by a single individual, like a toothbrush. If you want to share your toothbrush with others, skip to a later use case covering many users to many devices (m:n).

On the technical front, identity for the 1:1 use case can be realized in AWS IoT Core using the Amazon Cognito identity service. AWS IoT Core enables applications and administrators to attach individual users represented as Amazon
Cognito
principal to AWS IoT policies. This association enables the Amazon Cognito principal to communicate directly with the AWS IoT Core endpoints using HTTPS or MQTT over WebSockets. Through AWS IoT Core policies, this configuration allows the Amazon Cognito principal to be authorized for all the same actions and resources as an IoT device. This enables communication with any MQTT topic namespace, including special topics with $aws prefixes for device shadow and jobs interactions.

Detailed steps for setting up Amazon Cognito and AWS IoT Core devices for a 1:1 use-case scenario can be found in this blog post titled Configuring Cognito User Pools to Communicate with AWS IoT Core.

Use-case extension: 1 user to many devices (1:m)

Now we’ll extend the use-case scope to include more than one device for a single end-user principal. For this use case, let’s say the end user (we’ll call her Cheryl) has multiple IoT devices. Cheryl’s devices share a brand name and are marketed for their ability to be managed from a single application. We, as the builders of the application and device software, must consider the functional requirements along with the AAA requirements of the solution of this expanded scope.

Now multiple devices require interaction from the end user’s application. This seems simple enough. We can create an AWS IoT Core policy for each device and attach it to the Amazon Cognito principal associated with Cheryl. We can use the same identity federation options, enabling Cheryl to log in using Amazon Cognito user pools or other identity providers such as Google, Facebook, Login with Amazon, and others.

However, there’s an “and” in this solution. The “and” is important in this use case and exceptionally important in the next one. Let’s dive a bit deeper.

Anytime you design for a seemingly unbounded quantity of entities (for example, users, principals, devices, instances, etc.) there are generally some boundaries that you should check for. Many times, the boundaries are large and far away and an understanding of the growth dynamics of your solution are important to confirm and monitor. However, you don’t generally have to design using those boundaries as near-term constraints. In this particular situation, there are a couple of boundaries that we should evaluate.

First, since we are expanding the number of devices that Cheryl can have, and thereby adding additional policies, we should check to see if there are any boundaries that we may encounter. We decided to solve this requirement by creating a new policy per device and attaching it to the Amazon Cognito identity principal for Cheryl. Let’s consult the AWS IoT Service Quotas documentation to see if there are any boundaries that we should consider.

What you find are these relevant limits:

Maximum number of policies that can be attached to a certificate
or Amazon Cognito identity – 10

Maximum policy document size – 2048 characters (excluding white space)

This means that Cheryl is limited to a maximum of 10 devices. Depending on the types of devices, this might be satisfactory. For a scenario where Cheryl may be using a smartphone or web application to manage a thermostat, water heater, lighting controller, and perhaps an appliance or two, we seem to be at just half of our limit of 10. Should our use case expand to perhaps each lightbulb in the house, each sprinkler head in the yard, and every power receptacle in the wall, then we could easily exceed our limit of 10 devices per user.

We have several options. Let’s examine an early alternative candidate using a different approach.

Aggregating permissions for multiple devices into fewer policy documents

Device policy documents protect the basic functions of interacting with AWS IoT Core in flexible ways. Fundamentally, the primary interface to AWS IoT Core is MQTT topics. Protecting devices essentially means protecting the topics from unwanted communication. AWS IoT Core topics are denied by default. Permission to even connect to the device gateway endpoint must be explicitly granted. Nothing prevents the accumulation of permissions to actions and resources associated with multiple device topics into a single policy. The only constraint is that the total policy document size, excluding white space (non-printable characters) must be less than 2048 characters.

What this means for our design is that we can add device permissions to a single policy until that policy begins to approach the maximum size. Then we can create a new policy and begin adding additional permissions.

Consider the following approach:

Initial state: Cheryl’s Amazon Cognito Identity exists and has one policy attached.

Desired Operation: Add the ability to interact with the shadow topics of an IoT kitchen light for Cheryl with the thing name of ‘cheryl-kitchen-light-01’.

To start, we must build the JSON required to add the permissions for Cheryl’s kitchen light device. Below are the resource strings must add the shadow topics to a policy that already permits connect, publish, subscribe, and receive:

For publish and receive actions (85 characters):

arn:aws:iot:us-east-1:123456789012:topic/$aws/things/cheryl-kitchen-light-01/shadow/*

For subscribe action (91 characters):

arn:aws:iot:us-east-1:123456789012:topicfilter/$aws/things/cheryl-kitchen-light-01/shadow/*

Then, we must add 176 characters to an IoT policy.

To do this, we perform the following actions with our application code:

Read the policies attached to Cheryl’s Amazon Cognito principal with ListPrincipalPolicies.

For each policy do the following:

Get the policy document with GetPolicy. (Mind the Service Quotas on this one, there is currently a 10 transaction per second (TPS) limit on certain control plane calls such as GetPolicy.)

1. Strip the white space from the policy document and check the size.

2. If the policy has capacity (current size + 176 is less than 2048)

Add the resources to the policy.

3. If the policy has no capacity

Go to the next policy.

If we can’t find a policy with capacity, then we can create a new policy if we are under the limit of 10. If 10 policies are attached and they are all close to the maximum size, then we throw an error or we could do something a bit more clever.

Scaling with intelligent thing names

The naming of objects has a long history in computing. Much like variables in a computer program, object naming can have a significant effect on the comprehensibility and usability of a system. The scheme associated with object naming can also lend itself to some creative uses and enable rather elegant configurations.

In AWS IoT Core, there are several types of entities. There are policies, certificates, and things to start with. There are also thing types, attributes, and thing groups, which enable richer device management use cases. For this scaling use case, we are going to use a naming and a wildcard feature found in IoT policies.

First, let us consider a familiar naming abstraction, the prefix. If you are familiar with Amazon Simple Storage Service (S3), you may know how the namespace works in that service. The namespace is flat with a concept of naming prefixes and delimiters that enable this flat namespace to take on hierarchical features. We are going to use this same concept of a prefix to add hierarchical management of the thing namespace to enable grouping of things.

Just to be clear, we are not using the AWS IoT Device Management feature called ”thing groups” in this scenario. While the thing groups feature does serve many useful purposes for device organization and management, it is not purposed for our aims in this particular use case.

Let’s get back to Cheryl and her family and smart home full of connected devices.

Let’s start when Cheryl purchases her first smart devices: a smart home hub, a couple of smart bulbs, a connected garage door opener, and how about a smart bird feeder?

Cheryl starts her setup by registering her smart hub on the associated website. She creates an account and adds the device to her account. Let’s say that the application generates a unique prefix for Cheryl’s account at this time. We call this prefix ”xyz123”.

When Cheryl’s first device is registered under her account, the thing name in AWS IoT Core is created with the prefix xyz123. So, the IoT thing name for Cheryl’s smart hub might be xyz123-home-hub-00. Next, Cheryl adds her other devices to her account with thing names like these:

Smart garage door opener: xyz123-garage-door-00

Smart bird feeder: xyz123-bird-feeder-00

Cheryl proceeds to add all of her devices to her account for a total of 12 devices. This is in excess of the 10-policy limit. We are not able to attach 12 policies to Cheryl’s Amazon Cognito principal. Additionally, Cheryl is now going to grant access to her devices to the rest of her family of four additional people.

Using our prefix naming scheme, we can create a policy like the one below. This grants access permissions to any principal to which the policy is attached to access special topics like for the device shadow:

{
    "Version" : "2012-10-17",
    "Statement": [
            {
                "Effect" : "Allow",
                "Action" : [
                    "iot:Publish",
                    "iot:Receive"
                ],
                "Resource": "arn:aws:iot:us-east-1:1234567890:topic/$aws/things/xyz123*/shadow/*"
            },
            {
                "Effect" : "Allow",
                "Action" : [
                    "iot:Subscribe"
                ],
                "Resource" : "arn:aws:iot:us-east-1:1234567890:topicfilter/$aws/things/xyz123*/shadow/*"
            }
        ]
}

 

This policy can be created once, given a name like xyz123-policy-00, and be attached to Cheryl’s Amazon Cognito principal as well as each of the Amazon Cognito principals associated with each of her family members. This policy provides authorization to shadow service topics for any IoT thing with a name that starts with the prefix xyz123.

Now, instead of needing to do clever policy management by size and count, we can provide a named collection of things grouped by end users using naming prefixes. This solution is simple and works well within all of the service limits associated with policy sizes and attachments.

Conclusion

We’ve covered a lot here, from a light treatment of identity federation options to using prefixed thing naming for scaling out authorization policies. What is of utmost importance to cover in any use case is that only trusted identities have access to the interfaces that allow interaction to functions and data of not just IoT solution but to any digital system. AWS IoT Core provides features that can be combined in ways that allow exceptional flexibility in designing these systems to be scalable, resilient, and secure.