Using Thing Policy Variable to set permissions for shadow interactions with greengrass

0

I am trying to set an IoT policy which uses "${iot:Connection.Thing.ThingName} variable to access the thing name for setting these permissions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:DeleteThingShadow",
      "Resource": [
        "arn:aws:iot:region:123456789101:thing/${iot:Connection.Thing.ThingName}",
        "arn:aws:iot:region:123456789101:thing/${iot:Connection.Thing.ThingName}/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "iot:GetThingShadow",
      "Resource": [
        "arn:aws:iot:region:123456789101:thing/${iot:Connection.Thing.ThingName}",
        "arn:aws:iot:region:123456789101:thing/${iot:Connection.Thing.ThingName}/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "iot:UpdateThingShadow",
      "Resource": [
        "arn:aws:iot:region:123456789101:thing/${iot:Connection.Thing.ThingName}",
        "arn:aws:iot:region:123456789101:thing/${iot:Connection.Thing.ThingName}/*"
      ]
    }
]
}

When I restart greengrass I get the following errors when trying to sync

2023-08-25T06:11:59.847Z [INFO] (pool-2-thread-17) com.aws.greengrass.shadowmanager.sync.strategy.BaseSyncStrategy: sync. Executing sync request. {Type=FullShadowSyncRequest, thing name=Dev, shadow name=onwatch_notifications-plugin}
2023-08-25T06:12:00.128Z [ERROR] (pool-2-thread-17) com.aws.greengrass.shadowmanager.sync.model.BaseSyncRequest: Could not execute cloud shadow get request. {thing name=Dev, shadow name=onwatch_notifications-plugin}
2023-08-25T06:12:00.129Z [ERROR] (pool-2-thread-17) com.aws.greengrass.shadowmanager.sync.strategy.BaseSyncStrategy: sync. Skipping sync request. {thing name=Dev, shadow name=onwatch_notifications-plugin}
com.aws.greengrass.shadowmanager.exception.SkipSyncRequestException: software.amazon.awssdk.services.iotdataplane.model.IotDataPlaneException: null (Service: IotDataPlane, Status Code: 403, Request ID: d737e717-18d2-0c19-cf54-70e220ef87d6)
        at com.aws.greengrass.shadowmanager.sync.model.BaseSyncRequest.getCloudShadowDocument(BaseSyncRequest.java:407)
        at com.aws.greengrass.shadowmanager.sync.model.FullShadowSyncRequest.execute(FullShadowSyncRequest.java:79)
        at com.aws.greengrass.shadowmanager.sync.SyncHandler.lambda$static$0(SyncHandler.java:98)
        at com.aws.greengrass.util.RetryUtils.runWithRetry(RetryUtils.java:50)
        at com.aws.greengrass.shadowmanager.sync.SyncHandler.lambda$static$1(SyncHandler.java:96)
        at com.aws.greengrass.shadowmanager.sync.strategy.BaseSyncStrategy.lambda$new$0(BaseSyncStrategy.java:155)
        at com.aws.greengrass.shadowmanager.sync.strategy.BaseSyncStrategy.syncLoop(BaseSyncStrategy.java:366)
        at com.aws.greengrass.shadowmanager.sync.strategy.RealTimeSyncStrategy.syncLoop(RealTimeSyncStrategy.java:77)
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: software.amazon.awssdk.services.iotdataplane.model.IotDataPlaneException: null (Service: IotDataPlane, Status Code: 403, Request ID: d737e717-18d2-0c19-cf54-70e220ef87d6)
        at software.amazon.awssdk.core.internal.http.CombinedResponseHandler.handleErrorResponse(CombinedResponseHandler.java:125)
        at software.amazon.awssdk.core.internal.http.CombinedResponseHandler.handleResponse(CombinedResponseHandler.java:82)
        at software.amazon.awssdk.core.internal.http.CombinedResponseHandler.handle(CombinedResponseHandler.java:60)
        at software.amazon.awssdk.core.internal.http.CombinedResponseHandler.handle(CombinedResponseHandler.java:41)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.HandleResponseStage.execute(HandleResponseStage.java:40)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.HandleResponseStage.execute(HandleResponseStage.java:30)
        at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptTimeoutTrackingStage.execute(ApiCallAttemptTimeoutTrackingStage.java:73)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptTimeoutTrackingStage.execute(ApiCallAttemptTimeoutTrackingStage.java:42)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.TimeoutExceptionHandlingStage.execute(TimeoutExceptionHandlingStage.java:78)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.TimeoutExceptionHandlingStage.execute(TimeoutExceptionHandlingStage.java:40)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptMetricCollectionStage.execute(ApiCallAttemptMetricCollectionStage.java:50)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptMetricCollectionStage.execute(ApiCallAttemptMetricCollectionStage.java:36)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.RetryableStage.execute(RetryableStage.java:81)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.RetryableStage.execute(RetryableStage.java:36)
        at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
        at software.amazon.awssdk.core.internal.http.StreamManagingStage.execute(StreamManagingStage.java:56)
        at software.amazon.awssdk.core.internal.http.StreamManagingStage.execute(StreamManagingStage.java:36)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallTimeoutTrackingStage.executeWithTimer(ApiCallTimeoutTrackingStage.java:80)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallTimeoutTrackingStage.execute(ApiCallTimeoutTrackingStage.java:60)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallTimeoutTrackingStage.execute(ApiCallTimeoutTrackingStage.java:42)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallMetricCollectionStage.execute(ApiCallMetricCollectionStage.java:48)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallMetricCollectionStage.execute(ApiCallMetricCollectionStage.java:31)
     

