MicrosoftDocs / azure-docs

Open source documentation of Microsoft Azure
https://docs.microsoft.com/azure
Creative Commons Attribution 4.0 International
10.29k stars 21.47k forks source link

Can I limit a service SAS token to only have access to certain devices? #22175

Closed spotlesscoder closed 5 years ago

spotlesscoder commented 5 years ago

I tried az iot hub generate-sas-token -d <DEVICE_NAME> -n <HUB_NAME> --policy service But I get the error

{u'ExceptionMessage': u'Tracking ID<HIDDEN`enter code here`>:TimeStamp:01/01/2019 14:30:33', u'Message': u'ErrorCode:IotHubUnauthorizedAccess;Unauthorized'}

What am I doing wrong?


Document Details

Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

asergaz commented 5 years ago

Hello @CodingSpiderFox see the answer on the MSDN Thread: https://social.msdn.microsoft.com/Forums/en-US/d8b7afac-433c-4126-a451-16618fe6b783/how-to-generate-an-azure-iot-hub-sas-token-for-one-deviceservice-only?forum=azureiothub

Thanks.

asergaz commented 5 years ago

We will now proceed to close this thread. If there are further questions regarding this matter, please tag me in your reply. We will gladly continue the discussion and we will reopen the issue.

spotlesscoder commented 5 years ago

Hello @sergaz-msft and thanks for your assistance

As the forum is not really usable (so many little bugs), I'd like to continue the discussion here.

In your answer, you said:

You don't have a way to define a shared access policy that allows access to a subset of devices and that is by design.

I don't want to use a shared access policy inside my backend service (a Java service that runs in a docker container and retrieves measurements from MQTT messages from the IoT hub) because that gives the service permission as the iothubowner on the whole IoT Hub which I consider very insecure.

You can't generate a sas token for a device using only the ServiceConnect or DeviceConnect permission. You will need RegistryRead and\or RegistryReadWrite permission to create a SAS Token for a device.

I don't want to create a token for the device, I want to create a token for my Java service to connect to the hab using Paho MQTT (I know that there is the IoT Hub SDK but I don't want to be coupled tightly to IoT Hub, I might switch to Mosquitto for an on-prem use case)

If you use: "az iot hub generate-sas-token -d [Device ID] -n [IoTHub Name] --policy registryRead" you will be able to create the SAS Token to be used by that device because you have Read Access to the Identity Registry (given by registryRead policy).

Did I understand correctly, that I can then use this token with registryRead permission to generate another token with ServiceConnect permission?

How would I do that then?

spotlesscoder commented 5 years ago

I clarified my questions in my last comment a bit

asergaz commented 5 years ago

Hi @CodingSpiderFox , Let me first point you to the Azure IoT Reference Architecture that I believe may answer some of your current architectural questions: https://aka.ms/iotrefarchitecture

I don't want to use a shared access policy inside my backend service (a Java service that runs in a docker container and retrieves measurements from MQTT messages from the IoT hub) because that gives the service permission as the iothubowner on the whole IoT Hub which I consider very insecure.

I got your point and what I would suggest (if you just want to access a specific range of devices) is that you use routing and read from a Cosmos DB (as an eg.) where only the services you give access can read from a specific container (where only the devices you configure are writing to).

I don't want to create a token for the device, I want to create a token for my Java service to connect to the hab using Paho MQTT (I know that there is the IoT Hub SDK but I don't want to be coupled tightly to IoT Hub, I might switch to Mosquitto for an on-prem use case)

You may want to consider Azure IoT Edge for your scenario as well.

Did I understand correctly, that I can then use this token with registryRead permission to generate another token with ServiceConnect permission?

I didn't get your question? Can you give an example?

Thanks

asergaz commented 5 years ago

Since we have not heard back from you we will now proceed to close this thread. If there are further questions regarding this matter, please tag me in your reply. We will gladly continue the discussion and we will reopen the issue.

spotlesscoder commented 5 years ago

@sergaz-msft

I just finished reading the IoT Reference Architecture document which was helpful for other concerns. Thanks a lot for pointing me to that document :)

