Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for MFA #447

Open
ncalteen opened this issue Mar 4, 2019 · 4 comments
Open

Support for MFA #447

ncalteen opened this issue Mar 4, 2019 · 4 comments

Comments

@ncalteen
Copy link

ncalteen commented Mar 4, 2019

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:

  1. Create a new AWS Identity and Access Management (AWS IAM) user.
  2. Configure MFA for the user.
  3. Create a role that can be assumed by said user.
  4. Add this user as a new profile in ~/.aws/config.
  5. Add a second profile for the role to be assumed, using the user profile as source_profile.
  6. Configure a simple Amazon Linux example in .kitchen.yml.
  7. 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
>>>>>>-----------------------
@ncalteen
Copy link
Author

ncalteen commented Mar 4, 2019

Current workaround:

  1. 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
  2. Create a separate profile in ~/.aws/config to include these values.

  3. Create a separate profile in ~/.aws/config to assume the role mentioned previously, using the profile profile you just created as source_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
  4. Update .kitchen.yml to use kitchenrole as shared_credentials_profile.

  5. Any time credentials expire, repeat above steps.

@marcparadise
Copy link

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?

@ncalteen
Copy link
Author

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.

@JaBurd
Copy link

JaBurd commented Dec 3, 2021

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants