In the IT Industry, it is common not to realize that many security teams today have to instruct engineers to use Multi-Factor Authentication on cloud accounts. As a result, hackers have an easy way to hack cloud accounts. This blog post explains in detail how to enable MFA in AWS and how does IAM support Multi-Factor Authentication?
|TABLE OF CONTENT|
|2. AWS Lambda|
|3. AWS CloudFormation|
|4. AWS Eventbridge|
The problem statement got formulated when we saw that there are many users in our AWS infrastructure who are not using Multi-Factor Authentication (MFA) in AWS and because of this our Security Hub Score was also getting impacted. I had just started to learn cloud and I thought of solving the problem statement using some level of automation and by AWS IAM MFA policies.
But before I dig deeper, first things first, Let me brief you about a few services/resources of AWS I have used to achieve the goal and also learn how do you enable MFA with IAM users?
AWS Lambda is a serverless, event-driven compute service that lets you run code for virtually any type of application or backend service without provisioning or managing servers. By Serverless we mean you don’t need to maintain your servers to run lambda functions. It is a compute service that lets you run the code without provisioning or managing the server. You can trigger Lambda from over 200 AWS services and software as a service (SaaS) applications and only pay for what you use. Our Lambda function will get the AWS IAM Users on which MFA security is not enabled, create our custom-made MFA policy, and attach it to the IAM User. We will be scheduling events that will run our Lambda code every day at a defined interval of time.
AWS CloudFormation is an Infrastructure as a Code(IAC) service that helps you model and set up your AWS resources so that you can spend less time managing those resources and more time focusing on your applications that run in AWS. CloudFormation is defining the template which will automatically provision and set up the infrastructure for you.
Classic Example: Defining the stack which will create EC2 Instance, Install WordPress, Setup Security Groups, RDS for you, and get your static website up and running in minutes.
How does CloudFormation work? For the CloudFormation service to work, you create a template that describes all the AWS resources that you want (like Amazon EC2 instances or Amazon RDS DB instances), and CloudFormation takes care of provisioning and configuring those resources for you. You don’t need to individually create and configure AWS resources and figure out what’s dependent on what, CloudFormation handles that for you.
Amazon EventBridge is a serverless event bus that makes it easier to build event-driven applications at scale using events generated from your applications, integrated Software-as-a-Service (SaaS) applications, and AWS services. For our use case, we used AWS Eventbridge to schedule an event. We will be using AWS Eventbridge to trigger our Lambda at our desired time.
We will be using slack to send notifications whenever there is any IAM Enforce MFA policy attached to an IAM User.
Before we dig deeper, In a nutshell, to understand our methodology, whenever we deploy our stack using the CloudFormation template, a lambda function is created which makes a JSON Policy so that whenever there is a violation of our MFA, it automatically attaches the Enforce MFA Policy to an IAM User. As a result of which, IAM user is forced to set up multi-factor authentication. Once the policy is attached, our lambda triggers a slack notification.
We have defined two environment variables in Lambda’s Configuration section which we have used in our Lambda function
- WEBHOOK_URL: This Environment variable we have used to define the Webhook URL for slack in order to trigger a slack notification from our Lambda.
- WHITELIST_TAG: At times, there are service accounts that are created as an IAM User(Though not a good practice). Instead, We should consider using IAM Roles for Service Accounts.
We have imported various Libraries which we will be using to achieve the objective.
We have a defined policy that will be created in every account wherever our lambda runs. For policy, we have used Deny all approach i.e. We have just allowed users to set up MFA security and perform basic tasks.
The above headers variable is used for sending our notification to our slack.
We have defined global variables, Global Variable in the coding world means that the variable can be used by all the functions and they can directly perform actions on that.
When Lambda is triggered, lambda_handler is the first function that is executed. Our lambda will make sure of the following on every run:-
- If the Policy JSON already exists in the account, if not it will create the IAM policy so that it can attach to the users. The reason to check and create policy in the lambda function itself is to scale our lambda function and reduce the manual efforts of creating an IAM policy for every account. Nowadays, most companies use multiple accounts for their various use cases, so it becomes inefficient for us to create an IAM policy for every account. The function used is: is_policy_exist()
- Check whether the user is already whitelisted: We are whitelisting users if it is a service account or any other account which is defined in the WHITELIST_TAG environment variable. The function used is: is_user_whitelisted()
- We will not attach the policy if Enforce MFA policy is already attached to the user. This may have happened in the old run. The function used is:
- Our Lambda will not attach policy if the user has already set up MFA. The function used is: is_mfa_enabled()
get_account_alias(): The main objective of this function is to get the Alias Name so that it becomes easy for us to recognize the account whenever we receive a notification. As we all know, it is easy to remember names than numbers.
As the name suggests, we have used this function to send notifications to our slack channel if MFA on service accounts is attached to any user or our lambda failed in some way or the other.
The classic use case which we encountered because of which our Lambda didn’t work was AWS constraints on how many policies(AWS Managed + Customer Managed) can be attached to an IAM User. We found that only 10 policies in total can be attached. So in case, there are 10 policies already attached, our objective to enforce MFA on IAM users who have not enabled MFA would fail badly.
In order to get this resolved, we have used the get_attached_policy_count() function which will do the heavy lifting for us.
Since we now understand the flow of our lambda function, Let’s get our hands rolling on the CloudFormation template.
Let’s look at our CFT-:
You can see the resources tab in EnforceMFA Stack which shows what all resources were used by our Stack set.
Line 8 – 35:
We have defined Parameters in the Parameters section of Stacks. Our CFT is expecting the following parameters:
- LambdaHandler: This executes the lambda_handler() function of our lambda code.
- S3Bucket: Where our Lambda code is stored.
- S3Key: The filename
- SlackChannelName: Slack channel where we want to receive a notification.
- SlackWebhookParameter: Slack Webhook URL
- WhitelistTag: The key: value pair against which we want to whitelist IAM Users(Eg: userType: Service).
We have created IAM Policy for our Lambda function in order to authorize our Lambda to make changes to an IAM user or make changes in our AWS account.
ScheduleRule block is the rule used to trigger EventBridge Service of AWS which helps us to run our EnforceMFALambda every 12PM(UTC).
By Combining all the above blocks, we were able to achieve our main objective of getting our IAM users to set up multi-factor authentication. Using CloudFormation stack sets helped us to Scale so that whenever a new account is spun up, the same stack will be created, hence giving us better AWS security.
GitHub and aws.amazon.com/blogs for helping me whenever I get stuck.