cfn-nag 0.6.10 → 0.6.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cfn-nag/cfn_nag.rb +1 -2
  3. data/lib/cfn-nag/cfn_nag_config.rb +2 -8
  4. data/lib/cfn-nag/custom_rule_loader.rb +1 -1
  5. data/lib/cfn-nag/custom_rules/DynamoDBBackupRule.rb +28 -0
  6. data/lib/cfn-nag/custom_rules/ECRRepositoryScanOnPushRule.rb +28 -0
  7. data/lib/cfn-nag/custom_rules/ElasticLoadBalancerV2AccessLoggingRule.rb +1 -2
  8. data/lib/cfn-nag/custom_rules/ElasticsearchDomainEncryptionAtRestOptionsRule.rb +0 -1
  9. data/lib/cfn-nag/custom_rules/IamRolePassRoleWildcardResourceRule.rb +1 -1
  10. data/lib/cfn-nag/custom_rules/LogsLogGroupRetentionRule.rb +27 -0
  11. data/lib/cfn-nag/custom_rules/RDSInstanceDeletionProtectionRule.rb +1 -1
  12. data/lib/cfn-nag/custom_rules/SPCMRule.rb +1 -0
  13. data/lib/cfn-nag/custom_rules/SecurityGroupEgressOpenToWorldRule.rb +8 -2
  14. data/lib/cfn-nag/custom_rules/SecurityGroupIngressCidrNon32Rule.rb +8 -2
  15. data/lib/cfn-nag/custom_rules/SecurityGroupIngressOpenToWorldRule.rb +8 -2
  16. data/lib/cfn-nag/custom_rules/SecurityGroupRuleDescriptionRule.rb +1 -1
  17. data/lib/cfn-nag/custom_rules/boolean_base_rule.rb +1 -1
  18. data/lib/cfn-nag/custom_rules/passrole_base_rule.rb +1 -1
  19. data/lib/cfn-nag/iam_complexity_metric/condition_metric.rb +3 -2
  20. data/lib/cfn-nag/ip_addr.rb +3 -2
  21. data/lib/cfn-nag/metadata.rb +2 -2
  22. data/lib/cfn-nag/result_view/stdout_results.rb +2 -2
  23. data/lib/cfn-nag/rule_repos/gem_based_rule_repo.rb +1 -1
  24. data/lib/cfn-nag/rule_repository_loader.rb +1 -1
  25. data/lib/cfn-nag/util/enforce_reference_parameter.rb +1 -1
  26. data/lib/cfn-nag/util/enforce_string_or_dynamic_reference.rb +5 -6
  27. metadata +9 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: abfc80557991b6243d7324acf49f7f86d878a9a076e9760bd42eab6af5a02132
4
- data.tar.gz: 28516fe4a3ee488d6608f85a4e4d00d30cd09464e5515b6e7da05b0c2ece771d
3
+ metadata.gz: 16861651aa50f0df55c1f09ab3ee2b6805a5bbe5df2553509f1728922809d878
4
+ data.tar.gz: ecf3c006adc7f35cd5f01246b2cb9315c029c7b86055d5ee5438fa2eeb44b68c
5
5
  SHA512:
6
- metadata.gz: c59247c40157d4f5af73a09ed733e72b26e8a9d5e79e61f304bbbf91b8bba3562a2176a5c0d411755a31f98aef012500ca78e29a8546a0c4a2795e12257cae3e
7
- data.tar.gz: 8f343d1a16de3fe03385a757c5b30f4944a70b7223ce116950d7fd4d95fa1f8ac55ea9a7b550d8a36c4de1aa05e05c9fae3f0cc88af1e45514185f0e9dba844f
6
+ metadata.gz: 640dcd9fe284f48ddcc714fc8573115062547e4e81c7b73500f7369e37392b7c4e06666ec1ac0d294d6f737d31f62be0062eaf745a1e5b640401b79ccafbf4cd
7
+ data.tar.gz: df569ee1ad3089fd480dd9957cc7dbca4a0d4ec469aadc81048d143f9584369987ce3de53798e3ebd2b986a1ae44f6844c32b3e9e30b242ed7938f8edf2b1799
@@ -135,12 +135,11 @@ class CfnNag
135
135
  )
136
136
 
137
137
  # this must come after - blacklist should always win
