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.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +63 -0
  3. data/inspec.gemspec +36 -0
  4. data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/Gemfile +11 -0
  5. data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/inspec-plugin-template.gemspec +43 -0
  6. data/lib/plugins/inspec-init/templates/profiles/aws/README.md +192 -0
  7. data/lib/plugins/inspec-init/templates/profiles/aws/attributes.yml +2 -0
  8. data/lib/plugins/inspec-init/templates/profiles/aws/controls/example.rb +39 -0
  9. data/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml +22 -0
  10. data/lib/plugins/inspec-init/templates/profiles/azure/README.md +56 -0
  11. data/lib/plugins/inspec-init/templates/profiles/azure/controls/example.rb +14 -0
  12. data/lib/plugins/inspec-init/templates/profiles/azure/inspec.yml +14 -0
  13. data/lib/plugins/inspec-init/templates/profiles/gcp/README.md +66 -0
  14. data/lib/plugins/inspec-init/templates/profiles/gcp/attributes.yml +2 -0
  15. data/lib/plugins/inspec-init/templates/profiles/gcp/controls/example.rb +27 -0
  16. data/lib/plugins/inspec-init/templates/profiles/gcp/inspec.yml +19 -0
  17. data/lib/resource_support/aws.rb +76 -0
  18. data/lib/resource_support/aws/aws_backend_base.rb +12 -0
  19. data/lib/resource_support/aws/aws_backend_factory_mixin.rb +12 -0
  20. data/lib/resource_support/aws/aws_plural_resource_mixin.rb +24 -0
  21. data/lib/resource_support/aws/aws_resource_mixin.rb +69 -0
  22. data/lib/resource_support/aws/aws_singular_resource_mixin.rb +27 -0
  23. data/lib/resources/aws/aws_billing_report.rb +107 -0
  24. data/lib/resources/aws/aws_billing_reports.rb +74 -0
  25. data/lib/resources/aws/aws_cloudtrail_trail.rb +97 -0
  26. data/lib/resources/aws/aws_cloudtrail_trails.rb +51 -0
  27. data/lib/resources/aws/aws_cloudwatch_alarm.rb +67 -0
  28. data/lib/resources/aws/aws_cloudwatch_log_metric_filter.rb +105 -0
  29. data/lib/resources/aws/aws_config_delivery_channel.rb +74 -0
  30. data/lib/resources/aws/aws_config_recorder.rb +99 -0
  31. data/lib/resources/aws/aws_ebs_volume.rb +127 -0
  32. data/lib/resources/aws/aws_ebs_volumes.rb +69 -0
  33. data/lib/resources/aws/aws_ec2_instance.rb +162 -0
  34. data/lib/resources/aws/aws_ec2_instances.rb +69 -0
  35. data/lib/resources/aws/aws_ecs_cluster.rb +88 -0
  36. data/lib/resources/aws/aws_eks_cluster.rb +105 -0
  37. data/lib/resources/aws/aws_elb.rb +85 -0
  38. data/lib/resources/aws/aws_elbs.rb +84 -0
  39. data/lib/resources/aws/aws_flow_log.rb +106 -0
  40. data/lib/resources/aws/aws_iam_access_key.rb +112 -0
  41. data/lib/resources/aws/aws_iam_access_keys.rb +153 -0
  42. data/lib/resources/aws/aws_iam_group.rb +62 -0
  43. data/lib/resources/aws/aws_iam_groups.rb +56 -0
  44. data/lib/resources/aws/aws_iam_password_policy.rb +121 -0
  45. data/lib/resources/aws/aws_iam_policies.rb +57 -0
  46. data/lib/resources/aws/aws_iam_policy.rb +311 -0
  47. data/lib/resources/aws/aws_iam_role.rb +60 -0
  48. data/lib/resources/aws/aws_iam_root_user.rb +82 -0
  49. data/lib/resources/aws/aws_iam_user.rb +145 -0
  50. data/lib/resources/aws/aws_iam_users.rb +160 -0
  51. data/lib/resources/aws/aws_kms_key.rb +100 -0
  52. data/lib/resources/aws/aws_kms_keys.rb +58 -0
  53. data/lib/resources/aws/aws_rds_instance.rb +74 -0
  54. data/lib/resources/aws/aws_route_table.rb +67 -0
  55. data/lib/resources/aws/aws_route_tables.rb +64 -0
  56. data/lib/resources/aws/aws_s3_bucket.rb +142 -0
  57. data/lib/resources/aws/aws_s3_bucket_object.rb +87 -0
  58. data/lib/resources/aws/aws_s3_buckets.rb +52 -0
  59. data/lib/resources/aws/aws_security_group.rb +314 -0
  60. data/lib/resources/aws/aws_security_groups.rb +71 -0
  61. data/lib/resources/aws/aws_sns_subscription.rb +82 -0
  62. data/lib/resources/aws/aws_sns_topic.rb +57 -0
  63. data/lib/resources/aws/aws_sns_topics.rb +60 -0
  64. data/lib/resources/aws/aws_sqs_queue.rb +66 -0
  65. data/lib/resources/aws/aws_subnet.rb +92 -0
  66. data/lib/resources/aws/aws_subnets.rb +56 -0
  67. data/lib/resources/aws/aws_vpc.rb +77 -0
  68. data/lib/resources/aws/aws_vpcs.rb +55 -0
  69. data/lib/resources/azure/azure_backend.rb +379 -0
  70. data/lib/resources/azure/azure_generic_resource.rb +55 -0
  71. data/lib/resources/azure/azure_resource_group.rb +151 -0
  72. data/lib/resources/azure/azure_virtual_machine.rb +262 -0
  73. data/lib/resources/azure/azure_virtual_machine_data_disk.rb +131 -0
  74. metadata +202 -0