I can change the policy to include the actual thing name "Dev" and it then syncs successfully

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:DeleteThingShadow",
      "Resource": [
        "arn:aws:iot:region:123456789101:thing/Dev",
        "arn:aws:iot:region:123456789101:thing/Dev/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "iot:GetThingShadow",
      "Resource": [
        "arn:aws:iot:region:123456789101:thing/Dev",
        "arn:aws:iot:region:123456789101:thing/Dev/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "iot:UpdateThingShadow",
      "Resource": [
        "arn:aws:iot:region:123456789101:thing/Dev",
        "arn:aws:iot:region:123456789101:thing/Dev/*"
      ]
    }
]
}

I am using the same variable for iot:Publish which is working fine:

Allow	iot:Publish	arn:aws:iot:region:123456789101:topic/onwatchIot/${iot:Connection.Thing.ThingName}/*
asked 8 months ago276 views
2 Answers
0

Thanks Greg,

I'm not quite sure I understand the where the policy variable (iot:Connection:Thing.*) can and cant be used. Can you clarify what is a Greengrass data plane operation?

I am using the following IoT Policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:DeleteThingShadow",
      "Resource": [
        "arn:aws:iot:ap-southeast-2:123456778910:thing/${iot:Connection.Thing.ThingName}",
        "arn:aws:iot:ap-southeast-2:123456778910:thing/${iot:Connection.Thing.ThingName}/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "iot:GetThingShadow",
      "Resource": [
        "arn:aws:iot:ap-southeast-2:123456778910:thing/${iot:Connection.Thing.ThingName}",
        "arn:aws:iot:ap-southeast-2:123456778910:thing/${iot:Connection.Thing.ThingName}/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "iot:UpdateThingShadow",
      "Resource": [
        "arn:aws:iot:ap-southeast-2:123456778910:thing/${iot:Connection.Thing.ThingName}",
        "arn:aws:iot:ap-southeast-2:123456778910:thing/${iot:Connection.Thing.ThingName}/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "iot:ListNamedShadowsForThing",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Subscribe",
      "Resource": "arn:aws:iot:ap-southeast-2:123456778910:topicfilter/onwatchIot/${iot:Connection.Thing.ThingName}*/clientRequests"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Receive",
      "Resource": "arn:aws:iot:ap-southeast-2:123456778910:topic/onwatchIot/${iot:Connection.Thing.ThingName}*/clientRequests"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Publish",
      "Resource": "arn:aws:iot:ap-southeast-2:123456778910:topic/onwatchIot/${iot:Connection.Thing.Attributes[fleetOperator]}/${iot:Connection.Thing.ThingName}/*"
    },
    {
      "Effect": "Allow",
      "Action": "iot:AssumeRoleWithCertificate",
      "Resource": "arn:aws:iot:ap-southeast-2:123456778910:rolealias/TokenExchangeRoleAlias"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Publish",
      "Resource": "arn:aws:iot:ap-southeast-2:123456778910:topic/onwatchIot/${iot:Connection.Thing.ThingName}/*"
    }
  ]
}

I use the greengrass IPC client to subscribe to and receive on topic onwatchIot/Dev-plugin/clientRequests it works successfully, and I am using the policy variable. Not sure what the difference is?

answered 8 months ago
0

Hi Phil. Unfortunately the thing policy variables are not currently supported for Greengrass core devices: https://docs.aws.amazon.com/greengrass/v2/developerguide/device-auth.html#iot-policies

Enter image description here

UPDATE: The GG data plane operations are listed here: https://docs.aws.amazon.com/greengrass/v2/developerguide/device-auth.html#iot-policies. Basically, the Thing name variable doesn't work for those, because GG data plane operations are HTTP requests, and the thing name variable is derived from the MQTT client ID. As stated here: https://docs.aws.amazon.com/iot/latest/developerguide/thing-policy-variables.html.

This policy variable is only available when a device connects over MQTT or MQTT over the WebSocket protocol.

And shadow manager makes HTTP requests to get/update/delete/ shadows.

Also be careful about the effect of multiple connections as outlined here: https://docs.aws.amazon.com/greengrass/v2/developerguide/device-auth.html#greengrass-core-minimal-iot-policy. That is, the client ID won't match the Thing name on all connections.

profile pictureAWS
EXPERT
Greg_B
answered 8 months ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions