Enforce MFA for AWS IAM users.

Jose López
July 29th, 2019 · 1 min read

AWS Multi-Factor Authentication (MFA) 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 response 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.

In this article, we are going to explain how to enforce the usage of MFA for your IAM users (in the Console and in awscli) by using a custom policy that requires that MFA is enabled to perform any action. We are also going to provide a custom script to automate session token generation (required to use awscli).

Policy to enforce MFA for AWS IAM users

We are going to create a policy that allows IAM users to self-manage an MFA device. This policy grants the permissions necessary to complete this action from the AWS API or AWS CLI only.

1{
2 "Version": "2012-10-17",
3 "Statement": [
4 {
5 "Sid": "AllowViewAccountInfo",
6 "Effect": "Allow",
7 "Action": [
8 "iam:GetAccountPasswordPolicy",
9 "iam:GetAccountSummary",
10 "iam:ListVirtualMFADevices"
11 ],
12 "Resource": "*"
13 },
14 {
15 "Sid": "AllowManageOwnPasswords",
16 "Effect": "Allow",
17 "Action": [
18 "iam:ChangePassword",
19 "iam:GetUser"
20 ],
21 "Resource": "arn:aws:iam::*:user/${aws:username}"
22 },
23 {
24 "Sid": "AllowManageOwnAccessKeys",
25 "Effect": "Allow",
26 "Action": [
27 "iam:CreateAccessKey",
28 "iam:DeleteAccessKey",
29 "iam:ListAccessKeys",
30 "iam:UpdateAccessKey"
31 ],
32 "Resource": "arn:aws:iam::*:user/${aws:username}"
33 },
34 {
35 "Sid": "AllowManageOwnSigningCertificates",
36 "Effect": "Allow",
37 "Action": [
38 "iam:DeleteSigningCertificate",
39 "iam:ListSigningCertificates",
40 "iam:UpdateSigningCertificate",
41 "iam:UploadSigningCertificate"
42 ],
43 "Resource": "arn:aws:iam::*:user/${aws:username}"
44 },
45 {
46 "Sid": "AllowManageOwnSSHPublicKeys",
47 "Effect": "Allow",
48 "Action": [
49 "iam:DeleteSSHPublicKey",
50 "iam:GetSSHPublicKey",
51 "iam:ListSSHPublicKeys",
52 "iam:UpdateSSHPublicKey",
53 "iam:UploadSSHPublicKey"
54 ],
55 "Resource": "arn:aws:iam::*:user/${aws:username}"
56 },
57 {
58 "Sid": "AllowManageOwnGitCredentials",
59 "Effect": "Allow",
60 "Action": [
61 "iam:CreateServiceSpecificCredential",
62 "iam:DeleteServiceSpecificCredential",
63 "iam:ListServiceSpecificCredentials",
64 "iam:ResetServiceSpecificCredential",
65 "iam:UpdateServiceSpecificCredential"
66 ],
67 "Resource": "arn:aws:iam::*:user/${aws:username}"
68 },
69 {
70 "Sid": "AllowManageOwnVirtualMFADevice",
71 "Effect": "Allow",
72 "Action": [
73 "iam:CreateVirtualMFADevice",
74 "iam:DeleteVirtualMFADevice"
75 ],
76 "Resource": "arn:aws:iam::*:mfa/${aws:username}"
77 },
78 {
79 "Sid": "AllowManageOwnUserMFA",
80 "Effect": "Allow",
81 "Action": [
82 "iam:DeactivateMFADevice",
83 "iam:EnableMFADevice",
84 "iam:ListMFADevices",
85 "iam:ResyncMFADevice"
86 ],
87 "Resource": "arn:aws:iam::*:user/${aws:username}"
88 },
89 {
90 "Sid": "DenyAllExceptListedIfNoMFA",
91 "Effect": "Deny",
92 "NotAction": [
93 "iam:CreateVirtualMFADevice",
94 "iam:EnableMFADevice",
95 "iam:GetUser",
96 "iam:ListMFADevices",
97 "iam:ListVirtualMFADevices",
98 "iam:ResyncMFADevice",
99 "sts:GetSessionToken"
100 ],
101 "Resource": "*",
102 "Condition": {
103 "BoolIfExists": {
104 "aws:MultiFactorAuthPresent": "false"
105 }
106 }
107 }
108 ]
109}

