nccgroup / opinel

Python code shared by Scout2 and AWS-Recipes
GNU General Public License v2.0
24 stars 18 forks source link

why have ~/.aws/credentials.no-mfa at all ? #4

Closed philsnow closed 9 years ago

philsnow commented 9 years ago

Walking through the workflow, it seems somewhat troublesome.

status quo workflow

Here's what is in what cred file, when. From a clean slate, start by aws configure.

Now credentials contains

[default]
aws_access_key_id = AKIA123121123123123123
aws_secret_access_key = 12312312312312312312312312312313123

Now, aws_iam_enable_mfa.py, go through the prompts. credentials is unchanged (still has the AKIA.... key) and credentials.no-mfa has these contents:

[default]
aws_access_key_id = AKIA123121123123123123
aws_secret_access_key = 12312312312312312312312312312313123
aws_mfa_serial = arn:aws:iam::987654321:mfa/UserName

Now, we need to aws_recipes_init_sts_session.py. After that, credentials.no-mfa is unchanged, and credentials contains:

[default]
aws_access_key_id = ASIA8768768768768
aws_secret_access_key = 876876876876876876876876
aws_session_token = 8768768768768.......................876876876876

Now we can use awscli commands and it will use credentials. But, consider the case where some organizations only require MFA for certain API actions. The original credentials have been sequestered away in credentials.no-mfa, and to perform actions that they would ordinarily be allowed to do, they have to either re-MFA or else fetch them from credentials.no-mfa somehow.

But, why do any of this?

We could just keep all the bookkeeping in the same credentials file, under a new default-MFA profile. Under that model, the flow would go like this:

From a clean slate, aws configure, then aws_iam_enable_mfa.py. Now credentials is:

[default]
aws_access_key_id = AKIA123121123123123123
aws_secret_access_key = 12312312312312312312312312312313123
aws_mfa_serial = arn:aws:iam::987654321:mfa/UserName

Then after aws_recipes_init_sts_session.py:

[default]
aws_access_key_id = AKIA123121123123123123
aws_secret_access_key = 12312312312312312312312312312313123
aws_mfa_serial = arn:aws:iam::987654321:mfa/UserName
[default-MFA]
aws_access_key_id = ASIA8768768768768
aws_secret_access_key = 876876876876876876876876
aws_session_token = 8768768768768.......................876876876876

So then the user can use awscli 's --profile option to pick whether they want to use their MFA/ASIA... creds or their non-MFA/AKIA... creds.

I just verified that aws configure seems to pass through lines that it doesn't know about. I put a line

some_garbage = osidjfsoidjfoij

and it survived a re-run of aws configure, as did the aws_mfa_serial line belonging to the default profile.

Alternatively, the final state of the credentials file could be similar but with profiles default-NO-MFA and default (which contains the MFA creds). That's probably more likely to be useful, since people who are setting this up are probably going to want to prefer their MFA creds but be able to fall back to non-MFA creds.

If you think this is reasonable, I can take a stab at it.

I have really only been paying attention to the MFA-related things in AWSUtils, so if there are other reasons to use credentials.no-mfa let me know and I'll see if I can think of a workaround.

@l01cd3v thanks for looking

l01cd3v commented 9 years ago

At first glance, my one and only (but big) concern about your request is the motivation behind it: why do you need to enable users to access the API without MFA (or don't want to enforce use of MFA)? If this is not something you wish to discuss on this thread, you can contact me at loic [at] isecpartners [dot] com; my PGP key is on the MIT key server at https://pgp.mit.edu/pks/lookup?op=get&search=0x1A9A639A8DB9603E

Also, a suggested improvement on this collection of tools is to password-protect the API key secret before writing it to file (so that your long-lived credentials are never stored in plaintext). The target workflow would be such as init_session requires the password to decrypt the secret and the mfa token to send a request to STS. If implemented, I think that keeping two separate files makes sense as the long-lived credentials would be garbage to any other tool.

philsnow commented 9 years ago

It's possible to set up IAM policies such that only more-"sensitive" API actions require MFA and less-sensitive ones don't (completely up to one's administrator). Right now with non-MFA creds sequestered into the .no-mfa file, it's more difficult to use them.

Regarding password-protecting secrets, first I should say that I wish everybody could trivially use full disk encryption. Failing that, though, the above approach does not preclude encrypting secrets: the non-MFA profile's aws_secret_access_key can be stored as base64(encrypt(secret)). If you're encrypting the long-lived credentials, it doesn't matter where you store them since awscli etc won't be able to use them, so.. putting them in ~/.aws/credentials under profile default-NO-MFA is as good a place as any, I think.

l01cd3v commented 9 years ago

Hi Phil,

I understand that enforcing MFA-protected API access can be set for a subset of the AWS API; however, I consider doing so an insecure practice. My recommendation is to enforce it for all APIs (as discussed in the blog post: https://isecpartners.github.io/aws/2015/04/02/use_and_enforce_mfa.html) because a partial approach is most likely to leave some sensitive APIs exposed.

That being said, I think moving everything to a single configuration file is necessary to ensure that this collection of tools is helpful to all AWS users. When doing so, I'd like to keep the name of the profile unchanged when using MFA. What do you think about storing the long lived creds under $profile_name-nomfa (automatically appended) and placing the STS creds under a profile with $profile_name?

The init session will automatically read the -nomfa profile if it exists. It will also rename (after prompt/warning) the long lived-profile to -nomfa. I understand having to type -nomfa and changing an existing profile name may be an inconvenience, but I believe that it is best to do it this way as the end goal is to use MFA every time (no need to use type -MFA). It will also remind users every time they access the AWS API without using STS credentials.

l01cd3v commented 9 years ago

Hey Phil,

I implemented the change described above in the boto3-migration branch. Feel free to check it out and please share your thoughts. You can run the following command to migrate your long-lived credentials so that they work with the new scheme:

cat ~/.aws/credentials.no-mfa | sed -e 's/]$/-nomfa]/g' >> ~/.aws/credentials

I hope to make this dev branch mainstream by the end of the month.