Wie verbindet man Cognito mit IoT Core?

September 30, 2024

Bei der Entwicklung einer MQTT-basierten Lösung mit AWS werden oft zunächst statische AWS-Anmeldeinformationen für den Proof of Concept verwendet. Wenn dein Projekt jedoch wächst, musst du möglicherweise den Zugriff einschränken und für jeden Benutzer detailliertere Berechtigungen festlegen. Hier kommt Amazon Cognito ins Spiel. Es hilft dir, Benutzer authentifiziert und autorisiert in das AWS IoT Core-Ökosystem einzubinden.

Was ist Amazon Cognito?

Amazon Cognito ist ein Authentifizierungs- und Autorisierungsdienst, der die Benutzerverwaltung und Zugriffskontrolle für deine Anwendungen vereinfacht. Damit können Entwickler Benutzeridentitäten konfigurieren was wichtig ist, um IoT-Geräte sicher zu verbinden.

Benutzerpool vs. Identitäts-Pool: Was ist der Unterschied?

Ein Benutzerpool in Amazon Cognito ist ein Benutzerverzeichnis, das die Authentifizierung von Benutzern auf verschiedene Weisen ermöglicht, z. B. durch traditionelle Anmeldeinformationen oder über andere Identitätsanbieter (wie Google oder Facebook). Ein Identity Pool hingegen gewährt authentifizierten Benutzern temporäre AWS-Berechtigungen, um kontrollierten Zugriff auf AWS-Ressourcen zu erhalten.

Im Zusammenhang mit der Verbindung von AWS IoT Core mit Cognito ist es wichtig zu verstehen, wie beide Elemente funktionieren, um eine sichere und skalierbare Lösung zu implementieren. Lass uns einen Blick darauf werfen, wie du diese Integration effektiv erreichst!

Benutzerpool-Konfiguration

Der erste Schritt zur Integration von Cognito mit IoT Core ist die Einrichtung eines Benutzerpools zur Verwaltung der Benutzer. Erstellen Sie den Benutzerpool über die Cognito-Konsole. Im Formular kannst du die bevorzugte Anmeldeoption auswählen (Benutzername, E-Mail oder Telefonnummer) oder aktivierst föderierte Optionen wenn du externe Anbieter verwenden möchtest.

fig1.webp image

In den folgenden Schritten wählst du die Passwort- und Sicherheitseinstellungen deiner Wahl. Wenn du zur Sektion „Benutzerdefinierte Attribute" kommst, beachte folgendes: hier kannst du zusätzliche Felder für deine Benutzer hinzufügen. Zum Beispiel fügen wir das Feld buildingId hinzu, um die Gebäudenummer zu speichern, in der der Benutzer wohnt. Benutzerdefinierte Attribute können nach Bedarf erstellt werden.

fig2.webp image

Gib dem Pool und dem App-Client schließlich einen Namen. Der App-Client repräsentiert die Anwendung, in der die Cognito-Anmeldung genutzt wird. Stelle sicher, dass alle Parameter korrekt sind und beende das Formular.

fig3.webp image

fig4.webp image

Nach der Erstellung gehe zum Benutzerpool und kopiere den Wert der Benutzerpool-ID.

fig5.webp image

Dann gehe zum Reiter App-Integration. Unten findest du den erstellten App-Client und die Client-ID. Die Benutzerpool-ID und die Client-ID werden später benötigt, um eine Anmeldeseite mit der Cognito-Bibliothek einzurichten.

fig6.webp image

Identitätspool-Konfiguration

Mit dem Benutzerpool kannst du nun eine sichere Authentifizierung für deine Benutzer erstellen. Unser Ziel ist es jedoch, Benutzern selektiven Zugriff auf IoT Core via MQTT zu gewähren. Dafür verwenden wir den Identity Pool. Mit dem Identity Pool können wir temporäre AWS-Anmeldeinformationen generieren, insbesondere AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY und AWS_SESSION_TOKEN, die pro Benutzer einzigartig sind und eine begrenzte Dauer haben.

Der Identitätspool ist ein vom Benutzerpool getrennter Dienst. Während der Benutzerpool Anwendungsbenutzer verwaltet, verwaltet der Identitätspool Identitäten.

