inspec 4.56.17 → 5.7.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/inspec.gemspec +4 -1
- data/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml +1 -1
- metadata +19 -62
- data/lib/resource_support/aws/aws_backend_base.rb +0 -12
- data/lib/resource_support/aws/aws_backend_factory_mixin.rb +0 -12
- data/lib/resource_support/aws/aws_plural_resource_mixin.rb +0 -24
- data/lib/resource_support/aws/aws_resource_mixin.rb +0 -69
- data/lib/resource_support/aws/aws_singular_resource_mixin.rb +0 -27
- data/lib/resource_support/aws.rb +0 -76
- data/lib/resources/aws/aws_billing_report.rb +0 -105
- data/lib/resources/aws/aws_billing_reports.rb +0 -74
- data/lib/resources/aws/aws_cloudtrail_trail.rb +0 -97
- data/lib/resources/aws/aws_cloudtrail_trails.rb +0 -51
- data/lib/resources/aws/aws_cloudwatch_alarm.rb +0 -67
- data/lib/resources/aws/aws_cloudwatch_log_metric_filter.rb +0 -105
- data/lib/resources/aws/aws_config_delivery_channel.rb +0 -74
- data/lib/resources/aws/aws_config_recorder.rb +0 -99
- data/lib/resources/aws/aws_ebs_volume.rb +0 -127
- data/lib/resources/aws/aws_ebs_volumes.rb +0 -69
- data/lib/resources/aws/aws_ec2_instance.rb +0 -162
- data/lib/resources/aws/aws_ec2_instances.rb +0 -69
- data/lib/resources/aws/aws_ecs_cluster.rb +0 -87
- data/lib/resources/aws/aws_eks_cluster.rb +0 -105
- data/lib/resources/aws/aws_elb.rb +0 -85
- data/lib/resources/aws/aws_elbs.rb +0 -84
- data/lib/resources/aws/aws_flow_log.rb +0 -106
- data/lib/resources/aws/aws_iam_access_key.rb +0 -112
- data/lib/resources/aws/aws_iam_access_keys.rb +0 -153
- data/lib/resources/aws/aws_iam_group.rb +0 -62
- data/lib/resources/aws/aws_iam_groups.rb +0 -56
- data/lib/resources/aws/aws_iam_password_policy.rb +0 -121
- data/lib/resources/aws/aws_iam_policies.rb +0 -57
- data/lib/resources/aws/aws_iam_policy.rb +0 -311
- data/lib/resources/aws/aws_iam_role.rb +0 -60
- data/lib/resources/aws/aws_iam_root_user.rb +0 -82
- data/lib/resources/aws/aws_iam_user.rb +0 -145
- data/lib/resources/aws/aws_iam_users.rb +0 -160
- data/lib/resources/aws/aws_kms_key.rb +0 -100
- data/lib/resources/aws/aws_kms_keys.rb +0 -58
- data/lib/resources/aws/aws_rds_instance.rb +0 -74
- data/lib/resources/aws/aws_route_table.rb +0 -67
- data/lib/resources/aws/aws_route_tables.rb +0 -64
- data/lib/resources/aws/aws_s3_bucket.rb +0 -141
- data/lib/resources/aws/aws_s3_bucket_object.rb +0 -87
- data/lib/resources/aws/aws_s3_buckets.rb +0 -52
- data/lib/resources/aws/aws_security_group.rb +0 -314
- data/lib/resources/aws/aws_security_groups.rb +0 -71
- data/lib/resources/aws/aws_sns_subscription.rb +0 -82
- data/lib/resources/aws/aws_sns_topic.rb +0 -57
- data/lib/resources/aws/aws_sns_topics.rb +0 -60
- data/lib/resources/aws/aws_sqs_queue.rb +0 -66
- data/lib/resources/aws/aws_subnet.rb +0 -92
- data/lib/resources/aws/aws_subnets.rb +0 -56
- data/lib/resources/aws/aws_vpc.rb +0 -77
- data/lib/resources/aws/aws_vpcs.rb +0 -55
- data/lib/resources/azure/azure_backend.rb +0 -379
- data/lib/resources/azure/azure_generic_resource.rb +0 -55
- data/lib/resources/azure/azure_resource_group.rb +0 -151
- data/lib/resources/azure/azure_virtual_machine.rb +0 -262
- data/lib/resources/azure/azure_virtual_machine_data_disk.rb +0 -131
@@ -1,51 +0,0 @@
|
|
1
|
-
require "resource_support/aws/aws_plural_resource_mixin"
|
2
|
-
require "resource_support/aws/aws_backend_base"
|
3
|
-
require "aws-sdk-cloudtrail"
|
4
|
-
|
5
|
-
class AwsCloudTrailTrails < Inspec.resource(1)
|
6
|
-
name "aws_cloudtrail_trails"
|
7
|
-
desc "Verifies settings for AWS CloudTrail Trails in bulk"
|
8
|
-
example <<~EXAMPLE
|
9
|
-
describe aws_cloudtrail_trails do
|
10
|
-
it { should exist }
|
11
|
-
end
|
12
|
-
EXAMPLE
|
13
|
-
supports platform: "aws"
|
14
|
-
|
15
|
-
include AwsPluralResourceMixin
|
16
|
-
|
17
|
-
def validate_params(resource_params)
|
18
|
-
unless resource_params.empty?
|
19
|
-
raise ArgumentError, "aws_cloudtrail_trails does not accept resource parameters."
|
20
|
-
end
|
21
|
-
|
22
|
-
resource_params
|
23
|
-
end
|
24
|
-
|
25
|
-
# Underlying FilterTable implementation.
|
26
|
-
filter = FilterTable.create
|
27
|
-
filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
|
28
|
-
filter.register_column(:trail_arns, field: :trail_arn)
|
29
|
-
filter.register_column(:names, field: :name)
|
30
|
-
filter.install_filter_methods_on_resource(self, :table)
|
31
|
-
|
32
|
-
def to_s
|
33
|
-
"CloudTrail Trails"
|
34
|
-
end
|
35
|
-
|
36
|
-
def fetch_from_api
|
37
|
-
backend = BackendFactory.create(inspec_runner)
|
38
|
-
@table = backend.describe_trails({}).to_h[:trail_list]
|
39
|
-
end
|
40
|
-
|
41
|
-
class Backend
|
42
|
-
class AwsClientApi < AwsBackendBase
|
43
|
-
AwsCloudTrailTrails::BackendFactory.set_default_backend(self)
|
44
|
-
self.aws_client_class = Aws::CloudTrail::Client
|
45
|
-
|
46
|
-
def describe_trails(query)
|
47
|
-
aws_service_client.describe_trails(query)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
require "resource_support/aws/aws_singular_resource_mixin"
|
2
|
-
require "resource_support/aws/aws_backend_base"
|
3
|
-
require "aws-sdk-cloudwatch"
|
4
|
-
|
5
|
-
class AwsCloudwatchAlarm < Inspec.resource(1)
|
6
|
-
name "aws_cloudwatch_alarm"
|
7
|
-
desc <<~EXAMPLE
|
8
|
-
# Look for a specific alarm
|
9
|
-
aws_cloudwatch_alarm(
|
10
|
-
metric_name: 'my-metric-name',
|
11
|
-
metric_namespace: 'my-metric-namespace',
|
12
|
-
) do
|
13
|
-
it { should exist }
|
14
|
-
end
|
15
|
-
EXAMPLE
|
16
|
-
supports platform: "aws"
|
17
|
-
|
18
|
-
include AwsSingularResourceMixin
|
19
|
-
attr_reader :alarm_actions, :alarm_name, :metric_name, :metric_namespace
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def validate_params(raw_params)
|
24
|
-
recognized_params = check_resource_param_names(
|
25
|
-
raw_params: raw_params,
|
26
|
-
allowed_params: %i{metric_name metric_namespace}
|
27
|
-
)
|
28
|
-
validated_params = {}
|
29
|
-
# Currently you must specify exactly metric_name and metric_namespace
|
30
|
-
%i{metric_name metric_namespace}.each do |param|
|
31
|
-
raise ArgumentError, "Missing resource param #{param}" unless recognized_params.key?(param)
|
32
|
-
|
33
|
-
validated_params[param] = recognized_params.delete(param)
|
34
|
-
end
|
35
|
-
|
36
|
-
validated_params
|
37
|
-
end
|
38
|
-
|
39
|
-
def fetch_from_api
|
40
|
-
aws_alarms = BackendFactory.create(inspec_runner).describe_alarms_for_metric(
|
41
|
-
metric_name: @metric_name,
|
42
|
-
namespace: @metric_namespace
|
43
|
-
)
|
44
|
-
if aws_alarms.metric_alarms.empty?
|
45
|
-
@exists = false
|
46
|
-
elsif aws_alarms.metric_alarms.count > 1
|
47
|
-
alarms = aws_alarms.metric_alarms.map(&:alarm_name)
|
48
|
-
raise "More than one Cloudwatch Alarm was matched. Try using " \
|
49
|
-
"more specific resource parameters. Alarms matched: #{alarms.join(", ")}"
|
50
|
-
else
|
51
|
-
@alarm_actions = aws_alarms.metric_alarms.first.alarm_actions
|
52
|
-
@alarm_name = aws_alarms.metric_alarms.first.alarm_name
|
53
|
-
@exists = true
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
class Backend
|
58
|
-
class AwsClientApi < AwsBackendBase
|
59
|
-
AwsCloudwatchAlarm::BackendFactory.set_default_backend(self)
|
60
|
-
self.aws_client_class = Aws::CloudWatch::Client
|
61
|
-
|
62
|
-
def describe_alarms_for_metric(query)
|
63
|
-
aws_service_client.describe_alarms_for_metric(query)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
@@ -1,105 +0,0 @@
|
|
1
|
-
require "resource_support/aws/aws_singular_resource_mixin"
|
2
|
-
require "resource_support/aws/aws_backend_base"
|
3
|
-
require "aws-sdk-cloudwatchlogs"
|
4
|
-
|
5
|
-
class AwsCloudwatchLogMetricFilter < Inspec.resource(1)
|
6
|
-
name "aws_cloudwatch_log_metric_filter"
|
7
|
-
desc "Verifies individual Cloudwatch Log Metric Filters"
|
8
|
-
example <<~EXAMPLE
|
9
|
-
# Look for a LMF by its filter name and log group name. This combination
|
10
|
-
# will always either find at most one LMF - no duplicates.
|
11
|
-
describe aws_cloudwatch_log_metric_filter(
|
12
|
-
filter_name: 'my-filter',
|
13
|
-
log_group_name: 'my-log-group'
|
14
|
-
) do
|
15
|
-
it { should exist }
|
16
|
-
end
|
17
|
-
|
18
|
-
# Search for an LMF by pattern and log group.
|
19
|
-
# This could result in an error if the results are not unique.
|
20
|
-
describe aws_cloudwatch_log_metric_filter(
|
21
|
-
log_group_name: 'my-log-group',
|
22
|
-
pattern: 'my-filter'
|
23
|
-
) do
|
24
|
-
it { should exist }
|
25
|
-
end
|
26
|
-
EXAMPLE
|
27
|
-
supports platform: "aws"
|
28
|
-
include AwsSingularResourceMixin
|
29
|
-
attr_reader :filter_name, :log_group_name, :metric_name, :metric_namespace, :pattern
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def validate_params(raw_params)
|
34
|
-
validated_params = check_resource_param_names(
|
35
|
-
raw_params: raw_params,
|
36
|
-
allowed_params: %i{filter_name log_group_name pattern}
|
37
|
-
)
|
38
|
-
if validated_params.empty?
|
39
|
-
raise ArgumentError, "You must provide either filter_name, log_group, or pattern to aws_cloudwatch_log_metric_filter."
|
40
|
-
end
|
41
|
-
|
42
|
-
validated_params
|
43
|
-
end
|
44
|
-
|
45
|
-
def fetch_from_api
|
46
|
-
# get a backend
|
47
|
-
backend = BackendFactory.create(inspec_runner)
|
48
|
-
|
49
|
-
# Perform query with remote filtering
|
50
|
-
aws_search_criteria = {}
|
51
|
-
aws_search_criteria[:filter_name] = filter_name if filter_name
|
52
|
-
aws_search_criteria[:log_group_name] = log_group_name if log_group_name
|
53
|
-
begin
|
54
|
-
aws_results = backend.describe_metric_filters(aws_search_criteria)
|
55
|
-
rescue Aws::CloudWatchLogs::Errors::ResourceNotFoundException
|
56
|
-
@exists = false
|
57
|
-
return
|
58
|
-
end
|
59
|
-
|
60
|
-
# Then perform local filtering
|
61
|
-
if pattern
|
62
|
-
aws_results.select! { |lmf| lmf.filter_pattern == pattern }
|
63
|
-
end
|
64
|
-
|
65
|
-
# Check result count. We're a singular resource and can tolerate
|
66
|
-
# 0 or 1 results, not multiple.
|
67
|
-
if aws_results.count > 1
|
68
|
-
raise "More than one result was returned, but aws_cloudwatch_log_metric_filter "\
|
69
|
-
"can only handle a single AWS resource. Consider passing more resource "\
|
70
|
-
"parameters to narrow down the search."
|
71
|
-
elsif aws_results.empty?
|
72
|
-
@exists = false
|
73
|
-
else
|
74
|
-
@exists = true
|
75
|
-
# Unpack the funny-shaped object we got back from AWS into our instance vars
|
76
|
-
lmf = aws_results.first
|
77
|
-
@filter_name = lmf.filter_name
|
78
|
-
@log_group_name = lmf.log_group_name
|
79
|
-
@pattern = lmf.filter_pattern # Note inconsistent name
|
80
|
-
# AWS SDK returns an array of metric transformations
|
81
|
-
# but only allows one (mandatory) entry, let's flatten that
|
82
|
-
@metric_name = lmf.metric_transformations.first.metric_name
|
83
|
-
@metric_namespace = lmf.metric_transformations.first.metric_namespace
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
class Backend
|
88
|
-
# Uses the cloudwatch API to really talk to AWS
|
89
|
-
class AwsClientApi < AwsBackendBase
|
90
|
-
BackendFactory.set_default_backend(self)
|
91
|
-
self.aws_client_class = Aws::CloudWatchLogs::Client
|
92
|
-
|
93
|
-
def describe_metric_filters(criteria)
|
94
|
-
query = {}
|
95
|
-
query[:filter_name_prefix] = criteria[:filter_name] if criteria[:filter_name]
|
96
|
-
query[:log_group_name] = criteria[:log_group_name] if criteria[:log_group_name]
|
97
|
-
# 'pattern' is not available as a remote filter,
|
98
|
-
# we filter it after the fact locally
|
99
|
-
# TODO: handle pagination? Max 50/page. Maybe you want a plural resource?
|
100
|
-
aws_response = aws_service_client.describe_metric_filters(query)
|
101
|
-
aws_response.metric_filters
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
require "resource_support/aws/aws_singular_resource_mixin"
|
2
|
-
require "resource_support/aws/aws_backend_base"
|
3
|
-
require "aws-sdk-configservice"
|
4
|
-
|
5
|
-
class AwsConfigDeliveryChannel < Inspec.resource(1)
|
6
|
-
name "aws_config_delivery_channel"
|
7
|
-
desc "Verifies settings for AWS Config Delivery Channel"
|
8
|
-
example <<~EXAMPLE
|
9
|
-
describe aws_config_delivery_channel do
|
10
|
-
it { should exist }
|
11
|
-
its('s3_bucket_name') { should eq 'my_bucket' }
|
12
|
-
its('sns_topic_arn') { should eq arn:aws:sns:us-east-1:721741954427:sns_topic' }
|
13
|
-
end
|
14
|
-
EXAMPLE
|
15
|
-
supports platform: "aws"
|
16
|
-
|
17
|
-
include AwsSingularResourceMixin
|
18
|
-
attr_reader :channel_name, :s3_bucket_name, :s3_key_prefix, :sns_topic_arn,
|
19
|
-
:delivery_frequency_in_hours
|
20
|
-
|
21
|
-
def to_s
|
22
|
-
"Config_Delivery_Channel: #{@channel_name}"
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def validate_params(raw_params)
|
28
|
-
validated_params = check_resource_param_names(
|
29
|
-
raw_params: raw_params,
|
30
|
-
allowed_params: [:channel_name],
|
31
|
-
allowed_scalar_name: :channel_name,
|
32
|
-
allowed_scalar_type: String
|
33
|
-
)
|
34
|
-
|
35
|
-
validated_params
|
36
|
-
end
|
37
|
-
|
38
|
-
def fetch_from_api
|
39
|
-
backend = BackendFactory.create(inspec_runner)
|
40
|
-
query = @channel_name ? { delivery_channel_names: [@channel_name] } : {}
|
41
|
-
response = backend.describe_delivery_channels(query)
|
42
|
-
|
43
|
-
@exists = !response.delivery_channels.empty?
|
44
|
-
return unless exists?
|
45
|
-
|
46
|
-
channel = response.delivery_channels.first.to_h
|
47
|
-
@channel_name = channel[:name]
|
48
|
-
@s3_bucket_name = channel[:s3_bucket_name]
|
49
|
-
@s3_key_prefix = channel[:s3_key_prefix]
|
50
|
-
@sns_topic_arn = channel[:sns_topic_arn]
|
51
|
-
@delivery_frequency_in_hours = channel.dig(:config_snapshot_delivery_properties, :delivery_frequency)
|
52
|
-
frequencies = {
|
53
|
-
"One_Hour" => 1,
|
54
|
-
"TwentyFour_Hours" => 24,
|
55
|
-
"Three_Hours" => 3,
|
56
|
-
"Six_Hours" => 6,
|
57
|
-
"Twelve_Hours" => 12,
|
58
|
-
}
|
59
|
-
@delivery_frequency_in_hours = frequencies[@delivery_frequency_in_hours]
|
60
|
-
rescue Aws::ConfigService::Errors::NoSuchDeliveryChannelException
|
61
|
-
@exists = false
|
62
|
-
end
|
63
|
-
|
64
|
-
class Backend
|
65
|
-
class AwsClientApi < AwsBackendBase
|
66
|
-
BackendFactory.set_default_backend(self)
|
67
|
-
self.aws_client_class = Aws::ConfigService::Client
|
68
|
-
|
69
|
-
def describe_delivery_channels(query = {})
|
70
|
-
aws_service_client.describe_delivery_channels(query)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
@@ -1,99 +0,0 @@
|
|
1
|
-
require "resource_support/aws/aws_singular_resource_mixin"
|
2
|
-
require "resource_support/aws/aws_backend_base"
|
3
|
-
require "aws-sdk-configservice"
|
4
|
-
|
5
|
-
class AwsConfigurationRecorder < Inspec.resource(1)
|
6
|
-
name "aws_config_recorder"
|
7
|
-
desc "Verifies settings for AWS Configuration Recorder"
|
8
|
-
example <<~EXAMPLE
|
9
|
-
describe aws_config_recorder('My_Recorder') do
|
10
|
-
it { should exist }
|
11
|
-
it { should be_recording }
|
12
|
-
it { should be_all_supported }
|
13
|
-
it { should have_include_global_resource_types }
|
14
|
-
end
|
15
|
-
EXAMPLE
|
16
|
-
supports platform: "aws"
|
17
|
-
|
18
|
-
include AwsSingularResourceMixin
|
19
|
-
attr_reader :role_arn, :resource_types, :recorder_name
|
20
|
-
|
21
|
-
def to_s
|
22
|
-
"Configuration_Recorder: #{@recorder_name}"
|
23
|
-
end
|
24
|
-
|
25
|
-
def recording_all_resource_types?
|
26
|
-
@recording_all_resource_types
|
27
|
-
end
|
28
|
-
|
29
|
-
def recording_all_global_types?
|
30
|
-
@recording_all_global_types
|
31
|
-
end
|
32
|
-
|
33
|
-
def status
|
34
|
-
return {} unless @exists
|
35
|
-
|
36
|
-
backend = BackendFactory.create(inspec_runner)
|
37
|
-
catch_aws_errors do
|
38
|
-
response = backend.describe_configuration_recorder_status(configuration_recorder_names: [@recorder_name])
|
39
|
-
@status = response.configuration_recorders_status.first.to_h
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def recording?
|
44
|
-
return unless @exists
|
45
|
-
|
46
|
-
status[:recording]
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def validate_params(raw_params)
|
52
|
-
validated_params = check_resource_param_names(
|
53
|
-
raw_params: raw_params,
|
54
|
-
allowed_params: [:recorder_name],
|
55
|
-
allowed_scalar_name: :recorder_name,
|
56
|
-
allowed_scalar_type: String
|
57
|
-
)
|
58
|
-
|
59
|
-
validated_params
|
60
|
-
end
|
61
|
-
|
62
|
-
def fetch_from_api
|
63
|
-
backend = BackendFactory.create(inspec_runner)
|
64
|
-
query = @recorder_name ? { configuration_recorder_names: [@recorder_name] } : {}
|
65
|
-
response = backend.describe_configuration_recorders(query)
|
66
|
-
|
67
|
-
@exists = !response.configuration_recorders.empty?
|
68
|
-
return unless exists?
|
69
|
-
|
70
|
-
if response.configuration_recorders.count > 1
|
71
|
-
raise ArgumentError, "Internal error: unexpectedly received multiple AWS Config Recorder objects from API; expected to be singleton per-region. Please file a bug report at https://github.com/chef/inspec/issues ."
|
72
|
-
end
|
73
|
-
|
74
|
-
recorder = response.configuration_recorders.first.to_h
|
75
|
-
@recorder_name = recorder[:name]
|
76
|
-
@role_arn = recorder[:role_arn]
|
77
|
-
@recording_all_resource_types = recorder[:recording_group][:all_supported]
|
78
|
-
@recording_all_global_types = recorder[:recording_group][:include_global_resource_types]
|
79
|
-
@resource_types = recorder[:recording_group][:resource_types]
|
80
|
-
rescue Aws::ConfigService::Errors::NoSuchConfigurationRecorderException
|
81
|
-
@exists = false
|
82
|
-
nil
|
83
|
-
end
|
84
|
-
|
85
|
-
class Backend
|
86
|
-
class AwsClientApi < AwsBackendBase
|
87
|
-
BackendFactory.set_default_backend(self)
|
88
|
-
self.aws_client_class = Aws::ConfigService::Client
|
89
|
-
|
90
|
-
def describe_configuration_recorders(query)
|
91
|
-
aws_service_client.describe_configuration_recorders(query)
|
92
|
-
end
|
93
|
-
|
94
|
-
def describe_configuration_recorder_status(query)
|
95
|
-
aws_service_client.describe_configuration_recorder_status(query)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
@@ -1,127 +0,0 @@
|
|
1
|
-
require "resource_support/aws/aws_singular_resource_mixin"
|
2
|
-
require "resource_support/aws/aws_backend_base"
|
3
|
-
require "aws-sdk-ec2"
|
4
|
-
|
5
|
-
class AwsEbsVolume < Inspec.resource(1)
|
6
|
-
name "aws_ebs_volume"
|
7
|
-
desc "Verifies settings for an EBS volume"
|
8
|
-
|
9
|
-
example <<~EXAMPLE
|
10
|
-
describe aws_ebs_volume('vol-123456') do
|
11
|
-
it { should be_encrypted }
|
12
|
-
its('size') { should cmp 8 }
|
13
|
-
end
|
14
|
-
|
15
|
-
describe aws_ebs_volume(name: 'my-volume') do
|
16
|
-
its('encrypted') { should eq true }
|
17
|
-
its('iops') { should cmp 100 }
|
18
|
-
end
|
19
|
-
EXAMPLE
|
20
|
-
supports platform: "aws"
|
21
|
-
|
22
|
-
# TODO: rewrite to avoid direct injection, match other resources, use AwsSingularResourceMixin
|
23
|
-
def initialize(opts, conn = nil)
|
24
|
-
@opts = opts
|
25
|
-
@display_name = opts.is_a?(Hash) ? @opts[:name] : opts
|
26
|
-
@ec2_client = conn ? conn.ec2_client : inspec_runner.backend.aws_client(Aws::EC2::Client)
|
27
|
-
@ec2_resource = conn ? conn.ec2_resource : inspec_runner.backend.aws_resource(Aws::EC2::Resource, {})
|
28
|
-
end
|
29
|
-
|
30
|
-
# TODO: DRY up, see https://github.com/chef/inspec/issues/2633
|
31
|
-
# Copied from resource_support/aws/aws_resource_mixin.rb
|
32
|
-
def catch_aws_errors
|
33
|
-
yield
|
34
|
-
rescue Aws::Errors::MissingCredentialsError
|
35
|
-
# The AWS error here is unhelpful:
|
36
|
-
# "unable to sign request without credentials set"
|
37
|
-
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://docs.chef.io/inspec/platforms/ for details."
|
38
|
-
fail_resource("No AWS credentials available")
|
39
|
-
rescue Aws::Errors::ServiceError => e
|
40
|
-
fail_resource(e.message)
|
41
|
-
end
|
42
|
-
|
43
|
-
# TODO: DRY up, see https://github.com/chef/inspec/issues/2633
|
44
|
-
# Copied from resource_support/aws/aws_singular_resource_mixin.rb
|
45
|
-
def inspec_runner
|
46
|
-
# When running under inspec-cli, we have an 'inspec' method that
|
47
|
-
# returns the runner. When running under unit tests, we don't
|
48
|
-
# have that, but we still have to call this to pass something
|
49
|
-
# (nil is OK) to the backend.
|
50
|
-
# TODO: remove with https://github.com/chef/inspec-aws/issues/216
|
51
|
-
# TODO: remove after rewrite to include AwsSingularResource
|
52
|
-
inspec if respond_to?(:inspec)
|
53
|
-
end
|
54
|
-
|
55
|
-
def id
|
56
|
-
return @volume_id if defined?(@volume_id)
|
57
|
-
|
58
|
-
catch_aws_errors do
|
59
|
-
if @opts.is_a?(Hash)
|
60
|
-
first = @ec2_resource.volumes(
|
61
|
-
{
|
62
|
-
filters: [{
|
63
|
-
name: "tag:Name",
|
64
|
-
values: [@opts[:name]],
|
65
|
-
}],
|
66
|
-
}
|
67
|
-
).first
|
68
|
-
# catch case where the volume is not known
|
69
|
-
@volume_id = first.id unless first.nil?
|
70
|
-
else
|
71
|
-
@volume_id = @opts
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
alias volume_id id
|
76
|
-
|
77
|
-
def exists?
|
78
|
-
!volume.nil?
|
79
|
-
end
|
80
|
-
|
81
|
-
def encrypted?
|
82
|
-
volume.encrypted
|
83
|
-
end
|
84
|
-
|
85
|
-
# attributes that we want to expose
|
86
|
-
%w{
|
87
|
-
availability_zone encrypted iops kms_key_id size snapshot_id state volume_type
|
88
|
-
}.each do |attribute|
|
89
|
-
define_method attribute do
|
90
|
-
catch_aws_errors do
|
91
|
-
volume.send(attribute) if volume
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# Don't document this - it's a bit hard to use. Our current doctrine
|
97
|
-
# is to use dumb things, like arrays of strings - use security_group_ids instead.
|
98
|
-
def security_groups
|
99
|
-
catch_aws_errors do
|
100
|
-
@security_groups ||= volume.security_groups.map do |sg|
|
101
|
-
{ id: sg.group_id, name: sg.group_name }
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def security_group_ids
|
107
|
-
catch_aws_errors do
|
108
|
-
@security_group_ids ||= volume.security_groups.map(&:group_id)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def tags
|
113
|
-
catch_aws_errors do
|
114
|
-
@tags ||= volume.tags.map { |tag| { key: tag.key, value: tag.value } }
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def to_s
|
119
|
-
"EBS Volume #{@display_name}"
|
120
|
-
end
|
121
|
-
|
122
|
-
private
|
123
|
-
|
124
|
-
def volume
|
125
|
-
catch_aws_errors { @volume ||= @ec2_resource.volume(id) }
|
126
|
-
end
|
127
|
-
end
|
@@ -1,69 +0,0 @@
|
|
1
|
-
require "resource_support/aws/aws_plural_resource_mixin"
|
2
|
-
require "resource_support/aws/aws_backend_base"
|
3
|
-
require "aws-sdk-ec2"
|
4
|
-
|
5
|
-
class AwsEbsVolumes < Inspec.resource(1)
|
6
|
-
name "aws_ebs_volumes"
|
7
|
-
desc "Verifies settings for AWS EBS Volumes in bulk"
|
8
|
-
example <<~EXAMPLE
|
9
|
-
describe aws_ebs_volumes do
|
10
|
-
it { should exist }
|
11
|
-
end
|
12
|
-
EXAMPLE
|
13
|
-
supports platform: "aws"
|
14
|
-
|
15
|
-
include AwsPluralResourceMixin
|
16
|
-
def validate_params(resource_params)
|
17
|
-
unless resource_params.empty?
|
18
|
-
raise ArgumentError, "aws_ebs_volumes does not accept resource parameters."
|
19
|
-
end
|
20
|
-
|
21
|
-
resource_params
|
22
|
-
end
|
23
|
-
|
24
|
-
# Underlying FilterTable implementation.
|
25
|
-
filter = FilterTable.create
|
26
|
-
filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
|
27
|
-
filter.register_column(:volume_ids, field: :volume_id)
|
28
|
-
filter.install_filter_methods_on_resource(self, :table)
|
29
|
-
|
30
|
-
def to_s
|
31
|
-
"EBS Volumes"
|
32
|
-
end
|
33
|
-
|
34
|
-
def fetch_from_api
|
35
|
-
backend = BackendFactory.create(inspec_runner)
|
36
|
-
@table = []
|
37
|
-
pagination_opts = {}
|
38
|
-
loop do
|
39
|
-
api_result = backend.describe_volumes(pagination_opts)
|
40
|
-
@table += unpack_describe_volumes_response(api_result.volumes)
|
41
|
-
break unless api_result.next_token
|
42
|
-
|
43
|
-
pagination_opts = { next_token: api_result.next_token }
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def unpack_describe_volumes_response(volumes)
|
48
|
-
volume_rows = []
|
49
|
-
volumes.each do |res|
|
50
|
-
volume_rows += res.attachments.map do |volume_struct|
|
51
|
-
{
|
52
|
-
volume_id: volume_struct.volume_id,
|
53
|
-
}
|
54
|
-
end
|
55
|
-
end
|
56
|
-
volume_rows
|
57
|
-
end
|
58
|
-
|
59
|
-
class Backend
|
60
|
-
class AwsClientApi < AwsBackendBase
|
61
|
-
BackendFactory.set_default_backend(self)
|
62
|
-
self.aws_client_class = Aws::EC2::Client
|
63
|
-
|
64
|
-
def describe_volumes(query)
|
65
|
-
aws_service_client.describe_volumes(query)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|