Amazon AWS Identity and Access Management (IAM) is a powerful tool. Access for any user can be granted or denied, even on individual API calls. Security is always a concern for all users, and Amazon AWS provides a resource that can further prevent unauthorized access. Multi-Factor Authentication (MFA) requires a user to present two or more independent credentials to gain access. Simply put, Multi-Factor Authentication provides more than one layer of defense to prevent an unauthorized breach. Even on individual API calls, you can specify whether MFA must be enabled in order for the API to return data. In order to ensure all users are using MFA, we’re going to build a Lambda function that will find all users that are lacking both a physical MFA device and a Virtual MFA device. This list of users will then be sent daily to an SNS topic so that the users can be instructed to enable MFA.
This walkthrough will demonstrate how to use and create the following:
- MFA types and calls
- Python implementation of logic
- AWS Identity and Access Management (IAM) Policy, and Role definition for Lambda function
- AWS Lambda function creation
MFA Types and API Calls to Describe MFA Devices
There are two API calls Amazon AWS provides for checking whether MFA is enabled, list_mfa_devices and list_virtual_mfa_devices. The call list_mfa_devices checks which users have physical MFA enabled. The request syntax accepts a UserName, so it’s simple to check which users have physical MFA. The call list_virtual_mfa_devices lists all virtual MFA devices on the AWS instance. The request syntax for list_virtual_mfa_devices does not accept a UserName, but the response syntax returns which users have virtual MFA.
The function checks if a user lacks both a virtual MFA device and a physical MFA device. The API calls for physical and virtual MFA take different parameters, so it’s not as simple as looping through users and passing a UserName to both calls. Once it discovers who does not have MFA enabled, it publishes a list of UserNames to an SNS topic that we’re going to name “MfaLacking”.
Required IAM Policy and Role
AWS Lambda can invoke AWS APIs through a number of different SDKs, but only if it has proper permissions to do so. Permissions in this context are two-fold:
- Allow AWS Lambda to call AWS APIs on your behalf (Service Role/Trust Relationship)
- Allow specific API actions for the Role (Policy)
The steps to create this function are as follows:
- Create the policy. From the AWS Console, navigate to Identity and Access Management (IAM) and find the Policies tab.
- Create a Policy by using the Policy Generator. For the AWS Service input select “AWS Identity and Access Management”. We will then need 3 “Actions” selected: ListMFADevices, ListUsers, and ListVirtualMFADevices. The “Amazon Resource Name” input set to *. After selecting the actions, you must select the “Add Statement” button for them to be added to the policy.
- Select Next Step and after providing a name and description, then select the “Create Policy” button.
- Create the IAM Role associated with this policy created above by selecting the Roles tab, then selecting the “Create Role” button and specifying AWS Lambda as the Service Role. Next, attach the recently created Policy (from the previous step) and review before creating.
- Create an SNS topic by navigating to the SNS from the AWS Console and select “Create New Topic”. As shown below, enter the “Topic name” of “mfa_lacking” and the “Display name” of “MfaLacking”. The “Display name” must be 11 characters or less.
- Copy the “Topic ARN” after clicking create topic (as shown below). We will use the “Topic ARN” to assign policy permissions for this topic.
- From the AWS Console, navigate to Identity and Access Management (IAM) and select the Policies tab. Select Create Policy and then select Policy Generator.
- For AWS Service, select Amazon SNS. For Actions, select Publish. For Amazon Resource Name, paste the ARN number of the topic you copied earlier. This gives this role the ability to publish to only this SNS topic.
AWS Lambda Function
It is easiest to create Lambda functions using the web console, but you can also use the CLI or SDKs to accomplish the same result.
From the AWS Console , navigate to Lambda and continue on to create a function without using a blueprint (click the “Skip” button).
The following sections shown below should be set as follows:
- “Name” should be “dailyMfaCheck”
- “Description” is what the function does, and the “Runtime” is Python 2.7
- “Handler” should be “lambda_function.lamda_handler”
- “Role” should be “lamda_mfa_role”, the role we created with all the permissions above
- “Timeout” should be increased to 10 seconds, in case you have a large list of users the function must iterate over. Even if you do not have a large list of users, your user list may grow over time. The timeout increase will prevent the function from stopping prematurely
Examples and Benchmarks
Here’s an example of an email sent to someone subscribed to the SNS topic we created:
- This AWS instance had a small amount of users, and it still took 4 seconds for this command to run. If there are a large number of users, it may be necessary to increase the amount of time the function is allowed to run (the timeout value) or increase the memory allocation (to increase performance). Either can be edited in the Lambda function “Configuration” tab and selecting “Advanced settings” as shown below:
- When publishing to an SNS Topic, no one is required to subscribe to that topic. If the goal is to alert users that do not have MFA, they must be subscribed to the topic in order to receive the notification.
- AWS Lambda is only available in some regions, preventing some users from being able to run Lambda functions.