aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.42k stars 2.12k forks source link

PubSub Websocket: "AMQJS0008I Socket closed." when trying to subscribe #2739

Closed BenediktMiller closed 5 years ago

BenediktMiller commented 5 years ago

Describe the bug I followed the tutorial to create Auth for my React App, then I followed the tutorial on using PubSub with AWS IoT. The first Problem I encountered was that using the pubsub endpoint: wss://xxxxxxx-iot.eu-central-1.amazonaws.com/mqtt resulted in a "legancy certificate error" (I am using chrome) so i replaced the endpoint with wss://xxxxxxx-ats.iot.eu-central-1.amazonaws.com/mqtt. Now as soon as I try to subscribe I get the following error: {invocationContext: undefined, errorCode: 8, errorMessage: "AMQJS0008I Socket closed."}

I have attached the Policy using the command from the tutorial, but since attach-principal-policy is deprecated I also tried: aws iot attach-policy --policy-name 'myIOTPolicy' --target 'eu-central-1:xxxxxxxxxxxxxxxxxxx'

To Reproduce

  1. Follow all the steps from the tutorial for setting up a react app, adding auth and using PubSub. Expected behavior A clear and concise description of what you expected to happen.

Desktop (please complete the following information):

This might be just an issue with the documentation

mbonig commented 5 years ago

Having the same problem, and it seems like all the solutions on all other forums are not working here. Can say I'm seeing the exact same issue (except using Ionic instead of React)

kevin-mitchell commented 5 years ago

I just want to say I'm having the exact same issue. Or at least the symptoms appear the same to me.

All of my testing is on localhost:3000 if that matters - this is using React.

@mbonig actually helped me a bit on gitter as I believe he resolved the issue he was having and I believe his recommendation was to use the specific Cognito identity ID (rather than the aws_cognito_identity_pool_id from the aws-exports.js file) but I've added both and get the same results.

My policy looks like

(ARN is arn:aws:iot:us-west-2:XXXXXX:policy/webIoT)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:*",
      "Resource": "arn:aws:iot:us-west-2:XXXXXXXX/*"
    }
  ]
}

I used both the depreciated aws iot attach-principal-policy.... (docs should be updated) as well as the correct aws iot attach-policy... but no difference. I'm fairly certain the policy is attached correct though, because when I list out the targets attached to the policy I created both the targets that come back match what I set (one of them is the identity pool id, one of them is the specific cognito user from Auth.currentCredentials()...)

aws iot list-targets-for-policy --policy-name 'webIoT' --profile amplify-fdk92-test
{
    "targets": [
        "xxxx:us-west-2:zzzzzz",
        "yyyy:us-west-2:aaaaa"
    ]
}