138
- violations = filter_violations_by_blacklist(
138
+ filter_violations_by_blacklist(
139
139
  blacklist_definition: @config.blacklist_definition,
140
140
  rule_definitions: @config.custom_rule_loader.rule_definitions,
141
141
  violations: violations
142
142
  )
143
- violations
144
143
  rescue StandardError => blacklist_or_profile_parse_error
145
144
  violations << fatal_violation(blacklist_or_profile_parse_error.to_s)
146
145
  violations
@@ -29,12 +29,6 @@ class CfnNagConfig
29
29
  end
30
30
  # rubocop:enable Metrics/ParameterLists
31
31
 
32
- attr_reader :rule_arguments
33
- attr_reader :rule_directory
34
- attr_reader :custom_rule_loader
35
- attr_reader :profile_definition
36
- attr_reader :blacklist_definition
37
- attr_reader :fail_on_warnings
38
- attr_reader :rule_repositories
39
- attr_reader :ignore_fatal
32
+ attr_reader :rule_arguments, :rule_directory, :custom_rule_loader, :profile_definition, :blacklist_definition, \
33
+ :fail_on_warnings, :rule_repositories, :ignore_fatal
40
34
  end
@@ -93,7 +93,7 @@ class CustomRuleLoader
93
93
  rescue ScriptError, StandardError => rule_error
94
94
  raise rule_error unless @isolate_custom_rule_exceptions
95
95
 
96
- STDERR.puts rule_error
96
+ $stderr.puts rule_error
97
97
  end
98
98
  end
99
99
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cfn-nag/violation'
4
+ require 'cfn-nag/util/truthy'
5
+ require_relative 'base'
6
+
7
+ class DynamoDBBackupRule < BaseRule
8
+ def rule_text
9
+ 'DynamoDB table should have backup enabled, should be set using PointInTimeRecoveryEnabled'
10
+ end
11
+
12
+ def rule_type
13
+ Violation::WARNING
14
+ end
15
+
16
+ def rule_id
17
+ 'W78'
18
+ end
19
+
20
+ def audit_impl(cfn_model)
21
+ violating_ddb_tables = cfn_model.resources_by_type('AWS::DynamoDB::Table').select do |table|
22
+ table.pointInTimeRecoverySpecification.nil? ||
23
+ !truthy?(table.pointInTimeRecoverySpecification['PointInTimeRecoveryEnabled'].to_s)
24
+ end
25
+
26
+ violating_ddb_tables.map(&:logical_resource_id)
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cfn-nag/violation'
4
+ require 'cfn-nag/util/truthy'
5
+ require_relative 'base'
6
+
7
+ class ECRRepositoryScanOnPushRule < BaseRule
8
+ def rule_text
9
+ 'ECR Repository should have scanOnPush enabled'
10
+ end
11
+
12
+ def rule_type
13
+ Violation::WARNING
14
+ end
15
+
16
+ def rule_id
17
+ 'W79'
18
+ end
19
+
20
+ def audit_impl(cfn_model)
21
+ violating_ecr_registries = cfn_model.resources_by_type('AWS::ECR::Repository').select do |registry|
22
+ registry.imageScanningConfiguration.nil? ||
23
+ !truthy?(registry.imageScanningConfiguration['scanOnPush'].to_s)
24
+ end
25
+
26
+ violating_ecr_registries.map(&:logical_resource_id)
27
+ end
28
+ end
@@ -29,10 +29,9 @@ class ElasticLoadBalancerV2AccessLoggingRule < BaseRule
29
29
  private
30
30
 
31
31
  def access_logging_is_false?(load_balancer)
32
- false_access_log_attribute = load_balancer.loadBalancerAttributes.find do |load_balancer_attribute|
32
+ load_balancer.loadBalancerAttributes.find do |load_balancer_attribute|
33
33
  load_balancer_attribute['Key'] == 'access_logs.s3.enabled' && not_truthy?(load_balancer_attribute['Value'])
34
34
  end
35
- false_access_log_attribute
36
35
  end
37
36
 
38
37
  def missing_access_logs?(load_balancer)
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'cfn-nag/util/truthy'
4
4
  require 'cfn-nag/violation'
5
- require 'cfn-nag/util/truthy'
6
5
  require_relative 'base'
7
6
 
8
7
  class ElasticsearchDomainEncryptionAtRestOptionsRule < BaseRule
@@ -5,7 +5,7 @@ require_relative 'base'
5
5
  require 'cfn-nag/util/wildcard_patterns'
6
6
 
7
7
  class IamRolePassRoleWildcardResourceRule < BaseRule
8
- IAM_ACTION_PATTERNS = wildcard_patterns('PassRole').map! { |x| 'iam:' + x } + ['*']
8
+ IAM_ACTION_PATTERNS = wildcard_patterns('PassRole').map! { |x| "iam:#{x}" } + ['*']
9
9
 
10
10
  def rule_text
11
11
  'IAM role should not allow * resource with PassRole action on its permissions policy'
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cfn-nag/violation'
4
+ require 'cfn-nag/util/truthy'
5
+ require_relative 'base'
6
+
7
+ class LogsLogGroupRetentionRule < BaseRule
8
+ def rule_text
9
+ 'CloudWatchLogs LogGroup should specify RetentionInDays to expire the log data'
10
+ end
11
+
12
+ def rule_type
13
+ Violation::WARNING
14
+ end
15
+
16
+ def rule_id
17
+ 'W86'
18
+ end
19
+
20
+ def audit_impl(cfn_model)
21
+ violating_groups = cfn_model.resources_by_type('AWS::Logs::LogGroup').select do |group|
22
+ group.retentionInDays.nil?
23
+ end
24
+
25
+ violating_groups.map(&:logical_resource_id)
26
+ end
27
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'base'
4
- require 'cfn-nag/util/truthy.rb'
4
+ require 'cfn-nag/util/truthy'
5
5
  require 'cfn-nag/violation'
6
6
 
7
7
  class RDSInstanceDeletionProtectionRule < BaseRule
@@ -6,6 +6,7 @@ require_relative 'base'
6
6
 
7
7
  class SPCMRule < BaseRule
8
8
  attr_accessor :spcm_threshold
9
+
9
10
  DEFAULT_THRESHOLD = 25
10
11
 
11
12
  def rule_text
@@ -25,16 +25,22 @@ class SecurityGroupEgressOpenToWorldRule < BaseRule
25
25
  def audit_impl(cfn_model)
26
26
  violating_security_groups = cfn_model.security_groups.select do |security_group|
27
27
  violating_egresses = security_group.egresses.select do |egress|
28
- ip4_open?(egress) || ip6_open?(egress)
28
+ violating_egress(egress)
29
29
  end
30
30
 
31
31
  !violating_egresses.empty?
32
32
  end
33
33
 
34
34
  violating_egresses = cfn_model.standalone_egress.select do |standalone_egress|
35
- ip4_open?(standalone_egress) || ip6_open?(standalone_egress)
35
+ violating_egress(standalone_egress)
36
36
  end
37
37
 
38
38
  violating_security_groups.map(&:logical_resource_id) + violating_egresses.map(&:logical_resource_id)
39
39
  end
40
+
41
+ private
42
+
43
+ def violating_egress(egress)
44
+ ip4_open?(egress) || ip6_open?(egress)
45
+ end
40
46
  end
@@ -25,16 +25,22 @@ class SecurityGroupIngressCidrNon32Rule < BaseRule
25
25
  def audit_impl(cfn_model)
26
26
  violating_security_groups = cfn_model.security_groups.select do |security_group|
27
27
  violating_ingresses = security_group.ingresses.select do |ingress|
28
- ip4_cidr_range?(ingress) || ip6_cidr_range?(ingress)
28
+ violating_ingress(ingress)
29
29
  end
30
30
 
31
31
  !violating_ingresses.empty?
32
32
  end
33
33
 
34
34
  violating_ingresses = cfn_model.standalone_ingress.select do |standalone_ingress|
35
- ip4_cidr_range?(standalone_ingress) || ip6_cidr_range?(standalone_ingress)
35
+ violating_ingress(standalone_ingress)
36
36
  end
37
37
 
38
38
  violating_security_groups.map(&:logical_resource_id) + violating_ingresses.map(&:logical_resource_id)
39
39
  end
40
+
41
+ private
42
+
43
+ def violating_ingress(ingress)
44
+ ip4_cidr_range?(ingress) || ip6_cidr_range?(ingress)
45
+ end
40
46
  end
@@ -26,16 +26,22 @@ class SecurityGroupIngressOpenToWorldRule < BaseRule
26
26
  def audit_impl(cfn_model)
27
27
  violating_security_groups = cfn_model.security_groups.select do |security_group|
28
28
  violating_ingresses = security_group.ingresses.select do |ingress|
29
- ip4_open?(ingress) || ip6_open?(ingress)
29
+ violating_ingress(ingress)
30
30
  end
31
31
 
32
32
  !violating_ingresses.empty?
33
33
  end
34
34
 
35
35
  violating_ingresses = cfn_model.standalone_ingress.select do |standalone_ingress|
36
- ip4_open?(standalone_ingress) || ip6_open?(standalone_ingress)
36
+ violating_ingress(standalone_ingress)
37
37
  end
38
38
 
39
39
  violating_security_groups.map(&:logical_resource_id) + violating_ingresses.map(&:logical_resource_id)
40
40
  end
41
+
42
+ private
43
+
44
+ def violating_ingress(ingress)
45
+ ip4_open?(ingress) || ip6_open?(ingress)
46
+ end
41
47
  end
@@ -3,7 +3,7 @@
3
3
  require 'cfn-nag/violation'
4
4
  require_relative 'base'
5
5
  require 'cfn-nag/ip_addr'
6
- require 'cfn-nag/util/blank.rb'
6
+ require 'cfn-nag/util/blank'
7
7
 
8
8
  class SecurityGroupRuleDescriptionRule < BaseRule
9
9
  def rule_text
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'cfn-nag/violation'
4
4
  require_relative 'base'
5
- require 'cfn-nag/util/truthy.rb'
5
+ require 'cfn-nag/util/truthy'
6
6
 
7
7
  ##
8
8
  # Derive from this rule to ensure that a resource
@@ -5,7 +5,7 @@ require_relative 'base'
5
5
  require 'cfn-nag/util/wildcard_patterns'
6
6
 
7
7
  class PassRoleBaseRule < BaseRule
8
- IAM_ACTION_PATTERNS = wildcard_patterns('PassRole').map { |pattern| 'iam:' + pattern } + ['*']
8
+ IAM_ACTION_PATTERNS = wildcard_patterns('PassRole').map { |pattern| "iam:#{pattern}" } + ['*']
9
9
 
10
10
  def policy_type
11
11
  raise 'must implement in subclass'
@@ -41,9 +41,10 @@ class ConditionMetric
41
41
  result = []
42
42
  conditions.each do |_, expression|
43
43
  expression.each do |_, value|
44
- if value.is_a? String
44
+ case value
45
+ when String
45
46
  result << value
46
- elsif value.is_a? Array
47
+ when Array
47
48
  result += value
48
49
  end
49
50
  end
@@ -47,9 +47,10 @@ module IpAddr
47
47
  # anything with it
48
48
  #
49
49
  def normalize_cidr_ip6(ingress)
50
- if ingress.cidrIpv6.is_a?(Symbol)
50
+ case ingress.cidrIpv6
51
+ when Symbol
51
52
  ":#{ingress.cidrIpv6}"
52
- elsif ingress.cidrIpv6.is_a?(String)
53
+ when String
53
54
  ingress.cidrIpv6
54
55
  end
55
56
  end
@@ -13,7 +13,7 @@ module Metadata
13
13
  logical_resource_id = mangled_metadata.first
14
14
  mangled_rules = mangled_metadata[1]
15
15
 
16
- STDERR.puts "#{logical_resource_id} has missing cfn_nag suppression rule id: #{mangled_rules}"
16
+ $stderr.puts "#{logical_resource_id} has missing cfn_nag suppression rule id: #{mangled_rules}"
17
17
  end
18
18
  end
19
19
 
@@ -46,7 +46,7 @@ module Metadata
46
46
  end
47
47
  if found_suppression_rule && print_suppression
48
48
  message = "Suppressing #{rule_id} on #{logical_resource_id} for reason: #{found_suppression_rule['reason']}"
49
- STDERR.puts message
49
+ $stderr.puts message
50
50
  end
51
51
  !found_suppression_rule.nil?
52
52
  end
@@ -27,7 +27,7 @@ class StdoutResults
27
27
  def render(results)
28
28
  results.each do |result|
29
29
  60.times { print '-' }
30
- puts "\n" + result[:filename]
30
+ puts "\n#{result[:filename]}"
31
31
  60.times { print '-' }
32
32
 
33
33
  violations = result[:file_results][:violations]
@@ -45,6 +45,6 @@ class StdoutResults
45
45
  end
46
46
 
47
47
  def indent_multiline_string_with_prefix(prefix, multiline_string)
48
- prefix + ' ' + multiline_string.gsub(/\n/, "\n#{prefix} ")
48
+ "#{prefix} #{multiline_string.gsub(/\n/, "\n#{prefix} ")}"
49
49
  end
50
50
  end
@@ -53,7 +53,7 @@ class GemBasedRuleRepo
53
53
  require rule_gem_name
54
54
  true
55
55
  rescue LoadError
56
- STDERR.puts "Could not require #{rule_gem_name} - does the rule gem have a top level entry point?"
56
+ $stderr.puts "Could not require #{rule_gem_name} - does the rule gem have a top level entry point?"
57
57
  false
58
58
  end
59
59
 
@@ -33,7 +33,7 @@ class RuleRepositoryLoader
33
33
  end
34
34
 
35
35
  repo_class = class_from_name(rule_repository_definition['repo_class_name'])
36
- if rule_repository_definition['repo_arguments']&.is_a?(Hash)
36
+ if rule_repository_definition['repo_arguments'].is_a?(Hash)
37
37
  repo_class.new(**to_sym_keys(rule_repository_definition['repo_arguments']))
38
38
  else
39
39
  repo_class.new
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'cfn-nag/util/truthy.rb'
3
+ require 'cfn-nag/util/truthy'
4
4
 
5
5
  # Returns false if the provided key_to_check is a no-echo parameter without a
6
6
  # default value, or pseudo parameter reference to 'AWS::NoValue'; true otherwise.
@@ -9,17 +9,16 @@ def insecure_string_or_dynamic_reference?(_cfn_model, key_to_check)
9
9
 
10
10
  # Check if string starts with a Dynamic Reference pointing to SecretsManager
11
11
  # or SSM Secure
12
+ # &&
13
+ # Verify that the secure string ends properly with the double curly braces
12
14
  if key_to_check.start_with?(
13
15
  '{{resolve:secretsmanager:',
14
16
  '{{resolve:ssm-secure:'
15
- )
16
- # Verify that the secure string ends properly with the double curly braces
17
- if key_to_check.end_with? '}}'
18
- return false
19
- end
17
+ ) && key_to_check.end_with?('}}')
18
+ return false
20
19
  end