Erstelle den Identity Pool in der Cognito-Konsole. Im ersten Schritt wählst du die Authentifizierung über den Amazon Benutzerpool.

fig7.webp image

Erstelle anschließend eine neue Rolle für den Identity Pool. Diese Rolle hat die Standardberechtigung „cognito-identity:GetCredentialsForIdentity", die es den Benutzern ermöglicht temporäre Anmeldeinformationen zu generieren.

fig8.webp image

Wähle den zuvor erstellten Benutzerpool und App-Client aus.

fig9.webp image

Am Ende des Formulars findest du den Abschnitt „Zuweisung des temporären Zertifikats/ Anspruchszuweisung". Da der Identitätspool vom Benutzerpool getrennt ist, kannst du mit der Zuordnung Attribute aus dem Benutzerpool mit der neuen Identität im Identity Pool verknüpfen. So kannst du Richtlinien basierend auf Variablen konfigurieren, wie wir später sehen werden.

Erinnerst du dich an das buildingId-Feld, das wir beim Erstellen des Benutzerpools hinzugefügt haben? Wir werden es in die Anspruchszuordnung einfügen. Gib dazu einen Bezeichner als Tag Key und den Attributnamen im Claim an. Bei benutzerdefinierten Attributen wird das Präfix „custom" verwendet, z. B. custom:buildingId. Ist es kein benutzerdefiniertes Attribut, wird „custom" weggelassen.

fig10.webp image

Gib dem Identity Pool schließlich einen Namen und aktiviere keine grundlegende Authentifizierung (es sei denn, du benötigst sie), um den Prozess zu vereinfachen.

fig11.webp image

Aktivieren von Anspruchszuweisung-Tags

Im vorherigen Abschnitt haben wir eine Attributzuordnung hinzugefügt. Falls du in Zukunft weitere Zuordnungen hinzufügen möchtest, kannst du dies tun indem du den erstellten Identity Pool öffnest, zur Benutzerzugriffssektion gehst und den Identitätsanbieter auswählst. Öffne den Anbieter und unten kannst du die Zuordnungen bearbeiten.

fig12.webp image

Um das Taggen von Sitzungen durch Ansprüche zu aktivieren öffne die Rolle des Identity Pools.

fig13.webp image

Bearbeite in der Rolle den Abschnitt „Vertrauensbeziehungen" und füge die Aktion „sts:TagSession" hinzu. Diese Aktion ermöglicht es uns, Richtlinien basierend auf den zugeordneten Attributen zu konfigurieren.

fig14.webp image

Konfigurieren von IAM-Richtlinien für den Identitätsanbieter

Um eine Verbindung zu IoT Core über Cognito herzustellen, müssen wir zwei Richtlinien konfigurieren: eine IAM-Richtlinie und eine IoT-Richtlinie. Die IAM-Richtlinie gewährt dem Identitätsanbieter die Berechtigung auf IoT Core-Dienste zuzugreifen. Eine einfache Richtlinie, die die Verbindung zu jedem MQTT-Topic ermöglicht könnte so aussehen:

{ "Version": "2012-10-17", "Statement": [ { "Sid": "ConnectClient", "Effect": "Allow", "Action": [ "iot:Connect" ], "Resource": "*" }, { "Sid": "SubscribeToTopics", "Effect": "Allow", "Action": [ "iot:Subscribe" ], "Resource": "*" }, { "Sid": "ReceiveMessages", "Effect": "Allow", "Action": [ "iot:Receive", "iot:Publish" ], "Resource": "*" } ] }

Diese Richtlinie ist in einer Testumgebung in Ordnung aber in einer Produktionsumgebung sollten Benutzer nur mit einer begrenzten Anzahl von Topics interagieren können. Um dies zu erreichen können wir Richtlinienvariablen verwenden. Mit Richtlinienvariablen ist es möglich Anspruchszuordnungstags zu nutzen, um die Verbindung zu bestimmten Topics pro Benutzer zu beschränken. Um auf eine Richtlinienvariable zuzugreifen kannst du eine Vorlage wie diese verwenden:

${variableName}

Um exklusiv auf eine Tag-Variable zuzugreifen verwende das Präfix aws:PrincipalTag/ gefolgt vom Tag-Namen, der bei der Anspruchszuordnung angegeben wurde:

${aws:PrincipalTag/tag_name}