Now, assign this policy to your users or groups along with the other policies you desire and they will be forced to use MFA to perform any action.

Automate temporary AWS keys generation using a custom script

With the former policy, in order to be able to use awscli, you must create a temporary session token instead. To do this, you have to run the sts get-session-token AWS CLI command, replacing the variables with information from your account, resources, and MFA device:

1$ aws sts get-session-token --serial-number arn-of-the-mfa-device --token-code code-from-token

You’ll receive output with temporary credentials and an expiration time for those temporary credentials (by default, 12 hours). However, it’s quite painful having to do this, at maximum, every 36 hours. We created a custom script to automate this process. When invoked, it will call sts get-session-token command and populate awscli config profile with this temporary token. To invoke it, use the following command. Remember to replace the placeholder values on the script with your profile names and AWS account ID.

1./aws-token.sh <username> <mfa_token_code>
1#!/bin/bash
2
3AWS_CLI=`which aws`
4
5if [ $? -ne 0 ]; then
6 echo "AWS CLI is not installed; exiting"
7 exit 1
8else
9 echo "Using AWS CLI found at $AWS_CLI"
10fi
11
12if [ $# -ne 2 ]; then
13 echo "Usage: $0 <IAM_USER> <MFA_TOKEN_CODE>"
14 echo "Where:"
15 echo " <IAM_USER> = IAM user name"
16 echo " <MFA_TOKEN_CODE> = Code from virtual MFA device"
17 exit 2
18fi
19
20AWS_USER_PROFILE=<AWS_ORIGINAL_PROFILE_NAME>
21AWS_2AUTH_PROFILE=<AWS_mfa_PROFILE_NAME>
22ARN_OF_MFA=arn:aws:iam::<AWS_ACCOUNT_ID>:mfa/$1
23MFA_TOKEN_CODE=$2
24DURATION=129600
25
26echo "AWS-CLI Profile: $AWS_CLI_PROFILE"
27echo "MFA ARN: $ARN_OF_MFA"
28echo "MFA Token Code: $MFA_TOKEN_CODE"
29set -x
30
31read AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN <<< \
32$( aws --profile $AWS_USER_PROFILE sts get-session-token \
33 --duration $DURATION \
34 --serial-number $ARN_OF_MFA \
35 --token-code $MFA_TOKEN_CODE \
36 --output text | awk '{ print $2, $4, $5 }')
37
38echo "AWS_ACCESS_KEY_ID: " $AWS_ACCESS_KEY_ID
39echo "AWS_SECRET_ACCESS_KEY: " $AWS_SECRET_ACCESS_KEY
40echo "AWS_SESSION_TOKEN: " $AWS_SESSION_TOKEN
41
42if [ -z "$AWS_ACCESS_KEY_ID" ]
43then
44 exit 1
45fi
46
47`aws --profile $AWS_2AUTH_PROFILE configure set aws_access_key_id "$AWS_ACCESS_KEY_ID"`
48`aws --profile $AWS_2AUTH_PROFILE configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY"`
49`aws --profile $AWS_2AUTH_PROFILE configure set aws_session_token "$AWS_SESSION_TOKEN"`

More articles from Obytes

Design Sprint: The Startups Superpower 💪💪💪

A design sprint is a five-day process that helps test any idea and answer critical business questions through rapid prototyping and user testing by compressing months of time into a single week.

July 7th, 2019 · 5 min read

Enable CI/CD with AWS developer Tools(AWS Codebuild, AWS CodePipeline, ECS), github, terraform

In this article, we will discover how to configure a continuous integration and delivery pipeline (CI / CD) on AWS.

June 30th, 2019 · 7 min read

ABOUT US

Our mission and ambition is to challenge the status quo, by doing things differently we nurture our love for craft and technology allowing us to create the unexpected.