2019-06-11 22:24:35 +00:00
require " resource_support/aws/aws_singular_resource_mixin "
require " resource_support/aws/aws_backend_base "
require " aws-sdk-iam "
2019-05-25 08:33:26 +00:00
2017-04-28 10:50:26 +00:00
class AwsIamPasswordPolicy < Inspec . resource ( 1 )
2019-06-11 22:24:35 +00:00
name " aws_iam_password_policy "
desc " Verifies iam password policy "
2017-04-06 19:12:19 +00:00
2019-03-19 14:17:32 +00:00
example << ~ EXAMPLE
2017-04-28 10:50:26 +00:00
describe aws_iam_password_policy do
2017-10-12 15:54:55 +00:00
its ( 'requires_lowercase_characters?' ) { should be true }
2017-04-06 19:12:19 +00:00
end
2017-04-28 10:50:26 +00:00
describe aws_iam_password_policy do
2017-10-12 15:54:55 +00:00
its ( 'requires_uppercase_characters?' ) { should be true }
2017-04-06 19:12:19 +00:00
end
2019-03-19 14:17:32 +00:00
EXAMPLE
2019-06-11 22:24:35 +00:00
supports platform : " aws "
2017-04-06 19:12:19 +00:00
2018-02-08 04:26:37 +00:00
# TODO: rewrite to avoid direct injection, match other resources, use AwsSingularResourceMixin
def initialize ( conn = nil )
2018-02-14 19:15:20 +00:00
catch_aws_errors do
2018-02-14 20:59:57 +00:00
begin
if conn
# We're in a mocked unit test.
@policy = conn . iam_resource . account_password_policy
else
# Don't use the resource approach. It's a CRUD operation
# - if the policy does not exist, you get back a blank object to populate and save.
# Using the Client will throw an exception if no policy exists.
@policy = inspec_runner . backend . aws_client ( Aws :: IAM :: Client ) . get_account_password_policy . password_policy
end
rescue Aws :: IAM :: Errors :: NoSuchEntity
@policy = nil
end
2018-02-14 19:15:20 +00:00
end
2017-04-06 19:12:19 +00:00
end
2018-02-14 19:15:20 +00:00
# TODO: DRY up, see https://github.com/chef/inspec/issues/2633
# Copied from resource_support/aws/aws_resource_mixin.rb
def catch_aws_errors
yield
rescue Aws :: Errors :: MissingCredentialsError
# The AWS error here is unhelpful:
# "unable to sign request without credentials set"
Inspec :: Log . error " It appears that you have not set your AWS credentials. You may set them using environment variables, or using the 'aws://region/aws_credentials_profile' target. See https://www.inspec.io/docs/reference/platforms for details. "
2019-06-11 22:24:35 +00:00
fail_resource ( " No AWS credentials available " )
2018-02-14 19:15:20 +00:00
rescue Aws :: Errors :: ServiceError = > e
fail_resource e . message
end
# TODO: DRY up, see https://github.com/chef/inspec/issues/2633
# Copied from resource_support/aws/aws_singular_resource_mixin.rb
2018-02-08 04:26:37 +00:00
def inspec_runner
# When running under inspec-cli, we have an 'inspec' method that
# returns the runner. When running under unit tests, we don't
# have that, but we still have to call this to pass something
# (nil is OK) to the backend.
# TODO: remove with https://github.com/chef/inspec-aws/issues/216
# TODO: remove after rewrite to include AwsSingularResource
inspec if respond_to? ( :inspec )
end
2018-02-14 20:59:57 +00:00
def to_s
2019-06-11 22:24:35 +00:00
" IAM Password-Policy "
2017-04-06 19:12:19 +00:00
end
2018-02-14 20:59:57 +00:00
def exists?
! @policy . nil?
2017-04-06 19:12:19 +00:00
end
2018-02-14 20:59:57 +00:00
#-------------------------- Properties ----------------------------#
2017-04-06 19:12:19 +00:00
def minimum_password_length
@policy . minimum_password_length
end
2018-02-14 20:59:57 +00:00
def max_password_age_in_days
2019-06-11 22:24:35 +00:00
raise " this policy does not expire passwords " unless expire_passwords?
2019-07-09 00:20:30 +00:00
2018-02-14 20:59:57 +00:00
@policy . max_password_age
2017-04-06 19:12:19 +00:00
end
2018-02-14 20:59:57 +00:00
def number_of_passwords_to_remember
2019-06-11 22:24:35 +00:00
raise " this policy does not prevent password reuse " \
2018-02-14 20:59:57 +00:00
unless prevent_password_reuse?
2019-07-09 00:20:30 +00:00
2018-02-14 20:59:57 +00:00
@policy . password_reuse_prevention
2017-04-06 19:12:19 +00:00
end
2017-04-13 19:00:04 +00:00
2018-02-14 20:59:57 +00:00
#-------------------------- Matchers ----------------------------#
2019-07-09 00:20:30 +00:00
% i {
require_lowercase_characters
require_uppercase_characters
require_symbols
require_numbers
expire_passwords
} . each do | matcher_stem |
2018-02-14 20:59:57 +00:00
# Create our predicates (for example, 'require_symbols?')
2019-06-11 22:24:35 +00:00
stem_with_question_mark = ( matcher_stem . to_s + " ? " ) . to_sym
2018-02-14 20:59:57 +00:00
define_method stem_with_question_mark do
@policy . send ( matcher_stem )
end
# RSpec will expose that as (for example) `be_require_symbols`.
# To undo that, we have to make a matcher alias.
2019-06-11 22:24:35 +00:00
stem_with_be = ( " be_ " + matcher_stem . to_s ) . to_sym
2018-02-14 20:59:57 +00:00
RSpec :: Matchers . alias_matcher matcher_stem , stem_with_be
2017-04-13 19:00:04 +00:00
end
2018-02-14 20:59:57 +00:00
# This one has an awkward name mapping
def allow_users_to_change_passwords?
@policy . allow_users_to_change_password
2017-04-13 19:00:04 +00:00
end
2018-02-14 20:59:57 +00:00
RSpec :: Matchers . alias_matcher :allow_users_to_change_passwords , :be_allow_users_to_change_passwords
2017-06-13 05:41:43 +00:00
2018-02-14 20:59:57 +00:00
# This one has custom logic and renaming
def prevent_password_reuse?
2017-06-13 05:41:43 +00:00
! @policy . password_reuse_prevention . nil?
end
2018-02-14 20:59:57 +00:00
RSpec :: Matchers . alias_matcher :prevent_password_reuse , :be_prevent_password_reuse
2017-04-06 19:12:19 +00:00
end