avatar
Grant IAM Permissions for Assumed Role Lambda

In AWS, an assumed role is a set of permissions that can be temporarily assigned to an IAM user, AWS service, or an external user (such as an AWS Identity Federation user) to access AWS resources securely.

We will illustrate the usage context of an assumed role as below:

As you can see, the assumed role was created successfully when we initialized the new Lambda function. Here is the code for this Lambda.

» index.js

const crypto = require('crypto');
const { outboundVoiceFunc } = require('./MFA.js');

exports.handler = async (event) => {

    let otpCode = crypto.randomInt(100000, 999999).toString(); 
    const optCodeStr = otpCode.toString().split('').join(' ');
    
    await outboundVoiceFunc({
      phoneNumber: '+12139156465',
      contactFlowId: 'fda6f30e-6cbf-4d78-87ca-94164ae2baa4',
      verificationCode: optCodeStr
    });
  return event;
};
Note: We add spaces between digits to ensure that each digit is read aloud distinctly (spaces will slow down the reading of the next digit).

» MFA.js

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

AWS.config.update({ region: process.env.region });
const connect = new AWS.Connect();

async function outboundVoiceFunc(params) {
  try {
    const { phoneNumber, contactFlowId, otpCodeStr } = params; 

    const connectParams = {
      DestinationPhoneNumber: phoneNumber,
      ContactFlowId: contactFlowId, 
      InstanceId: '8e5bb349-23f0-478a-ac58-e09ba143ec3a', 
      SourcePhoneNumber: '<claim phone number>', 
      Attributes: { 'VoiceMFA': otpCodeStr }
    };

    await connect.startOutboundVoiceContact(connectParams).promise();
  } catch (error) {
    console.error('Error initiating the call', error);
    throw error;
  }
}

module.exports = { outboundVoiceFunc };

Following that, you will see `connect.startOutboundVoiceContact`, which is the function used to access the AWS Connect service from the Lambda function.

ERROR	Error initiating the call AccessDeniedException: User: arn:aws:sts::<aws account id>:assumed-role/outboundCallRole/outboundCallFunc is not authorized to perform: connect:StartOutboundVoiceContact on resource: arn:aws:connect:ap-southeast-1:<aws account id>:instance/8e5bb349-23f0-478a-ac58-e09ba143ec3a/contact/*

Here, you will check if your AWS account has permission to access IAM for modifying the outboundCallRole. This applies to:

- The management account (AWS Account)

- IAM users managed by Control Tower with granted permissions to access IAM.

Now, navigate to Identity and Access Management (IAM) to review all configurations.

When you log in under an IAM user, you can see permissions associated with the email in profile name, like `AWSAdministratorAccess/[email protected]`. On the other hand, with the root account, you won't see it.

Let us make a slight distinction between User Groups and Users. In practice, User Groups represent groups of users within the organization, typically organized by department or role. 

For instance, User Groups could include Administrators, Developers, DevOps, Maintainers, and TechLeads.

Let us navigate to the Roles menu in the IAM dashboard sidebar. From there, we will search for `outboundCallRole` and add an inline policy for this assumed role.

As you can see, we need to add ARN to the `Resource` field to limit the scope of impact for this policy. The action should only be executed within the outboundCallFunc Lambda function.

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "Statement2",
			"Effect": "Allow",
			"Action": [
				"connect:StartOutboundVoiceContact"
			],
			"Resource": "arn:aws:lambda:ap-southeast-1:<AWS Account ID>:function:outboundCallFunc"
		}
	]
}

Note: To locate the ARN needed for the policy, open the `outboundCallFunc` Lambda function.

You need to login to do this manipulation!