cfn-nag 0.3.73 → 0.3.74

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f92b4e5025b097a9c43fb1bedd691f61611e8902109f2e6ac1500819ce7a966
4
- data.tar.gz: 5fc445b20109d8b843a1946adf29941f235fff67bc8bd8a5e3bcbdfc2c158ce5
3
+ metadata.gz: df7c2cd400873808f2c86c468bf2b8fe254b4f818629ca85cae8d4249e61e91b
4
+ data.tar.gz: b07f2ab8db5b52656283fb72ed7660abb8d9461323230fca262434e0d9e1f8b6
5
5
  SHA512:
6
- metadata.gz: e184524a035bf8be537b23e52f8718969aa7342e9834fff65931928d5e8f107b9fc6b42bab97a2c451c0d1f502d4d78b9c830a73543bb3dd58c4d6cc6e99fcd8
7
- data.tar.gz: 8c0729ab854708080bef5a2bcc71292c1a51787cd0856877481f1d929c2efe7d4574875bc077a69c237ab22038e11cf3fdef239c187c9a7fb9c35a95447f33e0
6
+ metadata.gz: ad73aa5062aee010cf3a3ebdee335ec54e7e13f1dd366f003d7c9b613c0c91868f65508c8e6e68d883fa2dba5954c08576c1365840612b99214dda3f81655940
7
+ data.tar.gz: 5c72467fe9904e35a3871186b1217890c8662010795d47d950e2980674ce53e7967f4d94b63b515067df7bba7e3f7b4c7b18f909a8ef9afa6ecc99f94423ddf0
data/bin/cfn_nag CHANGED
@@ -42,6 +42,11 @@ opts = Trollop.options do
42
42
  type: :io,
43
43
  required: false,
44
44
  default: nil
45
+ opt :blacklist_path,
46
+ 'Path to a blacklist file',
47
+ type: :io,
48
+ required: false,
49
+ default: nil
45
50
  opt :parameter_values_path,
46
51
  'Path to a JSON file to pull Parameter values from',
47
52
  type: :io,
@@ -55,13 +60,18 @@ opts = Trollop.options do
55
60
  end
56
61
  # rubocop:enable Metrics/BlockLength
57
62
 
58
- CfnNag.configure_logging(opts)
63
+ CfnNagLogging.configure_logging(opts)
59
64
 
60
65
  profile_definition = nil
61
66
  unless opts[:profile_path].nil?
62
67
  profile_definition = IO.read(opts[:profile_path])
63
68
  end
64
69
 
70
+ blacklist_definition = nil
71
+ unless opts[:blacklist_path].nil?
72
+ blacklist_definition = IO.read(opts[:blacklist_path])
73
+ end
74
+
65
75
  parameter_values_string = nil
66
76
  unless opts[:parameter_values_path].nil?
67
77
  parameter_values_string = IO.read(opts[:parameter_values_path])
@@ -69,6 +79,7 @@ end
69
79
 
70
80
  cfn_nag = CfnNag.new(
71
81
  profile_definition: profile_definition,
82
+ blacklist_definition: blacklist_definition,
72
83
  rule_directory: opts[:rule_directory],
73
84
  allow_suppression: opts[:allow_suppression],
74
85
  print_suppression: opts[:print_suppression],
data/bin/cfn_nag_scan CHANGED
@@ -46,6 +46,11 @@ opts = Trollop.options do
46
46
  type: :io,
47
47
  required: false,
48
48
  default: nil
49
+ opt :blacklist_path,
50
+ 'Path to a blacklist file',
51
+ type: :io,
52
+ required: false,
53
+ default: nil
49
54
  opt :parameter_values_path,
50
55
  'Path to a JSON file to pull Parameter values from',
51
56
  type: :io,
@@ -79,15 +84,21 @@ unless %w[txt json].include?(opts[:output_format])
79
84
  'Must be txt or json')
80
85
  end
81
86
 
82
- CfnNag.configure_logging(opts)
87
+ CfnNagLogging.configure_logging(opts)
83
88
 
84
89
  profile_definition = nil
85
90
  unless opts[:profile_path].nil?