@@ -0,0 +1,99 @@
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
@@ -0,0 +1,127 @@
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://www.inspec.io/docs/reference/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
@@ -0,0 +1,69 @@
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
@@ -0,0 +1,162 @@
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 AwsEc2Instance < Inspec.resource(1)
6
+ name "aws_ec2_instance"
7
+ desc "Verifies settings for an EC2 instance"
8
+
9
+ example <<~EXAMPLE
10
+ describe aws_ec2_instance('i-123456') do
11
+ it { should be_running }
12
+ it { should have_roles }
13
+ end
14
+
15
+ describe aws_ec2_instance(name: 'my-instance') do
16
+ it { should be_running }
17
+ it { should have_roles }
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
+ @opts.is_a?(Hash) ? @display_name = @opts[:name] : @display_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
+ @iam_resource = conn ? conn.iam_resource : inspec_runner.backend.aws_resource(Aws::IAM::Resource, {})
29
+ end
30
+
31
+ # TODO: DRY up, see https://github.com/chef/inspec/issues/2633
32
+ # Copied from resource_support/aws/aws_resource_mixin.rb
33
+ def catch_aws_errors
34
+ yield
35
+ rescue Aws::Errors::MissingCredentialsError
36
+ # The AWS error here is unhelpful:
37
+ # "unable to sign request without credentials set"
38
+ 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."
39
+ fail_resource("No AWS credentials available")
40
+ rescue Aws::Errors::ServiceError => e
41
+ fail_resource e.message
42
+ end
43
+
44
+ # TODO: DRY up, see https://github.com/chef/inspec/issues/2633
45
+ # Copied from resource_support/aws/aws_singular_resource_mixin.rb
46
+ def inspec_runner
47
+ # When running under inspec-cli, we have an 'inspec' method that
48
+ # returns the runner. When running under unit tests, we don't
49
+ # have that, but we still have to call this to pass something
50
+ # (nil is OK) to the backend.
51
+ # TODO: remove with https://github.com/chef/inspec-aws/issues/216
52
+ # TODO: remove after rewrite to include AwsSingularResource
53
+ inspec if respond_to?(:inspec)
54
+ end
55
+
56
+ def id
57
+ return @instance_id if defined?(@instance_id)
58
+
59
+ catch_aws_errors do
60
+ if @opts.is_a?(Hash)
61
+ first = @ec2_resource.instances(
62
+ {
63
+ filters: [{
64
+ name: "tag:Name",
65
+ values: [@opts[:name]],
66
+ }],
67
+ }
68
+ ).first
69
+ # catch case where the instance is not known
70
+ @instance_id = first.id unless first.nil?
71
+ else
72
+ @instance_id = @opts
73
+ end
74
+ end
75
+ end
76
+ alias instance_id id
77
+
78
+ def exists?
79
+ return false if instance.nil?
80
+
81
+ instance.exists?
82
+ end
83
+
84
+ # returns the instance state
85
+ def state
86
+ catch_aws_errors do
87
+ instance&.state&.name
88
+ end
89
+ end
90
+
91
+ # helper methods for each state
92
+ %w{
93
+ pending running shutting-down
94
+ terminated stopping stopped unknown
95
+ }.each do |state_name|
96
+ define_method state_name.tr("-", "_") + "?" do
97
+ state == state_name
98
+ end
99
+ end
100
+
101
+ # attributes that we want to expose
102
+ %w{
103
+ public_ip_address private_ip_address key_name private_dns_name
104
+ public_dns_name subnet_id architecture root_device_type
105
+ root_device_name virtualization_type client_token launch_time
106
+ instance_type image_id vpc_id
107
+ }.each do |attribute|
108
+ define_method attribute do
109
+ catch_aws_errors do
110
+ instance.send(attribute) if instance
111
+ end
112
+ end
113
+ end
114
+
115
+ # Don't document this - it's a bit hard to use. Our current doctrine
116
+ # is to use dumb things, like arrays of strings - use security_group_ids instead.
117
+ def security_groups
118
+ catch_aws_errors do
119
+ @security_groups ||= instance.security_groups.map do |sg|
120
+ { id: sg.group_id, name: sg.group_name }
121
+ end
122
+ end
123
+ end
124
+
125
+ def security_group_ids
126
+ catch_aws_errors do
127
+ @security_group_ids ||= instance.security_groups.map(&:group_id)
128
+ end
129
+ end
130
+
131
+ def tags
132
+ catch_aws_errors do
133
+ @tags ||= instance.tags.map { |tag| { key: tag.key, value: tag.value } }
134
+ end
135
+ end
136
+
137
+ def to_s
138
+ "EC2 Instance #{@display_name}"
139
+ end
140
+
141
+ def has_roles?
142
+ catch_aws_errors do
143
+ instance_profile = instance.iam_instance_profile
144
+
145
+ if instance_profile
146
+ roles = @iam_resource.instance_profile(
147
+ instance_profile.arn.gsub(%r{^.*\/}, "")
148
+ ).roles
149
+ else
150
+ roles = nil
151
+ end
152
+
153
+ roles && !roles.empty?
154
+ end
155
+ end
156
+
157
+ private
158
+
159
+ def instance
160
+ catch_aws_errors { @instance ||= @ec2_resource.instance(id) }
161
+ end
162
+ end