Many organisations will want to enforce MFA for an added security layer for their users. As each service is different, in some cases enforcing MFA may not be as easy as it sound.
In AWS, an administrator cannot simply “tick” to enable MFA on all users (as of this writing). However, MFA can be enforced on API calling, to “force” a user to setup MFA. Think of it as a backdoor, to forcing or enabling MFA on all your IAM users.
The only way in which that can be achieved, is by creating a policy. This policy is a based on a JSON script. You could use AWS for that, or Visual Studio.
In this blog, I will demonstrate how to enforce MFA in AWS for all your IAM users. This blog will not go through setting up MFA for IAM users. This could be achieved by following the steps here .
This blog assumes you have some AWS knowledge and experience, and will not go into detailing how to attach a policy or step-by-step creating a policy, this can be found here .
How Does AWS define MFA?

AWS Multi-Factor Authentication (MFA) is a simple best practice that adds an extra layer of protection on top of your user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password (the first factor—what they know), as well as for an authentication code from their AWS MFA device (the second factor—what they have). Taken together, these multiple factors provide increased security for your AWS account settings and resources.
You can enable MFA for your AWS account and for individual IAM users you have created under your account. MFA can be also be used to control access to AWS service APIs.

You can read more about it here.
What is API Calling?
Enforcing MFA on API calling means that an IAM user, for example will not be able to make any changes to EC2 instances, or launch new EC2 instances unless they’re MFA authenticated. Even if users have full admin permissions.
This is not to be confused with enforcing MFA upon signing in, the IAM user will still have to setup MFA to complete tasks in AWS.
Not very descriptive, but an IAM user will be faced with the following error messages if MFA isn’t setup.
ec2
In terms of Route53, the IAM users will have different error messages.
route53
In this case, it is up for administrators to let IAM users know that MFA should be setup upon signing in.
Setting up and creating the MFA Policy
The MFA policy that we will create and apply, will only allow the use of IAM services, for users to setup their MFA, among other configurations.
iam
IAM Policy:
[code language=”javascript”]
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAllUsersToListAccounts",
"Effect": "Allow",
"Action": [
"iam:ListAccountAliases",
"iam:ListUsers",
"iam:GetAccountPasswordPolicy",
"iam:GetAccountSummary"
],
"Resource": "*"
},
{
"Sid": "AllowIndividualUserToSeeAndManageOnlyTheirOwnAccountInformation",
"Effect": "Allow",
"Action": [
"iam:ChangePassword",
"iam:CreateAccessKey",
"iam:CreateLoginProfile",
"iam:DeleteAccessKey",
"iam:DeleteLoginProfile",
"iam:GetLoginProfile",
"iam:ListAccessKeys",
"iam:UpdateAccessKey",
"iam:UpdateLoginProfile",
"iam:ListSigningCertificates",
"iam:DeleteSigningCertificate",
"iam:UpdateSigningCertificate",
"iam:UploadSigningCertificate",
"iam:ListSSHPublicKeys",
"iam:GetSSHPublicKey",
"iam:DeleteSSHPublicKey",
"iam:UpdateSSHPublicKey",
"iam:UploadSSHPublicKey"
],
"Resource": "arn:aws:iam::*:user/${aws:username}"
},
{
"Sid": "AllowIndividualUserToListOnlyTheirOwnMFA",
"Effect": "Allow",
"Action": [
"iam:ListVirtualMFADevices",
"iam:ListMFADevices"
],
"Resource": [
"arn:aws:iam::*:mfa/*",
"arn:aws:iam::*:user/${aws:username}"
]
},
{
"Sid": "AllowIndividualUserToManageTheirOwnMFA",
"Effect": "Allow",
"Action": [
"iam:CreateVirtualMFADevice",
"iam:DeleteVirtualMFADevice",
"iam:EnableMFADevice",
"iam:ResyncMFADevice"
],
"Resource": [
"arn:aws:iam::*:mfa/${aws:username}",
"arn:aws:iam::*:user/${aws:username}"
]
},
{
"Sid": "AllowIndividualUserToDeactivateOnlyTheirOwnMFAOnlyWhenUsingMFA",
"Effect": "Allow",
"Action": [
"iam:DeactivateMFADevice"
],
"Resource": [
"arn:aws:iam::*:mfa/${aws:username}",
"arn:aws:iam::*:user/${aws:username}"
],
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
},
{
"Sid": "BlockMostAccessUnlessSignedInWithMFA",
"Effect": "Deny",
"NotAction": [
"iam:CreateVirtualMFADevice",
"iam:DeleteVirtualMFADevice",
"iam:ListVirtualMFADevices",
"iam:EnableMFADevice",
"iam:ResyncMFADevice",
"iam:ListAccountAliases",
"iam:ListUsers",
"iam:ListSSHPublicKeys",
"iam:ListAccessKeys",
"iam:ListServiceSpecificCredentials",
"iam:ListMFADevices",
"iam:GetAccountSummary",
"sts:GetSessionToken"
],
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
}
]
}
[/code]
If you want to enforce MFA on particular groups or users, then you will have to include them as follows.
Example:
[code language=”javascript”]
"Resource": [
"arn:aws:iam::*:group/AmazonEC2FullAccess:mfa/*",
"arn:aws:iam::*:group/AmazonEC2FullAccess:user/${aws:username}",
"arn:aws:iam::*:group/AmazonAppStreamFullAccess:mfa/*",
"arn:aws:iam::*:group/AmazonAppStreamFullAccess:user/${aws:username}"
]
},
[/code]

Note that in the script, in resource we specified all groups by adding * at the end. Same applies for users if you need to include all users.

Example:
[code language=”javascript”]
"Resource": [
"arn:aws:iam::123456789:group/*"
]
},
[/code]

Previously created users may have to have this policy attached to them manually. Creating IAM users after creating this policy will be attached to the newly created users by default.

I hope you found this blog informative. Please feel free to post your comments below.
Thanks for reading.

**** Updated 13th December 2017 ****

IAM policy has been changed to address security shortcomings identified by DUO as described here. Many thanks to Scott Piper who alerted us to this gap in the original blog post.  Cheers!

Category:
Amazon Web Services, Cloud Infrastructure, Identity and Access Management, Security, User Experience, WebAPI