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-04 21:57:16 +00:00
|
|
|
class AwsIamAccessKey < Inspec.resource(1)
|
2019-06-11 22:24:35 +00:00
|
|
|
name "aws_iam_access_key"
|
|
|
|
desc "Verifies settings for an individual IAM access key"
|
2019-03-19 14:17:32 +00:00
|
|
|
example <<~EXAMPLE
|
2017-04-05 09:46:11 +00:00
|
|
|
describe aws_iam_access_key(username: 'username', id: 'access-key id') do
|
2017-04-15 12:47:16 +00:00
|
|
|
it { should exist }
|
|
|
|
it { should_not be_active }
|
|
|
|
its('create_date') { should be > Time.now - 365 * 86400 }
|
|
|
|
its('last_used_date') { should be > Time.now - 90 * 86400 }
|
2017-04-04 21:57:16 +00:00
|
|
|
end
|
2019-03-19 14:17:32 +00:00
|
|
|
EXAMPLE
|
2019-06-11 22:24:35 +00:00
|
|
|
supports platform: "aws"
|
2018-02-08 04:26:37 +00:00
|
|
|
|
|
|
|
include AwsSingularResourceMixin
|
|
|
|
attr_reader :access_key_id, :create_date, :status, :username
|
|
|
|
alias id access_key_id
|
|
|
|
|
|
|
|
def validate_params(raw_params)
|
|
|
|
recognized_params = check_resource_param_names(
|
|
|
|
raw_params: raw_params,
|
2019-07-09 00:20:30 +00:00
|
|
|
allowed_params: %i{username id access_key_id},
|
2018-02-08 04:26:37 +00:00
|
|
|
allowed_scalar_name: :access_key_id,
|
2019-06-11 22:24:35 +00:00
|
|
|
allowed_scalar_type: String
|
2018-02-08 04:26:37 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
# id and access_key_id are aliases; standardize on access_key_id
|
|
|
|
recognized_params[:access_key_id] = recognized_params.delete(:id) if recognized_params.key?(:id)
|
|
|
|
|
|
|
|
# Validate format of access_key_id
|
2019-06-11 22:24:35 +00:00
|
|
|
if recognized_params[:access_key_id] &&
|
|
|
|
recognized_params[:access_key_id] !~ (/^AKIA[0-9A-Z]{16}$/)
|
|
|
|
raise ArgumentError, "Incorrect format for Access Key ID - expected AKIA followed " \
|
|
|
|
"by 16 letters or numbers"
|
2018-02-08 04:26:37 +00:00
|
|
|
end
|
2017-04-15 12:47:16 +00:00
|
|
|
|
2018-02-08 04:26:37 +00:00
|
|
|
# One of username and access_key_id is required
|
|
|
|
if recognized_params[:username].nil? && recognized_params[:access_key_id].nil?
|
2019-06-11 22:24:35 +00:00
|
|
|
raise ArgumentError, "You must provide at lease one of access_key_id or username to aws_iam_access_key"
|
2018-02-08 04:26:37 +00:00
|
|
|
end
|
2017-04-04 21:57:16 +00:00
|
|
|
|
2018-02-08 04:26:37 +00:00
|
|
|
recognized_params
|
2017-04-04 21:57:16 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def active?
|
2018-02-08 04:26:37 +00:00
|
|
|
return nil unless exists?
|
2019-07-09 00:20:30 +00:00
|
|
|
|
2019-06-11 22:24:35 +00:00
|
|
|
status == "Active"
|
2017-04-04 21:57:16 +00:00
|
|
|
end
|
|
|
|
|
2017-04-15 12:47:16 +00:00
|
|
|
def to_s
|
2018-02-08 04:26:37 +00:00
|
|
|
"IAM Access-Key #{access_key_id}"
|
2017-04-15 12:47:16 +00:00
|
|
|
end
|
2017-04-04 21:57:16 +00:00
|
|
|
|
2018-02-08 04:26:37 +00:00
|
|
|
def last_used_date
|
|
|
|
return nil unless exists?
|
|
|
|
return @last_used_date if defined? @last_used_date
|
2019-07-09 00:20:30 +00:00
|
|
|
|
2018-02-08 04:26:37 +00:00
|
|
|
backend = BackendFactory.create(inspec_runner)
|
2018-02-14 19:15:20 +00:00
|
|
|
catch_aws_errors do
|
|
|
|
@last_used_date = backend.get_access_key_last_used({ access_key_id: access_key_id }).access_key_last_used.last_used_date
|
|
|
|
end
|
2017-04-15 12:47:16 +00:00
|
|
|
end
|
|
|
|
|
2018-02-08 04:26:37 +00:00
|
|
|
def fetch_from_api
|
|
|
|
backend = BackendFactory.create(inspec_runner)
|
|
|
|
query = {}
|
|
|
|
query[:user_name] = username if username
|
2017-04-15 12:47:16 +00:00
|
|
|
|
2018-02-08 04:26:37 +00:00
|
|
|
response = backend.list_access_keys(query)
|
2017-04-15 12:47:16 +00:00
|
|
|
|
2018-02-08 04:26:37 +00:00
|
|
|
access_keys = response.access_key_metadata.select do |key|
|
|
|
|
if access_key_id
|
|
|
|
key.access_key_id == access_key_id
|
|
|
|
else
|
|
|
|
true
|
2017-04-15 12:47:16 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-02-08 04:26:37 +00:00
|
|
|
if access_keys.empty?
|
|
|
|
@exists = false
|
|
|
|
return
|
2017-04-15 12:47:16 +00:00
|
|
|
end
|
|
|
|
|
2018-02-08 04:26:37 +00:00
|
|
|
if access_keys.count > 1
|
2019-06-11 22:24:35 +00:00
|
|
|
raise "More than one access key matched for aws_iam_access_key. Use more specific paramaters, such as access_key_id."
|
2017-04-04 21:57:16 +00:00
|
|
|
end
|
|
|
|
|
2018-02-08 04:26:37 +00:00
|
|
|
@exists = true
|
|
|
|
@access_key_id = access_keys[0].access_key_id
|
|
|
|
@username = access_keys[0].user_name
|
|
|
|
@create_date = access_keys[0].create_date
|
|
|
|
@status = access_keys[0].status
|
|
|
|
# Last used date is lazily loaded, separate API call
|
|
|
|
rescue Aws::IAM::Errors::NoSuchEntity
|
|
|
|
@exists = false
|
2017-04-15 12:47:16 +00:00
|
|
|
end
|
|
|
|
|
2018-02-08 04:26:37 +00:00
|
|
|
class Backend
|
|
|
|
class AwsClientApi < AwsBackendBase
|
|
|
|
BackendFactory.set_default_backend(self)
|
|
|
|
self.aws_client_class = Aws::IAM::Client
|
|
|
|
|
|
|
|
def list_access_keys(query)
|
|
|
|
aws_service_client.list_access_keys(query)
|
|
|
|
end
|
|
|
|
end
|
2017-04-04 21:57:16 +00:00
|
|
|
end
|
|
|
|
end
|