What I learned is that it might be possible to use an Azure Function to push the data to my relational DB (MySQL or PgSQL or maybe also a NoSQL DB later on, see page 29 in the IoT Reference Architecture document), or like you proposed, to use routing to Cosmos DB (which I couldn't find a good example for yet). But I want a solution that is independent of Azure specific functionality like Cosmos DB or Azure Functions.

And in that case, I would feel better about using a native MQTT library like Paho MQTT to fetch the data from a MQTT broker myself and store it in a DB myself (only the sensor values by the way, so no metadata for now). In order to use the Azure IoT Hub in this scenario, I need to know what the suggested way of authenticating a "fetch-mqtt-and-write-to-rdbms" backend service against the IoT Hub would be.

This should be done using minimum privileges for the MQTT receiving backend service. So I need to know how to generate a SAS token that only allows reading MQTT messages from certain devices, and not other devices, neither registering new devices etc.

About IoT Edge, what I think I understood so far is, that IoT Edge makes use of devices (field gateways) that are a bit more powerful and thus could execute such a backend service on premises of the devices. This will not be possible in my scenario.

About the last point in your reply regarding the registryRead permission, correct me if I'm wrong:

But I want to enable a backend service, be it a service running in the Azure cloud or in an own datacenter, to receive a SAS token with minimum privileges, and then connect to the IoT Hub using the Paho MQTT library and retrieve the sensor values.

dominicbetts commented 5 years ago

Hi @CodingSpiderFox

To clarify a couple of points relating to IoT Hub messaging:

For information about tokens and how they are scoped, see https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-security.

If you want to limit a backend service to only be able to read telemetry from a subset of your devices, you could consider these options:

spotlesscoder commented 5 years ago

A backend service can read from the default endpoint in an IoT hub using the AMQP protocol only.

That's a key information I didn't know, thank you! (Just because I'm feeling like I'm missing another key information: why has this design choice been made that retrieving messages directly from the IoT Hub only works with AMQP?)

Now I have another question regarding the retrieval of AMQP messages:

In this file https://github.com/Azure/azure-iot-sdk-java/blob/master/service/iot-service-client/src/main/java/com/microsoft/azure/sdk/iot/service/transport/amqps/AmqpReceive.java

the qpid.proton.Reactor class is used to retrieve the AMQP messages. Would it be correct, in order to retrieve all messages continuously, to set a very large timeout? Or will the IoT hub disconnect the backend service client after a certain timeout?

Would a message which is being retrieved during the moment when the timeout is over be lost or would the IoT hub keep that message so that I can read it after initiating a new connection?

asergaz commented 5 years ago

Hi @CodingSpiderFox ,

why has this design choice been made that retrieving messages directly from the IoT Hub only works with AMQP?

See https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-amqp-protocol-guide

In this file https://github.com/Azure/azure-iot-sdk-java/blob/master/service/iot-service-client/src/main/java/com/microsoft/azure/sdk/iot/service/transport/amqps/AmqpReceive.java the qpid.proton.Reactor class is used to retrieve the AMQP messages. Would it be correct, in order to retrieve all messages continuously, to set a very large timeout? Or will the IoT hub disconnect the backend service client after a certain timeout? Would a message which is being retrieved during the moment when the timeout is over be lost or would the IoT hub keep that message so that I can read it after initiating a new connection?

All those scenarios are address by the Azure IoT SDKs. In short yes, IoTHub keeps the message so that it can be read after initiaing a new connection.

Let me also recommend that you take a look at the following blog post: Benefits of using the Azure IoT SDKs, and pitfalls to avoid if you don’t

spotlesscoder commented 5 years ago

@dominicbetts: Another question regarding the retrieval of messages using AMQP

I tried out this code snippet: https://github.com/Azure/azure-iot-sdk-java/blob/master/service/iot-service-samples/service-client-sample/src/main/java/samples/com/microsoft/azure/sdk/iot/ServiceClientSample.java

But I can't figure out how to change it to also output the message payload when a message is received. It seems to me like this is not available in the feedbackRecord.

What do I have to do in order to get the message payload?

dominicbetts commented 5 years ago

Hi @CodingSpiderFox - please take a look at the following Quickstart: https://docs.microsoft.com/en-us/azure/iot-hub/quickstart-send-telemetry-java#read-the-telemetry-from-your-hub The read-d2c-messages applications shows you how to read the messages sent from your devices.

spotlesscoder commented 5 years ago

Hi @CodingSpiderFox - please take a look at the following Quickstart: https://docs.microsoft.com/en-us/azure/iot-hub/quickstart-send-telemetry-java#read-the-telemetry-from-your-hub The read-d2c-messages applications shows you how to read the messages sent from your devices.

Thanks, that works.

So that means that the AMQP messages do not contain the payload? What would I use the AMQP protocol endpoint of the IoT hub for then?

dominicbetts commented 5 years ago

Hi @CodingSpiderFox - I'm not sure I follow - that sample uses AMQP to read telemetry from the service-side endpoint on the IoT hub. It reads the message payload (temperature and humidity telemetry values) and all the metadata added by the sending device and by IoT Hub.

spotlesscoder commented 5 years ago

OK thanks.

larsonmpdx commented 5 years ago

Can I reopen this? I am able to create a service token scoped to a single device using the example code on this page:

https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-security

I wanted to verify generation of the token using the sample code by using the 'az' cli tool to make a known-good token, but I get the same "unauthorized" error as @CodingSpiderFox. My manually generated service tokens do work and seem to be correctly scoped to the device I choose. Am I missing something? If not it looks like the 'az' tool is overly restrictive

My goal is to make a SAS token to give to users so that they can use the new "azure iot device streams" feature to connect to their devices, but only give out a token for a single device since it's going to end users. My tokens seem to work and are limited to single devices but this thread has me worried.

asergaz commented 5 years ago

@larsonmpdx this issue is slighty different. For better tracking and scoping can I kindly ask you to open a new one and reference this issue?

@dominicbetts since January, do you recall if we enabled IoT Service Side Tokens to read telemetry from a single device?

Thanks!