cfn-nag 0.4.7 → 0.4.8

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: dde33b49425ca0e1a6934b7e12dc42f0c5cd1e31eb3acd68d68855bf9b14eb1b
4
- data.tar.gz: 32aada5f010677e26eb6f9eb78d248bd6c775e3507a1026cc088ec934042dc2f
3
+ metadata.gz: 6d85a44eca7647f151c4cdc8824e7ce8664eeafda1739cbdabeae094ba1a0831
4
+ data.tar.gz: 92375694b6b968bdc588229e7c4d50ae6feba4aeb05b4e7d450d1060444aa938
5
5
  SHA512:
6
- metadata.gz: 0b92f6565787554d80446906103ede76aaa37bc3bdf89b612d6be2c3fa80304b618b7eef8b49f22da7f95648321103b27ce1622b031c3101ce086859d92aa851
7
- data.tar.gz: aaecb9016668eb6193e7bab33df27be0285d35b02b641e54a364d252e9d10aba7fd02ff59df86c8cc31201f2483e296d7ecea64f35be910a36314030c66531c5
6
+ metadata.gz: a95e5fb81745dc369c348acbc0cf2a605e9638bf74a8586c20da8fbc0a1ad24a8d9734226f5cbc805a02edb2bf2b701453649cadad267047ada5ba935407eec4
7
+ data.tar.gz: 121fc4bdc07e51b00cf8fb7b33598a47af5b58b14f5f0f7056b122005b4ebd851feb5831750de0f29ac01187239e395d6cdf0d4460bd7fc7f636bedc351b96f1
@@ -1,110 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'trollop'
5
4
  require 'cfn-nag'
6
5
  require 'logging'
7
6
  require 'json'
8
7
  require 'rubygems/specification'
9
8
 
10
- # rubocop:disable Metrics/BlockLength
11
- opts = Trollop.options do
12
- options_message = '[options] <cloudformation template path ...>|' \
13
- '<cloudformation template in STDIN>'
14
- custom_rule_exceptions_message = 'Isolate custom rule exceptions - ' \
15
- 'just emit the exception without stack ' \
16
- ' trace and keep chugging'
17
- usage options_message
18
- version Gem::Specification.find_by_name('cfn-nag').version
9
+ exec = CfnNagExecutor.new
19
10
 
20
- opt :debug,
21
- 'Enable debug output',
22
- type: :boolean,
23
- required: false,
24
- default: false
25
- opt :allow_suppression,
26
- 'Allow using Metadata to suppress violations',
27
- type: :boolean,
28
- required: false,
29
- default: true
30
- opt :print_suppression,
31
- 'Emit suppressions to stderr',
32
- type: :boolean,
33
- required: false,
34
- default: false
35
- opt :rule_directory,
36
- 'Extra rule directory',
37
- type: :io,
38
- required: false,
39
- default: nil
40
- opt :profile_path,
41
- 'Path to a profile file',
42
- type: :io,
43
- required: false,
44
- default: nil
45
- opt :blacklist_path,
46
- 'Path to a blacklist file',
47
- type: :io,
48
- required: false,
49
- default: nil
50
- opt :parameter_values_path,
51
- 'Path to a JSON file to pull Parameter values from',
52
- type: :io,
53
- required: false,
54
- default: nil
55
- opt :isolate_custom_rule_exceptions,
56
- custom_rule_exceptions_message,
57
- type: :boolean,
58
- required: false,
59
- default: false
60
- opt :fail_on_warnings,
61
- 'Treat warnings as failing violations',
62
- type: :boolean,
63
- required: false,
64
- default: false
65
- end
66
- # rubocop:enable Metrics/BlockLength
67
-
68
- CfnNagLogging.configure_logging(opts)
69
-
70
- profile_definition = nil
71
- unless opts[:profile_path].nil?
72
- profile_definition = IO.read(opts[:profile_path])
73
- end
74
-
75
- blacklist_definition = nil
76
- unless opts[:blacklist_path].nil?
77
- blacklist_definition = IO.read(opts[:blacklist_path])
78
- end
79
-
80
- parameter_values_string = nil
81
- unless opts[:parameter_values_path].nil?
82
- parameter_values_string = IO.read(opts[:parameter_values_path])
83
- end
84
-
85
- cfn_nag = CfnNag.new(
86
- profile_definition: profile_definition,
87
- blacklist_definition: blacklist_definition,
88
- rule_directory: opts[:rule_directory],
89
- allow_suppression: opts[:allow_suppression],
90
- print_suppression: opts[:print_suppression],
91
- isolate_custom_rule_exceptions: opts[:isolate_custom_rule_exceptions]
92
- )
93
-
94
- total_failure_count = 0
95
- until ARGF.closed? || ARGF.eof?
96
- results = cfn_nag.audit(cloudformation_string: ARGF.file.read,
97
- parameter_values_string: parameter_values_string)
98
- ARGF.close
99
-
100
- total_failure_count += if opts[:fail_on_warnings]
101
- results[:violations].length
102
- else
103
- results[:failure_count]
104
- end
105
-
106
- results[:violations] = results[:violations].map(&:to_h)
107
- puts JSON.pretty_generate(results)
108
- end
109
-
110
- exit total_failure_count
11
+ exit exec.scan(options_type: 'file')
@@ -1,113 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'trollop'
5
4
  require 'cfn-nag'
