Azure IoT Hub – Shared Access Signature

Pro Device Authentifizierung/Autorisierung

Um Telemetry Daten von einem Gerät/Device an einen Azure IoT Hub zu senden stellt dieser, im Unterschied zu einem Azure Event Hub, eine pro Device Authentifizierung/Autorisierung zur Verfügung. D. h. für jedes Gerät muss ein Set an symmetrischen Schlüsseln erstellt werden.

Dies kann sowohl über Code und die Verwendung eines entsprechenden SDK erfolgen (siehe: https://github.com/RobertEichenseer/IoT_MasterClass/blob/master/MC_SensorIoTHub/MC_AdminBackend/ManageDevice.cs ) oder mit dem auf GitHub zum Download (https://github.com/Azure/azure-iot-sdks/releases ) zur Verfügung stehenden Device Explorer.

In vielen Beispielen wird nun einer dieser Schlüssel bzw. ein Connection-String, der diesen Schlüssel enthält, verwendet um Daten von einem Device zu einem IoT Hub zu senden bzw. Kommandos von diesem zu erhalten. Im „Get-Started“ Tutorial unter https://azure.microsoft.com/en-us/develop/iot/get-started/ findet sich der notwendige Source Code um basierend auf einem Device Connection String eine Verbindung zu einem IoT Hub aufzubauen. Der hierfür notwendige Connection String kann einfach erstellt oder z. B. aus einer Instanz des Device Explorers kopiert werden.

Device Explorer
Device Explorer

Der Connection String besteht hierbei aus der öffentlich verfügbaren Url der IoT Hub Instanz, der eindeutigen Id des Devices (erzeugt im Device Explorer oder via Code) und aus einem der für das Device erzeugtem symmetrischen Schlüssel.

Bsp.: HostName=iotvd.azure-devices.net;DeviceId=Device01;SharedAccessKey=4Ml+KlkFvFoggFJlb…t/I=

Authentifizierung von Datenpaketen

Interessant ist nun die Betrachtung einzelner Datenpakete und wie der symmetrische Schlüssel benützt wird um diese Datenpakete zu authentifizieren. Hierbei bietet sich an mit Hilfe von Fiddler und einem Device welches via https Datenpakete an eine IoT Hub Instanz sendet.

Beispielhafter Post:

POST https://robeich.azure-devices.net/devices/Device01/messages/events?api-version=2016-02-03 HTTP/1.1

iothub-messageid: 707aadea-9aff-43f4-b52b-c2b9b426d68d

Accept: application/json

iothub-app-CustomInfo: FromEmulator

Authorization: SharedAccessSignature sr=robeich-iotpoc.azure-devices.net%2Fdevices%2FDevice01&sig=pqauHmdPnd1VcxoKx6xKWW2s7SUjzPoXZyy87m7UX70%3D&se=1473178007

Content-Length: 150

Host: robeich-iotpoc.azure-devices.net

Connection: Keep-Alive

{"DeviceId":2385964,"Longitude":105.9,"Latitude":105.9,"RPM":600,"TyrePressure":3.1,"Speed":45.0,"OilTemperature":25.0,"CreationTime":"0001-01-01T00:00:00"}

Interessant ist hierbei, dass der Payload der Message nicht mit dem symmetrischen Schlüssel verschlüsselt worden ist. Vielmehr ist „nur“ ein zusätzlicher Headereintrag „Authorization“ hinzugefügt worden. Splittet man den Headereintrag auf findet sich der String „SharedAccessSignature“ sowie die drei Werte sr, sig und se. Dieser Headereintrag wird vom SDK automatisch erzeugt und von der IoT Hub Instanz verwendet um das Datenpaket zu autorisieren.

Shared Access Signature

Betrachtet man das Azure IoT SDK welches den Headereintrag erzeugt, zeigt sich, dass der Wert „se“ ein Zeitwert ist, der festlegt, wie lange das Nachrichtenpaket „gültig ist“ und somit von der IoT Hub Instanz akzeptiert und angenommen wird. Die Zahl steht für Sekunden ab dem 01.01.1970. Dieser Wert wird vom SDK automatisch berechnet und auf 60 Minuten ab der aktuellen Systemzeit gesetzt, sowie für jedes Datenpaket neu berechnet. Aktuell findet sich im SDK kein Property mit dem dieser Wert von außerhalb des SDK manuell gesetzt und damit beeinflusst werden kann.

Bei „sig“ handelt es sich um einen auf Basis des symmetrischen Schlüssel errechneten Hash Wert (HmacSha256) eines Strings. Dieser String setzt sich folgendermaßen zusammen:

<<Url_der_ IoT_Hub_Instanz>>/devices/<<DeviceId>>\n<<ExpirationInSeconds>>

Bsp.: iotvd.azure-devices.net/Fdevices/Device01\n1483142400

Bei “sr” handelt es sich um die Url der IoT Hub Instanz dem Literal devices sowie der eindeutigen Id des Devices welches das Nachrichtenpaket versendet

Diese drei errechneten Werte plus der String Konstante „SharedAccessSignature“ werden von der IoT Hub Instanz verwendet um das Nachrichtenpaket zu authentifizieren/autorisieren.

Erweiterungen

Da das auf dem Client ausgeführte SDK den Payload der Nachricht nicht mit dem symmetrischen Schlüssel chiffriert ergeben sich viele Möglichkeiten um die Sicherheit bei der Erteilung der Erlaubnis Daten von einem Device an eine IoT Hub Instanz zu versenden zu erhöhen. So muss beispielsweise der symmetrische Schlüssel, der bei der Anlage des Devices in der IoT Hub Instanz nicht auf dem Client übertragen und gespeichert werden. Dieser muss das sichere Umfeld der Cloud Instanzen nicht verlassen um den String Eintrag im Authorization Header zu erzeugen.

Dass Device kann diesen String z. B. in bestimmten Intervallen von einer einer WebApp anfordern. Wobei der vom Device bisher verwendete String automatisch nach Ablauf der Zeitspanne automatisch ungültig wird. Sollte dieser Fall auftreten kann das Device die WebApp kontaktieren, welche den Symmetrischen Schlüssel aus der IoT Hub Instanz aufgrund der eindeutigen Device Id welchem vom Device im Request mitgeliefert wird ausliest. Solch eine WebApp wird häufig als Discovery Service bezeichnet, da sie auch für andere Zwecke wie z. B. automatischer Failover, 24/7 Szenarien benützt werden kann. Die Absicherung der Kommunikation mit dem Discovery Service kann nun den jeweiligen Sicherheitsanforderungen angepasst werden. Die Palette reicht hier vom manuellen Eingriff, Multifaktor Systemen bis zu innovativen Machine Learning Algorythmen.

Ein Beispiel wie das Token off-Board, d. h. nicht auf dem Device erzeugt werden kann findet sich auf meinem GitHub Account unter: https://github.com/RobertEichenseer/IoT_HardeningIoTSecurity

Hardening Azure Event Hub Solutions

Allgemein

In vielen IoT Scenarien stellt sich immer wieder die Frage wie der Daten Ingest von Devices (Things) zu einem zentralen Backend abgesichert werden kann. Hierbei ist neben der grundsätzlichen Absicherung des Transportweges auch die Absicherung des Dateningest einzelner Devices zu verstehen. Verwendet man den Azure IoT Hub kann jedes Device in dem zentralen Repository angelegt und mit entsprechenden Security Credentials versorgt werden. Dadurch ist eine feingranulare Verwaltung von Devices möglich. Letztendlich kann dadurch auf Device Ebene entschieden werden, ob die Daten des Device akzeptiert werden oder ggf. als kompromitiert betrachtet und verworfen werden.

Azure Event Hub stellt eine ähnliche Funktionalität zur Verfügung welche ebenfalls ermöglicht, den Daten Ingest von einzelnen Devices bereits auf Ebene des Event Hub zu blockieren.

Shared Access Policy

Nach Anlage eines Event Hub im Azure Portal können sogenannte „Shared Access Policies“ angelegt werden. Zu jeder Shared Access Policy werden zwei Keys erzeugt welche verwendet werden können, um ein Datenpaket zu signieren. D. h. Datenpakete welche von einem Device zu Azure Event Hub übertragen werden verwenden einen dieser Keys um einen Hash des Datenpaketes zu errechnen. Dieser Hash wird mit einem Key der erzeugten Shared Access Policy verschlüssen und zusammen mit anderen Informationen wie z. B. Event Hub Name und  Shared Access Policy Name zu einem String zusammengefasst. Dieser String wird nun jedem Datenpaket welches vom Device zum Event Hub übertragen wird beigefügt. Vereinfacht gesprochen handelt es sich bei diesem String um eine „Eintrittskarte“ welche das Datenpaket gegenüber dem Event Hub ausweist. Der Event Hub kann mittels der im String enthaltenen Informationen und einem privatem Schlüssel, der während der Anlage der Shared Access Policy ebenfalls erzeugt wurde und im Portal nicht sichtbar ist, prüfen ob die Signatur korrekt und damit das Datenpaket valide ist.

Der Key einer Shared Access Policy muss dementsprechend vertraulich behandelt werden. Viele Beispiele zu Übertragung von Daten von einem Device zu Event Hub verwenden jedoch den Key im Code des Devices. Insbesondere die Methode ServiceBusConnectionStringBuilder.CreateUseingSharedAccessKey() des aktuellen Azure Service Bus SDK (Azure Event Hub ist Teil des Azure Service Bus) macht es sehr einfach, auf Basis eines Shared Access Policy Key einen Connection String zum Event Hub zu erzeugen.

      

        public void TelemetryIngest()
        {
            string serviceBusNamespace = "<<Your Service Bus Namespace>> e. g. -> iotmc-ns";
            string eventHubName = "<<your Event Hub Name>> e. g. -> IoTMC";
            string eventHubSAPKeyName = "<<your Shared Access Policy Name>> e. g. -> Device01";
            string eventHubSAPKey = "<<your Key>> e.g. -> t0JK197745t345…s4N09aNI0s=";
            string eventHubConnectionString = ServiceBusConnectionStringBuilder.CreateUsingSharedAccessKey(
            ServiceBusEnvironment.CreateServiceUri("sb", serviceBusNamespace, string.Empty),
                eventHubSAPKeyName,
                eventHubSAPKey);
            EventHubClient eventHubClient = EventHubClient.CreateFromConnectionString(eventHubConnectionString, eventHubName);
            //Your code to ingest telemetry data
        }

Wurde das Device kompromitiert, muss serverseiting ein neuer Key generiert werden, damit Event Hub zukünftig Telemetry Ingests von diesem Device ablehnt. Dies ist solange machbar, wie eine geringe Anzahl von Devices installiert worden sind und für jedes Device eine eigene Shared Access Policy erzeugt wurde. Jedoch ist die Anzahl der erzeugbaren Shared Access Policies begrenzt, so dass mehrere (unter Umständen hunderte oder tausende) Devices mit dem Key einer einzigen Shared Access Policy Key provisioniert werden müssen. Wird nun ein einzelnes Device kompromitiert müssen unter Umständen hunderte oder tausende weitere Devices aktualisiert bzw. ausgetauscht werden.

Betrachtet man z. B. Devices die an einem Fließband z. B. die Tätigkeit von Robotern überwachen übermitteln so können diese in einer einfachen Anbindung den Key einer Shared Access Policy benützen, um Daten gegenüber einem Event Hub zu legitimitieren. In der Regel finden sich an einem Fließband sehr viele Sensoren und Devices so dass ein Key einer Shared Access Policy von ggf. vielen Devices verwendet werden muss.

Um diese Problematik zu adressieren, bietet sich eine Architektur an, bei der die Keys nicht auf dem Device gespeichert werden und sogenannte Shared Access Signature Tokens (SAS Token) „off-board“ erzeugt werden, die einen zeitlich begrenzten Daten-Ingest von den Devices erlauben.

„Off-Board“ Token Erzeugung

Bei der Erzeugung eines SAS Tokens „off-Board“ wird der Key der Shared Access Policy nicht auf den Devices  vorgehalten sondern von einem externen Service verwendet um ein SAS Token zu erzeugen, dass ebenfalls zur Legitimitierung von Telemetry Ingest am Event Hub verwendet werden kann. Diese Tokens beinhalten eine temporäre Komponente, d. h. sie sind nur für eine bestimmte definierbare Zeitspanne zur Legitimitierung am Event Hub gültig. Ein typischer Workflow bei der „off-Board“ Token Erzeugung stellt sich folgendermaßen dar:

  1. Device kontaktiert einen externen Service, in der Regel ein REST basierter Service (Discovery Service) und authorisiert sich mit den üblichen Verfahren (Pre-Shared-Key, OAuth etc.) I.d.R. werden hier noch zusätzliche Metadaten übertragen und die vom Discovery Service geprüft. Z. B. aktuelle IP Adresse oder GPS Daten um zu prüfen, ob das Device sich noch an der vorgesehen physikalischen oder netzwerktechnischen Position befindet. Sehr häufig findet sich hier auch eine Prüfung des letzten Daten Ingest. Diese Information kann im Backend ermittelt werden und ist hier bereits eine gewisse Zeitspanne seit dem letzen Daten Ingest verstrichen und es sind keine Wartungsarbeiten, Bandstillstand etc. aufgetreten kann dieses Device als zumindest „wartungsbedürftig“ oder im extremen Fall als kompromitiert betrachtet werden. In diesem Fall wird kein Token vom Service ausgestellt. Ohne gültiges Token ist auch kein Telemetry Ingest am Event Hub möglich.
  2. Ist die Authorisierung und Prüfung der Metadaten erfolgreich, kann der Discovery Service ein Token für das jeweilige Device erstellen und als Return Value eines potentiellen REST Call an das Device übermittelt werden. Die detailierte Beschreibung, wie dieses Token erzeugt wird, findet sich im weiteren Verlauf des Artikels.
  3. Das Device verwendet das erzeugte Token beim Telemetry Ingest an den Event Hub um diesen zu legitimitieren.

Erzeugung Shared Access Signature (SAS) Token

Ein SAS Token beinhaltet neben der bereits erwähnten zeitlichen Komponente zusätzlich die Möglichkeit ein einzelnes Device eindeutig zu identifizieren. Dies kann über einen String z. B. eine Guid oder einen beliebige andere Kennung erfolgen. Im SDK wird hierbei von einem Publisher gesprochen. Die Erzeugung eines SAS Token gestaltet sich nun mit Hilfe des Service Bus SDK sehr einfach. Die Methode SharedAccessSigantureTokenProvider.GetPublisherSharedAccessSignature() erzeugt ein entsprechendes SAS Token:

        string CreateSASToken()
        {
            Uri serviceBusEndPoint = new Uri("<<your service bus endpoint e.g. -> sb://iotvd-ns.servicebus.windows.net/");
            string eventHubName = "<<your Event Hub Name>> e.g. -> IoTMC"; ;
            string publisherId = "<<your device publisher id e.g. -> DeviceLocatedAtMachine01";
            string eventHubSAPKeyName = "<<your Shared Access Policy Name>> e. g. -> send";
            string eventHubSAPKey = "<<your Key>> e.g. -> t0JK197745t345…s4N09aNI0s=";
            TimeSpan ingestValidTimeSpan = new TimeSpan(0, 5, 0);

            return SharedAccessSignatureTokenProvider.GetPublisherSharedAccessSignature(
                            serviceBusEndPoint, 
                            eventHubName, 
                            publisherId, 
                            eventHubSAPKeyName, 
                            eventHubSAPKey, 
                            ingestValidTimeSpan);
      }

Auf dem Device kann das erzeugte Token nun verwendet werden um einen Telemetry Ingest zum Event Hub durchzuführen:

void IngestTelemetry()
 {
Uri serviceBusEndPoint = new Uri("< sb://iotvd-ns.servicebus.windows.net/");
 string eventHubName = "<> e.g. -> IoTMC";
 string publisherId = "< DeviceLocatedAtMachine01";
 string sASToken = "<>";
string eventHubConnectionString = ServiceBusConnectionStringBuilder.CreateUsingSharedAccessSignature(
serviceBusEndPoint,
eventHubName,
publisherId,
sAStoken);
var eventHubSender = EventHubSender.CreateFromConnectionString(eventHubConnectionString);
eventHubSender.Send(new EventData(Encoding.UTF8.GetBytes("<>>")));

Das Device kann nun bis zum Ablauf der vom Discovery Service gewählten Zeitspanne das SAS Token benützen, um Daten an den Event Hub zu senden. Sobald diese Zeitspanne abgelaufen ist wird das Token ungültig und beim Senden der Telemetry Daten tritt eine Exception auf. In diesem Fall kann das Device wieder den Discovery Service kontaktieren und ein neues SAS Token anfordern. Sollte der Discovery Service Unregelmäßigkeiten feststellen, kann er diese Ausstellung verweigern und der Telemetry Ingest von evtl. kompromitierten oder fehlerhaften Devices somit unterbinden.

 

Blockierung von einzelnen Devices

Solange die Zeitspanne die bei der Erzeugung eines SAS Tokens angegeben worden ist, kann dieses Token verwendet werden um Daten an einen Event Hub zu senden. Es gibt keine Möglichkeit, ein Token vor Ablauf der Gültigkeit als ungültig zu kennzeichnen und damit einen Telemetry Ingest zu unterbinden.

Um trotzdem den Ingest von einem als fehlerhaft oder kompromitiert eingestuftem Device vor Ablauf der Token Gültigkeit zu unterbinden kann die Publisher Id des jeweiligen Device verwendet werden. Diese Publisher Id wird der Methode ServiceBsConnectionStringBuilder.CreateUsingSharedAccessSignature() übergeben um einen ConnectionString zum Event Hub zu erzeugen.

        
        void IngestTelemetry()
        {

            Uri serviceBusEndPoint = new Uri("<<your service bus endpoint e.g. -> sb://iotvd-ns.servicebus.windows.net/");
            string eventHubName = "<<your Event Hub Name>> e.g. -> IoTMC";
            string publisherId = "<<your device publisher id e.g. -> DeviceLocatedAtMachine01";
 string sASToken = "<<Token generated by Discovery Service>>";
 
            string eventHubConnectionString = ServiceBusConnectionStringBuilder.CreateUsingSharedAccessSignature(
                serviceBusEndPoint, 
                eventHubName, 
                publisherId, 
                sAStoken);

            var eventHubSender = EventHubSender.CreateFromConnectionString(eventHubConnectionString);

            eventHubSender.Send(new EventData(Encoding.UTF8.GetBytes("<<Your Telemetry Data")));
        }

Diese Publisher Id kann wie bereits erwähnt beliebig gewählt werden und sollte jedes Device eindeuting kennzeichnen.

Soll nun der Telemetry Ingest von einem bestimmten Device vor Ablauf der Token Lebenszeit gesperrt werden, kann dies über die Methode RevokePublisher()  einer Instanz des Objektes NamespaceManger des Service Bus SDK erreicht werden. Zu beachten ist, dass hierfür eine Verbindung zum Service Bus Namespace in dem der Event Hub angelegt wurde notwendig ist. Eine Verbindung zum jeweiligen Event Hub auf dem der Telemetry Ingest eines Devices blockiert werden soll ist hierfür nicht ausreichend. Die Verbindung muss zusätzlich über die Berechtigung „manage“ verfügen. Am einfachsten ist es hierbei den notwendigen Connection String direkt aus dem Azure Portal zu kopieren. Nach erfolgreicher Instanzierung eines Namespace Manger Objektes können die Methoden RevokePublisher() und RestorePublisher() verwendet werden, um den Telemetry Ingest zu blockieren oder nach bereits erfolgter Blockierung wieder zuzulassen. Beide Methoden erwarten hierfür zum einen den Namen des Event Hub und die jeweilige Publisher Id des Devices:

        void IngestTelemetry()
        {
            Uri serviceBusEndPoint = new Uri("<<your service bus endpoint e.g. -> sb://iotvd-ns.servicebus.windows.net/");
            string eventHubName = "<<your Event Hub Name>> e.g. -> IoTMC";
            string publisherId = "<<your device publisher id e.g. -> DeviceLocatedAtMachine01";
            string sASToken = "<<Token generated by Discovery Service>>";
 
            string eventHubConnectionString = ServiceBusConnectionStringBuilder.CreateUsingSharedAccessSignature(
                serviceBusEndPoint, 
                eventHubName, 
                publisherId, 
                sAStoken);
            var eventHubSender = EventHubSender.CreateFromConnectionString(eventHubConnectionString);
            eventHubSender.Send(new EventData(Encoding.UTF8.GetBytes("<<Your Telemetry Data")));
        }

Fazit

Auch wenn es auf den ersten Blick kofortabel und schnell möglich ist, den Key einer Shared Access Policy direkt in einem Device zu verwenden, sollte man bei der Konzeption einer IoT Lösung einen sogenannten Discovery Service mit der „off-board“ Erzeugung von sogenannten Shared Access Policy Tokens berücksichtigen. Die dadurch gewonnenen Möglichkeiten eine IoT Lösung abzusichern wiegen in der Regel den zusätlichen Aufwand und die zusätzlichen Kosten zur Betreibung/Wartung des Discovery Service auf.

 

C# Entwicklung + Arduino/Genuino

Gerade im privaten Umfeld erfreuen sich die Arduino/Genuino Boards großer Beliebtheit um alle Arten von IoT  Projekten umzusetzen.  Auch im kommerziellen / professionellen Umfeld erfreuen sich die Boards großer Beliebtheit um prototypische Umsetzungen von Projekten bzw. Geschäftsideen schnell und kostengünstig zu verproben. Um Arduino Boards anzuprogrammieren kann die Open Source Arduino IDE erwendet werden. Die Programmierung von sog. Sketchen (d. h. Programme die auf den Arduino Boards ausgeführt werden) ähnelt C/C++ und ist einfach zu erlernen.

Für C# / VisualBasic.NET oder generell Windows Runtime Entwickler welche die Hardware Möglichkeiten eines Arduino nutzen möchten gibt es noch eine zusätzliche Möglichkeit. Windows Remote Arduino ist eine Open Source Windows Runtime Komponente die es ermöglicht die analogen und digitalen Ports eines Arduino Uno von einem beliebigen Windows 10 Device aus zu benützen. Gerade wenn ein User Interface, UMTS, WiFi, Storage etc.  zusammen mit dem Arduino Board benötigt wird lohnt es sich ggf. ein günstiges Windows 10 Device zusammen mit dem Arduino einzusetzen. Auf dem GitHub Account des Projektes findet sich eine einfache Step-by-Step Anleitung um ein Windows 10 Device via USB, Bluetooth, WiFi oder Ethernet mit dem Arduino zu verbinden.

Folgt man der Anleitung, verbindet den Arduino z. B. via USB, lädt die notwendige Firmata Implementierung auf den Arduino und beginnt in Visual Studio mit einem leeren UWP Projekt, könnenzwar mittels UsbSerial.listAvailableDevicesAsync()

RemoteArduiono_01

 

alle verbundenen Arduino(s) (in diesem Falle über USB angebunden) ohne Fehler ermittelt werden. Versucht man jedoch die Kommunikation mit dem Arduiono mittels .begin() RemoteArduiono_02aufzubauen. Kommt es zu folgender Fehlermeldung

UsbSerial::connectToDeviceAsync failed with a Platform::Exception type. (message: Catastrophic failure Unable to initialize the device. Did you forget your USB device capabilities in the manifest? SerialDevice::FromIdAsync returned null.)

Selbst wenn im Manifest der UWP Applikation explizit der Zugriff auf den USB Port erlaubt wurde tritt der Fehler auf. RemoteArduiono_03

Trotzdem gibt die Fehlermeldung den entscheidenden Hiweis auf fehlende Capabilities im Manifest der Applikation. Um die Kommunikation mit dem Arduino erfolgreich durchführen zu können, muß die folgende Device Capability im Manifest eingetragen werden:

<DeviceCapability Name=“serialcommunication“>
      <Device Id=“any“>
        <Function Type=“name:serialPort“ />
      </Device>
    </DeviceCapability>
  </Capabilities>

RemoteArduiono_04

 

Nach einem nochmaligem Deploy der UWP App kann auch die Kommunikation mit dem Arduino erfolgreich initiiert werden.

 

IoT Hackathon UG Nürnberg

image

Vielen Dank an alle Teilnehmer des Azure IoT TechCamp am 23.04.2014 in Nürnberg. Wie während des Event angekündigt hier noch einmal eine Zusammenfassung der Links zu Code-Snippets bzw. Hardware Intro sowie die verwendeten Slide – Decks:

Getting started:

Tessel: http://start.tessel.io/install

Arduino Yun: http://www.arduino.cc/en/Guide/ArduinoYun

Code Snippets / Dienste:

https://github.com/dx-ted-emea/azure-tessel

Hier finden sich komplette Hands-On-Labs wie ein Tessel Microcontroller (oder generell “Things” mit einem HTTP Stack) Azure basierte Resourcen wie z. B. EventHub, ServiceBus, Mobile Services, WebSites etc. benützen können.

https://github.com/dx-ted-emea/iot-labs

Unter dem Link findet sich ein komplettes End-To-End Szenario aufgeteilt in mehrere Labs. Die Labs decken den Daten Ingest als auch die Verarbeitung der Daten als Stream sowie Rückmeldungen (Command & Control) an die Endgeräte ab.

http://www.connectthedots.io

Ebenfalls ein komplettes Hands-On-Lab welches ein IoT Szenario abdeckt. Ein sehr interessantes Mittel zum Eigenstudium welches viele Azure Backend Dienste vorstellt.

https://github.com/RobertEichenseer/IoT_MasterClass

Sammlung von hilfreichen Code-Snippets wie z. B. das Senden von Telemetrie Daten an einen Azure Event Hub aus einer Universal App, einer Win32 App, .net Micro Framework etc.

https://github.com/crossbario/crossbarexamples/wiki/TechCamp

Crossbar.IO ein Open Source Produkt welches einfach über den Azure Marketplace installiert und benützt werden kann. Crossbar.IO adressiert unter anderem das “Command & Control” Paradigma welches in nahezu jeder IoT Lösung benötigt wird.  

Slide Decks:

Die verwendeten Slide Decks finden sich unter: http://1drv.ms/1DZhqR9

Azure Event Hubs – Partitions und Retention Time

 

Competing Consumer vs. Partitioned Consumer

Betrachtet man rein den Funktionsumfang den Azure Service Bus Event Hubs und Azure Service Bus Topics/Subscription zur Verfügung stellen, erscheint im ersten Augenblick kein großer Unterschied. Beide Dienste können über verschiedene Protokolle (http(s), AMQP) Daten bzw. Telemetrie von mehreren Sendern entgegennehmen und an multiple Empfänger zur weiteren Bearbeitung weiterleiten.

Einer der großen Unterschiede findet sich in der Möglichkeit Daten mit geringer Latenz und hoher Zuverlässigkeit entgegenzunehmen und dabei zusätzlich eine hohe Bandbreite (aktuell bis zu 1 GB (!!) pro Sekunde) Daten an einen Event Hub zu senden. Dies wird unter anderem dadurch erreicht, dass ein Event Hub ein “Partitioned Consumer” Modell verfolgt. Topic/Subscriptions arbeiten dagegen nach einem “Competing Consumer” Modell. Vereinfacht ausgedrückt verwendet ein EventHub einen “client-seitigen” Cursor. D. h. wenn ein Client von Event Hubs Daten anfordert, so muss dieser dem Event Hub die Stelle bzw. ein Offset mitteilen, ab dem er Daten empfangen möchte. Im Gegensatz dazu verwendet Topic/Subscriptions einen “server-seitigen” Cursor bei dem der Client keine weiteren Informationen welche Daten er abfordern möchte senden muss.

IEventProcessor / Cursorverwaltung

Um die Verwaltung des “client-seitigen” Cursors so einfach wie möglich zu gestalten, stellt Microsoft ein Nuget Package zur Verfügung, welches in der Package Manager Console dem Projekt hinzugefügt werden kann

PM> install-package Microsoft.Azure.ServiceBus.EventProcessorHost

Nach Implementierung des Interface IEventProcessor in einer Klasse müssen die Funktionen CloseAsync(), OpenAsync() und ProcessEventsAsync() implementiert werden. Besonderes Augenmerk liegt hierbei auf OpenAsync(). Die Library startet für jede Partition die bei der Anlage des EventHub definiert wurde eine eigene Instanz der Klasse. Die Referenz auf die jeweilige Partition wird dabei im Parameter PartitionContext übergeben. Dieser PartitionContext kann nun wiederum verwendet werden um die Informationen für den “client-seitigen” Cursor zu speichern. Mit Aufruf der Methode CheckpointAsync() wird die letzte verarbeitete Nachricht gespeichert und bei einem evtl. Neustart der Applikation nicht wieder vom Event Hub abgerufen. 

image

Intern speichert die Library die Informationen über den “client-seitigen” Cursor in einer JSON formatierten Datei  pro Partition in einem Azure Storage Account ab.

{
    „PartitionId“:“0″,
    „Owner“:“MSTechDemoWorker“,
    „Token“:“7886f96a-990c-4049-93a3-432dc159a4fa“,
    „Epoch“:1,
    „Offset“:““,
    „SequenceNumber“:0
}

Retention Time

Bei der Anlage eines Event Hub muss neben der Anzahl der gewünschten Partitionen ebenfalls eine sog. Retention Time (in Tagen) angegeben werden. Der minimale Wert beträgt hierbei ein Tag und der maximale Wert aktuell 7 Tage. Die Angabe der Retention Time legt fest, wie lange der jeweilige Event Hub die eingehenden Daten, für die weitere Verarbeitung durch Konsumenten speichert.

Häufig wird jedoch z. B. bei einer Retention Time von einem Tag davon ausgegangen, dass alle eingegangenen Daten auch automatisch nach Ablauf des einen Tages wieder aus dem Event Hub gelöscht werden. Dies ist nicht der Fall! Die Angabe der Retention Time ist dahingehend zu verstehen, dass die eingegangenen Daten mindestens für diesen Zeitraum zur Verfügung stehen. Gerade während der Entwicklung von Event Hub Consumern muss man häufig die “client-seitigen” Cursor Informationen löschen um wieder mit den “letzten” Test Daten arbeiten zu können. Sehr häufig stellt man dabei fest, dass der Event Hub auch ältere Daten (z. B. Daten welche vor mehreren Tagen an den Event Hub gesendet wurden) zurück meldet, auch wenn man diese aufgrund der Retention Time (von z. B. einem Tag) nicht mehr erwartet.

Um zu verstehen, warum diese Daten trotzdem noch zur Verfügung stehen muss man sich die interne Arbeitsweise des Event Hub näher betrachten. Um die hohe Skalierungsrate zu erreichen, speichert der Event Hub eingehende Daten in Blöcken von definierter Größe pro Partition. Diese Blöcke werden nun wiederum nur gelöscht, wenn diese eine gewisse Größe und die Retention Time überschritten haben. Dadurch erklärt sich auch, warum gerade in der Entwicklung häufig Daten aus einem EventHub zurück geliefert werden, welche die Retention Time bereits überschritten haben. 

Möchte man dieses Verhalten umgehen, ist es möglich, beim Start des EventHubProcessor eine Lambda Funktion für den InitialOffsetProvider zu definieren. Diese Lambda wird wiederum für jede Partition aufgerufen.

image

Ein einfaches Beispiel mit Code Snippets findet sich auf meinem GitHub Account.

dotnetpro 3/15; “Schlankheitskur für dicke Daten”

dotnetpro 03/2015

Unter diesem Titel ist vor kurzem die aktuelle dotnetpro erschienen. Häufig denkt man dabei an “Big Data” und deren Verarbeitung oder Speicherung in einem Parallel Data Warehouse oder in einem Hadoop bzw. HD-Insight Cluster.

Hierbei handelt es sich jedoch um “Data @ Rest”, d. h. die Daten werden zunächst in einem Storage Container gespeichert um danach in batch-ähnlichen Verarbeitungsschritten analysiert bzw. verarbeitet zu werden.

Bei manchen Anforderungen ist dieser Ansatz jedoch nicht leistungsfähig genug. Soll z. B. in einem Datenstrom die aktuelle Temperatur überwacht werden und sobald diese einen bestimmten Schwellenwert überschreitet eine Aktion ausgelöst werden, am besten noch in “Near Real Time”, stößt dieser Ansatz an seine Grenzen.

In meinem Artikel zu Azure Stream Analytics wird in dieser Ausgabe der dotnetpro eine Möglichkeit vorgestellt, wie diese Anforderung elegant umgesetzt werden kann.

Der Artikel findet sich zum freien Download unter folgendem Link.

Azure Event Hub Ingest; Universal App

image Azure Event Hub ist ein weiterer Service innhalb der Azure Service Bus Familie und ist konzipiert für den Daten Ingest mit hoher  Skalierung und Verfügbarkeit. Ein einzelner Event Hub kann z. B. Daten von bis zu 1 Mega Byte (!) pro Sekunde aufnehmen und für weitere Analyse bzw. Bearbeitung speichern.

Das Azure Service Bus SDK macht es einfach Daten in einen Event Hub zu posten bzw. diese zur weiteren Verarbeitung abzurufen. Verwendet man jedoch eine Universal App (Windows Phone, Windows Store App) steht das entsprechende SDK zum aktuellen Zeitpunkt nicht zur Verfügung. Dies stellt jedoch keine große Problematik dar, da Azure Event Hub für den Daten Ingest neben AMQP auch ein REST API zur Verfügung stellt. So kann mit einfachen HTTP Posts ebenfalls ein Daten Ingest durchgeführt werden.

Um den HTTP Post am Event Hub zu autorisieren, muss dieser im Header mit einer Shared Access Signature ausgestattet werden. Hierzu kann die beigefügte Methode CreateServiceBusSASToken() verwendet werden:

private string CreateServiceBusSASToken(string eventHubSASKeyName, string eventHubSASKey, string serviceBusUri)
{
    int expirySeconds = (int)DateTime.UtcNow.AddMinutes(20).Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
    string stringToSign = WebUtility.UrlEncode(serviceBusUri) + „n“ + expirySeconds.ToString();
    string signature = HmacSha256(eventHubSASKey, stringToSign);
    return String.Format(„sr={0}&sig={1}&se={2}&skn={3}“, WebUtility.UrlEncode(serviceBusUri), WebUtility.UrlEncode(signature), expirySeconds, eventHubSASKeyName);
}

public  string HmacSha256(string eventHubSASKey, string serviceBusUriExpiry)
{
    var keyStrm = CryptographicBuffer.ConvertStringToBinary(eventHubSASKey, BinaryStringEncoding.Utf8);
    var valueStrm = CryptographicBuffer.ConvertStringToBinary(serviceBusUriExpiry, BinaryStringEncoding.Utf8);

    MacAlgorithmProvider macAlgorithmProvider = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha256);
    CryptographicHash cryptographicHash = macAlgorithmProvider.CreateHash(keyStrm);
    cryptographicHash.Append(valueStrm);

    return CryptographicBuffer.EncodeToBase64String(cryptographicHash.GetValueAndReset());
}

Der vollständige Code um einen HTTP Post Ingest in EventHub durchzuführen, sieht folgendermaßen aus:

public async Task<bool> TelemetryIngest(Telemetry telemetry)
{

    string serviceBusNamespace = „iotmc-ns“;
    string serviceBusUri = string.Format(„{0}.servicebus.windows.net“, serviceBusNamespace);
    string eventHubName = „IoTMC“;
    string eventHubSASKeyName = „Device01“;
    string eventHubSASKey = „t0JK19v94H3R8yAZ1uVkGcIUFi8zmGmBts4N09aNI0s=“;

    using (HttpClient httpClient = new HttpClient())
    {
        httpClient.BaseAddress = new Uri(String.Format(„
https://{0}“, serviceBusUri));
        httpClient.DefaultRequestHeaders.Accept.Clear();

        string sBToken = CreateServiceBusSASToken(eventHubSASKeyName, eventHubSASKey, serviceBusUri);
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(„SharedAccessSignature“, sBToken);
        HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(telemetry), Encoding.UTF8);
        httpContent.Headers.ContentType = new MediaTypeHeaderValue(„application/json“);

        string ingestPath = String.Format(„/{0}/publishers/device01/messages“, eventHubName);
        var response =  await httpClient.PostAsync(ingestPath, httpContent);
        if (response.IsSuccessStatusCode)
        {
            return true;
        }

        return false;
    }
}

Mit Hilfe eines HTTP Post ist es einfach möglich, von einer Universal App, sowohl Windows Phone als auch Windows Store App, Daten an einen EventHub zu senden.

IoT; Themenschwerpunkt dotnetpro

dotnetpro 02/2015In der aktuellen dotnetpro findet sich ein Themenschwerpunkt rund um IoT (Internet of Things). Zum Thema durfte ich ebenfalls einen Artikel zusteuern, der die Funktionalität von Microsoft Azure Event Hubs näher beleuchtet. Im Artikel werden Code Snippets sowohl für den Ingest von Sensordaten als auch für die nachgelagerte Verarbeitung zur Verfügung gestellt. In der nächsten dotnetpro Ausgabe findet sich dann ein Folgeartikel, der erläutert, wie in einem IoT Szenario Ingest Daten mittels Azure Stream Analytics weiterverarbeitet werden können.

Wer noch einen Schritt weiter gehen möchte, findet unter meinem GitHub Account ein einfaches End-To-End Beispiel das als Grundlage für eigene IoT Anwendungen Verwendung finden kann. Nachfolgend eine Übersicht der jeweiligen Projekte im Repository:

MC_PowerShellScripts Anlage eines Azure Service Bus als Host Namespace für einen Event Hub mittels Powershell Script
MC_AdminConsole Anlage eines Azure Event Hub mit SAS Token für Daten Ingest von Sensoren. 
MC_SensorDotNet Daten Ingest in einen Event Hub von managed Code (C#) aus
MC_FieldGateway Daten Sammlung (http Server) + Daten Ingest in Event Hub in Node.js zur Ausführung auf einem Field Gateway
MC_SensorNetduino Daten Ingest von einem Netduino 2 Plus zum Field Gateway. Entwicklung und Debugging in VS 2013 möglich (!)
MC_EventConsumer Auslesen  von Daten aus einem Event Hub in managed Code (C#)
MC_EventConsumerAnalyse Auslesen und Verarbeiten bzw. Analyse von Daten aus einem Event Hub in managed Code (C#).
MC_StreamAnalytics Auslesen und Verarbeiten von Daten aus einem Event Hub bei Benützung von Azure Stream Analytics (identische Funktionalität wie MC_EventConsumerAnalyse)

Viel Spaß beim Entwickeln von eigenen IoT Lösungen.

Netduino, IoT Applikationen mit VS 2013 erstellen

imageDas Netduino Prototyping Board ist ein in der .NET community beliebtes Board, welches auf dem .NET Micro Framework aufbaut. Das Netduino ist pin-kompatibel mit dem Arduino Board und damit steht eine große Anzahl an Sensoren, Aktoren und Gadgets zur Verfügung die in eigenen IoT Applikationen eingesetzt werden können. Für viele .NET Entwickler ist jedoch der größte Vorteil, dass zur Entwicklung von Applikationen C# und Visual Studio eingesetzt werden kann. Das Lernen von neuen Sprachen und Entwicklungsumgebungen ist dadurch nicht nötig. 

Colin Miller hat auf dem .NET Micro Framework Blog angekündigt, dass Microsoft das Investment in die Plattform wieder erhöhen wird. Erste Ankündigungen zeigen Investment im Bereich der asynchronen Entwicklung und der Integration in die aktuellen Visual Studio Versionen. Aktuell wird auf der Netduino Homepage noch Visual Studio 2010 als notwendige Entwicklungsumgebung genannt. Eine Side-By-Side Installation von VS 2010 mit VS2013 oder der Beta von VS2014 ist zwar möglich, trotzdem erscheint die Installation einer “alten” Version von VS nicht komfortabel, gerade wenn die “Device-Entwicklung” Bestandteil eines größeren Projektes ist und eine gemeinsame Solution für alle Komponenten gepflegt werden soll. Aktuell existiert eine Beta Integration, die es ermöglicht, Netduino Apps mit Visual Studio 2013 zu erstellen.

Folgende Schritte sind dazu nötig:

  1. Deinstallation aller evtl. vorhandenen .NET Micro Framework und Netduino SDKs vom Computer
  2. Deinstallation aller VS Extensions (Tools –> Extension and Updates; nach .NET Micro suchen)
  3. Installation des .NET MF SDK v4.3 R2 (beta)
  4. Installation des .NET MF v4.3 R2 (beta) add-in für VS 2013
  5. Installation des Netduino SDK v4.3.1

Nach Installation aller Komponenten sollte in VS 2013 neue Projekt Templates für das Micro Framework und die Netduino Entwicklung angezeigt werden.

image

Die nächste Herausforderung stellt i. d. R. das Netduino Board selbst dar. Meist ist nicht die in der Beta Version verwendete Firmware Version 4.3.1 sondern 4.2 bzw. 4.1 installiert. Dies äußert sich in einer Fehlermeldung

Cannot deploy the base assembly ‚mscorlib‘, or any of his satellite assemblies, to device – USB:Netduino twice. Assembly ‚mscorlib‘ on the device has version 4.2.0.0, while the program is trying to deploy version 4.3.1.0

Chris Walker hat auf seinem Blog eine Update Tool zur Verfügung gestellt um die Firmware auf dem Netduino (Achtung: nur für Netduino Plus 2) zu flashen. Folgende Schritte sind nötig:

  1. Netduino vom USB Port des Computers trennen um in auszuschalten
  2. Den Button auf dem Netduino drücken und gedrückt halten während dieser via USB mit dem Computer verbunden wird.
  3. Das oben verlinkte Update Tool starten und die Firmware 4.3.1 auf das Netduino Board übertragen.

Nach erfolgreichem Flash der Firmware können die Netzwerkeinstellungen (IP oder DHCP) des Board mit MFDeploy (Target –> Configuration –> Networking) neu vergeben werden.

Azure Event Hub; automatisierte Anlage

Die Anlage eines Event Hub bei bereits existierendem Service Bus Namespace ist kein großer Aufwand. Im NuGet Package WindowsAzure.Servicebus finden sich alle Objekte um einen Event Hub bequem in managed Code anzulegen, wie das nachfolgende Code-Beispiel zeigt.

   1: public async Task<EventHubDescription> CreateEventHubAsync()

   2: {

   3:  

   4:     string serviceBusNamespace = "iotmc-ns";

   5:     string serviceBusManageKey = "32GP81C2B/eWHQ/MlZomaV8Sr4nnzeRCrJQCrYr/Wi4=";

   6:     string eventHubName = "IoTMC";

   7:     string eventHubSASKeyName = "Device01";

   8:  

   9:     Uri serviceBusUri = ServiceBusEnvironment.CreateServiceUri("sb", serviceBusNamespace, string.Empty);

  10:     TokenProvider tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider("RootManageSharedAccessKey", serviceBusManageKey);

  11:     NamespaceManager nameSpaceManager = new NamespaceManager(string.Format("//{0}/", serviceBusUri.Host), tokenProvider);

  12:     string eventHubKey = SharedAccessAuthorizationRule.GenerateRandomKey();

  13:  

  14:     EventHubDescription eventHubDescription = new EventHubDescription(eventHubName)

  15:     {

  16:         PartitionCount = 8,

  17:         MessageRetentionInDays = 1

  18:     };

  19:     SharedAccessAuthorizationRule eventHubSendRule = new SharedAccessAuthorizationRule(eventHubSASKeyName, eventHubKey, new[] { AccessRights.Send, AccessRights.Listen });

  20:     eventHubDescription.Authorization.Add(eventHubSendRule);

  21:     eventHubDescription = await nameSpaceManager.CreateEventHubIfNotExistsAsync(eventHubDescription);

  22:  

  23:     string eventHubSASKey = ((SharedAccessAuthorizationRule)eventHubDescription.Authorization.First()).PrimaryKey;

  24:  

  25:     return eventHubDescription;

  26: }

Eine kleine Hürde gibt es jedoch, wenn auch der Service Bus Namespace via Code oder Powershell angelegt werden soll. Zum jetzigen Zeitpunkt gibt es einen Unterschied, wenn ein Service Bus Namespace via Management Portal oder via Powershell oder REST Api angelegt wird.

Bei Anlage über das Management Portal wird eine Shared Access Signature als Default Autorisierungsmechanismus angelegt. Legt man jedoch einen Service Bus Namespace via Powershell mit dem Komando:

   1: New-AzureSBNamespace -Name "CreatedUsingPowerShellDefaultValues" -Location "West Europe"

 
an, wird dieser als Default mit ACS Autorisierung erstellt. Versucht man im Nachgang in diesem Namespace einen Event Hub anzulegen, egal ob dies via Code oder Management Portal durchgeführt wird, kommt es zu einer Fehlermeldung “500 interner Server Error”.
 
Deshalb muss bei der Anlage des Service Bus Namespace via Powershell die Parameter –CreateACSNamespace und –NamespaceType mit Werten belegt werden.
 
   1: Param

   2: (

   3:         [bool]$falseValue = $false

   4: )

   5: New-AzureSBNamespace -Name "DelDel-ns" -Location "West Europe" -CreateACSNamespace $falseValue -NamespaceType Messaging