Als Beispiel erstellen wir eine Richtlinie, die es Benutzern erlaubt nur auf Topics zuzugreifen, die zu ihrem Gebäude gehören indem wir das zuvor erstellte building_id -Tag verwenden.

{ "Version": "2012-10-17", "Statement": [ { "Sid": "ConnectClient", "Effect": "Allow", "Action": [ "iot:Connect" ], "Resource": "*" }, { "Sid": "SubscribeToTopics", "Effect": "Allow", "Action": [ "iot:Subscribe" ], "Resource": "arn:aws:iot:eu-central-1:123456789012:topicfilter/building/${aws:PrincipalTag/building_id}" }, { "Sid": "ReceiveMessages", "Effect": "Allow", "Action": [ "iot:Receive", "iot:Publish" ], "Resource": "arn:aws:iot:eu-central-1:123456789012:topic/${aws:PrincipalTag/building_id}" } ] }

In der obigen Richtlinie wird das Schlüsselwort topicfilter normalerweise für Abonnements verwendet und das Schlüsselwort topic wird für das Veröffentlichen verwendet. Sobald die Richtlinie erstellt ist (TestIamPolicyBuilding), sollte sie der Rolle zugewiesen werden, die mit dem Identity Pool (TestIdentityPoolRole) verknüpft ist.

fig15.webp image

Einrichten von IoT-Richtlinien für den Identitätsanbieter

Um sich mit temporären Anmeldedaten des Identitätsanbieters über MQTT zu verbinden reicht die IAM-Richtlinie allein nicht aus. Du musst auch eine IoT-Richtlinie erstellen, die später an die Identität angehängt wird. Die IoT-Richtlinie hat das gleiche Format wie die IAM-Richtlinie muss jedoch im Sicherheitsbereich von IoT Core erstellt werden.

fig16.webp image

Genau wie bei der IAM-Richtlinie kannst du auch in der IoT-Richtlinie Richtlinienvariablen verwenden. Da wir building_id in der Anspruchszuordnung für den Identitätspool gemappt haben, haben wir auch Zugriff auf diese Tags in der IoT-Richtlinie.

Cognito-Identitäten erstellen

Bisher haben wir alle notwendigen Dienste konfiguriert, um Cognito mit IoT Core zu verbinden. Jetzt schauen wir uns Cognito-Identitäten und deren Berechtigungen genauer an. Eine Cognito-Identität wird erstellt nachdem sich ein Benutzer über den Benutzerpool angemeldet hat und dann den Endpunkt GetCredentialsForIdentity von AWS aufruft. Um diesen Endpunkt aufzurufen muss der idToken des Benutzers verwendet werden. Der idToken wird als Ergebnis der Anmeldung über den Benutzerpool generiert. Nach der Anmeldung kann eine Antwort ähnlich der folgenden erstellt werden, die abhängig von der verwendeten SDK oder Bibliothek ist:

json { "AccessToken": "eyJra........", "ExpiresIn": 3600, "IdToken": "eyJra........", "RefreshToken": "eyJjd........", "TokenType": "Bearer" }

Mit dem idToken und dem SDK für Node.js, kann eine Cognito-Identität für den Benutzer wie folgt erstellt werden:

import { fromCognitoIdentityPool } from "@aws-sdk/credential-providers"; ... const loginProvider = `cognito-idp.${awsRegionName}.amazonaws.com/${userPoolId}`; const credentials = await fromCognitoIdentityPool({ identityPoolId: 'identityPoolId', clientConfig: { region: 'aws region' }, logins: { [loginProvider]: idToken } })();

Für den obigen Code musst du die identityPoolId kennen, die der ID des Identitätspools entspricht. Du findest sie indem du auf den zuvor erstellten Pool zugreifst. Denke daran, dass sie sich von der Benutzerpool ID unterscheidet.

fig17.webp image

Nach dem Aufruf des GetCredentialsForIdentity-Endpunkts, entweder direkt oder über das SDK, wird für den Benutzer eine eindeutige Identität im Identitätspool erstellt, und es werden temporäre AWS-Anmeldedaten (accessKeyId, secretAccessKey, und sessionToken) generiert.

{ "accessKeyId": "string", "expiration": number, "secretAccessKey": "string", "sessionToken": "string" "identityId": "string" }

