Reputation: 53
There have been similar questions to this before, and I have searched plenty, although the answers I have found haven't helped me solve the problem.
I am trying to connect to AWS's MQTT broker for my IoT device, I am using MQTT over Web Sockets through AWS Amplify's PubSub library. The authentication is also handled through Amplify (and yes, the user is successfully authenticated). When I try to connect it is immediately closed with the error message:
errorCode: 8, errorMessage: AMQJS0008I Socket closed.
I have setup both an IAM role for the identity pool, and attached an IoT policy to the authenticated user (with the identity ID retrieved from Amplify).
Command used for attaching policy:
aws iot attach-principal-policy --policy-name "Air-RME-Users" --principal "ap-northeast-1:4f76a019-9f84-44f0-a23d-48357210016c"
Any help is appreciated, thanks!
CloudWatch
log for IoT:
{
"timestamp": "2018-07-05 04:00:42.998",
"logLevel": "ERROR",
"traceId": "<removed>",
"accountId": "<removed>",
"status": "Failure",
"eventType": "Connect",
"protocol": "MQTT",
"clientId": "4e900ea4-8f05-4022-98a8-c1b26280b2a2",
"principalId": "<removed>:CognitoIdentityCredentials",
"sourceIp": "<removed>",
"sourcePort": 54641,
"reason": "AUTHORIZATION_FAILURE"
}
Cognito Identity pool policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:Connect",
"iot:Publish",
"iot:Subscribe",
"iot:Receive",
"iot:GetThingShadow",
"iot:UpdateThingShadow",
"iot:DeleteThingShadow"
],
"Resource": [
"*"
]
}
]
}
IoT Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iot:*",
"Resource": "arn:aws:iot:ap-northeast-1:<removed>:topic/*"
}
]
}
Test code:
import Amplify from 'aws-amplify';
import {AWSIoTProvider} from 'aws-amplify/lib/PubSub/Providers';
require('babel-polyfill');
global.app = function () {
let user = null;
const onBtn = document.getElementById("on");
const offBtn = document.getElementById("off");
Amplify.configure({
Auth: {
// REQUIRED only for Federated Authentication - Amazon Cognito Identity Pool ID
identityPoolId: 'ap-northeast-1:<removed>',
// REQUIRED - Amazon Cognito Region
region: 'ap-northeast-1',
// OPTIONAL - Amazon Cognito User Pool ID
userPoolId: 'ap-northeast-1_<removed>',
// OPTIONAL - Amazon Cognito Web Client ID (26-char alphanumeric string)
userPoolWebClientId: '<removed>',
// OPTIONAL - Enforce user authentication prior to accessing AWS resources or not
mandatorySignIn: true,
}
});
Amplify.addPluggable(new AWSIoTProvider({
aws_pubsub_region: 'ap-northeast-1',
aws_pubsub_endpoint: 'wss://<removed>.iot.ap-northeast-1.amazonaws.com/mqtt',
}));
process();
async function process() {
await Amplify.Auth.signIn("[email protected]", "Test1234567")
.then(user => {
console.log("ログインできました。")
onBtn.style.visibility = "visible";
offBtn.style.visibility = "visible";
console.log(user);
if (user.challengeName === "NEW_PASSWORD_REQUIRED") {
const currentPassword = "Test123456";
const newPassword = "Test1234567"
user.completeNewPasswordChallenge(newPassword)
.then(() => {
// winning
}).catch(error => {
console.log(error);
});
}
})
.catch(err => {
alert("ログインできませんでした。");
console.log(err);
});
Amplify.Auth.currentCredentials().then((info) => {
const cognitoIdentityId = info._identityId;
console.log(cognitoIdentityId);
});
Amplify.PubSub.subscribe('$aws/things/Air-RME-test/shadow/get/accepted').subscribe({
next: data => console.log('Message received', data),
error: error => console.error(error),
close: () => console.log('Done'),
});
Amplify.PubSub.publish('$aws/things/Air-RME-test/shadow/get', '');
}
};
Edit:
Adding the following policy to the authenticated cognito identity role, before attaching the policy solved my problem. There was also a problem with the arn I was using, so I will be using the * wildcard in the meanwhile. Will update again, once I have gotten it working.
Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:AttachPrincipalPolicy"
],
"Resource": [
"*"
]
}
]
}
Upvotes: 5
Views: 3143
Reputation: 1009
So there is one policy missing. That policy has to attach to each user that is iot:AttachPrincipalPolicy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:AttachPrincipalPolicy"
],
"Resource": [
"*"
]
}
] }
Currently, there are two ways one is through CLI and another way is through AWS Lambda Function:
'use strict';
console.log('Loading function');
var AWS = require('aws-sdk');
exports.handler = (event, context, callback) => {
console.log('Received event:', JSON.stringify(event, null, 2))
event.Records.forEach((record) => {
console.log(record.eventName);
if (record.eventName == "INSERT") {
console.log('DynamoDB Record:', JSON.stringify(record));
console.log('DynamoDB Record:', record.dynamodb['Keys']['UserId']['S']);
var user = record.dynamodb['Keys']['UserId']['S'];
const iotMgmt = new AWS.Iot();
return new Promise(function(resolve, reject) {
let params = {
policyName: "basic",
principal: user
};
iotMgmt.attachPrincipalPolicy(params, (err, res) => {
console.log("Attaching IoT policy to " + user);
if (err) {
console.error(err);
reject(err);
}
else {
resolve();
}
});
});
}
});
};
Upvotes: 4