86
91
  profile_definition = IO.read(opts[:profile_path])
87
92
  end
88
93
 
94
+ blacklist_definition = nil
95
+ unless opts[:blacklist_path].nil?
96
+ blacklist_definition = IO.read(opts[:blacklist_path])
97
+ end
98
+
89
99
  cfn_nag = CfnNag.new(
90
100
  profile_definition: profile_definition,
101
+ blacklist_definition: blacklist_definition,
91
102
  rule_directory: opts[:rule_directory],
92
103
  allow_suppression: opts[:allow_suppression],
93
104
  print_suppression: opts[:print_suppression],
data/lib/cfn-nag.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'cfn-nag/cfn_nag'
4
+ require 'cfn-nag/cfn_nag_logging'
4
5
  require 'cfn-nag/violation'
5
6
  require 'cfn-nag/rule_dumper'
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ class BlackListLoader
6
+ def initialize(rules_registry)
7
+ @rules_registry = rules_registry
8
+ end
9
+
10
+ def load(blacklist_definition:)
11
+ raise 'Empty profile' if blacklist_definition.strip == ''
12
+
13
+ blacklist_ruleset = RuleIdSet.new
14
+
15
+ blacklist_hash = load_blacklist_yaml(blacklist_definition)
16
+ raise 'Blacklist is malformed' unless blacklist_hash.is_a? Hash
17
+
18
+ rules_to_suppress = blacklist_hash.fetch('RulesToSuppress', {})
19
+ raise 'Missing RulesToSuppress key in black list' if rules_to_suppress.empty?
20
+
21
+ rule_ids_to_suppress = rules_to_suppress.map { |rule| rule['id'] }
22
+ rule_ids_to_suppress.each do |rule_id|
23
+ check_valid_rule_id rule_id
24
+ blacklist_ruleset.add_rule rule_id
25
+ end
26
+
27
+ blacklist_ruleset
28
+ end
29
+
30
+ private
31
+
32
+ def load_blacklist_yaml(blacklist_definition)
33
+ YAML.safe_load(blacklist_definition)
34
+ rescue StandardError => yaml_parse_error
35
+ raise "YAML parse of blacklist failed: #{yaml_parse_error}"
36
+ end
37
+
38
+ def check_valid_rule_id(rule_id)
39
+ return true unless @rules_registry.by_id(rule_id).nil?
40
+
41
+ raise "#{rule_id} is not a legal rule identifier from: #{rules_ids}"
42
+ end
43
+ end
@@ -2,28 +2,34 @@
2
2
 
3
3
  require_relative 'custom_rule_loader'
4
4
  require_relative 'rule_registry'
5
- require_relative 'profile_loader'
5
+ require_relative 'violation_filtering'
6
6
  require_relative 'template_discovery'
7
7
  require_relative 'result_view/simple_stdout_results'
8
8
  require_relative 'result_view/json_results'
9
9
  require 'cfn-model'
10
- require 'logging'
11
10
 
12
11
  # Top-level CfnNag class for running profiles
13
12
  class CfnNag
13
+ include ViolationFiltering
14
+
15
+ # rubocop:disable Metrics/ParameterLists
14
16
  def initialize(profile_definition: nil,
17
+ blacklist_definition: nil,
15
18
  rule_directory: nil,
16
19
  allow_suppression: true,
17
20
  print_suppression: false,
18
21
  isolate_custom_rule_exceptions: false)
19
22
  @rule_directory = rule_directory
20
23
  @custom_rule_loader = CustomRuleLoader.new(
21
- rule_directory: rule_directory, allow_suppression: allow_suppression,
24
+ rule_directory: rule_directory,
25
+ allow_suppression: allow_suppression,
22
26
  print_suppression: print_suppression,
23
27
  isolate_custom_rule_exceptions: isolate_custom_rule_exceptions
24
28
  )
25
29
  @profile_definition = profile_definition
30
+ @blacklist_definition = blacklist_definition
26
31
  end
32
+ # rubocop:enable Metrics/ParameterLists
27
33
 
28
34
  ##
29
35
  # Given a file or directory path, emit aggregate results to stdout
@@ -81,7 +87,8 @@ class CfnNag
81
87
  cfn_model = CfnParser.new.parse cloudformation_string,
82
88
  parameter_values_string
83
89
  violations += @custom_rule_loader.execute_custom_rules(cfn_model)
84
- violations = filter_violations_by_profile violations
90
+
91
+ violations = filter_violations_by_blacklist_and_profile(violations)
85
92
  rescue Psych::SyntaxError, ParserError => parser_error
86
93
  violations << fatal_violation(parser_error.to_s)
87
94
  rescue JSON::ParserError => json_parameters_error
@@ -92,18 +99,26 @@ class CfnNag
92
99
  audit_result(violations)
93
100
  end
94
101
 
95
- def self.configure_logging(opts)
96
- logger = Logging.logger['log']
97
- logger.level = if opts[:debug]
98
- :debug
99
- else
100
- :info
101
- end
102
+ private
102
103
 
103
- logger.add_appenders Logging.appenders.stdout
104
- end
104
+ def filter_violations_by_blacklist_and_profile(violations)
105
+ violations = filter_violations_by_profile(
106
+ profile_definition: @profile_definition,
107
+ rule_definitions: @custom_rule_loader.rule_definitions,
108
+ violations: violations
109
+ )
105
110
 
106
- private
111
+ # this must come after - blacklist should always win
112
+ violations = filter_violations_by_blacklist(
113
+ blacklist_definition: @blacklist_definition,
114
+ rule_definitions: @custom_rule_loader.rule_definitions,
115
+ violations: violations
116
+ )
117
+ violations
118
+ rescue StandardError => blacklist_or_profile_parse_error
119
+ violations << fatal_violation(blacklist_or_profile_parse_error.to_s)
120
+ violations
121
+ end
107
122
 
108
123
  def audit_result(violations)
109
124
  {
@@ -118,18 +133,6 @@ class CfnNag
118
133
  message: message)
119
134
  end
120
135
 
121
- def filter_violations_by_profile(violations)
122
- profile = nil
123
- unless @profile_definition.nil?
124
- profile = ProfileLoader.new(@custom_rule_loader.rule_definitions)
125
- .load(profile_definition: @profile_definition)
126
- end
127
-
128
- violations.reject do |violation|
129
- !profile.nil? && !profile.execute_rule?(violation.id)
130
- end
131
- end
132
-
133
136
  def render_results(aggregate_results:,
134
137
  output_format:)
135
138
  results_renderer(output_format).new.render(aggregate_results)
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logging'
4
+
5
+ class CfnNagLogging
6
+ def self.configure_logging(opts)
7
+ logger = Logging.logger['log']
8
+ logger.level = opts[:debug] ? :debug : :info
9
+ logger.add_appenders Logging.appenders.stdout
10
+ end
11
+ end
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'profile'
3
+ require_relative 'rule_id_set'
4
4
 
5
- # Load rule profile
6
5
  class ProfileLoader
7
6
  def initialize(rules_registry)
8
7
  @rules_registry = rules_registry
@@ -15,7 +14,7 @@ class ProfileLoader
15
14
  profile_definition ||= ''
16
15
  raise 'Empty profile' if profile_definition.strip == ''
17
16
 
18
- new_profile = Profile.new
17
+ new_profile = RuleIdSet.new
19
18
 
20
19
  profile_definition.each_line do |line|
21
20
  next unless (rule_id = rule_line_match(line))
@@ -16,7 +16,7 @@ class RulesView
16
16
  warnings.sort { |left, right| sort_id(left, right) }.each do |warning|
17
17
  if profile.nil?
18
18
  puts "#{warning.id} #{warning.message}"
19
- elsif profile.execute_rule?(warning.id)
19
+ elsif profile.contains_rule?(warning.id)
20
20
  puts "#{warning.id} #{warning.message}"
21
21
  end
22
22
  end
@@ -26,7 +26,7 @@ class RulesView
26
26
  failings.sort { |left, right| sort_id(left, right) }.each do |failing|
27
27
  if profile.nil?
28
28
  puts "#{failing.id} #{failing.message}"
29
- elsif profile.execute_rule?(failing.id)
29
+ elsif profile.contains_rule?(failing.id)
30
30
  puts "#{failing.id} #{failing.message}"
31
31
  end
32
32
  end
@@ -3,7 +3,7 @@
3
3
  require 'set'
4
4
 
5
5
  # Container class for profiles
6
- class Profile
6
+ class RuleIdSet
7
7
  attr_reader :rule_ids
8
8
 
9
9
  def initialize
@@ -16,7 +16,7 @@ class Profile
16
16
  end
17
17
 
18
18
  # Does the list of rule ids contain rule_id?
19
- def execute_rule?(rule_id)
19
+ def contains_rule?(rule_id)
20
20
  @rule_ids.include? rule_id
21
21
  end
22
22
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cfn-nag/profile_loader'
4
+ require 'cfn-nag/blacklist_loader'
5
+
6
+ module ViolationFiltering
7
+ def filter_violations_by_profile(profile_definition:, rule_definitions:, violations:)
8
+ profile = nil
9
+ unless profile_definition.nil?
10
+ begin
11
+ profile = ProfileLoader.new(rule_definitions)
12
+ .load(profile_definition: profile_definition)
13
+ rescue StandardError => profile_load_error
14
+ raise "Profile loading error: #{profile_load_error}"
15
+ end
16
+ end
17
+
18
+ violations.reject do |violation|
19
+ !profile.nil? && !profile.contains_rule?(violation.id)
20
+ end
21
+ end
22
+
23
+ def filter_violations_by_blacklist(blacklist_definition:, rule_definitions:, violations:)
24
+ blacklist = nil
25
+ unless blacklist_definition.nil?
26
+ begin
27
+ blacklist = BlackListLoader.new(rule_definitions)
28
+ .load(blacklist_definition: blacklist_definition)
29
+ rescue StandardError => blacklist_load_error
30
+ raise "Blacklist loading error: #{blacklist_load_error}"
31
+ end
32
+ end
33
+
34
+ violations.reject do |violation|
35
+ !blacklist.nil? && blacklist.contains_rule?(violation.id)
36
+ end
37
+ end
38
+ 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.3.73
4
+ version: 0.3.74
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Kascic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-18 00:00:00.000000000 Z
11
+ date: 2019-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -135,7 +135,9 @@ files:
135
135
  - bin/cfn_nag_rules
136
136
  - bin/cfn_nag_scan
137
137
  - lib/cfn-nag.rb
138
+ - lib/cfn-nag/blacklist_loader.rb
138
139
  - lib/cfn-nag/cfn_nag.rb
140
+ - lib/cfn-nag/cfn_nag_logging.rb
139
141
  - lib/cfn-nag/custom_rule_loader.rb
140
142
  - lib/cfn-nag/custom_rules/CloudFormationAuthenticationRule.rb
141
143
  - lib/cfn-nag/custom_rules/CloudFrontDistributionAccessLoggingRule.rb
@@ -196,16 +198,17 @@ files:
196
198
  - lib/cfn-nag/ip_addr.rb
197
199
  - lib/cfn-nag/jmes_path_discovery.rb
198
200
  - lib/cfn-nag/jmes_path_evaluator.rb
199
- - lib/cfn-nag/profile.rb
200
201
  - lib/cfn-nag/profile_loader.rb
201
202
  - lib/cfn-nag/result_view/json_results.rb
202
203
  - lib/cfn-nag/result_view/rules_view.rb
203
204
  - lib/cfn-nag/result_view/simple_stdout_results.rb
204
205
  - lib/cfn-nag/rule_definition.rb
205
206
  - lib/cfn-nag/rule_dumper.rb
207
+ - lib/cfn-nag/rule_id_set.rb
206
208
  - lib/cfn-nag/rule_registry.rb
207
209
  - lib/cfn-nag/template_discovery.rb
208
210
  - lib/cfn-nag/violation.rb
211
+ - lib/cfn-nag/violation_filtering.rb
209
212
  homepage: https://github.com/stelligent/cfn_nag
210
213
  licenses:
211
214
  - MIT