Подключиться к AWS IoT с помощью веб-сокета с аутентифицированными пользователями Cognito

Я пытаюсь подключиться к AWS IoT с помощью веб-сокета из браузера.

Я попробовал этот пример: https://github.com/awslabs/aws-iot-examples/tree/master/mqttSample

И еще один, немного измененный, чтобы его можно было использовать с зарегистрированными пользователями Cognito Identity Pool. https://github.com/dwyl/learn-aws-iot/blob/master/src/js/utils/request.js#L27

Я могу успешно подключиться, если я использую пользователя IAM с действующей политикой IoT, но если я использую учетные данные пользователя, я получаю ответ "101 Switching Protocols", но затем он закрывается.

Роль IAM, связанная с аутентифицированным пользователем, является правильной, и я могу подписывать запросы и выполнять другие частные операции, такие как вызов конечных точек APIG. Кроме того, соединение с сокетом не отвечает с 403. Таким образом, это, вероятно, не проблема с разрешениями.

Что еще это может быть?

6 ответов

Решение

Для неаутентифицированных идентификаторов Cognito достаточно роли "Аутентифицированный пул идентификаторов", чтобы разрешить подключение к брокеру IoT MQTT. Однако для аутентифицированных идентификаторов Cognito требуются две вещи:

  1. Роль "Идентифицированный пул удостоверений" должна разрешать доступ к нужным вам действиям IoT (например, подключение, публикация и т. Д.).

  2. Вы должны присоединить политику IoT (точно так же, как те, которые подключены к вашим устройствам) к идентификатору Cognito, используя API AttachPrincipalPolicy

Шаг 2 - это то, где я застрял ранее сегодня, поскольку нигде не было особенно ясно, что это требовалось.

AFAIK. Нет способа прикрепить политику IoT к пользователю cognito с любого из веб-сайтов AWS. Однако если на вашем компьютере настроен интерфейс командной строки AWS, вы можете сделать это оттуда. Команда выглядит так:

aws iot attach-principal-policy --policy-name <iot-policy-name> --principal <cognito-identity-id>

Идентификатор Cognito можно найти с помощью Federated Identities > Your Pool > Identity browser или вы также можете найти его в ответах на ваш CognitoIdentityCredentials.get вызов. Это выглядит так us-east-1:ba7cef62-f3eb-5be2-87e5-fffbdeed2824

Для производственной системы вы, очевидно, захотите автоматизировать присоединение этой политики, возможно, используя лямбда-функцию при регистрации пользователя.

Раздел документации, в котором говорится о необходимости присоединения политики IoT, можно найти на этой странице:

Чтобы аутентифицированная личность Amazon Cognito публиковала MQTT-сообщения по HTTP на topic1 в вашей учетной записи AWS, вы должны указать две политики, как описано здесь. Первая политика должна быть присоединена к роли пула удостоверений Amazon Cognito и разрешать удостоверениям из этого пула выполнять вызов публикации. Вторая политика присоединяется к пользователю Amazon Cognito с помощью API AWS IoT AttachPrincipalPolicy и разрешает указанному пользователю Amazon Cognito доступ к теме topic1.

Чтобы реализовать ответ Калеба на внешнем интерфейсе, мне пришлось сделать пару вещей:

  1. Создайте политику IoT (с именем "по умолчанию"), перейдя в Консоль IoT> Безопасность> Политики, скопировав и вставив AWSIoTDataAccess содержание политики в нем
  2. Добавьте следующую встроенную политику к проверенной роли моего Cognito Identity Pool: {"Effect": "Allow", "Action": ["iot:AttachPrincipalPolicy"], "Resource": ["*"]

Затем я обновил свой интерфейсный код, чтобы он выглядел так:

AWS.config.region = process.env.AWS_REGION;
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
  IdentityPoolId: process.env.AWS_IDENTITY_POOL,
  Logins: {
    'graph.facebook.com': FACEBOOK_ACCESS_TOKEN
  }
});
AWS.config.credentials.get(() => {
  const IoT = new AWS.Iot();
  IoT.attachPrincipalPolicy({
    policyName: 'default',
    principal: AWS.config.credentials.identityId
  }, (err, res) => {
    if (err) console.error(err);
    // Connect to AWS IoT MQTT
  });
});

Вот пример кода для присоединения политики IoT к идентификатору пользователя Cognito из функции Lambda (NodeJS).

function attachPrincipalPolicy(device_id, cognito_user_id) {
    const iotMgmt = new AWS.Iot();
    return new Promise(function(resolve, reject) {
        let params = {
            policyName: device_id + '_policy',
            principal: cognito_user_id
        };
        console.log("Attaching IoT policy to Cognito principal")
        iotMgmt.attachPrincipalPolicy(params, (err, res) => {
            if (err) {
                console.error(err);
                reject(err);
            } else {
                resolve();
            }
        });
    });
}

Я сослался на ответы Калеба и сенорнестора, и у меня сработала следующая реализация:

AWS.config.credentials = new AWS.CognitoIdentityCredentials({
  IdentityPoolId: AWSConfiguration.poolId,
  Logins: {
     'accounts.google.com': user.Zi.id_token
  }
});

var cognitoIdentity = new AWS.CognitoIdentity();

AWS.config.credentials.get(function(err, data) {
  if (!err) {
     console.log('retrieved identity: ' + AWS.config.credentials.identityId);

     var params = {
        IdentityId: AWS.config.credentials.identityId,
        Logins: {
           "accounts.google.com": user.Zi.id_token
        }
     };
     cognitoIdentity.getCredentialsForIdentity(params, function(err, data) {
        if (!err) {
           console.log('retrieved credentials');
           const IoT = new AWS.Iot();
           IoT.attachPrincipalPolicy({
              policyName: 'exampleIoTPolicy',
              principal: AWS.config.credentials.identityId
           }, (err, res) => {
              if (err) console.error(err);
           });  // Change the "policyName" to match your IoT Policy
        } else {
           console.log('error retrieving credentials: ' + err);
           alert('error retrieving credentials: ' + err);
        }
     });
  } else {
     console.log('error retrieving identity:' + err);
     alert('error retrieving identity: ' + err);
  }
});

Вот пример приложения, которое должно помочь продемонстрировать, как аутентифицировать IoT с помощью Cognito:

https://github.com/awslabs/aws-iot-chat-example

Для подробных инструкций вы можете прочитать:

https://github.com/awslabs/aws-iot-chat-example/blob/master/docs/authentication.md

Оказывается, даже в 2021 году необходимо создать специальную лямбда-функцию, которая AttachPolicy. Как указано в официальных документах :

Чтобы привязать политику AWS IoT Core к Amazon Cognito Identity, необходимо определить функцию Lambda, которая вызывает AttachPolicy.

Другие ответы показали, как реализовать эту Lambda.

Другие вопросы по тегам