21
20
 
22
- # Retrun true if key_to_check is a string and is not calling a secured
21
+ # Return true if key_to_check is a string and is not calling a secured
23
22
  # dynamic reference pattern (Secrets Manager or SSM-Secure)
24
23
  true
25
24
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cfn-nag
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.10
4
+ version: 0.6.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Kascic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-12 00:00:00.000000000 Z
11
+ date: 2021-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: 0.5.2
75
+ version: 0.5.4
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: 0.5.2
82
+ version: 0.5.4
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: logging
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -203,6 +203,7 @@ files:
203
203
  - lib/cfn-nag/custom_rules/DirectoryServiceMicrosoftADPasswordRule.rb
204
204
  - lib/cfn-nag/custom_rules/DirectoryServiceSimpleADPasswordRule.rb
205
205
  - lib/cfn-nag/custom_rules/DocDBDBClusterMasterUserPasswordRule.rb
206
+ - lib/cfn-nag/custom_rules/DynamoDBBackupRule.rb
206
207
  - lib/cfn-nag/custom_rules/DynamoDBBillingModeRule.rb
207
208
  - lib/cfn-nag/custom_rules/DynamoDBEncryptionRule.rb
208
209
  - lib/cfn-nag/custom_rules/EC2NetworkAclEntryDuplicateRule.rb
