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

Add AWS hardware MFA matcher #2892

Merged
merged 3 commits into from
Apr 3, 2018
Merged

Add AWS hardware MFA matcher #2892

merged 3 commits into from
Apr 3, 2018

Conversation

pwelch
Copy link
Contributor

@pwelch pwelch commented Mar 28, 2018

Adding a hardware as well as a virtual MFA matcher for aws_iam_root_user
resource

Fixes #2750

Signed-off-by: Paul Welch [email protected]

Adding a hardware as well as a virtual MFA matcher for aws_iam_root_user
resource

Fixes #2750

Signed-off-by: Paul Welch <[email protected]>
@pwelch pwelch requested a review from clintoncwolfe March 28, 2018 15:53
@pwelch pwelch requested a review from a team as a code owner March 28, 2018 15:53
Copy link
Contributor

@clintoncwolfe clintoncwolfe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A great start! I suggest a couple of renames, and I found a logic error. And we need docs! Great unit tests, though - this is coming along nicely!

@@ -44,4 +44,52 @@ def test_has_mfa_enabled_returns_false_when_account_mfa_devices_is_zero

assert_equal false, AwsIamRootUser.new(@mock_conn).has_mfa_enabled?
end
end

def test_has_virtual_mfa_enabled_returns_true_when_account_vmfa_devices_is_one
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯 for meaningful unit test names

@@ -46,6 +46,20 @@ def has_mfa_enabled?
summary_account['AccountMFAEnabled'] == 1
end

def has_virtual_mfa_devices?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, it turns out that even though the API returns an array, you can only have one MFA device total per root account or IAM user (see FAQ, 'Q. Can I have multiple authentication devices active for my AWS account?').

Based on that, I think we should rename this matcher to be has_virtual_mfa_enabled?.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL!

false
end

def has_hardware_mfa_devices?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise, this should be renamed has_hardware_mfa_enabled?.

@@ -46,6 +46,20 @@ def has_mfa_enabled?
summary_account['AccountMFAEnabled'] == 1
end

def has_virtual_mfa_devices?
virtual_mfa_devices.each do |device|
if %r{arn:aws:iam::\d{12}:mfa\/root-account-mfa-device} =~
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to add a comment here - if the root account has a VMFA, it will have this special serial number, ending in 'root-account-mfa-device'.

@@ -57,4 +71,8 @@ def summary_account
@summary_account ||= @client.get_account_summary.summary_map
end
end

def virtual_mfa_devices
@__virtual_devices ||= @client.list_virtual_mfa_devices.virtual_mfa_devices
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to wrap this in a catch_aws_errors block.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

end

def has_hardware_mfa_devices?
@__hardware_devices ||= [email protected]_mfa_devices.mfa_devices.empty?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alas, this isn't the right logic. list_mfa_devices will list mfa devices for a particular user, or the currently authenticated user - which would be the test harness user, not the root user. You can't pass the username 'root', either:

[cwolfe@lodi inspec-review]$ aws --profile inspec-aws-test-default iam list-mfa-devices --user-name root

An error occurred (NoSuchEntity) when calling the ListMFADevices operation: The user with name root cannot be found.

So that's no fun. However, the CIS PDF tells us that if the account has MFA enabled (which we know from get_account_summary, and we have a predicate for it in has_mfa_enabled?) BUT has no virtual MFA device (which you have added a predicate for), then it must have a hardware MFA. So I think this can simply be:

   has_mfa_enabled? && !has_virtual_mfa_enabled?


assert_equal false, AwsIamRootUser.new(@mock_conn).has_hardware_mfa_devices?
end
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One missing piece: you need to add the two new matchers to the docs, at docs/resources/aws_iam_root_account.md.erb. Thanks!

@pwelch
Copy link
Contributor Author

pwelch commented Mar 28, 2018

@clintoncwolfe Thanks for the feedback! Pushed up changes.

- Add documentation for new root MFA matchers
- Fix logic for checking MFA devices from feedback on PR

Signed-off-by: Paul Welch <[email protected]>
@pwelch pwelch force-pushed the pw/add-hardware-mfa-matcher branch from 5f18c54 to ac6119b Compare March 29, 2018 14:55
end
end
false
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about extracting the pattern to an explaining variable and using Enumerable#any?() instead?

# if the root account has a Virtual MFA device then it will have a special
# serial number ending in 'root-account-mfa-device'
def has_virtual_mfa_enabled?
  mfa_device_pattern = %r{arn:aws:iam::\d{12}:mfa\/root-account-mfa-device}

  virtual_mfa_devices.any? { |device| mfa_device_pattern =~ device['serial_number'] }
end

serial_number: "arn:aws:iam::123456789011:mfa/root-account-mfa-device",
user: Aws::IAM::Types::User.new(
user_id: "123456789011",
arn: "arn:aws:iam::123456789011:root",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're aligning single quotes in this project?

@clintoncwolfe
Copy link
Contributor

I'm happy with the docs and the code changes. One last thing, could you addd some integration tests? Thanks!

- Add integration tests for virtual and hardware MFA matchers
- Clean up logic for has_virtual_mfa_enabled? method

Signed-off-by: Paul Welch <[email protected]>
@pwelch
Copy link
Contributor Author

pwelch commented Mar 29, 2018

@clintoncwolfe integration tests added.

Copy link
Contributor

@jquick jquick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @pwelch !

@jquick jquick added the Type: Enhancement Improves an existing feature label Apr 3, 2018
@jquick jquick merged commit 2720311 into master Apr 3, 2018
@jquick jquick deleted the pw/add-hardware-mfa-matcher branch April 3, 2018 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Enhancement Improves an existing feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants