Contents

AWS IoT Core Policy Variables

How to use the AWS IoT Core Policy Variables to create fine-tuned access permissions for connected IoT Devices?

IoT Policy

To put it simply, IoT Policy allows IoT Device (represented by the IoT Thing) to send and receive MQTT Messages on specified MQTT Topics.

NOTE: The IoT Policy is attached to the X.509 Certificate, not to the IoT Thing. I explained the IoT Thing in my previous post.

/posts/iot_policy/iot_policy.png

Sample IoT Policy

Let’s start with a simple IoT Policy:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "iot:Connect",
      "Resource": "arn:aws:iot:eu-west-1:693854281758:client/*",
      "Effect": "Allow"
    },
    {
      "Action": "iot:Publish",
      "Resource": "arn:aws:iot:eu-west-1:693854281758:topic/dt/telemetry",
      "Effect": "Allow"
    }
  ]
}

This policy does not validate the clientId during connection setup (client/*) and allows devices to publish MQTT messages to the dt/telemetry Topic.

For example, thing0001 Device can send telemetry data:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
mosquitto_pub -h a1pmmrdn6yc5il-ats.iot.eu-west-1.amazonaws.com \
-i thing0001 \
--key creds/thing0001.key \
--cert creds/thing0001.pem \
--cafile creds/AmazonRootCa1.pem \
-t dt/telemetry \
-m '{"temp": 20}' -q 1 -d

Client thing0001 sending CONNECT
Client thing0001 received CONNACK (0)
Client thing0001 sending PUBLISH (d0, q1, r0, m1, 'dt/telemetry', ... (12 bytes))
Client thing0001 received PUBACK (Mid: 1, RC:0)
Client thing0001 sending DISCONNECT

From the IoT Core perspective, we can not easily identify which device sent the specific message.

/posts/iot_policy/iot_core_001.png

Let’s update our IoT Policy to make it a bit more specific:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "iot:Connect",
      "Resource": "arn:aws:iot:eu-west-1:693854281758:client/*",
      "Effect": "Allow"
    },
    {
      "Action": "iot:Publish",
      "Resource": "arn:aws:iot:eu-west-1:693854281758:topic/dt/telemetry/thing0001",
      "Effect": "Allow"
    }
  ]
}

Now our device can send its telemetry to dedicated MQTT Topic:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
mosquitto_pub -h a1pmmrdn6yc5il-ats.iot.eu-west-1.amazonaws.com \
-i thing0001 \
--key creds/thing0001.key \
--cert creds/thing0001.pem \
--cafile creds/AmazonRootCa1.pem \
-t dt/telemetry/thing0001 \
-m '{"temp": 21}' -q 1 -d

Client thing0001 sending CONNECT
Client thing0001 received CONNACK (0)
Client thing0001 sending PUBLISH (d0, q1, r0, m1, 'dt/telemetry/thing0001', ... (12 bytes))
Client thing0001 received PUBACK (Mid: 1, RC:0)
Client thing0001 sending DISCONNECT

and it is easily visible which telemetry message comes from which IoT Device:

/posts/iot_policy/iot_core_002.png

The challenge

What if we want to connect 100 000 IoT Devices to our system? Should we create 100 000 unique IoT Policies (one for every device)?

Sample IoT Policy for our second device called thing0002:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "iot:Connect",
      "Resource": "arn:aws:iot:eu-west-1:693854281758:client/*",
      "Effect": "Allow"
    },
    {
      "Action": "iot:Publish",
      "Resource": "arn:aws:iot:eu-west-1:693854281758:topic/dt/telemetry/thing0002",
      "Effect": "Allow"
    }
  ]
}

What if we do not know the number of devices upfront? Do we have to create a new IoT Policy for every new IoT Device?

We could change our IoT Policy and make it a bit more open:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "iot:Connect",
      "Resource": "arn:aws:iot:eu-west-1:693854281758:client/*",
      "Effect": "Allow"
    },
    {
      "Action": "iot:Publish",
      "Resource": "arn:aws:iot:eu-west-1:693854281758:topic/dt/telemetry/*",
      "Effect": "Allow"
    }
  ]
}

This way every IoT Device can publish messages to separate topic (dt/telemetry/*):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
mosquitto_pub -h a1pmmrdn6yc5il-ats.iot.eu-west-1.amazonaws.com \
-i thing0001 \
--key creds/thing0001.key \
--cert creds/thing0001.pem \
--cafile creds/AmazonRootCa1.pem \
-t dt/telemetry/thing0001 \
-m '{"temp": 22}' -q 1 -d

Client thing0001 sending CONNECT
Client thing0001 received CONNACK (0)
Client thing0001 sending PUBLISH (d0, q1, r0, m1, 'dt/telemetry/thing0001', ... (12 bytes))
Client thing0001 received PUBACK (Mid: 1, RC:0)
Client thing0001 sending DISCONNECT

But it can also publish telemetry using topics assigned to other devices:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
mosquitto_pub -h a1pmmrdn6yc5il-ats.iot.eu-west-1.amazonaws.com \
-i thing0001 \
--key creds/thing0001.key \
--cert creds/thing0001.pem \
--cafile creds/AmazonRootCa1.pem \
-t dt/telemetry/thing0002 \
-m '{"temp": 21}' -q 1 -d

Client thing0001 sending CONNECT
Client thing0001 received CONNACK (0)
Client thing0001 sending PUBLISH (d0, q1, r0, m1, 'dt/telemetry/thing0002', ... (12 bytes))
Client thing0001 received PUBACK (Mid: 1, RC:0)
Client thing0001 sending DISCONNECT

/posts/iot_policy/iot_core_003.png

That is NOT a desired outcome!

Is there a way to make our IoT Policy flexible yet restrictive?

IoT Policy Variables

Thing Policy Variables allow writing IoT Policies that grant or deny permissions based on IoT Thing properties like:

  • Thing Names
  • Thing Type
  • Thing Attribute value

Today we will use the following IoT Policy Variables:

  • iot:Connection.Thing.ThingName - AWS IoT Core calculates the value of this variable based on the X.509 Certificate used by the IoT Device. (you can read about X.509 Certificates in my previous post)
  • iot:Connection.Thing.ThingTypeName - AWS IoT Core calculates the value of this variable based on the Thing Type associated with the IoT Device. (I cover the Thing Type in that post)

There are many other variables available, please check the AWS documentation for the complete list.

Let’s say that IoT Device is a temperature sensor. We can create a Thing Type called temp-sensor and assign it to our thing0001 IoT Thing.

Now we can update our IoT Policy and use the IoT Policy Variables:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "iot:Connect",
      "Resource": "arn:aws:iot:eu-west-1:693854281758:client/${iot:Connection.Thing.ThingName}",
      "Effect": "Allow"
    },
    {
      "Action": "iot:Publish",
      "Resource": "arn:aws:iot:eu-west-1:693854281758:topic/dt/telemetry/${iot:Connection.Thing.ThingTypeName}/${iot:Connection.Thing.ThingName}",
      "Effect": "Allow"
    }
  ]
}

That IoT Policy is restrictive as it precisely defines MQTT Topics allowed for specific IoT Device. Thanks to the IoT Policy Variables, we need only one IoT Policy that can be safely used by many IoT Devices.

Let’s check if our IoT Policy actually works:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
mosquitto_pub -h a1pmmrdn6yc5il-ats.iot.eu-west-1.amazonaws.com \
-i thing0001 \
--key creds/thing0001.key \
--cert creds/thing0001.pem \
--cafile creds/AmazonRootCa1.pem \
-t dt/telemetry/temp-sensor/thing0001 \
-m '{"temp": 22}' -q 1 -d

Client thing0001 sending CONNECT
Client thing0001 received CONNACK (0)
Client thing0001 sending PUBLISH (d0, q1, r0, m1, 'dt/telemetry/temp-sensor/thing0001', ... (12 bytes))
Client thing0001 received PUBACK (Mid: 1, RC:0)
Client thing0001 sending DISCONNECT

Now let’s try to publish the MQTT Message to a Topic dedicated to some other IoT Device:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
mosquitto_pub -h a1pmmrdn6yc5il-ats.iot.eu-west-1.amazonaws.com \
-i thing0001 \
--key creds/thing0001.key \
--cert creds/thing0001.pem \
--cafile creds/AmazonRootCa1.pem \
-t dt/telemetry/temp-sensor/thing0002 \
-m '{"temp": 23}' -q 1 -d

Client thing0001 sending CONNECT
Client thing0001 received CONNACK (0)
Client thing0001 sending PUBLISH (d0, q1, r0, m1, 'dt/telemetry/temp-sensor/thing0002', ... (12 bytes))
Error: The connection was lost.

Error: The connection was lost. - means that our thing0001 was not allowed to publish an MQTT message on the dt/telemetry/temp-sensor/thing0002 topic.

Summary

I hope that this document helped you understand how to use the IoT Policy Variables to create fine-tuned access permissions for connected IoT Devices.

Support quality content❤️ Donate💰

Sign up for news: (by subscribing you accept the privacy policy)