@@ -211,6 +212,7 @@ files:
211
212
  - lib/cfn-nag/custom_rules/EC2NetworkAclEntryPortRangeRule.rb
212
213
  - lib/cfn-nag/custom_rules/EC2NetworkAclEntryProtocolRule.rb
213
214
  - lib/cfn-nag/custom_rules/EC2SubnetMapPublicIpOnLaunchRule.rb
215
+ - lib/cfn-nag/custom_rules/ECRRepositoryScanOnPushRule.rb
214
216
  - lib/cfn-nag/custom_rules/EFSFileSystemEncryptedRule.rb
215
217
  - lib/cfn-nag/custom_rules/EMRClusterKerberosAttributesADDomainJoinPasswordRule.rb
216
218
  - lib/cfn-nag/custom_rules/EMRClusterKerberosAttributesCrossRealmTrustPrincipalPasswordRule.rb
@@ -261,6 +263,7 @@ files:
261
263
  - lib/cfn-nag/custom_rules/LambdaPermissionEventSourceTokenRule.rb
262
264
  - lib/cfn-nag/custom_rules/LambdaPermissionInvokeFunctionActionRule.rb
263
265
  - lib/cfn-nag/custom_rules/LambdaPermissionWildcardPrincipalRule.rb
266
+ - lib/cfn-nag/custom_rules/LogsLogGroupRetentionRule.rb
264
267
  - lib/cfn-nag/custom_rules/ManagedBlockchainMemberMemberFabricConfigurationAdminPasswordRule.rb
265
268
  - lib/cfn-nag/custom_rules/ManagedPolicyOnUserRule.rb
266
269
  - lib/cfn-nag/custom_rules/MissingBucketPolicyRule.rb
@@ -381,7 +384,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
381
384
  - !ruby/object:Gem::Version
382
385
  version: '0'
383
386
  requirements: []
384
- rubygems_version: 3.1.4
387
+ rubyforge_project:
388
+ rubygems_version: 2.7.6
385
389
  signing_key:
386
390
  specification_version: 4
387
391
  summary: cfn-nag