6
5
  require 'logging'
7
6
  require 'json'
8
7
  require 'rubygems/specification'
9
8
 
10
- # rubocop:disable Metrics/BlockLength
11
- opts = Trollop.options do
12
- version Gem::Specification.find_by_name('cfn-nag').version
9
+ exec = CfnNagExecutor.new
13
10
 
14
- input_path_message = 'CloudFormation template to nag on or directory of ' \
15
- 'templates. Default is all *.json, *.yaml, *.yml ' \
16
- 'and *.template recursively, but can be constrained ' \
17
- 'by --template-pattern'
18
-
19
- custom_rule_exceptions_message = 'Isolate custom rule exceptions - just ' \
20
- 'emit the exception without stack trace ' \
21
- 'and keep chugging'
22
-
23
- template_pattern_message = 'Within the --input-path, match files to scan ' \
24
- 'against this regular expression'
25
-
26
- opt :input_path,
27
- input_path_message,
28
- type: :io,
29
- required: true
30
- opt :output_format,
31
- 'Format of results: [txt, json]',
32
- type: :string,
33
- default: 'txt'
34
- opt :debug,
35
- 'Enable debug output',
36
- type: :boolean,
37
- required: false,
38
- default: false
39
- opt :rule_directory,
40
- 'Extra rule directory',
41
- type: :io,
42
- required: false,
43
- default: nil
44
- opt :profile_path,
45
- 'Path to a profile file',
46
- type: :io,
47
- required: false,
48
- default: nil
49
- opt :blacklist_path,
50
- 'Path to a blacklist file',
51
- type: :io,
52
- required: false,
53
- default: nil
54
- opt :parameter_values_path,
55
- 'Path to a JSON file to pull Parameter values from',
56
- type: :io,
57
- required: false,
58
- default: nil
59
- opt :allow_suppression,
60
- 'Allow using Metadata to suppress violations',
61
- type: :boolean,
62
- required: false,
63
- default: true
64
- opt :print_suppression,
65
- 'Emit suppressions to stderr',
66
- type: :boolean,
67
- required: false,
68
- default: false
69
- opt :isolate_custom_rule_exceptions,
70
- custom_rule_exceptions_message,
71
- type: :boolean,
72
- required: false,
73
- default: false
74
- opt :template_pattern,
75
- template_pattern_message,
76
- type: :string,
77
- required: false,
78
- default: '..*\.json|..*\.yaml|..*\.yml|..*\.template'
79
- end
80
- # rubocop:enable Metrics/BlockLength
81
-
82
- unless %w[txt json].include?(opts[:output_format])
83
- Trollop.die(:output_format,
84
- 'Must be txt or json')
85
- end
86
-
87
- CfnNagLogging.configure_logging(opts)
88
-
89
- profile_definition = nil
90
- unless opts[:profile_path].nil?
91
- profile_definition = IO.read(opts[:profile_path])
92
- end
93
-
94
- blacklist_definition = nil
95
- unless opts[:blacklist_path].nil?
96
- blacklist_definition = IO.read(opts[:blacklist_path])
97
- end
98
-
99
- cfn_nag = CfnNag.new(
100
- profile_definition: profile_definition,
101
- blacklist_definition: blacklist_definition,
102
- rule_directory: opts[:rule_directory],
103
- allow_suppression: opts[:allow_suppression],
104
- print_suppression: opts[:print_suppression],
105
- isolate_custom_rule_exceptions: opts[:isolate_custom_rule_exceptions]
106
- )
107
-
108
- exit cfn_nag.audit_aggregate_across_files_and_render_results(
109
- input_path: opts[:input_path],
110
- output_format: opts[:output_format],
111
- parameter_values_path: opts[:parameter_values_path],
112
- template_pattern: opts[:template_pattern]
11
+ exit exec.scan(
12
+ options_type: 'scan'
113
13
  )
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'cfn-nag/cfn_nag'
4
+ require 'cfn-nag/cfn_nag_executor'
4
5
  require 'cfn-nag/cfn_nag_logging'
5
6
  require 'cfn-nag/violation'
6
7
  require 'cfn-nag/rule_dumper'
@@ -12,24 +12,9 @@ require 'cfn-model'
12
12
  class CfnNag
13
13
  include ViolationFiltering
14
14
 
15
- # rubocop:disable Metrics/ParameterLists
16
- def initialize(profile_definition: nil,
17
- blacklist_definition: nil,
18
- rule_directory: nil,
19
- allow_suppression: true,
20
- print_suppression: false,
21
- isolate_custom_rule_exceptions: false)
22
- @rule_directory = rule_directory
23
- @custom_rule_loader = CustomRuleLoader.new(
24
- rule_directory: rule_directory,
25
- allow_suppression: allow_suppression,
26
- print_suppression: print_suppression,
27
- isolate_custom_rule_exceptions: isolate_custom_rule_exceptions
28
- )
29
- @profile_definition = profile_definition
30
- @blacklist_definition = blacklist_definition
15
+ def initialize(config:)
16
+ @config = config
31
17
  end
32
- # rubocop:enable Metrics/ParameterLists
33
18
 
34
19
  ##
35
20
  # Given a file or directory path, emit aggregate results to stdout
@@ -48,7 +33,11 @@ class CfnNag
48
33
  output_format: output_format)
