cfn-nag 0.3.73 → 0.3.74
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 +4 -4
- data/bin/cfn_nag +12 -1
- data/bin/cfn_nag_scan +12 -1
- data/lib/cfn-nag.rb +1 -0
- data/lib/cfn-nag/blacklist_loader.rb +43 -0
- data/lib/cfn-nag/cfn_nag.rb +29 -26
- data/lib/cfn-nag/cfn_nag_logging.rb +11 -0
- data/lib/cfn-nag/profile_loader.rb +2 -3
- data/lib/cfn-nag/result_view/rules_view.rb +2 -2
- data/lib/cfn-nag/{profile.rb → rule_id_set.rb} +2 -2
- data/lib/cfn-nag/violation_filtering.rb +38 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df7c2cd400873808f2c86c468bf2b8fe254b4f818629ca85cae8d4249e61e91b
|
4
|
+
data.tar.gz: b07f2ab8db5b52656283fb72ed7660abb8d9461323230fca262434e0d9e1f8b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
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
@@ -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
|
data/lib/cfn-nag/cfn_nag.rb
CHANGED
@@ -2,28 +2,34 @@
|
|
2
2
|
|
3
3
|
require_relative 'custom_rule_loader'
|
4
4
|
require_relative 'rule_registry'
|
5
|
-
require_relative '
|
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,
|
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
|
-
|
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
|
-
|
96
|
-
logger = Logging.logger['log']
|
97
|
-
logger.level = if opts[:debug]
|
98
|
-
:debug
|
99
|
-
else
|
100
|
-
:info
|
101
|
-
end
|
102
|
+
private
|
102
103
|
|
103
|
-
|
104
|
-
|
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
|
-
|
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)
|
@@ -1,8 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
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 =
|
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.
|
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.
|
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
|
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
|
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.
|
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-
|
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
|