Die in den vorherigen Schritten erstellten Identitäten werden im Identitätspool aufgelistet. Diese Identitäten entsprechen einer eindeutigen Kennung (identityId) pro Benutzer aus dem Benutzerpool, der die vorherigen Schritte abgeschlossen hat. Es ist jedoch nicht möglich über die AWS-Konsole festzustellen, welche Identität zu einem bestimmten Benutzer gehört.

fig18.webp image

Die generierten temporären Anmeldedaten können verwendet werden, um auf AWS-Dienste zuzugreifen die durch die mit dem Identitätspool verknüpfte Rolle autorisiert sind. Um jedoch eine Verbindung zu IoT Core über MQTT herzustellen ist ein weiterer Schritt erforderlich.

Anfügen von Richtlinien an die Cognito-Identität

Um sich über MQTT mit IoT Core zu verbinden, muss die in den vorherigen Schritten erstellte IoT-Richtlinie an die Identität angehängt werden. Es gibt einige Optionen dies zu tun und je nach dem Modell deiner Anwendung solltest du die passendste wählen. In jedem Fall beinhaltet der Prozess die Verwendung des AttachPolicy-Endpunkts entweder direkt oder über ein SDK, um den Namen der IoT-Richtlinie mit einem Ziel zu verknüpfen, das der im GetCredentialsForIdentity-Endpunkt erhaltenen identityId entspricht. Das folgende Diagramm fasst den Prozess der Identitätserstellung und der Richtlinienverknüpfung zusammen.

fig19.webp image

Um den Prozess zu vereinfachen nehmen wir die einfachste Option, obwohl diese Option nur in einer Testumgebung verwendet werden sollte. Sie beinhaltet das Bearbeiten der Richtlinie (TestIamPolicyBuilding), die mit der Rolle des Identitätspools (TestIdentityPoolRole) verknüpft ist und das Hinzufügen der AttachPolicy-Berechtigung.

Diese Berechtigung ermöglicht es temporäre Anmeldedaten zu verwenden, um die IoT-Richtlinie an die Cognito-Identität anzuhängen. Der folgende Code verwendet das Node.js SDK für diesen Zweck:

import { IoTClient, AttachPolicyCommand } from "@aws-sdk/client-iot"; const iotClient = new IoTClient({ region: config.region, credentials }); const attachPolicyCommand = new AttachPolicyCommand({ policyName: 'TestIotPolicyBuilding', // IoT policy name target: credentials.identityId, // identity id }); const result = await iotClient.send(attachPolicyCommand);

Nach der Ausführung kannst du überprüfen, ob die Richtlinie an die Identität angehängt wurde indem du zur IoT-Richtlinie gehst, die in der IoT Core-Konsole erstellt wurde. Im Tab Ziele solltest du dieselbe Identitäts-ID finden, die für den Benutzer generiert wurde.

fig20.webp image

Sobald dies erledigt ist kannst du die generierten temporären Anmeldedaten verwenden, um eine Verbindung zu IoT Core über MQTT herzustellen, zum Beispiel mit WebSockets:

import { iot, mqtt } from "aws-iot-device-sdk-v2"; const builder = iot.AwsIotMqttConnectionConfigBuilder.new_builder_for_websocket() .with_credentials( 'aws-region', credentials.accessKeyId, credentials.secretAccessKey, credentials.sessionToken ) .with_client_id('client-id') .with_endpoint('endpoint') .build(); const connection = new mqtt.MqttClient().new_connection(builder); connection.connect();

Wie bereits erwähnt ist dieser Ansatz für eine Entwicklungsumgebung gültig. In einer Produktionsumgebung wird jedoch nicht empfohlen, die AttachPolicy-Berechtigung zur Identitätspool-Rolle hinzuzufügen, da jeder Benutzer Richtlinien für andere Benutzer anhängen könnte. In solchen Fällen kannst du die Aufgabe an eine Lambda-Funktion delegieren, die vom Benutzer ausgeführt wird und ausschließlich das Anhängen der Richtlinie an die im Kontext enthaltene Identität übernimmt.

Die beste Lösung hängt von deinem Geschäftsmodell ab. Wir können dich dabei unterstützen deine Ziele zu erreichen. Vereinbare einen Termin mit uns: Kontaktieren Sie uns.