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
First of all you have to force your users to use MFA (if you assign MFA device to your user she is still NOT forced to use it via programmatic access — you have to force the user to use MFA via proper policy). The goal here is simple — you cannot use any service if you don’t have enabled MFA. You may achieve it by applying the following policy:
{
"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:
Alice receives access keys
Then I sent the temporal access keys (generated by admin) to alice and she has to enable MFA by herself (without this step she will not be able to access any service except those mentioned in ‘ConfigureCredentials’ policy).
Having the ‘aws_access_key_id’ and ‘aws_secret_access_key’ alice can configure her local profile (on her local machine), using awscli:
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:
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:
Issues with getting STS token
Now, here’s the tricky issue. For the first time, the ‘awsrecipes_init_sts_session.py’ script didn’t work for me, because it didn’t add the ‘aws_session_token’ to alice’s profile. If you faced the same situation, you have to generate the STS token manually (no worries you have to this only once!):
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
Your credentials work for just 8 hours. That means, that every 8 hours you have to renew your access keys and STS token, by running the ‘awsrecipes_init_sts_session.py’ script and type 6 digits from your Google Authenticator app. In the following example you may see how it works in practice. Using outdated session token, I got the error message. Then I renew STS token and finally I was able to do any operation on my S3 bucket.
Final thoughts
IMHO security guys often forgets about usability. People will do their best to find a way to make their life easier without any thought if this is secure or not. Thanks to scripts like aws-recipes, using MFA become a simple task and in the same time you significantly reduce a risk related with access keys’ leak. In the end I’m strongly reccommend you to watch a presentation of aws-recipes, by its developer Loïc Simon.