AWS IoT Core / mqtt.js - After Successful Topic Subscription, Still Not Able To Run a Callback On a Message

0

I'm trying to use the mqtt.js (https://github.com/mqttjs/MQTT.js) library in order to interact with the AWS IoT Core endpoint with the following code:

const mqtt = require("mqtt");

const IOT_ENDPOINT = "wss://xxxxxx-ats.iot.eu-central-1.amazonaws.com";
const client = mqtt.connect(`${IOT_ENDPOINT}/mqtt?x-amz-customauthorizer-name=Authorizer`);

client.on("connect", () => {
    client.subscribe("xyz", err => {
        if (!err) {
            // Works, I can see the message in AWS Console / MQTT test client.
            const dt = new Date().toISOString();
            client.publish("xyz", JSON.stringify({ message: "CURRENT DT:" + dt }));
        }
    });
});

// The callback never gets executed, nothing is printed in the console.
client.on("message", (topic, message) => {
    console.log("Message received.");
    client.end();
});

What's interesting is that I can see the published message in the xyz topic in the AWS Console / MQTT test client. Great!

What I can also see is that there are no messages being printed in my terminal, despite the fact that the client.subscribe call did not throw any errors (in other words, topic subscription was successful), and I am able to publish messages on the same topic from the AWS Console / MQTT test client.

I've tried multiple things, changing params when connecting, trying different variations of the code, no luck 😩.

My next idea on how to debug is to try enabling IOT CW logs and see if anything is logged in there maybe.

Until then, my question is: anybody have any suggestions on what else to check why nothing is being printed in my terminal?

Thank you!🍻

UPDATE: Sharing my AWS Lambda authorizer code, maybe it's something related to permissions? 🤔

module.exports.handler = async (event, _, callback) => {
    return ({
        isAuthenticated: true,
        principalId: 'Unauthenticated',
        policyDocuments: [
            {
                "Version": "2012-10-17",
                "Statement": [
              
                    {
                        "Effect": "Allow",
                        "Action": "iot:Connect",
                        "Resource": "arn:aws:iot:*:*:client/*"
                    },
                    {
                        "Effect": "Allow",
                        "Action": "iot:Subscribe",
                        "Resource": [
                             // Added '*' for testing purposes.
                            '*',
          "arn:aws:iot:*:*:client/*",
                            "arn:aws:iot:*:*:topicfilter/server"
                            
                            
                        ]
                    },
                    {
                        "Effect": "Allow",
                        "Action": "iot:Publish",
                        "Resource": [
                            "arn:aws:iot:*:*:client/*",
                            "arn:aws:iot:*:*:topic/xyz"
                        ]
                    }
                ]
            }
        ],
        disconnectAfterInSeconds: 3600,
        refreshAfterInSeconds: 300
    });
};
profile picture
Adrian
質問済み 1ヶ月前124ビュー
3回答
1
承認された回答

Hi Adrian,

in your code your subscribe to the topic xyz but your policy allows only to subscribe to the topic server. You don't need the client-resource in the publish or subscribe actions. You can find some sample IoT policies at https://docs.aws.amazon.com/iot/latest/developerguide/pub-sub-policy.html. Might be our blog about using standard MQTT libraries with AWS IoT Core can also provide some guidance for you.

Cheers,
Philipp

AWS
エキスパート
回答済み 1ヶ月前
profile picture
エキスパート
レビュー済み 1ヶ月前
1

It seems that your AWS Lambda authorizer configuration might be the source of the issue. Your authorizer is configured to allow the "iot:Subscribe" action on specific resources, including the topic "server", but it does not explicitly allow subscription to the "xyz" topic, which your client is subscribing to.

To fix this, you should add an explicit permission for subscribing to the "xyz" topic in your authorizer's policy document. Here's how you can modify your policy document:

{
    "Effect": "Allow",
    "Action": "iot:Subscribe",
    "Resource": [
        "*",
        "arn:aws:iot:*:*:client/*",
        "arn:aws:iot:*:*:topicfilter/server",
        "arn:aws:iot:*:*:topicfilter/xyz"  // Add this line to allow subscription to the "xyz" topic
    ]
}

After updating your authorizer's policy document, redeploy it and retry your MQTT client code. This should resolve the issue and allow your client to receive messages from the "xyz" topic.

profile picture
エキスパート
回答済み 1ヶ月前
0

Hey everybody, thanks for your answers and leading me to further inspect the permissions returned from the Lambda function authorizer.

Here's the policy I'm now returning and that finally works:

module.exports.handler = async (event, _, callback) => {
    return ({
        isAuthenticated: true,
        principalId: 'Unauthenticated',
        policyDocuments: [
            {
                "Version": "2012-10-17",
                "Statement": [

                    {
                        "Effect": "Allow",
                        "Action": "iot:Connect",
                        "Resource": "arn:aws:iot:*:*:client/*"
                    },
                    {
                        "Effect": "Allow",
                        "Action": "iot:Subscribe",
                        "Resource": [
                            "arn:aws:iot:*:*:topicfilter/xyz"
                        ]
                    },
                    {
                        "Effect": "Allow",
                        "Action": "iot:Publish",
                        "Resource": [
                            "arn:aws:iot:*:*:topic/xyz"
                        ]
                    },
                    {
                        "Effect": "Allow",
                        "Action": [
                            "iot:Receive"
                        ],
                        "Resource": [
                            "arn:aws:iot:*:*:topic/xyz"
                        ]
                    }
                ]
            }
        ],
        disconnectAfterInSeconds: 3600,
        refreshAfterInSeconds: 300
    });
};

The thing I was actually missing was the last iot:Receive action:

{
  "Effect": "Allow",
  "Action": [
    "iot:Receive"
  ],
  "Resource": [
    "arn:aws:iot:*:*:topic/xyz"
  ]
}

I saw this in the https://docs.aws.amazon.com/iot/latest/developerguide/pub-sub-policy.html article that Philipp shared. So I decided to mark his reply as the answer to my question. 😉

Thanks again guys for providing help!

Cheers! 🍻🍻

profile picture
Adrian
回答済み 1ヶ月前

ログインしていません。 ログイン 回答を投稿する。

優れた回答とは、質問に明確に答え、建設的なフィードバックを提供し、質問者の専門分野におけるスキルの向上を促すものです。

質問に答えるためのガイドライン

関連するコンテンツ