Add AWS hardware MFA matcher (#2892)

* Add AWS hardware MFA matcher
Adding a hardware as well as a virtual MFA matcher for aws_iam_root_user
resource

* Add New AWS Root Matcher Docs
- Add documentation for new root MFA matchers
- Fix logic for checking MFA devices from feedback on PR

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

Signed-off-by: Paul Welch <pwelch@chef.io>
This commit is contained in:
Paul Welch 2018-04-03 09:13:52 -04:00 committed by Jared Quick
parent 30fa6ecfb0
commit 27203110cd
5 changed files with 105 additions and 1 deletions

View file

@ -51,6 +51,18 @@ The `have_mfa_enabled` matcher tests if the AWS root user has Multi-Factor Authe
it { should have_mfa_enabled }
### have\_hardware\_mfa\_enabled
The `have_hardware_mfa_enabled` matcher tests if the AWS root user has Hardware Multi-Factor Authentication device enabled, requiring them to enter a secondary code when they login to the web console.
it { should have_hardware_mfa_enabled }
### have\_virtual\_mfa\_enabled
The `have_virtual_mfa_enabled` matcher tests if the AWS root user has Virtual Multi-Factor Authentication device enabled, requiring them to enter a secondary code when they login to the web console.
it { should have_virtual_mfa_enabled }
### have\_access\_key
The `have_access_key` matcher tests if the AWS root user has at least one access key.

View file

@ -46,6 +46,18 @@ class AwsIamRootUser < Inspec.resource(1)
summary_account['AccountMFAEnabled'] == 1
end
# 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? { |d| mfa_device_pattern =~ d['serial_number'] }
end
def has_hardware_mfa_enabled?
has_mfa_enabled? && !has_virtual_mfa_enabled?
end
def to_s
'AWS Root-User'
end
@ -57,4 +69,10 @@ class AwsIamRootUser < Inspec.resource(1)
@summary_account ||= @client.get_account_summary.summary_map
end
end
def virtual_mfa_devices
catch_aws_errors do
@__virtual_devices ||= @client.list_virtual_mfa_devices.virtual_mfa_devices
end
end
end

View file

@ -18,10 +18,18 @@ control "aws_iam_root_user has_mfa_enabled property" do
end
end
#---------- Property - has_virtual_mfa_enabled ----------#
# Negative test in 'minimal' test set.
control "aws_iam_root_user has_virtual_mfa_enabled property" do
describe aws_iam_root_user do
it { should have_virtual_mfa_enabled }
end
end
#------------- Property - has_access_key -------------#
# Positive test in 'minimal' test set
control "aws_iam_root_user has_access_key property" do
describe aws_iam_root_user do
it { should_not have_access_key }
end
end
end

View file

@ -18,6 +18,22 @@ control "aws_iam_root_user has_mfa_enabled property" do
end
end
#---------- Property - has_virtual_mfa_enabled ----------#
# Positive test in 'default' test set
control "aws_iam_root_user has_virtual_mfa_enabled property" do
describe aws_iam_root_user do
it { should_not have_virtual_mfa_enabled }
end
end
#---------- Property - has_hardware_mfa_enabled ----------#
# Positive test in 'default' test set
control "aws_iam_root_user has_hardware_mfa_enabled property" do
describe aws_iam_root_user do
it { should_not have_hardware_mfa_enabled }
end
end
#------------- Property - has_access_key -------------#
# Negative test in 'default' test set
control "aws_iam_root_user has_access_key property" do

View file

@ -44,4 +44,54 @@ class AwsIamRootUserTest < Minitest::Test
assert_equal false, AwsIamRootUser.new(@mock_conn).has_mfa_enabled?
end
def test_has_virtual_mfa_enabled_returns_true_when_account_vmfa_devices_is_one
test_list_virtual_mfa_devices = OpenStruct.new(
virtual_mfa_devices: [Aws::IAM::Types::VirtualMFADevice.new(
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',
)
)]
)
@mock_client.expect :list_virtual_mfa_devices, test_list_virtual_mfa_devices
assert_equal true, AwsIamRootUser.new(@mock_conn).has_virtual_mfa_enabled?
end
def test_has_virtual_mfa_enabled_returns_false_when_account_vmfa_devices_is_zero
test_list_virtual_mfa_devices = OpenStruct.new(
virtual_mfa_devices: []
)
@mock_client.expect :list_virtual_mfa_devices, test_list_virtual_mfa_devices
assert_equal false, AwsIamRootUser.new(@mock_conn).has_virtual_mfa_enabled?
end
def test_has_hardware_mfa_enabled_returns_true_when_account_hardware_devices_is_one
test_list_virtual_mfa_devices = OpenStruct.new(
virtual_mfa_devices: []
)
test_summary_map = OpenStruct.new(
summary_map: { 'AccountMFAEnabled' => 1 },
)
@mock_client.expect :list_virtual_mfa_devices, test_list_virtual_mfa_devices
@mock_client.expect :get_account_summary, test_summary_map
assert_equal true, AwsIamRootUser.new(@mock_conn).has_hardware_mfa_enabled?
end
def test_has_hardware_mfa_enabled_returns_false_when_account_hardware_devices_is_zero
test_list_virtual_mfa_devices = OpenStruct.new(
virtual_mfa_devices: []
)
test_summary_map = OpenStruct.new(
summary_map: { 'AccountMFAEnabled' => 0 },
)
@mock_client.expect :get_account_summary, test_summary_map
@mock_client.expect :list_virtual_mfa_devices, test_list_virtual_mfa_devices
assert_equal false, AwsIamRootUser.new(@mock_conn).has_hardware_mfa_enabled?
end
end