Support for MFA
ncalteen opened this issue · 4 comments
Version:
1.4.0
Environment:
OS: macOS 10.14
Ruby: 2.3.0p0
ChefDK: 3.8.14
Test Kitchen: 1.24.0
Scenario:
Due to compliance/regulatory requirements, some organizations enforce the requirement that programmatic access to AWS APIs use Multi-Factor Authentication (MFA). With the AWS Command Line Interface (AWS CLI), users are automatically prompted to provide their MFA token when making API calls. New session credentials are generated by AWS Security Token Service (AWS STS) and cached locally. The user is then prompted again when the credentials have expired. Currently, kitchen-ec2
does not "bubble up" this token request, instead failing with the following (having specified the shared_credentials_profile
in .kitchen.yml
.
$ kitchen create default-amazon-201803
-----> Starting Kitchen (v1.24.0)
-----> Creating <default-amazon-201803>...
>>>>>> ------Exception------
>>>>>> Class: Kitchen::ActionFailed
>>>>>> Message: 1 actions failed.
>>>>>> Failed to complete #create action: [unable to sign request without credentials set] on default-amazon-201803
>>>>>>-----------------------
Steps to Reproduce:
- Create a new AWS Identity and Access Management (AWS IAM) user.
- Configure MFA for the user.
- Create a role that can be assumed by said user.
- Add this user as a new profile in
~/.aws/config
. - Add a second profile for the role to be assumed, using the user profile as
source_profile
. - Configure a simple Amazon Linux example in
.kitchen.yml
. - Attempt to run a command such as
kitchen create
.
The AWS credentials configuration file should information similar to the following:
[profile mfauser]
region=us-east-1
aws_access_key_id=AKIAEXAMPLE1234
aws_secret_access_key=EXAMPLESECRETKEY12345
output=json
[profile adminrole]
source_profile=mfauser
role_arn=arn:aws:iam::123456789012:role/adminrole
output=json
mfa_serial=arn:aws:iam::123456789012:mfa/mfauser
The .kitchen.yml
should be similar to the following.
---
driver
name: ec2
provisioner:
name: chef_solo
platforms:
- name: amazon-2018.03
driver:
image_id: ami-0080e4c5bc078760e
aws_ssh_key_id: my_key
instance_type: t2.micro
security_group_ids: ["sg-12345678"]
region: us-east-1
subnet_id: subnet-12345678
shared_credentials_profile: adminrole
transport:
ssh_key: /path/to/private_key.pem
username: ec2-user
suites:
- name: default
run_list:
attributes:
Expected Result:
On the final step, the user should be prompted for their MFA token. This is in line with the result of running a similar AWS CLI command.
$ aws ec2 describe-instances --profile roleprofile
Enter MFA code for arn:aws:iam::123456789012:mfa/mfauser:
Actual Result:
See below output:
$ kitchen create default-amazon-201803
-----> Starting Kitchen (v1.24.0)
-----> Creating <default-amazon-201803>...
>>>>>> ------Exception------
>>>>>> Class: Kitchen::ActionFailed
>>>>>> Message: 1 actions failed.
>>>>>> Failed to complete #create action: [unable to sign request without credentials set] on default-amazon-201803
>>>>>>-----------------------
Current workaround:
-
Create new session credentials by running
aws sts get-session-token
.aws sts get-session-token \ --serial-number MFA_DEVICE_ARN \ --token-code MFA_DEVICE_TOKEN \ --profile mfauser
-
Create a separate profile in
~/.aws/config
to include these values. -
Create a separate profile in
~/.aws/config
to assume the role mentioned previously, using the profile profile you just created assource_profile
.[profile stscreds] region=us-east-1 aws_access_key_id=AKIAEXAMPLE1234 aws_secret_access_key=EXAMPLE1234567890 aws_session_token=EXAMPLE234567890 [profile kitchenrole] region=us-east-1 role_arn=arn:aws:iam::123456789012:role/adminrole source_profile=stscreds
-
Update
.kitchen.yml
to usekitchenrole
asshared_credentials_profile
. -
Any time credentials expire, repeat above steps.
That seems like a painful workaround, but prompting for it would not work in automated/headless situations. What about expecting it in an environment variable?
I would imagine automated/headless situations would not be configured to use IAM users that require MFA. The AWS-recommended approach would be to use an IAM instance profile, for example.
The documented process for setting the needed environment variables documented here is not much less painful. It still requires the aws get-session-token
call, and has the added complexity of needing to unset the same environment variables when the session expires before you can successfully call aws get-session-token
again.
@ncalteen We use a tool called Gossamer to setup sessions where we create a "session" for this and then you specify that "profile" in your .kitchen.yml to use that on your behalf.
https://github.com/GESkunkworks/gossamer3
Works for CLI and Chef and anything else that needs MFA auth that will map to an AWS role that you have permissions for.