0
votes

I need to give temporary Access Keys to my clients to connect to IoT services (publish, receive, etc.). To provide this access, I've created a Lambda function that calls sts.assumeRole to create temporary STS keys. Those keys are being created and look fine.

I'm using assumeRole with Lambda in a role with the following inline policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "iot:Connect",
                "iot:Subscribe",
                "iot:Publish",
                "iot:Receive"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "ec2:*"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "sts:AssumeRole"
            ],
            "Resource": "*",
            "Effect": "Allow"
        }
    ]
}

Note: I've added ec2 permissions to try a secondary (simplified) test.

This role has an open trust relationship:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

However, in my client code (browser), I can't connect to IoT and I receive the following error:

WebSocket connection to 'wss://my-endpoint.iot.us-east-1.amazonaws.com/mqtt?X-Amz-Algorithm=AWS4-H…Signature=my-signature' failed: Error during WebSocket handshake: Unexpected response code: 403

Trying a simplified test, I've used EC2, but received another permission error. The code used follows below (used browserify to bundle in browse).

const AWS = require('aws-sdk');

// connect to Lambda to retrieve accessKeyId and secretAccessKey
$.ajax({ 
    method: 'GET', 
    url: 'my-url',
    success: function(res) {

        // connect to EC2
        AWS.config.update({accessKeyId: res.accessKeyId, secretAccessKey: res.secretAccessKey, region: res.region});
        const ec2 = new AWS.EC2();

        ec2.describeInstances({}, function(err, data) {
            if (err) console.log(err, err.stack); // an error occurred
            else     console.log(data);           // successful response
        });
    });

Error:

POST https://ec2.us-east-1.amazonaws.com/ 401 (Unauthorized)

Error: AWS was not able to validate the provided access credentials(…) "AuthFailure: AWS was not able to validate the provided access credentials"

1

1 Answers

1
votes

Found the error. When connecting with the client, I need to provide the sessionToken created by the assumeRole.

Client code:

// connect to EC2
AWS.config.update({accessKeyId: res.accessKeyId, secretAccessKey: res.secretAccessKey, sessionToken: res.sessionToken, region: res.region});
const ec2 = new AWS.EC2();

ec2.describeInstances({}, function(err, data) {
    if (err) console.log(err, err.stack); // an error occurred
    else     console.log(data);           // successful response
});