My actual "app" (App.js, starting from a simple starter React project) looks like this (I didn't make this pretty, sorry!):

import Amplify, { Auth, PubSub, Logger } from "aws-amplify";
import { AWSIoTProvider } from "@aws-amplify/pubsub/lib/Providers";
import config from "./config";
import { withAuthenticator } from "aws-amplify-react"; // or 'aws-amplify-react-native';
// import { withOAuth } from "aws-amplify-react";
import React, { Component } from "react";
import {
  BrowserRouter as Router,
  Route,
  Link,
  Redirect
} from "react-router-dom";
import "./App.css";

Amplify.Logger.LOG_LEVEL = "DEBUG";

Amplify.configure(config);

//This doesn't really do anything here, but the cognitoIdentityId was used for attaching the policy
Auth.currentCredentials().then(info => {
  const cognitoIdentityId = info._identityId;
  console.log("cognito identity id", cognitoIdentityId);
});

Amplify.addPluggable(
  new AWSIoTProvider({
    aws_pubsub_region: "us-west-2",
    aws_pubsub_endpoint:
      "wss://XXXX.iot.us-west-2.amazonaws.com/mqtt"
  })
);

//Only reason I'm waiting here is just as a sanity check that there isn't a race condition I'm missing with how auth works
setTimeout(() => {
  PubSub.publish("topic/test", {
    msg: "Hello to all subscribers!"
  }).then(data => {
    console.log("data is ", data);
    data[0].then(blah => console.log(blah)).catch(blah => console.log(blah));
  });
}, 5000);

And finally, the actual output from when the timeout above fires and the publish happens:

ConsoleLogger.js:97 [DEBUG] 01:10.137 Credentials - getting credentials
ConsoleLogger.js:97 [DEBUG] 01:10.138 Credentials - picking up credentials
ConsoleLogger.js:97 [DEBUG] 01:10.139 Credentials - getting new cred promise
ConsoleLogger.js:97 [DEBUG] 01:10.139 Credentials - checking if credentials exists and not expired
ConsoleLogger.js:107 [DEBUG] 01:10.140 Credentials - is this credentials expired? CognitoIdentityCredentials {expired: false, expireTime: Tue Apr 09 2019 19:01:05 GMT+0900 (Japan Standard Time), accessKeyId: "XXXXXXX", sessionToken: "XXXXXX//////////XXXXXXX…ph/XXXXXXX/XXXXXXX/XXXXXXXX=", params: {…}, …}
ConsoleLogger.js:97 [DEBUG] 01:10.140 Credentials - credentials not changed and not expired, directly return
App.js:38 data is  [Promise]
ConsoleLogger.js:99 [DEBUG] 01:10.144 Signer {region: "us-west-2", service: "iotdevicegateway"}
ConsoleLogger.js:107 [DEBUG] 01:10.146 MqttOverWSProvider - Creating new MQTT client 2fa6b4a0-f880-4544-869a-XXXXXXXXX
App.js:39 {invocationContext: undefined, errorCode: 8, errorMessage: "AMQJS0008I Socket closed."}

edit: I get the exact same behavior if I try to subscribe to a topic instead of publish.

I'm not sure if my exmaple code above matches the AWS Amplify docs for PubSub 1:1, however I started with the PubSub docs and had this same issue. Then I went on from there and googled a bunch and found a number of people with the same issue(s), a number of different solutions, but none of them seemed to work from me.

It's possible that I am simply not using a valid topic name (?), or something stupid, I'm really at the early stages of understanding a lot of this. Regardless, from what I can tell something might be missing from the docs, even if that something is just a more complete "for dummies" example.

1f47a commented 5 years ago

I was able to resolve this error by attaching the AWSIoTDataAccess policy to the Cognito AuthRole

Cayce commented 5 years ago

Had the same error, changing IOT Core policy solved the problem for me:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:*",
      (NOT WORKS) "Resource": "arn:aws:iot:us-west-2:XXXXXXXX/*"
      (WORKS) "Resource": "*"
    }
  ]
}

My guess is that previous policy gave permission to subscribe/publish to topics, but didn't gave the permission to connect. Amplify JS PubSub docs can be improved IMHO.

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

mbonig commented 5 years ago

Had the same error, changing IOT Core policy solved the problem for me:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:*",
      (NOT WORKS) "Resource": "arn:aws:iot:us-west-2:XXXXXXXX/*"
      (WORKS) "Resource": "*"
    }
  ]
}

My guess is that previous policy gave permission to subscribe/publish to topics, but didn't gave the permission to connect. Amplify JS PubSub docs can be improved IMHO.

This solution should only be relevant in explaining the underlying issue. Please do not put * for resource identifiers. This is a massive security hole and goes against all best practices with IAM policies.

hanezu commented 5 years ago

I also had the same error and was only able to resolve it by changing the policy to "Resource": "*". Wondering if there are any better practices.

hanezu commented 5 years ago

Just literally did a brute force search over different specifications of "Resource", and below are my findings.

The ones that worked:

      "Resource": [
        "*"
      ]
      "Resource": [
        "arn:aws:iot:[region]:[AWS account ID]:*"
      ]
      "Resource": [
        "arn:aws:iot:[region]:[AWS account ID]:topic/*",
        "arn:aws:iot:[region]:[AWS account ID]:topicfilter/*",
        "arn:aws:iot:[region]:[AWS account ID]:client/*"
      ]

