inspec 4.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,14 @@
|
|
1
|
+
# copyright: 2018, The Authors
|
2
|
+
|
3
|
+
title "Sample Section"
|
4
|
+
|
5
|
+
# you add controls here
|
6
|
+
control "azure-virtual-machines-exist-check" do # A unique ID for this control.
|
7
|
+
impact 1.0 # The criticality, if this control fails.
|
8
|
+
title "Check resource groups to see if any VMs exist." # A human-readable title
|
9
|
+
azurerm_resource_groups.names.each do |resource_group_name| # Plural resources can be leveraged to loop across many resources
|
10
|
+
describe azurerm_virtual_machines(resource_group: resource_group_name) do
|
11
|
+
it { should exist } # The test itself.
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
name: <%= name %>
|
2
|
+
title: Azure InSpec Profile
|
3
|
+
maintainer: The Authors
|
4
|
+
copyright: The Authors
|
5
|
+
copyright_email: you@example.com
|
6
|
+
license: Apache-2.0
|
7
|
+
summary: An InSpec Compliance Profile For Azure
|
8
|
+
version: 0.1.0
|
9
|
+
inspec_version: '>= 2.2.7'
|
10
|
+
depends:
|
11
|
+
- name: inspec-azure
|
12
|
+
url: https://github.com/inspec/inspec-azure/archive/master.tar.gz
|
13
|
+
supports:
|
14
|
+
- platform: azure
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# Example InSpec Profile For GCP
|
2
|
+
|
3
|
+
This example shows the implementation of an InSpec profile for GCP that depends on the [InSpec GCP Resource Pack](https://github.com/inspec/inspec-gcp). See the [README](https://github.com/inspec/inspec-gcp) for instructions on setting up appropriate GCP credentials.
|
4
|
+
|
5
|
+
## Create a profile
|
6
|
+
|
7
|
+
```
|
8
|
+
$ inspec init profile --platform gcp my-profile
|
9
|
+
Create new profile at /Users/spaterson/my-profile
|
10
|
+
* Create directory libraries
|
11
|
+
* Create file README.md
|
12
|
+
* Create directory controls
|
13
|
+
* Create file controls/example.rb
|
14
|
+
* Create file inspec.yml
|
15
|
+
* Create file attributes.yml
|
16
|
+
* Create file libraries/.gitkeep
|
17
|
+
|
18
|
+
```
|
19
|
+
|
20
|
+
## Update `attributes.yml` to point to your project
|
21
|
+
|
22
|
+
```
|
23
|
+
gcp_project_id: 'my-gcp-project'
|
24
|
+
```
|
25
|
+
|
26
|
+
## Run the tests
|
27
|
+
|
28
|
+
```
|
29
|
+
$ cd gcp-profile/
|
30
|
+
$ inspec exec . -t gcp:// --attrs attributes.yml
|
31
|
+
|
32
|
+
Profile: GCP InSpec Profile (my-profile)
|
33
|
+
Version: 0.1.0
|
34
|
+
Target: gcp://local-service-account@my-gcp-project.iam.gserviceaccount.com
|
35
|
+
|
36
|
+
✔ gcp-single-region-1.0: Ensure single region has the correct properties.
|
37
|
+
✔ Region europe-west2 zone_names should include "europe-west2-a"
|
38
|
+
✔ gcp-regions-loop-1.0: Ensure regions have the correct properties in bulk.
|
39
|
+
✔ Region asia-east1 should be up
|
40
|
+
✔ Region asia-northeast1 should be up
|
41
|
+
✔ Region asia-south1 should be up
|
42
|
+
✔ Region asia-southeast1 should be up
|
43
|
+
✔ Region australia-southeast1 should be up
|
44
|
+
✔ Region europe-north1 should be up
|
45
|
+
✔ Region europe-west1 should be up
|
46
|
+
✔ Region europe-west2 should be up
|
47
|
+
✔ Region europe-west3 should be up
|
48
|
+
✔ Region europe-west4 should be up
|
49
|
+
✔ Region northamerica-northeast1 should be up
|
50
|
+
✔ Region southamerica-east1 should be up
|
51
|
+
✔ Region us-central1 should be up
|
52
|
+
✔ Region us-east1 should be up
|
53
|
+
✔ Region us-east4 should be up
|
54
|
+
✔ Region us-west1 should be up
|
55
|
+
✔ Region us-west2 should be up
|
56
|
+
|
57
|
+
|
58
|
+
Profile: Google Cloud Platform Resource Pack (inspec-gcp)
|
59
|
+
Version: 0.5.0
|
60
|
+
Target: gcp://local-service-account@my-gcp-project.iam.gserviceaccount.com
|
61
|
+
|
62
|
+
No tests executed.
|
63
|
+
|
64
|
+
Profile Summary: 2 successful controls, 0 control failures, 0 controls skipped
|
65
|
+
Test Summary: 18 successful, 0 failures, 0 skipped
|
66
|
+
```
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# copyright: 2018, The Authors
|
2
|
+
|
3
|
+
title "Sample Section"
|
4
|
+
|
5
|
+
gcp_project_id = attribute("gcp_project_id")
|
6
|
+
|
7
|
+
# you add controls here
|
8
|
+
control "gcp-single-region-1.0" do # A unique ID for this control
|
9
|
+
impact 1.0 # The criticality, if this control fails.
|
10
|
+
title "Ensure single region has the correct properties." # A human-readable title
|
11
|
+
desc "An optional description..."
|
12
|
+
describe google_compute_region(project: gcp_project_id, name: "europe-west2") do # The actual test
|
13
|
+
its("zone_names") { should include "europe-west2-a" }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# plural resources can be leveraged to loop across many resources
|
18
|
+
control "gcp-regions-loop-1.0" do # A unique ID for this control
|
19
|
+
impact 1.0 # The criticality, if this control fails.
|
20
|
+
title "Ensure regions have the correct properties in bulk." # A human-readable title
|
21
|
+
desc "An optional description..."
|
22
|
+
google_compute_regions(project: gcp_project_id).region_names.each do |region_name| # Loop across all regions by name
|
23
|
+
describe google_compute_region(project: gcp_project_id, name: region_name) do # The test for a single region
|
24
|
+
it { should be_up }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
name: <%= name %>
|
2
|
+
title: GCP InSpec Profile
|
3
|
+
maintainer: The Authors
|
4
|
+
copyright: The Authors
|
5
|
+
copyright_email: you@example.com
|
6
|
+
license: Apache-2.0
|
7
|
+
summary: An InSpec Compliance Profile For GCP
|
8
|
+
version: 0.1.0
|
9
|
+
inspec_version: '>= 2.3.5'
|
10
|
+
attributes:
|
11
|
+
- name: gcp_project_id
|
12
|
+
required: true
|
13
|
+
description: 'The GCP project identifier.'
|
14
|
+
type: string
|
15
|
+
depends:
|
16
|
+
- name: inspec-gcp
|
17
|
+
url: https://github.com/inspec/inspec-gcp/archive/master.tar.gz
|
18
|
+
supports:
|
19
|
+
- platform: gcp
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# Main AWS loader file. The intent is for this to be
|
2
|
+
# loaded only if AWS resources are needed.
|
3
|
+
|
4
|
+
require "aws-sdk-core"
|
5
|
+
|
6
|
+
require "aws-sdk-cloudtrail"
|
7
|
+
require "aws-sdk-cloudwatch"
|
8
|
+
require "aws-sdk-cloudwatchlogs"
|
9
|
+
require "aws-sdk-costandusagereportservice"
|
10
|
+
require "aws-sdk-configservice"
|
11
|
+
require "aws-sdk-ec2"
|
12
|
+
require "aws-sdk-ecs"
|
13
|
+
require "aws-sdk-eks"
|
14
|
+
require "aws-sdk-elasticloadbalancing"
|
15
|
+
require "aws-sdk-iam"
|
16
|
+
require "aws-sdk-kms"
|
17
|
+
require "aws-sdk-rds"
|
18
|
+
require "aws-sdk-s3"
|
19
|
+
require "aws-sdk-sqs"
|
20
|
+
require "aws-sdk-sns"
|
21
|
+
|
22
|
+
require "resource_support/aws/aws_backend_factory_mixin"
|
23
|
+
require "resource_support/aws/aws_resource_mixin"
|
24
|
+
require "resource_support/aws/aws_singular_resource_mixin"
|
25
|
+
require "resource_support/aws/aws_plural_resource_mixin"
|
26
|
+
require "resource_support/aws/aws_backend_base"
|
27
|
+
|
28
|
+
# Load all AWS resources
|
29
|
+
# TODO: loop over and load entire directory
|
30
|
+
# for f in ls lib/resources/aws/*; do t=$(echo $f | cut -c 5- | cut -f1 -d. ); echo "require '${t}'"; done
|
31
|
+
require "resources/aws/aws_billing_report"
|
32
|
+
require "resources/aws/aws_billing_reports"
|
33
|
+
require "resources/aws/aws_cloudtrail_trail"
|
34
|
+
require "resources/aws/aws_cloudtrail_trails"
|
35
|
+
require "resources/aws/aws_cloudwatch_alarm"
|
36
|
+
require "resources/aws/aws_cloudwatch_log_metric_filter"
|
37
|
+
require "resources/aws/aws_config_delivery_channel"
|
38
|
+
require "resources/aws/aws_config_recorder"
|
39
|
+
require "resources/aws/aws_ec2_instance"
|
40
|
+
require "resources/aws/aws_ebs_volume"
|
41
|
+
require "resources/aws/aws_ebs_volumes"
|
42
|
+
require "resources/aws/aws_flow_log"
|
43
|
+
require "resources/aws/aws_ec2_instances"
|
44
|
+
require "resources/aws/aws_ecs_cluster"
|
45
|
+
require "resources/aws/aws_eks_cluster"
|
46
|
+
require "resources/aws/aws_elb"
|
47
|
+
require "resources/aws/aws_elbs"
|
48
|
+
require "resources/aws/aws_iam_access_key"
|
49
|
+
require "resources/aws/aws_iam_access_keys"
|
50
|
+
require "resources/aws/aws_iam_group"
|
51
|
+
require "resources/aws/aws_iam_groups"
|
52
|
+
require "resources/aws/aws_iam_password_policy"
|
53
|
+
require "resources/aws/aws_iam_policies"
|
54
|
+
require "resources/aws/aws_iam_policy"
|
55
|
+
require "resources/aws/aws_iam_role"
|
56
|
+
require "resources/aws/aws_iam_root_user"
|
57
|
+
require "resources/aws/aws_iam_user"
|
58
|
+
require "resources/aws/aws_iam_users"
|
59
|
+
require "resources/aws/aws_kms_key"
|
60
|
+
require "resources/aws/aws_kms_keys"
|
61
|
+
require "resources/aws/aws_rds_instance"
|
62
|
+
require "resources/aws/aws_route_table"
|
63
|
+
require "resources/aws/aws_route_tables"
|
64
|
+
require "resources/aws/aws_s3_bucket"
|
65
|
+
require "resources/aws/aws_s3_bucket_object"
|
66
|
+
require "resources/aws/aws_s3_buckets"
|
67
|
+
require "resources/aws/aws_security_group"
|
68
|
+
require "resources/aws/aws_security_groups"
|
69
|
+
require "resources/aws/aws_sns_subscription"
|
70
|
+
require "resources/aws/aws_sns_topic"
|
71
|
+
require "resources/aws/aws_sns_topics"
|
72
|
+
require "resources/aws/aws_sqs_queue"
|
73
|
+
require "resources/aws/aws_subnet"
|
74
|
+
require "resources/aws/aws_subnets"
|
75
|
+
require "resources/aws/aws_vpc"
|
76
|
+
require "resources/aws/aws_vpcs"
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class AwsBackendBase
|
2
|
+
attr_reader :aws_transport
|
3
|
+
class << self; attr_accessor :aws_client_class end
|
4
|
+
|
5
|
+
def initialize(inspec = nil)
|
6
|
+
@aws_transport = inspec ? inspec.backend : nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def aws_service_client
|
10
|
+
aws_transport.aws_client(self.class.aws_client_class)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "resource_support/aws/aws_resource_mixin"
|
2
|
+
require "resource_support/aws/aws_backend_factory_mixin"
|
3
|
+
|
4
|
+
module AwsPluralResourceMixin
|
5
|
+
include AwsResourceMixin
|
6
|
+
attr_reader :table
|
7
|
+
|
8
|
+
# This sets up a class, AwsSomeResource::BackendFactory, that
|
9
|
+
# provides a mechanism to create and use backends without
|
10
|
+
# having to know which is selected. This is mainly used for
|
11
|
+
# unit testing.
|
12
|
+
# TODO: DRY up. This code exists in both the Singular and Plural mixins.
|
13
|
+
# We'd like to put it in AwsResourceMixin, but included only sees the
|
14
|
+
# directly-including class - we can't see second-order includers.
|
15
|
+
def self.included(base)
|
16
|
+
# Create a new class, whose body is simply to extend the
|
17
|
+
# backend factory mixin
|
18
|
+
resource_backend_factory_class = Class.new(Object) do
|
19
|
+
extend AwsBackendFactoryMixin
|
20
|
+
end
|
21
|
+
# Name that class
|
22
|
+
base.const_set("BackendFactory", resource_backend_factory_class)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module AwsResourceMixin
|
2
|
+
def initialize(resource_params = {})
|
3
|
+
Inspec.deprecate(:aws_resources_in_resource_pack,
|
4
|
+
"Resource '#{@__resource_name__ ||= self.class.to_s}'")
|
5
|
+
validate_params(resource_params).each do |param, value|
|
6
|
+
instance_variable_set(:"@#{param}", value)
|
7
|
+
end
|
8
|
+
catch_aws_errors do
|
9
|
+
fetch_from_api
|
10
|
+
end
|
11
|
+
rescue ArgumentError => e
|
12
|
+
# continue with ArgumentError if testing
|
13
|
+
raise unless respond_to?(:inspec) && inspec
|
14
|
+
|
15
|
+
raise Inspec::Exceptions::ResourceFailed, e.message
|
16
|
+
end
|
17
|
+
|
18
|
+
# Default implementation of validate params accepts everything.
|
19
|
+
def validate_params(resource_params)
|
20
|
+
resource_params
|
21
|
+
end
|
22
|
+
|
23
|
+
def check_resource_param_names(raw_params: {}, allowed_params: [], allowed_scalar_name: nil, allowed_scalar_type: nil)
|
24
|
+
# Some resources allow passing in a single ID value. Check and convert to hash if so.
|
25
|
+
if allowed_scalar_name && !raw_params.is_a?(Hash)
|
26
|
+
value_seen = raw_params
|
27
|
+
if value_seen.is_a?(allowed_scalar_type)
|
28
|
+
raw_params = { allowed_scalar_name => value_seen }
|
29
|
+
else
|
30
|
+
raise ArgumentError, "If you pass a single value to the resource, it must " \
|
31
|
+
"be a #{allowed_scalar_type}, not an #{value_seen.class}."
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Remove all expected params from the raw param hash
|
36
|
+
recognized_params = {}
|
37
|
+
allowed_params.each do |expected_param|
|
38
|
+
recognized_params[expected_param] = raw_params.delete(expected_param) if raw_params.key?(expected_param)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Any leftovers are unwelcome
|
42
|
+
unless raw_params.empty?
|
43
|
+
raise ArgumentError, "Unrecognized resource param '#{raw_params.keys.first}'. Expected parameters: #{allowed_params.join(", ")}"
|
44
|
+
end
|
45
|
+
|
46
|
+
recognized_params
|
47
|
+
end
|
48
|
+
|
49
|
+
def inspec_runner
|
50
|
+
# When running under inspec-cli, we have an 'inspec' method that
|
51
|
+
# returns the runner. When running under unit tests, we don't
|
52
|
+
# have that, but we still have to call this to pass something
|
53
|
+
# (nil is OK) to the backend.
|
54
|
+
# TODO: remove with https://github.com/chef/inspec-aws/issues/216
|
55
|
+
inspec if respond_to?(:inspec)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Intercept AWS exceptions
|
59
|
+
def catch_aws_errors
|
60
|
+
yield
|
61
|
+
rescue Aws::Errors::MissingCredentialsError
|
62
|
+
# The AWS error here is unhelpful:
|
63
|
+
# "unable to sign request without credentials set"
|
64
|
+
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."
|
65
|
+
fail_resource("No AWS credentials available")
|
66
|
+
rescue Aws::Errors::ServiceError => e
|
67
|
+
fail_resource e.message
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "resource_support/aws/aws_resource_mixin"
|
2
|
+
require "resource_support/aws/aws_backend_factory_mixin"
|
3
|
+
|
4
|
+
module AwsSingularResourceMixin
|
5
|
+
include AwsResourceMixin
|
6
|
+
|
7
|
+
def exists?
|
8
|
+
@exists
|
9
|
+
end
|
10
|
+
|
11
|
+
# This sets up a class, AwsSomeResource::BackendFactory, that
|
12
|
+
# provides a mechanism to create and use backends without
|
13
|
+
# having to know which is selected. This is mainly used for
|
14
|
+
# unit testing.
|
15
|
+
# TODO: DRY up. This code exists in both the Singular and Plural mixins.
|
16
|
+
# We'd like to put it in AwsResourceMixin, but included only sees the
|
17
|
+
# directly-including class - we can't see second-order includers.
|
18
|
+
def self.included(base)
|
19
|
+
# Create a new class, whose body is simply to extend the
|
20
|
+
# backend factory mixin
|
21
|
+
resource_backend_factory_class = Class.new(Object) do
|
22
|
+
extend AwsBackendFactoryMixin
|
23
|
+
end
|
24
|
+
# Name that class
|
25
|
+
base.const_set("BackendFactory", resource_backend_factory_class)
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require "resource_support/aws/aws_singular_resource_mixin"
|
2
|
+
require "resource_support/aws/aws_backend_base"
|
3
|
+
|
4
|
+
require "resource_support/aws/aws_singular_resource_mixin"
|
5
|
+
require "resource_support/aws/aws_backend_base"
|
6
|
+
require "aws-sdk-costandusagereportservice.rb"
|
7
|
+
|
8
|
+
class AwsBillingReport < Inspec.resource(1)
|
9
|
+
name "aws_billing_report"
|
10
|
+
supports platform: "aws"
|
11
|
+
desc "Verifies settings for AWS Cost and Billing Reports."
|
12
|
+
example <<~EXAMPLE
|
13
|
+
describe aws_billing_report('inspec1') do
|
14
|
+
its('report_name') { should cmp 'inspec1' }
|
15
|
+
its('time_unit') { should cmp 'hourly' }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe aws_billing_report(report: 'inspec1') do
|
19
|
+
it { should exist }
|
20
|
+
end
|
21
|
+
EXAMPLE
|
22
|
+
|
23
|
+
include AwsSingularResourceMixin
|
24
|
+
|
25
|
+
attr_reader :report_name, :time_unit, :format, :compression, :s3_bucket,
|
26
|
+
:s3_prefix, :s3_region
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
"AWS Billing Report #{report_name}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def hourly?
|
33
|
+
exists? ? time_unit.eql?("hourly") : nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def daily?
|
37
|
+
exists? ? time_unit.eql?("daily") : nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def zip?
|
41
|
+
exists? ? compression.eql?("zip") : nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def gzip?
|
45
|
+
exists? ? compression.eql?("gzip") : nil
|
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: [:report_name],
|
54
|
+
allowed_scalar_name: :report_name,
|
55
|
+
allowed_scalar_type: String
|
56
|
+
)
|
57
|
+
|
58
|
+
if validated_params.empty?
|
59
|
+
raise ArgumentError, "You must provide the parameter 'report_name' to aws_billing_report."
|
60
|
+
end
|
61
|
+
|
62
|
+
validated_params
|
63
|
+
end
|
64
|
+
|
65
|
+
def fetch_from_api
|
66
|
+
report = find_report(report_name)
|
67
|
+
@exists = !report.nil?
|
68
|
+
if exists?
|
69
|
+
@time_unit = report.time_unit.downcase
|
70
|
+
@format = report.format.downcase
|
71
|
+
@compression = report.compression.downcase
|
72
|
+
@s3_bucket = report.s3_bucket
|
73
|
+
@s3_prefix = report.s3_prefix
|
74
|
+
@s3_region = report.s3_region
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def find_report(report_name)
|
79
|
+
pagination_opts = {}
|
80
|
+
found_report_def = nil
|
81
|
+
while found_report_def.nil?
|
82
|
+
api_result = backend.describe_report_definitions(pagination_opts)
|
83
|
+
next_token = api_result.next_token
|
84
|
+
found_report_def = api_result.report_definitions.find { |report_def| report_def.report_name == report_name }
|
85
|
+
pagination_opts = { next_token: next_token }
|
86
|
+
|
87
|
+
next if found_report_def.nil? && next_token # Loop again: didn't find it, but there are more results
|
88
|
+
break if found_report_def.nil? && next_token.nil? # Give up: didn't find it, no more results
|
89
|
+
end
|
90
|
+
found_report_def
|
91
|
+
end
|
92
|
+
|
93
|
+
def backend
|
94
|
+
@backend ||= BackendFactory.create(inspec_runner)
|
95
|
+
end
|
96
|
+
|
97
|
+
class Backend
|
98
|
+
class AwsClientApi < AwsBackendBase
|
99
|
+
AwsBillingReport::BackendFactory.set_default_backend(self)
|
100
|
+
self.aws_client_class = Aws::CostandUsageReportService::Client
|
101
|
+
|
102
|
+
def describe_report_definitions(query = {})
|
103
|
+
aws_service_client.describe_report_definitions(query)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|