inspec 4.22.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +63 -0
- data/inspec.gemspec +36 -0
- data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/Gemfile +11 -0
- data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/inspec-plugin-template.gemspec +43 -0
- data/lib/plugins/inspec-init/templates/profiles/aws/README.md +192 -0
- data/lib/plugins/inspec-init/templates/profiles/aws/attributes.yml +2 -0
- data/lib/plugins/inspec-init/templates/profiles/aws/controls/example.rb +39 -0
- data/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml +22 -0
- data/lib/plugins/inspec-init/templates/profiles/azure/README.md +56 -0
- data/lib/plugins/inspec-init/templates/profiles/azure/controls/example.rb +14 -0
- data/lib/plugins/inspec-init/templates/profiles/azure/inspec.yml +14 -0
- data/lib/plugins/inspec-init/templates/profiles/gcp/README.md +66 -0
- data/lib/plugins/inspec-init/templates/profiles/gcp/attributes.yml +2 -0
- data/lib/plugins/inspec-init/templates/profiles/gcp/controls/example.rb +27 -0
- data/lib/plugins/inspec-init/templates/profiles/gcp/inspec.yml +19 -0
- data/lib/resource_support/aws.rb +76 -0
- data/lib/resource_support/aws/aws_backend_base.rb +12 -0
- data/lib/resource_support/aws/aws_backend_factory_mixin.rb +12 -0
- data/lib/resource_support/aws/aws_plural_resource_mixin.rb +24 -0
- data/lib/resource_support/aws/aws_resource_mixin.rb +69 -0
- data/lib/resource_support/aws/aws_singular_resource_mixin.rb +27 -0
- data/lib/resources/aws/aws_billing_report.rb +107 -0
- data/lib/resources/aws/aws_billing_reports.rb +74 -0
- data/lib/resources/aws/aws_cloudtrail_trail.rb +97 -0
- data/lib/resources/aws/aws_cloudtrail_trails.rb +51 -0
- data/lib/resources/aws/aws_cloudwatch_alarm.rb +67 -0
- data/lib/resources/aws/aws_cloudwatch_log_metric_filter.rb +105 -0
- data/lib/resources/aws/aws_config_delivery_channel.rb +74 -0
- data/lib/resources/aws/aws_config_recorder.rb +99 -0
- data/lib/resources/aws/aws_ebs_volume.rb +127 -0
- data/lib/resources/aws/aws_ebs_volumes.rb +69 -0
- data/lib/resources/aws/aws_ec2_instance.rb +162 -0
- data/lib/resources/aws/aws_ec2_instances.rb +69 -0
- data/lib/resources/aws/aws_ecs_cluster.rb +88 -0
- data/lib/resources/aws/aws_eks_cluster.rb +105 -0
- data/lib/resources/aws/aws_elb.rb +85 -0
- data/lib/resources/aws/aws_elbs.rb +84 -0
- data/lib/resources/aws/aws_flow_log.rb +106 -0
- data/lib/resources/aws/aws_iam_access_key.rb +112 -0
- data/lib/resources/aws/aws_iam_access_keys.rb +153 -0
- data/lib/resources/aws/aws_iam_group.rb +62 -0
- data/lib/resources/aws/aws_iam_groups.rb +56 -0
- data/lib/resources/aws/aws_iam_password_policy.rb +121 -0
- data/lib/resources/aws/aws_iam_policies.rb +57 -0
- data/lib/resources/aws/aws_iam_policy.rb +311 -0
- data/lib/resources/aws/aws_iam_role.rb +60 -0
- data/lib/resources/aws/aws_iam_root_user.rb +82 -0
- data/lib/resources/aws/aws_iam_user.rb +145 -0
- data/lib/resources/aws/aws_iam_users.rb +160 -0
- data/lib/resources/aws/aws_kms_key.rb +100 -0
- data/lib/resources/aws/aws_kms_keys.rb +58 -0
- data/lib/resources/aws/aws_rds_instance.rb +74 -0
- data/lib/resources/aws/aws_route_table.rb +67 -0
- data/lib/resources/aws/aws_route_tables.rb +64 -0
- data/lib/resources/aws/aws_s3_bucket.rb +142 -0
- data/lib/resources/aws/aws_s3_bucket_object.rb +87 -0
- data/lib/resources/aws/aws_s3_buckets.rb +52 -0
- data/lib/resources/aws/aws_security_group.rb +314 -0
- data/lib/resources/aws/aws_security_groups.rb +71 -0
- data/lib/resources/aws/aws_sns_subscription.rb +82 -0
- data/lib/resources/aws/aws_sns_topic.rb +57 -0
- data/lib/resources/aws/aws_sns_topics.rb +60 -0
- data/lib/resources/aws/aws_sqs_queue.rb +66 -0
- data/lib/resources/aws/aws_subnet.rb +92 -0
- data/lib/resources/aws/aws_subnets.rb +56 -0
- data/lib/resources/aws/aws_vpc.rb +77 -0
- data/lib/resources/aws/aws_vpcs.rb +55 -0
- data/lib/resources/azure/azure_backend.rb +379 -0
- data/lib/resources/azure/azure_generic_resource.rb +55 -0
- data/lib/resources/azure/azure_resource_group.rb +151 -0
- data/lib/resources/azure/azure_virtual_machine.rb +262 -0
- data/lib/resources/azure/azure_virtual_machine_data_disk.rb +131 -0
- metadata +202 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
require "inspec/utils/filter"
|
2
|
+
require "resource_support/aws/aws_plural_resource_mixin"
|
3
|
+
require "resource_support/aws/aws_backend_base"
|
4
|
+
require "aws-sdk-costandusagereportservice"
|
5
|
+
|
6
|
+
class AwsBillingReports < Inspec.resource(1)
|
7
|
+
name "aws_billing_reports"
|
8
|
+
supports platform: "aws"
|
9
|
+
desc "Verifies settings for AWS Cost and Billing Reports."
|
10
|
+
example <<~EXAMPLE
|
11
|
+
describe aws_billing_reports do
|
12
|
+
its('report_names') { should include 'inspec1' }
|
13
|
+
its('s3_buckets') { should include 'inspec1-s3-bucket' }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe aws_billing_reports.where { report_name =~ /inspec.*/ } do
|
17
|
+
its ('report_names') { should include ['inspec1'] }
|
18
|
+
its ('time_units') { should include ['DAILY'] }
|
19
|
+
its ('s3_buckets') { should include ['inspec1-s3-bucket'] }
|
20
|
+
end
|
21
|
+
EXAMPLE
|
22
|
+
|
23
|
+
include AwsPluralResourceMixin
|
24
|
+
|
25
|
+
filtertable = FilterTable.create
|
26
|
+
filtertable.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
|
27
|
+
.register_column(:report_names, field: :report_name)
|
28
|
+
.register_column(:time_units, field: :time_unit, style: :simple)
|
29
|
+
.register_column(:formats, field: :format, style: :simple)
|
30
|
+
.register_column(:compressions, field: :compression, style: :simple)
|
31
|
+
.register_column(:s3_buckets, field: :s3_bucket, style: :simple)
|
32
|
+
.register_column(:s3_prefixes, field: :s3_prefix, style: :simple)
|
33
|
+
.register_column(:s3_regions, field: :s3_region, style: :simple)
|
34
|
+
filtertable.install_filter_methods_on_resource(self, :table)
|
35
|
+
|
36
|
+
def validate_params(resource_params)
|
37
|
+
unless resource_params.empty?
|
38
|
+
raise ArgumentError, "aws_billing_reports does not accept resource parameters."
|
39
|
+
end
|
40
|
+
|
41
|
+
resource_params
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
"AWS Billing Reports"
|
46
|
+
end
|
47
|
+
|
48
|
+
def fetch_from_api
|
49
|
+
@table = []
|
50
|
+
pagination_opts = {}
|
51
|
+
backend = BackendFactory.create(inspec_runner)
|
52
|
+
loop do
|
53
|
+
api_result = backend.describe_report_definitions(pagination_opts)
|
54
|
+
api_result.report_definitions.each do |raw_report|
|
55
|
+
report = raw_report.to_h
|
56
|
+
%i{time_unit compression}.each { |field| report[field].downcase! }
|
57
|
+
@table << report
|
58
|
+
end
|
59
|
+
pagination_opts = { next_token: api_result.next_token }
|
60
|
+
break unless api_result.next_token
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Backend
|
65
|
+
class AwsClientApi < AwsBackendBase
|
66
|
+
AwsBillingReports::BackendFactory.set_default_backend(self)
|
67
|
+
self.aws_client_class = Aws::CostandUsageReportService::Client
|
68
|
+
|
69
|
+
def describe_report_definitions(options = {})
|
70
|
+
aws_service_client.describe_report_definitions(options)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require "resource_support/aws/aws_singular_resource_mixin"
|
2
|
+
require "resource_support/aws/aws_backend_base"
|
3
|
+
require "aws-sdk-cloudtrail"
|
4
|
+
|
5
|
+
class AwsCloudTrailTrail < Inspec.resource(1)
|
6
|
+
name "aws_cloudtrail_trail"
|
7
|
+
desc "Verifies settings for an individual AWS CloudTrail Trail"
|
8
|
+
example <<~EXAMPLE
|
9
|
+
describe aws_cloudtrail_trail('trail-name') do
|
10
|
+
it { should exist }
|
11
|
+
end
|
12
|
+
EXAMPLE
|
13
|
+
|
14
|
+
supports platform: "aws"
|
15
|
+
|
16
|
+
include AwsSingularResourceMixin
|
17
|
+
attr_reader :cloud_watch_logs_log_group_arn, :cloud_watch_logs_role_arn, :home_region,
|
18
|
+
:kms_key_id, :s3_bucket_name, :trail_arn
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
"CloudTrail #{@trail_name}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def multi_region_trail?
|
25
|
+
@is_multi_region_trail
|
26
|
+
end
|
27
|
+
|
28
|
+
def log_file_validation_enabled?
|
29
|
+
@log_file_validation_enabled
|
30
|
+
end
|
31
|
+
|
32
|
+
def encrypted?
|
33
|
+
!kms_key_id.nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
def delivered_logs_days_ago
|
37
|
+
query = { name: @trail_name }
|
38
|
+
catch_aws_errors do
|
39
|
+
begin
|
40
|
+
resp = BackendFactory.create(inspec_runner).get_trail_status(query).to_h
|
41
|
+
((Time.now - resp[:latest_cloud_watch_logs_delivery_time]) / (24 * 60 * 60)).to_i unless resp[:latest_cloud_watch_logs_delivery_time].nil?
|
42
|
+
rescue Aws::CloudTrail::Errors::TrailNotFoundException
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def validate_params(raw_params)
|
51
|
+
validated_params = check_resource_param_names(
|
52
|
+
raw_params: raw_params,
|
53
|
+
allowed_params: [:trail_name],
|
54
|
+
allowed_scalar_name: :trail_name,
|
55
|
+
allowed_scalar_type: String
|
56
|
+
)
|
57
|
+
|
58
|
+
if validated_params.empty?
|
59
|
+
raise ArgumentError, "You must provide the parameter 'trail_name' to aws_cloudtrail_trail."
|
60
|
+
end
|
61
|
+
|
62
|
+
validated_params
|
63
|
+
end
|
64
|
+
|
65
|
+
def fetch_from_api
|
66
|
+
backend = BackendFactory.create(inspec_runner)
|
67
|
+
|
68
|
+
query = { trail_name_list: [@trail_name] }
|
69
|
+
resp = backend.describe_trails(query)
|
70
|
+
|
71
|
+
@trail = resp.trail_list[0].to_h
|
72
|
+
@exists = !@trail.empty?
|
73
|
+
@s3_bucket_name = @trail[:s3_bucket_name]
|
74
|
+
@is_multi_region_trail = @trail[:is_multi_region_trail]
|
75
|
+
@trail_arn = @trail[:trail_arn]
|
76
|
+
@log_file_validation_enabled = @trail[:log_file_validation_enabled]
|
77
|
+
@cloud_watch_logs_role_arn = @trail[:cloud_watch_logs_role_arn]
|
78
|
+
@cloud_watch_logs_log_group_arn = @trail[:cloud_watch_logs_log_group_arn]
|
79
|
+
@kms_key_id = @trail[:kms_key_id]
|
80
|
+
@home_region = @trail[:home_region]
|
81
|
+
end
|
82
|
+
|
83
|
+
class Backend
|
84
|
+
class AwsClientApi < AwsBackendBase
|
85
|
+
AwsCloudTrailTrail::BackendFactory.set_default_backend(self)
|
86
|
+
self.aws_client_class = Aws::CloudTrail::Client
|
87
|
+
|
88
|
+
def describe_trails(query)
|
89
|
+
aws_service_client.describe_trails(query)
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_trail_status(query)
|
93
|
+
aws_service_client.get_trail_status(query)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,51 @@
|
|
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
|
@@ -0,0 +1,67 @@
|
|
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
|
@@ -0,0 +1,105 @@
|
|
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
|
@@ -0,0 +1,74 @@
|
|
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
|