The ones that did not work:

      "Resource": [
        "arn:aws:iot:[region]:[AWS account ID]:topic/*"
      ]
      "Resource": [
        "arn:aws:iot:[region]:[AWS account ID]:topic/*",
        "arn:aws:iot:[region]:[AWS account ID]:client/*"
      ]

I referred to this doc when iterating over available resources. So my guess is we simply need to add a bit more resource for subscribing if necessary.

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 5 years ago

This issue has been automatically closed because of inactivity. Please open a new issue if are still encountering problems.

maximelebastard commented 4 years ago

Hello, I still have this issue. The IoT Policy is well attached, I tried to put the Resource to "*" for the Iot Policy. I also tried to attach the identity_id from the aws-exports.js file. But it still don't work. I tried to redo the procedure from scratch, it stills don't work.

doraeball22 commented 4 years ago

I have the same issue. I have attached policy by following the amplify pubsub document. Anyone has some example?

xXGoth117Xx commented 3 years ago

Hi, Everyone I have the same issue and I dont know how to resolve, in my auth Role I attached the policies AWSIoTConfigAccess and AWSIoTDataAccess.

My IoT Policy is: { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "", "Resource": "" } ] }

The command to attach the policy to cognito:

aws iot attach-principal-policy --policy-name "IoTPolicy" --principal "us-west-2:xxxx-xxx-xxx-xxx-xxxxxx" --region us-west-2

image

But I have the same result:

image

Please help me

zigsolutions commented 3 years ago

I am also experiencing this issue BUT I did get it to work by following the guide below.

https://docs.amplify.aws/lib/pubsub/getting-started/q/platform/js#step-2-attach-your-policy-to-your-amazon-cognito-identity

Step 1: Create IAM policies for AWS IoT Step 2: Attach your policy to your Amazon Cognito Identity Step 3: Allow the Amazon Cognito Authenticated Role to access IoT Services

I created a new IAM policy for AWS IoT with the policy below and attached it to the Cognito Authenticated Role attached to the application as detailed in Step 1.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:*",
      "Resource": "arn:aws:iot:us-east-1:xxxxxxxxxxxxx:*"
    }
  ]
} 

After creating the IAM policy for AWS IoT, I added access to IoT Services for the Cognito Authenticated Role.

The part that messed me up at first was Step 2, attaching the policy to the Amazon Cognito Identity of the new user. I had to pull this value from the Auth Module in my javascript code using Auth.currentCredentials() and getting the value of info.IdentityId as detailed in Step 2.

I created a dashboard in Vue and use the JS AWS SDK with AWS Cognito, PubSub, etc. I am able to create users, authenticate them and even use the PubSub library for users after I run the command below from Step 2:

aws iot attach-principal-policy --policy-name 'myIoTPolicy' --principal '<YOUR_COGNITO_IDENTITY_ID>'

If I don't add the policy that I created to each new user I get this error message in the console:

errorCode: 8, errorMessage: AMQJS0008I Socket closed.

I also tried the following as others have suggested but still had to attach the policy to the Amazon Cognito Identity of the new user by running the CLI command in Step 2.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:*",
      "Resource": "*"
    }
  ]
} 

So when new users sign up I am forced to attach the policy to each users Cognito Identity manually in order for that user to have access and interact with AWS IoT. I'm having trouble trying to figure out a way to automatically attach the IAM policy I created above to a new Cognito Identity automatically/programmatically instead of manually for each user as detailed in the link in "Step 2."

So the questions that I have are: 1) Is there is a way to automate this process instead of using the CLI to run this command for each new user? 2) Is there another way to approach this so that you aren't required to manually run this command on each new user that signs up and is added to the User Pool?

I've tried to create a Lambda function but can't figure out how to pull the Cognito Identity Id in for that user. I can pull in other information like sub, email, etc. I am however able to pull the Cognito Identity Id from the Vue app.

I was thinking if I could pull the Cognito Identity Id into a Lambda function, then run the AWS CLI command to attach the policy to the new user, then I'd be good to go but that seems to be pretty tricky to set up. I was wondering if anyone had any ideas or insight and has encountered this? Maybe I'm approaching this the wrong way or missed something...

Thank you so much in advance!

github-actions[bot] commented 2 years ago

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.