Easy way to use MFA in AWS programmatic access using aws-recipes

Speaking about AWS security, access keys leak seems to be one of the worst scenario you can imagine. The risks depend on the permissions which you gave to compromised account. An attacker with your access keys may for example start a new service at your expense (read more about ~100K $ bill for OlinData) or even kick you out from the business (read more about a murder in Amazon). These examples should be enough to convince you that the access to your services requires a special care.

One of the mechanism that can significantly impede compromising your account via access keys leak is enabling Multi Factor Authentication. While it’s just a matter of few clicks to enable MFA in the console access, it’s not so trivial when we’re talking about programmatic access (via terminal). So in this post I’d like to guide you through whole process of enabling MFA in terminal using aws-recipes. Let’s get start it!

Creating policies

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"NotAction": [
"iam:ChangePassword",
"iam:CreateVirtualMFADevice",
"iam:EnableMFADevice",
"iam:GetUser",
"iam:ListMFADevices",
"iam:ListUsers",
"iam:ListVirtualMFADevices"
],
"Resource": "*",
"Condition": {
"Null": {
"aws:MultiFactorAuthAge": "true"
}
}
},
{
"Effect": "Deny",
"NotAction": [
"iam:ChangePassword",
"iam:CreateVirtualMFADevice",
"iam:EnableMFADevice",
"iam:GetUser",
"iam:ListMFADevices",
"iam:ListUsers",
"iam:ListVirtualMFADevices"
],
"Resource": "*",
"Condition": {
"NumericGreaterThan": {
"aws:MultiFactorAuthAge": "28800"
}
}
}
]
}

In the above mentioned policy I give permissions to perform an “on-boarding process” (manage user’s MFA device and change password) and block any other action if MFA token is not present. Additionally this policy accepts only MFA tokens for 8 hours (28800 seconds), so your users will have to change the token every 8 hours.

The next thing you should do is to set up another policy which is for authenticated users. Here I’ve created a policy for a user alice:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:*AccessKey*",
"iam:*Password",
"iam:*MFADevice*",
"iam:UpdateLoginProfile"
],
"Resource": "arn:aws:iam::908xxxxxxxx9:user/alice"
},
{
"Effect": "Allow",
"Action": [
"iam:CreateVirtualMFADevice",
"iam:DeleteVirtualMFADevice"
],
"Resource": "arn:aws:iam::908xxxxxxxx9:mfa/alice"
}
]
}

Using my admin account I created a user alice and assign above mentioned policy to her (or to group which contains alice). The role of user alice is to manage my S3 bucket, so I also assigned her a policy ‘AmazonS3FullAccess’. Finally here are my 3 policies:

Image for post
Image for post

Alice receives access keys

Having the ‘aws_access_key_id’ and ‘aws_secret_access_key’ alice can configure her local profile (on her local machine), using awscli:

Image for post
Image for post

Then she clones the aws-recipes and installs dependencies. Next thing is to get a virtual MFA device. In my examples I’m using Google Authenticator. You can get it on both Android and iOS. Once you’re done, it’s time to enable your MFA device. You can do this using ‘awsrecipes_enable_mfa.py’ script. The tool will firstly generate a QR code, which you should use to add new account in your Google Authenticator app, and then it asks you for 2 consecutive 6 digit numbers from the app. It should look like this:

Image for post
Image for post

Now, you can use your virtual MFA to get a session token, using ‘awsrecipes_init_sts_session.py’ script:

$ python awsrecipes_init_sts_session.py --profile alice

Basically, the idea of this script is to get a new STS session token, which requires the MFA code. Once it’s done, new access keys with STS token are saved under your profile in ‘~/.aws/credentials’ file. You may notice that the script creates a new profile alice-nomfa. This profile contains your long-lived credentials (the old access keys you received from admin). These access keys are actually kept “just in case” — you won’t use them anymore. Under alice profile you should notice new access keys and the new session token:

Image for post
Image for post

Issues with getting STS token

Image for post
Image for post

Then you have to simply update your current alice profile with new values of ‘AccessKeyId’, ‘SecretAccessKey’, ‘SessionToken’ (you can simply copy/paste it to your alice’s profile in ~/.aws/credentials file, or use export command). That’s all! Now, every time you run the script ‘awsrecipes_init_sts_session.py’, it will automatically update your alice profile.

Check how it works

Image for post
Image for post

Final thoughts

Written by

Interested in pentesting and cloud security | OSCP | eMAPT | AWS SAA | AWS CSS

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store