49
34
 
50
35
  aggregate_results.inject(0) do |total_failure_count, results|
51
- total_failure_count + results[:file_results][:failure_count]
36
+ if @config.fail_on_warnings
37
+ total_failure_count + results[:file_results][:violations].length
38
+ else
39
+ total_failure_count + results[:file_results][:failure_count]
40
+ end
52
41
  end
53
42
  end
54
43
 
@@ -87,7 +76,7 @@ class CfnNag
87
76
  cfn_model = CfnParser.new.parse cloudformation_string,
88
77
  parameter_values_string,
89
78
  true
90
- violations += @custom_rule_loader.execute_custom_rules(cfn_model)
79
+ violations += @config.custom_rule_loader.execute_custom_rules(cfn_model)
91
80
 
92
81
  violations = filter_violations_by_blacklist_and_profile(violations)
93
82
  violations = mark_line_numbers(violations, cfn_model)
@@ -115,15 +104,15 @@ class CfnNag
115
104
 
116
105
  def filter_violations_by_blacklist_and_profile(violations)
117
106
  violations = filter_violations_by_profile(
118
- profile_definition: @profile_definition,
119
- rule_definitions: @custom_rule_loader.rule_definitions,
107
+ profile_definition: @config.profile_definition,
108
+ rule_definitions: @config.custom_rule_loader.rule_definitions,
120
109
  violations: violations
121
110
  )
