mirror of
https://github.com/inspec/inspec
synced 2024-11-23 13:13:22 +00:00
Add aws_iam_access_keys resource (#112)
Signed-off-by: Clinton Wolfe <clintoncwolfe@gmail.com>
This commit is contained in:
parent
fdd04e31c6
commit
245efc4230
5 changed files with 722 additions and 3 deletions
165
docs/resources/aws_iam_access_keys.md
Normal file
165
docs/resources/aws_iam_access_keys.md
Normal file
|
@ -0,0 +1,165 @@
|
|||
---
|
||||
title: About the aws_iam_access_keys Resource
|
||||
---
|
||||
|
||||
# aws_iam_access_keys
|
||||
|
||||
Use the `aws_iam_access_keys` InSpec audit resource to test properties of some or all IAM Access Keys.
|
||||
|
||||
To test properties of a single Access Key, use the `aws_iam_access_key` resource instead.
|
||||
To test properties of an individual user's access keys, use the `aws_iam_user` resource.
|
||||
|
||||
Access Keys are closely related to AWS User resources. Use this resource to perform audits of all keys or of keys specified by criteria unrelated to any particular user.
|
||||
|
||||
<br>
|
||||
|
||||
## Syntax
|
||||
|
||||
An `aws_iam_access_keys` resource block uses an optional filter to select a group of access keys and then tests that group.
|
||||
|
||||
# Do not allow any access keys
|
||||
describe aws_iam_access_keys do
|
||||
it { should_not exist }
|
||||
end
|
||||
|
||||
# Don't let fred have access keys, using filter argument syntax
|
||||
describe aws_iam_access_keys.where(username: 'fred') do
|
||||
it { should_not exist }
|
||||
end
|
||||
|
||||
# Don't let fred have access keys, using filter block syntax (most flexible)
|
||||
describe aws_iam_access_keys.where { username == 'fred' } do
|
||||
it { should_not exist }
|
||||
end
|
||||
|
||||
<br>
|
||||
|
||||
## Examples
|
||||
|
||||
The following examples show how to use this InSpec audit resource.
|
||||
|
||||
### Disallow access keys created more than 90 days ago
|
||||
|
||||
describe aws_iam_access_keys.where { created_age > 90 } do
|
||||
it { should_not exist }
|
||||
end
|
||||
|
||||
<br>
|
||||
|
||||
## Matchers
|
||||
|
||||
### exists
|
||||
|
||||
The control will pass if the filter returns at least one result. Use should_not if you expect zero matches.
|
||||
|
||||
# Sally should have at least one access key
|
||||
describe aws_iam_access_keys.where(username: 'sally') do
|
||||
it { should exist }
|
||||
end
|
||||
|
||||
# Don't let fred have access keys
|
||||
describe aws_iam_access_keys.where(username: 'fred') do
|
||||
it { should_not exist }
|
||||
end
|
||||
|
||||
## Filter Criteria
|
||||
|
||||
### active
|
||||
|
||||
A true / false value indicating if an Access Key is currently "Active" (the normal state) in the AWS console. See also: `inactive`.
|
||||
|
||||
# Check whether a particular key is enabled
|
||||
describe aws_iam_access_keys.where { active } do
|
||||
its('access_key_ids') { should include('AKIA1234567890ABCDEF')}
|
||||
end
|
||||
|
||||
### created_date
|
||||
|
||||
A DateTime identifying when the Access Key was created. See also `created_days_ago` and `created_hours_ago`.
|
||||
|
||||
# Detect keys older than 2017
|
||||
describe aws_iam_access_keys.where { created_date < DateTime.parse('2017-01-01') } do
|
||||
it { should_not exist }
|
||||
end
|
||||
|
||||
### created_days_ago, created_hours_ago
|
||||
|
||||
An integer, representing how old the access key is.
|
||||
|
||||
# Don't allow keys that are older than 90 days
|
||||
describe aws_iam_access_keys.where { created_days_ago > 90 } do
|
||||
it { should_not exist }
|
||||
end
|
||||
|
||||
### ever_used
|
||||
|
||||
A true / false value indicating if the Access Key has ever been used, based on the last_used_date. See also: `never_used`.
|
||||
|
||||
# Check to see if a particular key has ever been used
|
||||
describe aws_iam_access_keys.where { ever_used } do
|
||||
its('access_key_ids') { should include('AKIA1234567890ABCDEF')}
|
||||
end
|
||||
|
||||
|
||||
### inactive
|
||||
|
||||
A true / false value indicating if the Access Key has been marked Inactive in the AWS console. See also: `active`.
|
||||
|
||||
# Don't leave inactive keys laying around
|
||||
describe aws_iam_access_keys.where { inactive } do
|
||||
it { should_not exist }
|
||||
end
|
||||
|
||||
### last_used_date
|
||||
|
||||
A DateTime identifying when the Access Key was last used. Returns nil if the key has never been used. See also: `ever_used`, `last_used_days_ago`, `last_used_hours_ago`, and `never_used`.
|
||||
|
||||
# No one should do anything on Mondays
|
||||
describe aws_iam_access_keys.where { ever_used and last_used_date.monday? } do
|
||||
it { should_not exist }
|
||||
end
|
||||
|
||||
### last_used_days_ago, last_used_hours_ago
|
||||
|
||||
An integer representing when the key was last used. See also: `ever_used`, `last_used_date`, and `never_used`.
|
||||
|
||||
# Don't allow keys that sit unused for more than 90 days
|
||||
describe aws_iam_access_keys.where { last_used_days_ago > 90 } do
|
||||
it { should_not exist }
|
||||
end
|
||||
|
||||
### never_used
|
||||
|
||||
A true / false value indicating if the Access Key has never been used, based on the last_used_date. See also: `ever_used`.
|
||||
|
||||
# Don't allow unused keys to lay around
|
||||
describe aws_iam_access_keys.where { never_used } do
|
||||
it { should_not exist }
|
||||
end
|
||||
|
||||
### username
|
||||
|
||||
Searches for access keys owned by the named user. Each user may have zero, one, or two access keys.
|
||||
|
||||
describe aws_iam_access_keys(username: 'bob') do
|
||||
it { should exist }
|
||||
end
|
||||
|
||||
## Properties
|
||||
|
||||
### access_key_ids
|
||||
|
||||
Provides a list of all access key IDs matched.
|
||||
|
||||
describe aws_iam_access_keys do
|
||||
its('access_key_ids') { should include('AKIA1234567890ABCDEF') }
|
||||
end
|
||||
|
||||
### entries
|
||||
|
||||
Provides access to the raw results of the query. This can be useful for checking counts and other advanced operations.
|
||||
|
||||
# Allow at most 100 access keys on the account
|
||||
describe aws_iam_access_keys do
|
||||
its('entries.count') { should be <= 100}
|
||||
end
|
164
libraries/aws_iam_access_keys.rb
Normal file
164
libraries/aws_iam_access_keys.rb
Normal file
|
@ -0,0 +1,164 @@
|
|||
class AwsIamAccessKeys < Inspec.resource(1)
|
||||
name 'aws_iam_access_keys'
|
||||
desc 'Verifies settings for AWS IAM Access Keys in bulk'
|
||||
example '
|
||||
describe aws_iam_access_keys do
|
||||
it { should_not exist }
|
||||
end
|
||||
'
|
||||
|
||||
VALUED_CRITERIA = [
|
||||
:username,
|
||||
:id,
|
||||
:access_key_id,
|
||||
:created_date,
|
||||
].freeze
|
||||
|
||||
# Constructor. Args are reserved for row fetch filtering.
|
||||
def initialize(filter_criteria = {})
|
||||
filter_criteria = validate_filter_criteria(filter_criteria)
|
||||
@table = AccessKeyProvider.create.fetch(filter_criteria)
|
||||
end
|
||||
|
||||
def validate_filter_criteria(criteria)
|
||||
# Allow passing a scalar string, the Access Key ID.
|
||||
criteria = { access_key_id: criteria } if criteria.is_a? String
|
||||
unless criteria.is_a? Hash
|
||||
raise 'Unrecognized criteria for fetching Access Keys. ' \
|
||||
"Use 'criteria: value' format."
|
||||
end
|
||||
|
||||
# id and access_key_id are aliases; standardize on access_key_id
|
||||
criteria[:access_key_id] = criteria.delete(:id) if criteria.key?(:id)
|
||||
if criteria[:access_key_id] and
|
||||
criteria[:access_key_id] !~ /^AKIA[0-9A-Z]{16}$/
|
||||
raise 'Incorrect format for Access Key ID - expected AKIA followed ' \
|
||||
'by 16 letters or numbers'
|
||||
end
|
||||
|
||||
criteria.keys.each do |criterion|
|
||||
unless VALUED_CRITERIA.include?(criterion) # rubocop:disable Style/Next
|
||||
raise 'Unrecognized filter criterion for aws_iam_access_keys, ' \
|
||||
"'#{criterion}'. Valid choices are " \
|
||||
"#{VALUED_CRITERIA.join(', ')}."
|
||||
end
|
||||
end
|
||||
|
||||
criteria
|
||||
end
|
||||
|
||||
# Underlying FilterTable implementation.
|
||||
filter = FilterTable.create
|
||||
filter.add_accessor(:where)
|
||||
.add_accessor(:entries)
|
||||
.add(:exists?) { |x| !x.entries.empty? }
|
||||
.add(:access_key_ids, field: :access_key_id)
|
||||
.add(:created_date, field: :created_date)
|
||||
.add(:created_days_ago, field: :created_days_ago)
|
||||
.add(:created_hours_ago, field: :created_hours_ago)
|
||||
.add(:usernames, field: :username)
|
||||
.add(:active, field: :active)
|
||||
.add(:inactive, field: :inactive)
|
||||
.add(:last_used_date, field: :last_used_date)
|
||||
.add(:last_used_hours_ago, field: :last_used_hours_ago)
|
||||
.add(:last_used_days_ago, field: :last_used_days_ago)
|
||||
.add(:ever_used, field: :ever_used)
|
||||
.add(:never_used, field: :never_used)
|
||||
filter.connect(self, :access_key_data)
|
||||
|
||||
def access_key_data
|
||||
@table
|
||||
end
|
||||
|
||||
def to_s
|
||||
'IAM Access Keys'
|
||||
end
|
||||
|
||||
# Internal support class. This is used to fetch
|
||||
# the users and access keys. We have an abstract
|
||||
# class with a concrete AWS implementation provided here;
|
||||
# a few mock implementations are also provided in the unit tests.
|
||||
class AccessKeyProvider
|
||||
# Implementation of AccessKeyProvider which operates by looping over
|
||||
# all users, then fetching their access keys.
|
||||
# TODO: An alternate, more scalable implementation could be made
|
||||
# using the Credential Report.
|
||||
class AwsUserIterator < AccessKeyProvider
|
||||
def fetch(criteria)
|
||||
iam_client = AWSConnection.new.iam_client
|
||||
usernames = []
|
||||
if criteria.key?(:username)
|
||||
usernames.push criteria[:username]
|
||||
else
|
||||
# TODO: pagination check and resume
|
||||
usernames = iam_client.list_users.users.map(&:user_name)
|
||||
end
|
||||
|
||||
access_key_data = []
|
||||
usernames.each do |username|
|
||||
begin
|
||||
user_keys = iam_client.list_access_keys(user_name: username)
|
||||
.access_key_metadata
|
||||
user_keys = user_keys.map do |metadata|
|
||||
{
|
||||
access_key_id: metadata.access_key_id,
|
||||
username: username,
|
||||
status: metadata.status,
|
||||
create_date: metadata.create_date, # DateTime.parse(metadata.create_date),
|
||||
}
|
||||
end
|
||||
|
||||
# Synthetics
|
||||
user_keys.each do |key_info|
|
||||
add_synthetic_fields(key_info)
|
||||
end
|
||||
access_key_data.concat(user_keys)
|
||||
rescue Aws::IAM::Errors::NoSuchEntity # rubocop:disable Lint/HandleExceptions
|
||||
# Swallow - a miss on search results should return an empty table
|
||||
end
|
||||
end
|
||||
access_key_data
|
||||
end
|
||||
|
||||
def add_synthetic_fields(key_info) # rubocop:disable Metrics/AbcSize
|
||||
key_info[:id] = key_info[:access_key_id]
|
||||
key_info[:active] = key_info[:status] == 'Active'
|
||||
key_info[:inactive] = key_info[:status] != 'Active'
|
||||
key_info[:created_hours_ago] = ((Time.now - key_info[:create_date]) / (60*60)).to_i
|
||||
key_info[:created_days_ago] = (key_info[:created_hours_ago] / 24).to_i
|
||||
|
||||
# Last used is a separate API call
|
||||
iam_client = AWSConnection.new.iam_client
|
||||
last_used =
|
||||
iam_client.get_access_key_last_used(access_key_id: key_info[:access_key_id])
|
||||
.access_key_last_used.last_used_date
|
||||
key_info[:ever_used] = !last_used.nil?
|
||||
key_info[:never_used] = last_used.nil?
|
||||
key_info[:last_used_time] = last_used
|
||||
return unless last_used
|
||||
key_info[:last_used_hours_ago] = ((Time.now - last_used) / (60*60)).to_i
|
||||
key_info[:last_used_days_ago] = (key_info[:last_used_hours_ago]/24).to_i
|
||||
end
|
||||
end
|
||||
|
||||
DEFAULT_PROVIDER = AwsIamAccessKeys::AccessKeyProvider::AwsUserIterator
|
||||
@selected_implementation = DEFAULT_PROVIDER
|
||||
|
||||
# Use this to change what class is created by create().
|
||||
def self.select(klass)
|
||||
@selected_implementation = klass
|
||||
end
|
||||
|
||||
def self.reset
|
||||
@selected_implementation = DEFAULT_PROVIDER
|
||||
end
|
||||
|
||||
def self.create
|
||||
@selected_implementation.new
|
||||
end
|
||||
|
||||
def fetch(_filter_criteria)
|
||||
raise 'Unimplemented abstract method - internal error.'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -159,6 +159,10 @@ output "access_key_user" {
|
|||
value = "${aws_iam_user.access_key_user.name}"
|
||||
}
|
||||
|
||||
output "access_key_id" {
|
||||
value = "${aws_iam_access_key.access_key.id}"
|
||||
}
|
||||
|
||||
output "example_ec2_name" {
|
||||
value = "${aws_instance.example.tags.Name}"
|
||||
}
|
||||
|
|
|
@ -1,3 +1,57 @@
|
|||
describe aws_iam_access_key(username: 'not-a-user', 'id': 'not-an-id') do
|
||||
it { should_not exist }
|
||||
end
|
||||
access_key_user = attribute(
|
||||
'access_key_user',
|
||||
default: 'default.access_key_user',
|
||||
description: 'Name of IAM user access_key_user')
|
||||
|
||||
access_key_id = attribute(
|
||||
'access_key_id',
|
||||
default: 'AKIA1234567890AZFAKE',
|
||||
description: 'Access Key ID of access key of IAM user access_key_user')
|
||||
|
||||
describe aws_iam_access_key(username: 'not-a-user', 'id': 'not-an-id') do
|
||||
it { should_not exist }
|
||||
end
|
||||
|
||||
describe aws_iam_access_key(username: access_key_user, 'id': access_key_id) do
|
||||
it { should exist }
|
||||
# TODO - check last used, created, other key metadata
|
||||
end
|
||||
|
||||
control 'IAM Access Keys' do
|
||||
title 'Fetch all'
|
||||
describe aws_iam_access_keys do
|
||||
it { should exist }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
control 'IAM Access Keys' do
|
||||
title 'Client-side filtering'
|
||||
all_keys = aws_iam_access_keys
|
||||
describe all_keys.where(username: access_key_user) do
|
||||
its('entries.length') { should be 1 }
|
||||
its('access_key_ids.first') { should eq access_key_id }
|
||||
end
|
||||
describe all_keys.where(created_days_ago: 0) do
|
||||
it { should exist }
|
||||
end
|
||||
describe all_keys.where { active } do
|
||||
it { should exist }
|
||||
end
|
||||
describe all_keys.where { ever_used }
|
||||
.where { last_used_days_ago > 0 } do
|
||||
it { should exist }
|
||||
end
|
||||
end
|
||||
|
||||
control 'AKS3' do
|
||||
title 'Fetch-time filtering'
|
||||
describe aws_iam_access_keys(username: access_key_user) do
|
||||
its('entries.length') { should be 1 }
|
||||
its('access_key_ids.first') { should eq access_key_id }
|
||||
end
|
||||
|
||||
describe aws_iam_access_keys(username: 'i-dont-exist-presumably') do
|
||||
it { should_not exist }
|
||||
end
|
||||
end
|
332
test/unit/resources/aws_iam_access_keys_test.rb
Normal file
332
test/unit/resources/aws_iam_access_keys_test.rb
Normal file
|
@ -0,0 +1,332 @@
|
|||
|
||||
require 'aws-sdk'
|
||||
require 'helper'
|
||||
require 'aws_iam_access_keys'
|
||||
|
||||
#==========================================================#
|
||||
# Constructor Tests #
|
||||
#==========================================================#
|
||||
|
||||
class AwsIamAccessKeysConstructorTest < Minitest::Test
|
||||
# Reset provider back to the implementation default prior
|
||||
# to each test. Tests must explicitly select an alternate.
|
||||
def setup
|
||||
AwsIamAccessKeys::AccessKeyProvider.reset
|
||||
end
|
||||
|
||||
def test_bare_constructor_does_not_explode
|
||||
AwsIamAccessKeys::AccessKeyProvider.select(AlwaysEmptyMAKP)
|
||||
AwsIamAccessKeys.new
|
||||
end
|
||||
end
|
||||
|
||||
#==========================================================#
|
||||
# Filtering Tests #
|
||||
#==========================================================#
|
||||
|
||||
class AwsIamAccessKeysFilterTest < Minitest::Test
|
||||
# Reset provider back to the implementation default prior
|
||||
# to each test. Tests must explicitly select an alternate.
|
||||
def setup
|
||||
AwsIamAccessKeys::AccessKeyProvider.reset
|
||||
end
|
||||
|
||||
def test_filter_methods_should_exist
|
||||
AwsIamAccessKeys::AccessKeyProvider.select(AlwaysEmptyMAKP)
|
||||
resource = AwsIamAccessKeys.new
|
||||
[:where, :'exists?'].each do |meth|
|
||||
assert_respond_to(resource, meth)
|
||||
end
|
||||
end
|
||||
|
||||
def test_filter_method_where_should_be_chainable
|
||||
AwsIamAccessKeys::AccessKeyProvider.select(AlwaysEmptyMAKP)
|
||||
resource = AwsIamAccessKeys.new
|
||||
assert_respond_to(resource.where, :where)
|
||||
end
|
||||
|
||||
def test_filter_method_exists_should_probe_empty_when_empty
|
||||
AwsIamAccessKeys::AccessKeyProvider.select(AlwaysEmptyMAKP)
|
||||
resource = AwsIamAccessKeys.new
|
||||
refute(resource.exists?)
|
||||
end
|
||||
|
||||
def test_filter_method_exists_should_probe_present_when_present
|
||||
AwsIamAccessKeys::AccessKeyProvider.select(BasicMAKP)
|
||||
resource = AwsIamAccessKeys.new
|
||||
assert(resource.exists?)
|
||||
end
|
||||
end
|
||||
|
||||
#==========================================================#
|
||||
# Filter Criteria Tests #
|
||||
#==========================================================#
|
||||
|
||||
class AwsIamAccessKeysFilterCriteriaTest < Minitest::Test
|
||||
def setup
|
||||
# Here we always want no rseults.
|
||||
AwsIamAccessKeys::AccessKeyProvider.select(AlwaysEmptyMAKP)
|
||||
@valued_criteria = {
|
||||
username: 'bob',
|
||||
id: 'AKIA1234567890ABCDEF',
|
||||
access_key_id: 'AKIA1234567890ABCDEF',
|
||||
}
|
||||
end
|
||||
|
||||
def test_criteria_when_used_in_constructor_with_value
|
||||
@valued_criteria.each do |criterion, value|
|
||||
AwsIamAccessKeys.new(criterion => value)
|
||||
end
|
||||
end
|
||||
|
||||
def test_criteria_when_used_in_where_with_value
|
||||
@valued_criteria.each do |criterion, value|
|
||||
AwsIamAccessKeys.new.where(criterion => value)
|
||||
end
|
||||
end
|
||||
|
||||
# Negative cases
|
||||
def test_criteria_when_used_in_constructor_with_bad_criterion
|
||||
assert_raises(RuntimeError) do
|
||||
AwsIamAccessKeys.new(nope: 'some_val')
|
||||
end
|
||||
end
|
||||
|
||||
def test_criteria_when_used_in_where_with_bad_criterion
|
||||
assert_raises(RuntimeError) do
|
||||
AwsIamAccessKeys.new(nope: 'some_val')
|
||||
end
|
||||
end
|
||||
|
||||
# Identity criterion is allowed based on regex
|
||||
def test_identity_criterion_when_used_in_constructor_positive
|
||||
AwsIamAccessKeys.new('AKIA1234567890ABCDEF')
|
||||
end
|
||||
|
||||
# Permitted by FilterTable?
|
||||
def test_identity_criterion_when_used_in_where_positive
|
||||
AwsIamAccessKeys.new.where('AKIA1234567890ABCDEF')
|
||||
end
|
||||
|
||||
def test_identity_criterion_when_used_in_constructor_negative
|
||||
assert_raises(RuntimeError) do
|
||||
AwsIamAccessKeys.new('NopeAKIA1234567890ABCDEF')
|
||||
end
|
||||
end
|
||||
|
||||
# Permitted by FilterTable?
|
||||
# def test_identity_criterion_when_used_in_where_negative
|
||||
# assert_raises(RuntimeError) do
|
||||
# AwsIamAccessKeys.new.where('NopeAKIA1234567890ABCDEF')
|
||||
# end
|
||||
# end
|
||||
end
|
||||
|
||||
#==========================================================#
|
||||
# Property Tests #
|
||||
#==========================================================#
|
||||
class AwsIamAccessKeysPropertiesTest < Minitest::Test
|
||||
def setup
|
||||
# Reset back to the basic kit each time.
|
||||
AwsIamAccessKeys::AccessKeyProvider.select(BasicMAKP)
|
||||
@all_basic = AwsIamAccessKeys.new
|
||||
end
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# created_date / created_days_ago / created_hours_ago #
|
||||
#----------------------------------------------------------#
|
||||
def test_property_created_date
|
||||
assert_kind_of(DateTime, @all_basic.entries.first.created_date)
|
||||
|
||||
arg_filtered = @all_basic.where(created_date: DateTime.parse('2017-10-27T17:58:00Z'))
|
||||
assert_equal(1, arg_filtered.entries.count)
|
||||
assert arg_filtered.access_key_ids.first.end_with?('BOB')
|
||||
|
||||
block_filtered = @all_basic.where { created_date.friday? }
|
||||
assert_equal(1, block_filtered.entries.count)
|
||||
assert block_filtered.access_key_ids.first.end_with?('BOB')
|
||||
end
|
||||
|
||||
def test_property_created_days_ago
|
||||
assert_kind_of(Integer, @all_basic.entries.first.created_days_ago)
|
||||
|
||||
arg_filtered = @all_basic.where(created_days_ago: 9)
|
||||
assert_equal(1, arg_filtered.entries.count)
|
||||
assert arg_filtered.access_key_ids.first.end_with?('SALLY')
|
||||
|
||||
block_filtered = @all_basic.where { created_days_ago > 2 }
|
||||
assert_equal(2, block_filtered.entries.count)
|
||||
end
|
||||
|
||||
def test_property_created_hours_ago
|
||||
assert_kind_of(Integer, @all_basic.entries.first.created_hours_ago)
|
||||
|
||||
arg_filtered = @all_basic.where(created_hours_ago: 222)
|
||||
assert_equal(1, arg_filtered.entries.count)
|
||||
assert arg_filtered.access_key_ids.first.end_with?('SALLY')
|
||||
|
||||
block_filtered = @all_basic.where { created_hours_ago > 100 }
|
||||
assert_equal(2, block_filtered.entries.count)
|
||||
end
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# active / inactive #
|
||||
#----------------------------------------------------------#
|
||||
def test_property_active
|
||||
assert_kind_of(TrueClass, @all_basic.entries.first.active)
|
||||
|
||||
arg_filtered = @all_basic.where(active: true)
|
||||
assert_equal(2, arg_filtered.entries.count)
|
||||
|
||||
block_filtered = @all_basic.where { active }
|
||||
assert_equal(2, block_filtered.entries.count)
|
||||
assert block_filtered.access_key_ids.first.end_with?('BOB')
|
||||
end
|
||||
|
||||
def test_property_inactive
|
||||
assert_kind_of(FalseClass, @all_basic.entries.first.inactive)
|
||||
|
||||
arg_filtered = @all_basic.where(inactive: true)
|
||||
assert_equal(1, arg_filtered.entries.count)
|
||||
|
||||
block_filtered = @all_basic.where { inactive }
|
||||
assert_equal(1, block_filtered.entries.count)
|
||||
assert block_filtered.access_key_ids.first.end_with?('ROBIN')
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------#
|
||||
# last_used_date / last_used_days_ago / last_used_hours_ago #
|
||||
#-----------------------------------------------------------#
|
||||
def test_property_last_used_date
|
||||
assert_kind_of(NilClass, @all_basic.entries[0].last_used_date)
|
||||
assert_kind_of(DateTime, @all_basic.entries[1].last_used_date)
|
||||
|
||||
arg_filtered = @all_basic.where(last_used_date: DateTime.parse('2017-10-27T17:58:00Z'))
|
||||
assert_equal(1, arg_filtered.entries.count)
|
||||
assert arg_filtered.access_key_ids.first.end_with?('SALLY')
|
||||
|
||||
block_filtered = @all_basic.where { last_used_date and last_used_date.friday? }
|
||||
assert_equal(1, block_filtered.entries.count)
|
||||
assert block_filtered.access_key_ids.first.end_with?('SALLY')
|
||||
end
|
||||
|
||||
def test_property_last_used_days_ago
|
||||
assert_kind_of(NilClass, @all_basic.entries[0].last_used_days_ago)
|
||||
assert_kind_of(Integer, @all_basic.entries[1].last_used_days_ago)
|
||||
|
||||
arg_filtered = @all_basic.where(last_used_days_ago: 4)
|
||||
assert_equal(1, arg_filtered.entries.count)
|
||||
assert arg_filtered.access_key_ids.first.end_with?('SALLY')
|
||||
|
||||
block_filtered = @all_basic.where { last_used_days_ago and last_used_days_ago < 2 }
|
||||
assert_equal(1, block_filtered.entries.count)
|
||||
assert block_filtered.access_key_ids.first.end_with?('ROBIN')
|
||||
end
|
||||
|
||||
def test_property_last_used_hours_ago
|
||||
assert_kind_of(NilClass, @all_basic.entries[0].last_used_hours_ago)
|
||||
assert_kind_of(Integer, @all_basic.entries[1].last_used_hours_ago)
|
||||
|
||||
arg_filtered = @all_basic.where(last_used_hours_ago: 102)
|
||||
assert_equal(1, arg_filtered.entries.count)
|
||||
assert arg_filtered.access_key_ids.first.end_with?('SALLY')
|
||||
|
||||
block_filtered = @all_basic.where { last_used_hours_ago and last_used_hours_ago < 10 }
|
||||
assert_equal(1, block_filtered.entries.count)
|
||||
assert block_filtered.access_key_ids.first.end_with?('ROBIN')
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------#
|
||||
# ever_used / never_used #
|
||||
#-----------------------------------------------------------#
|
||||
def test_property_ever_used
|
||||
assert_kind_of(FalseClass, @all_basic.entries[0].ever_used)
|
||||
assert_kind_of(TrueClass, @all_basic.entries[1].ever_used)
|
||||
|
||||
arg_filtered = @all_basic.where(ever_used: true)
|
||||
assert_equal(2, arg_filtered.entries.count)
|
||||
|
||||
block_filtered = @all_basic.where { ever_used }
|
||||
assert_equal(2, block_filtered.entries.count)
|
||||
assert block_filtered.access_key_ids.first.end_with?('SALLY')
|
||||
end
|
||||
|
||||
def test_property_never_used
|
||||
assert_kind_of(TrueClass, @all_basic.entries[0].never_used)
|
||||
assert_kind_of(FalseClass, @all_basic.entries[1].never_used)
|
||||
|
||||
arg_filtered = @all_basic.where(never_used: true)
|
||||
assert_equal(1, arg_filtered.entries.count)
|
||||
|
||||
block_filtered = @all_basic.where { never_used }
|
||||
assert_equal(1, block_filtered.entries.count)
|
||||
assert block_filtered.access_key_ids.first.end_with?('BOB')
|
||||
end
|
||||
end
|
||||
#==========================================================#
|
||||
# Mock Support Classes #
|
||||
#==========================================================#
|
||||
|
||||
# MAKP = MockAccessKeyProvider. Abbreviation not used
|
||||
# outside this file.
|
||||
|
||||
class AlwaysEmptyMAKP < AwsIamAccessKeys::AccessKeyProvider
|
||||
def fetch(_filter_criteria)
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
class BasicMAKP < AwsIamAccessKeys::AccessKeyProvider
|
||||
def fetch(_filter_criteria) # rubocop:disable Metrics/MethodLength
|
||||
[
|
||||
{
|
||||
username: 'bob',
|
||||
access_key_id: 'AKIA1234567890123BOB',
|
||||
id: 'AKIA1234567890123BOB',
|
||||
created_date: DateTime.parse('2017-10-27T17:58:00Z'),
|
||||
created_days_ago: 4,
|
||||
created_hours_ago: 102,
|
||||
status: 'Active',
|
||||
active: true,
|
||||
inactive: false,
|
||||
last_used_date: nil,
|
||||
last_used_days_ago: nil,
|
||||
last_used_hours_ago: nil,
|
||||
ever_used: false,
|
||||
never_used: true,
|
||||
},
|
||||
{
|
||||
username: 'sally',
|
||||
access_key_id: 'AKIA12345678901SALLY',
|
||||
id: 'AKIA12345678901SALLY',
|
||||
created_date: DateTime.parse('2017-10-22T17:58:00Z'),
|
||||
created_days_ago: 9,
|
||||
created_hours_ago: 222,
|
||||
status: 'Active',
|
||||
active: true,
|
||||
inactive: false,
|
||||
last_used_date: DateTime.parse('2017-10-27T17:58:00Z'),
|
||||
last_used_days_ago: 4,
|
||||
last_used_hours_ago: 102,
|
||||
ever_used: true,
|
||||
never_used: false,
|
||||
},
|
||||
{
|
||||
username: 'robin',
|
||||
access_key_id: 'AKIA12345678901ROBIN',
|
||||
id: 'AKIA12345678901ROBIN',
|
||||
created_date: DateTime.parse('2017-10-31T17:58:00Z'),
|
||||
created_days_ago: 1,
|
||||
created_hours_ago: 12,
|
||||
status: 'Inactive',
|
||||
active: false,
|
||||
inactive: true,
|
||||
last_used_date: DateTime.parse('2017-10-31T20:58:00Z'),
|
||||
last_used_days_ago: 0,
|
||||
last_used_hours_ago: 5,
|
||||
ever_used: true,
|
||||
never_used: false,
|
||||
},
|
||||
]
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue