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

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

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

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

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

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

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

Ответ 1

Для неаутентифицированных идентификаторов cognito роль "Identity pool anauthenticated" достаточна для подключения к брокеру IoT MQTT. Однако для аутентифицированных идентификаторов cognito требуются две вещи:

  • Роль аутентифицированного пула удостоверений должна обеспечивать доступ к требуемым действиям IoT (например, подключаться, публиковать и т.д.).

  • Вы должны приложить к идентификатору cognito политику IoT (точно так же, как те, которые прикреплены к вашим устройствам), используя 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.

Ответ 2

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

  • Создайте политику IoT (по умолчанию), перейдя в IoT Console > Безопасность > Политики и скопировав и вставив в нее содержимое политики AWSIoTDataAccess
  • Добавьте следующую встроенную политику в мою аутентифицированную роль пула Cognito Identity: {"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
  });
});

Ответ 3

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

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);
  }
});

Ответ 4

Вот пример кода для присоединения политики 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();
            }
        });
    });
}