122
111
 
123
112
  # this must come after - blacklist should always win
124
113
  violations = filter_violations_by_blacklist(
125
- blacklist_definition: @blacklist_definition,
126
- rule_definitions: @custom_rule_loader.rule_definitions,
114
+ blacklist_definition: @config.blacklist_definition,
115
+ rule_definitions: @config.custom_rule_loader.rule_definitions,
127
116
  violations: violations
128
117
  )
129
118
  violations
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CfnNagConfig
4
+ # rubocop:disable Metrics/ParameterLists
5
+ def initialize(profile_definition: nil,
6
+ blacklist_definition: nil,
7
+ rule_directory: nil,
8
+ allow_suppression: true,
9
+ print_suppression: false,
10
+ isolate_custom_rule_exceptions: false,
11
+ fail_on_warnings: false)
12
+ @rule_directory = rule_directory
13
+ @custom_rule_loader = CustomRuleLoader.new(
14
+ rule_directory: rule_directory,
15
+ allow_suppression: allow_suppression,
16
+ print_suppression: print_suppression,
17
+ isolate_custom_rule_exceptions: isolate_custom_rule_exceptions
18
+ )
19
+ @profile_definition = profile_definition
20
+ @blacklist_definition = blacklist_definition
21
+ @fail_on_warnings = fail_on_warnings
22
+ end
23
+ # rubocop:enable Metrics/ParameterLists
24
+
25
+ attr_reader :rule_directory
26
+ attr_reader :custom_rule_loader
27
+ attr_reader :profile_definition
28
+ attr_reader :blacklist_definition
29
+ attr_reader :fail_on_warnings
30
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'trollop'
4
+ require 'cfn-nag/cli_options'
5
+ require 'cfn-nag/cfn_nag_config'
6
+
7
+ class CfnNagExecutor
8
+ def initialize
9
+ @profile_definition = nil
10
+ @blacklist_definition = nil
11
+ @parameter_values_string = nil
12
+ end
13
+
14
+ def scan(options_type:)
15
+ options = Options.for(options_type)
16
+ validate_options(options)
17
+ execute_io_options(options)
18
+
19
+ CfnNagLogging.configure_logging(options)
20
+
21
+ cfn_nag = CfnNag.new(
22
+ config: cfn_nag_config(options)
23
+ )
24
+
25
+ options_type == 'scan' ? execute_aggregate_scan(cfn_nag, options) : execute_file_or_piped_scan(cfn_nag, options)
26
+ end
27
+
28
+ private
29
+
30
+ def execute_file_or_piped_scan(cfn_nag, opts)
31
+ total_failure_count = 0
32
+ until argf_finished?
33
+ results = cfn_nag.audit(cloudformation_string: argf_read,
34
+ parameter_values_string: @parameter_values_string)
35
+ argf_close
36
+
37
+ total_failure_count += if opts[:fail_on_warnings]
38
+ results[:violations].length
39
+ else
40
+ results[:failure_count]
41
+ end
42
+
43
+ results[:violations] = results[:violations].map(&:to_h)
44
+ puts JSON.pretty_generate(results)
45
+ end
46
+ total_failure_count
47
+ end
48
+
49
+ def execute_aggregate_scan(cfn_nag, opts)
50
+ cfn_nag.audit_aggregate_across_files_and_render_results(
51
+ input_path: opts[:input_path],
52
+ output_format: opts[:output_format],
53
+ parameter_values_path: opts[:parameter_values_path],
54
+ template_pattern: opts[:template_pattern]
55
+ )
56
+ end
57
+
58
+ def validate_options(opts)
59
+ unless opts[:output_format].nil? || %w[txt json].include?(opts[:output_format])
60
+ Trollop.die(:output_format,
61
+ 'Must be txt or json')
62
+ end
63
+ end
64
+
65
+ def execute_io_options(opts)
66
+ unless opts[:profile_path].nil?
67
+ @profile_definition = IO.read(opts[:profile_path])
68
+ end
69
+
70
+ unless opts[:blacklist_path].nil?
71
+ @blacklist_definition = IO.read(opts[:blacklist_path])
72
+ end
73
+
74
+ unless opts[:parameter_values_path].nil?
75
+ @parameter_values_string = IO.read(opts[:parameter_values_path])
76
+ end
77
+ end
78
+
79
+ def cfn_nag_config(opts)
80
+ CfnNagConfig.new(
81
+ profile_definition: @profile_definition,
82
+ blacklist_definition: @blacklist_definition,
83
+ rule_directory: opts[:rule_directory],
84
+ allow_suppression: opts[:allow_suppression],
85
+ print_suppression: opts[:print_suppression],
86
+ isolate_custom_rule_exceptions: opts[:isolate_custom_rule_exceptions],
87
+ fail_on_warnings: opts[:fail_on_warnings]
88
+ )
89
+ end
90
+
91
+ def argf_finished?
92
+ ARGF.closed? || ARGF.eof?
93
+ end
94
+
95
+ def argf_close
96
+ ARGF.close
97
+ end
98
+
99
+ def argf_read
100
+ ARGF.file.read
101
+ end
102
+ end
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'trollop'
4
+
5
+ # rubocop:disable Metrics/ClassLength
6
+ class Options
7
+ @custom_rule_exceptions_message = 'Isolate custom rule exceptions - just ' \
8
+ 'emit the exception without stack trace ' \
9
+ 'and keep chugging'
10
+
11
+ @version = Gem::Specification.find_by_name('cfn-nag').version
12
+
13
+ def self.for(type)
14
+ case type
15
+ when 'file'
16
+ file_options
17
+ when 'scan'
18
+ scan_options
19
+ else
20
+ raise "Unsupported Options type #{type}; use 'file' or 'scan'"
21
+ end
22
+ end
23
+
24
+ # rubocop:disable Metrics/BlockLength
25
+ # rubocop:disable Metrics/MethodLength
26
+ def self.file_options
27
+ options_message = '[options] <cloudformation template path ...>|' \
28
+ '<cloudformation template in STDIN>'
29
+ custom_rule_exceptions_message = @custom_rule_exceptions_message
30
+ version = @version
31
+
32
+ Trollop.options do
33
+ usage options_message
34
+ version version
35
+
36
+ opt :debug,
37
+ 'Enable debug output',
38
+ type: :boolean,
39
+ required: false,
40
+ default: false
41
+ opt :allow_suppression,
42
+ 'Allow using Metadata to suppress violations',
43
+ type: :boolean,
44
+ required: false,
45
+ default: true
46
+ opt :print_suppression,
47
+ 'Emit suppressions to stderr',
48
+ type: :boolean,
49
+ required: false,
50
+ default: false
51
+ opt :rule_directory,
52
+ 'Extra rule directory',
53
+ type: :io,
54
+ required: false,
55
+ default: nil
56
+ opt :profile_path,
57
+ 'Path to a profile file',
58
+ type: :io,
59
+ required: false,
60
+ default: nil
61
+ opt :blacklist_path,
62
+ 'Path to a blacklist file',
63
+ type: :io,
64
+ required: false,
65
+ default: nil
66
+ opt :parameter_values_path,
67
+ 'Path to a JSON file to pull Parameter values from',
68
+ type: :io,
69
+ required: false,
70
+ default: nil
71
+ opt :isolate_custom_rule_exceptions,
72
+ custom_rule_exceptions_message,
73
+ type: :boolean,
74
+ required: false,
75
+ default: false
76
+ opt :fail_on_warnings,
77
+ 'Treat warnings as failing violations',
78
+ type: :boolean,
79
+ required: false,
80
+ default: false
81
+ opt :output_format,
82
+ 'Format of results: [txt, json]',
83
+ type: :string,
84
+ default: 'txt'
85
+ end
86
+ end
87
+
88
+ def self.scan_options
89
+ input_path_message = 'CloudFormation template to nag on or directory of ' \
90
+ 'templates. Default is all *.json, *.yaml, *.yml ' \
91
+ 'and *.template recursively, but can be constrained ' \
92
+ 'by --template-pattern'
93
+
94
+ template_pattern_message = 'Within the --input-path, match files to scan ' \
95
+ 'against this regular expression'
96
+
97
+ custom_rule_exceptions_message = @custom_rule_exceptions_message
98
+ version = @version
99
+
100
+ Trollop.options do
101
+ version version
102
+ opt :input_path,
103
+ input_path_message,
104
+ type: :io,
105
+ required: true
106
+ opt :output_format,
107
+ 'Format of results: [txt, json]',
108
+ type: :string,
109
+ default: 'txt'
110
+ opt :debug,
111
+ 'Enable debug output',
112
+ type: :boolean,
113
+ required: false,
114
+ default: false
115
+ opt :rule_directory,
116
+ 'Extra rule directory',
117
+ type: :io,
118
+ required: false,
119
+ default: nil
120
+ opt :profile_path,
121
+ 'Path to a profile file',
122
+ type: :io,
123
+ required: false,
124
+ default: nil
125
+ opt :blacklist_path,
126
+ 'Path to a blacklist file',
127
+ type: :io,
128
+ required: false,
129
+ default: nil
130
+ opt :parameter_values_path,
131
+ 'Path to a JSON file to pull Parameter values from',
132
+ type: :io,
133
+ required: false,
134
+ default: nil
135
+ opt :allow_suppression,
136
+ 'Allow using Metadata to suppress violations',
137
+ type: :boolean,
138
+ required: false,
139
+ default: true
140
+ opt :print_suppression,
141
+ 'Emit suppressions to stderr',
142
+ type: :boolean,
143
+ required: false,
144
+ default: false
145
+ opt :isolate_custom_rule_exceptions,
146
+ custom_rule_exceptions_message,
147
+ type: :boolean,
148
+ required: false,
149
+ default: false
150
+ opt :template_pattern,
151
+ template_pattern_message,
152
+ type: :string,
153
+ required: false,
154
+ default: '..*\.json|..*\.yaml|..*\.yml|..*\.template'
155
+ opt :fail_on_warnings,
156
+ 'Treat warnings as failing violations',
157
+ type: :boolean,
158
+ required: false,
159
+ default: false
160
+ end
161
+ end
162
+ # rubocop:enable Metrics/BlockLength
163
+ # rubocop:enable Metrics/MethodLength
164
+ end
165
+ # rubocop:enable Metrics/ClassLength
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cfn-nag
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.7
4
+ version: 0.4.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Kascic
@@ -151,7 +151,10 @@ files:
151
151
  - lib/cfn-nag.rb
152
152
  - lib/cfn-nag/blacklist_loader.rb
153
153
  - lib/cfn-nag/cfn_nag.rb
154
+ - lib/cfn-nag/cfn_nag_config.rb
155
+ - lib/cfn-nag/cfn_nag_executor.rb
154
156
  - lib/cfn-nag/cfn_nag_logging.rb
157
+ - lib/cfn-nag/cli_options.rb
155
158
  - lib/cfn-nag/custom_rule_loader.rb
156
159
  - lib/cfn-nag/custom_rules/BatchJobDefinitionContainerPropertiesPrivilegedRule.rb
157
160
  - lib/cfn-nag/custom_rules/CloudFormationAuthenticationRule.rb