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,145 @@
1
+ require "resource_support/aws/aws_singular_resource_mixin"
2
+ require "resource_support/aws/aws_backend_base"
3
+ require "aws-sdk-iam"
4
+
5
+ class AwsIamUser < Inspec.resource(1)
6
+ name "aws_iam_user"
7
+ desc "Verifies settings for AWS IAM user"
8
+ example <<~EXAMPLE
9
+ describe aws_iam_user(username: 'test_user') do
10
+ it { should have_mfa_enabled }
11
+ it { should_not have_console_password }
12
+ it { should_not have_inline_user_policies }
13
+ it { should_not have_attached_user_policies }
14
+ end
15
+ EXAMPLE
16
+ supports platform: "aws"
17
+
18
+ include AwsSingularResourceMixin
19
+ attr_reader :access_keys, :attached_policy_names, :attached_policy_arns, \
20
+ :has_console_password, :has_mfa_enabled, :inline_policy_names, :username
21
+ alias has_mfa_enabled? has_mfa_enabled
22
+ alias has_console_password? has_console_password
23
+
24
+ def name
25
+ Inspec.deprecate(:properties_aws_iam_user, "The aws_iam_user `name` property is deprecated. Please use `username` instead")
26
+ username
27
+ end
28
+
29
+ def to_s
30
+ "IAM User #{username}"
31
+ end
32
+
33
+ def has_attached_policies?
34
+ return nil unless exists?
35
+
36
+ !attached_policy_names.empty?
37
+ end
38
+
39
+ def has_inline_policies?
40
+ return nil unless exists?
41
+
42
+ !inline_policy_names.empty?
43
+ end
44
+
45
+ private
46
+
47
+ def validate_params(raw_params)
48
+ validated_params = check_resource_param_names(
49
+ raw_params: raw_params,
50
+ allowed_params: %i{username aws_user_struct name user},
51
+ allowed_scalar_name: :username,
52
+ allowed_scalar_type: String
53
+ )
54
+ # If someone passed :name, rename it to :username
55
+ if validated_params.key?(:name)
56
+ Inspec.deprecate(:properties_aws_iam_user, "The aws_iam_users `name` property is deprecated. Please use `username` instead")
57
+ validated_params[:username] = validated_params.delete(:name)
58
+ end
59
+
60
+ # If someone passed :user, rename it to :aws_user_struct
61
+ if validated_params.key?(:user)
62
+ Inspec.deprecate(:properties_aws_iam_user, "The aws_iam_users `user` property is deprecated. Please use `aws_user_struct` instead")
63
+ validated_params[:aws_user_struct] = validated_params.delete(:user)
64
+ end
65
+
66
+ if validated_params.empty?
67
+ raise ArgumentError, "You must provide a username to aws_iam_user."
68
+ end
69
+
70
+ validated_params
71
+ end
72
+
73
+ def fetch_from_api
74
+ backend = BackendFactory.create(inspec_runner)
75
+ @aws_user_struct ||= nil # silence unitialized warning
76
+ unless @aws_user_struct
77
+ begin
78
+ @aws_user_struct = backend.get_user(user_name: username)
79
+ rescue Aws::IAM::Errors::NoSuchEntity
80
+ @exists = false
81
+ @access_keys = []
82
+ @inline_policy_names = []
83
+ @attached_policy_arns = []
84
+ @attached_policy_names = []
85
+ return
86
+ end
87
+ end
88
+ # TODO: extract properties from aws_user_struct?
89
+
90
+ @exists = true
91
+
92
+ begin
93
+ _login_profile = backend.get_login_profile(user_name: username)
94
+ @has_console_password = true
95
+ # Password age also available here
96
+ rescue Aws::IAM::Errors::NoSuchEntity
97
+ @has_console_password = false
98
+ end
99
+
100
+ mfa_info = backend.list_mfa_devices(user_name: username)
101
+ @has_mfa_enabled = !mfa_info.mfa_devices.empty?
102
+
103
+ # TODO: consider returning InSpec AwsIamAccessKey objects
104
+ @access_keys = backend.list_access_keys(user_name: username).access_key_metadata
105
+ # If the above call fails, we get nil here; but we promise access_keys will be an array.
106
+ @access_keys ||= []
107
+
108
+ @inline_policy_names = backend.list_user_policies(user_name: username).policy_names
109
+
110
+ attached_policies = backend.list_attached_user_policies(user_name: username).attached_policies
111
+ @attached_policy_arns = attached_policies.map { |p| p[:policy_arn] }
112
+ @attached_policy_names = attached_policies.map { |p| p[:policy_name] }
113
+ end
114
+
115
+ class Backend
116
+ class AwsClientApi < AwsBackendBase
117
+ BackendFactory.set_default_backend(self)
118
+ self.aws_client_class = Aws::IAM::Client
119
+
120
+ def get_user(criteria)
121
+ aws_service_client.get_user(criteria)
122
+ end
123
+
124
+ def get_login_profile(criteria)
125
+ aws_service_client.get_login_profile(criteria)
126
+ end
127
+
128
+ def list_mfa_devices(criteria)
129
+ aws_service_client.list_mfa_devices(criteria)
130
+ end
131
+
132
+ def list_access_keys(criteria)
133
+ aws_service_client.list_access_keys(criteria)
134
+ end
135
+
136
+ def list_user_policies(criteria)
137
+ aws_service_client.list_user_policies(criteria)
138
+ end
139
+
140
+ def list_attached_user_policies(criteria)
141
+ aws_service_client.list_attached_user_policies(criteria)
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,160 @@
1
+ require "resource_support/aws/aws_plural_resource_mixin"
2
+ require "resource_support/aws/aws_backend_base"
3
+ require "aws-sdk-iam"
4
+
5
+ class AwsIamUsers < Inspec.resource(1)
6
+ name "aws_iam_users"
7
+ desc "Verifies settings for AWS IAM users"
8
+ example <<~EXAMPLE
9
+ describe aws_iam_users.where(has_mfa_enabled?: false) do
10
+ it { should_not exist }
11
+ end
12
+ describe aws_iam_users.where(has_console_password?: true) do
13
+ it { should exist }
14
+ end
15
+ describe aws_iam_users.where(has_inline_policies?: true) do
16
+ it { should_not exist }
17
+ end
18
+ describe aws_iam_users.where(has_attached_policies?: true) do
19
+ it { should_not exist }
20
+ end
21
+ EXAMPLE
22
+ supports platform: "aws"
23
+
24
+ include AwsPluralResourceMixin
25
+
26
+ def self.lazy_get_login_profile(row, _criterion, table)
27
+ backend = BackendFactory.create(table.resource.inspec_runner)
28
+ begin
29
+ _login_profile = backend.get_login_profile(user_name: row[:user_name])
30
+ row[:has_console_password] = true
31
+ rescue Aws::IAM::Errors::NoSuchEntity
32
+ row[:has_console_password] = false
33
+ end
34
+ row[:has_console_password?] = row[:has_console_password]
35
+ end
36
+
37
+ def self.lazy_list_mfa_devices(row, _criterion, table)
38
+ backend = BackendFactory.create(table.resource.inspec_runner)
39
+ begin
40
+ aws_mfa_devices = backend.list_mfa_devices(user_name: row[:user_name])
41
+ row[:has_mfa_enabled] = !aws_mfa_devices.mfa_devices.empty?
42
+ rescue Aws::IAM::Errors::NoSuchEntity
43
+ row[:has_mfa_enabled] = false
44
+ end
45
+ row[:has_mfa_enabled?] = row[:has_mfa_enabled]
46
+ end
47
+
48
+ def self.lazy_list_user_policies(row, _criterion, table)
49
+ backend = BackendFactory.create(table.resource.inspec_runner)
50
+ row[:inline_policy_names] = backend.list_user_policies(user_name: row[:user_name]).policy_names
51
+ row[:has_inline_policies] = !row[:inline_policy_names].empty?
52
+ row[:has_inline_policies?] = row[:has_inline_policies]
53
+ end
54
+
55
+ def self.lazy_list_attached_policies(row, _criterion, table)
56
+ backend = BackendFactory.create(table.resource.inspec_runner)
57
+ attached_policies = backend.list_attached_user_policies(user_name: row[:user_name]).attached_policies
58
+ row[:has_attached_policies] = !attached_policies.empty?
59
+ row[:has_attached_policies?] = row[:has_attached_policies]
60
+ row[:attached_policy_names] = attached_policies.map { |p| p[:policy_name] }
61
+ row[:attached_policy_arns] = attached_policies.map { |p| p[:policy_arn] }
62
+ end
63
+
64
+ filter = FilterTable.create
65
+
66
+ # These are included on the initial fetch
67
+ filter.register_column(:usernames, field: :user_name)
68
+ .register_column(:username) { |res| res.entries.map { |row| row[:user_name] } } # We should deprecate this; plural resources get plural properties
69
+ .register_column(:password_ever_used?, field: :password_ever_used?)
70
+ .register_column(:password_never_used?, field: :password_never_used?)
71
+ .register_column(:password_last_used_days_ago, field: :password_last_used_days_ago)
72
+
73
+ # Remaining properties / criteria are handled lazily, grouped by fetcher
74
+ filter.register_column(:has_console_password?, field: :has_console_password?, lazy: method(:lazy_get_login_profile))
75
+ .register_column(:has_console_password, field: :has_console_password, lazy: method(:lazy_get_login_profile))
76
+
77
+ filter.register_column(:has_mfa_enabled?, field: :has_mfa_enabled?, lazy: method(:lazy_list_mfa_devices))
78
+ .register_column(:has_mfa_enabled, field: :has_mfa_enabled, lazy: method(:lazy_list_mfa_devices))
79
+
80
+ filter.register_column(:has_inline_policies?, field: :has_inline_policies?, lazy: method(:lazy_list_user_policies))
81
+ .register_column(:has_inline_policies, field: :has_inline_policies, lazy: method(:lazy_list_user_policies))
82
+ .register_column(:inline_policy_names, field: :inline_policy_names, style: :simple, lazy: method(:lazy_list_user_policies))
83
+
84
+ filter.register_column(:has_attached_policies?, field: :has_attached_policies?, lazy: method(:lazy_list_attached_policies))
85
+ .register_column(:has_attached_policies, field: :has_attached_policies, lazy: method(:lazy_list_attached_policies))
86
+ .register_column(:attached_policy_names, field: :attached_policy_names, style: :simple, lazy: method(:lazy_list_attached_policies))
87
+ .register_column(:attached_policy_arns, field: :attached_policy_arns, style: :simple, lazy: method(:lazy_list_attached_policies))
88
+ filter.install_filter_methods_on_resource(self, :table)
89
+
90
+ def validate_params(raw_params)
91
+ # No params yet
92
+ unless raw_params.empty?
93
+ raise ArgumentError, "aws_iam_users does not accept resource parameters"
94
+ end
95
+
96
+ raw_params
97
+ end
98
+
99
+ def fetch_from_api_paginated(backend)
100
+ table = []
101
+ page_marker = nil
102
+ loop do
103
+ api_result = backend.list_users(marker: page_marker)
104
+ table += api_result.users.map(&:to_h)
105
+ page_marker = api_result.marker
106
+ break unless api_result.is_truncated
107
+ end
108
+ table
109
+ end
110
+
111
+ def fetch_from_api
112
+ backend = BackendFactory.create(inspec_runner)
113
+ @table = fetch_from_api_paginated(backend)
114
+
115
+ @table.each do |user|
116
+ password_last_used = user[:password_last_used]
117
+ user[:password_ever_used?] = !password_last_used.nil?
118
+ user[:password_never_used?] = password_last_used.nil?
119
+ if user[:password_ever_used?]
120
+ user[:password_last_used_days_ago] = ((Time.now - password_last_used) / (24 * 60 * 60)).to_i
121
+ end
122
+ end
123
+ @table
124
+ end
125
+
126
+ def to_s
127
+ "IAM Users"
128
+ end
129
+
130
+ #===========================================================================#
131
+ # Backend Implementation
132
+ #===========================================================================#
133
+ class Backend
134
+ class AwsClientApi < AwsBackendBase
135
+ BackendFactory.set_default_backend(self)
136
+ self.aws_client_class = Aws::IAM::Client
137
+
138
+ # TODO: delegate this out
139
+ def list_users(query = {})
140
+ aws_service_client.list_users(query)
141
+ end
142
+
143
+ def get_login_profile(query)
144
+ aws_service_client.get_login_profile(query)
145
+ end
146
+
147
+ def list_mfa_devices(query)
148
+ aws_service_client.list_mfa_devices(query)
149
+ end
150
+
151
+ def list_user_policies(query)
152
+ aws_service_client.list_user_policies(query)
153
+ end
154
+
155
+ def list_attached_user_policies(query)
156
+ aws_service_client.list_attached_user_policies(query)
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,100 @@
1
+ require "resource_support/aws/aws_singular_resource_mixin"
2
+ require "resource_support/aws/aws_backend_base"
3
+ require "aws-sdk-kms"
4
+
5
+ class AwsKmsKey < Inspec.resource(1)
6
+ name "aws_kms_key"
7
+ desc "Verifies settings for an individual AWS KMS Key"
8
+ example <<~EXAMPLE
9
+ describe aws_kms_key('arn:aws:kms:us-east-1::key/4321dcba-21io-23de-85he-ab0987654321') do
10
+ it { should exist }
11
+ end
12
+ EXAMPLE
13
+
14
+ supports platform: "aws"
15
+
16
+ include AwsSingularResourceMixin
17
+ attr_reader :key_id, :arn, :creation_date, :key_usage, :key_state, :description,
18
+ :deletion_date, :valid_to, :external, :has_key_expiration, :managed_by_aws,
19
+ :has_rotation_enabled, :enabled
20
+ # Use aliases for matchers
21
+ alias deletion_time deletion_date
22
+ alias invalidation_time valid_to
23
+ alias external? external
24
+ alias enabled? enabled
25
+ alias managed_by_aws? managed_by_aws
26
+ alias has_key_expiration? has_key_expiration
27
+ alias has_rotation_enabled? has_rotation_enabled
28
+
29
+ def to_s
30
+ "KMS Key #{@key_id}"
31
+ end
32
+
33
+ def created_days_ago
34
+ ((Time.now - creation_date) / (24 * 60 * 60)).to_i unless creation_date.nil?
35
+ end
36
+
37
+ private
38
+
39
+ def validate_params(raw_params)
40
+ validated_params = check_resource_param_names(
41
+ raw_params: raw_params,
42
+ allowed_params: [:key_id],
43
+ allowed_scalar_name: :key_id,
44
+ allowed_scalar_type: String
45
+ )
46
+
47
+ if validated_params.empty?
48
+ raise ArgumentError, "You must provide the parameter 'key_id' to aws_kms_key."
49
+ end
50
+
51
+ validated_params
52
+ end
53
+
54
+ def fetch_from_api
55
+ backend = BackendFactory.create(inspec_runner)
56
+
57
+ query = { key_id: @key_id }
58
+ catch_aws_errors do
59
+ begin
60
+ resp = backend.describe_key(query)
61
+
62
+ @exists = true
63
+ @key = resp.key_metadata.to_h
64
+ @key_id = @key[:key_id]
65
+ @arn = @key[:arn]
66
+ @creation_date = @key[:creation_date]
67
+ @enabled = @key[:enabled]
68
+ @description = @key[:description]
69
+ @key_usage = @key[:key_usage]
70
+ @key_state = @key[:key_state]
71
+ @deletion_date = @key[:deletion_date]
72
+ @valid_to = @key[:valid_to]
73
+ @external = @key[:origin] == "EXTERNAL"
74
+ @has_key_expiration = @key[:expiration_model] == "KEY_MATERIAL_EXPIRES"
75
+ @managed_by_aws = @key[:key_manager] == "AWS"
76
+
77
+ resp = backend.get_key_rotation_status(query)
78
+ @has_rotation_enabled = resp.key_rotation_enabled unless resp.empty?
79
+ rescue Aws::KMS::Errors::NotFoundException
80
+ @exists = false
81
+ return
82
+ end
83
+ end
84
+ end
85
+
86
+ class Backend
87
+ class AwsClientApi < AwsBackendBase
88
+ BackendFactory.set_default_backend(self)
89
+ self.aws_client_class = Aws::KMS::Client
90
+
91
+ def describe_key(query)
92
+ aws_service_client.describe_key(query)
93
+ end
94
+
95
+ def get_key_rotation_status(query)
96
+ aws_service_client.get_key_rotation_status(query)
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,58 @@
1
+ require "resource_support/aws/aws_plural_resource_mixin"
2
+ require "resource_support/aws/aws_backend_base"
3
+ require "aws-sdk-kms"
4
+
5
+ class AwsKmsKeys < Inspec.resource(1)
6
+ name "aws_kms_keys"
7
+ desc "Verifies settings for AWS KMS Keys in bulk"
8
+ example <<~EXAMPLE
9
+ describe aws_kms_keys 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_kms_keys 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(:key_arns, field: :key_arn)
28
+ .register_column(:key_ids, field: :key_id)
29
+ filter.install_filter_methods_on_resource(self, :table)
30
+
31
+ def to_s
32
+ "KMS Keys"
33
+ end
34
+
35
+ def fetch_from_api
36
+ backend = BackendFactory.create(inspec_runner)
37
+ @table = []
38
+ pagination_opts = { limit: 1000 }
39
+ loop do
40
+ api_result = backend.list_keys(pagination_opts)
41
+ @table += api_result.keys.map(&:to_h)
42
+ break unless api_result.truncated
43
+
44
+ pagination_opts = { marker: api_result.next_marker }
45
+ end
46
+ end
47
+
48
+ class Backend
49
+ class AwsClientApi < AwsBackendBase
50
+ BackendFactory.set_default_backend(self)
51
+ self.aws_client_class = Aws::KMS::Client
52
+
53
+ def list_keys(query = {})
54
+ aws_service_client.list_keys(query)
55
+ end
56
+ end
57
+ end
58
+ end