cfn-nag 0.6.4 → 0.6.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb0243f0a2f327d0408fe6524596d7bf9a0ce8214fb217e869a785983dc30b88
4
- data.tar.gz: e9bc6213a3beb72d785abb9e58908460771d36b2127d72d0dde421c4c22b5daa
3
+ metadata.gz: 3f9f1d1c26fcff5f16d5a7f08db72e28dc7f0d4494dfdd4290e9c4d2d1c73632
4
+ data.tar.gz: 61b1cd680139fdfcdfcead2f89a4d9df2bb829570f4dadc590930e366b83f0a6
5
5
  SHA512:
6
- metadata.gz: 99a21920685b6a2a6762060c18d7aeef9881a2527e78324f949582a03b4003adba0713c5421a2bd2040e94c78cb969b1230cd6cbf1e624b7e3056050385011c2
7
- data.tar.gz: 3ffb6ec0595927f615efa3e653083fc9efa4bd60db1a20f48591205a06c20ebc07efcf7e6c8330aef0eaee9508cadae34becbbf73c8b3d4ffab25d7491579cba
6
+ metadata.gz: 30581a3a555205ea494ec63dfa059ceb2b04faed4bc20a36465e4c93afaa401c6fc1c5da10b87055df47858b0f43b7982485415ac2da0ceef0942e4a084be60b
7
+ data.tar.gz: 775886736eabe0a51107d69663305ced348a357958d073ec6d0393ea1ec940f5530c1ae0c18a59e893a2eeab4211ad6cee255d9bc7b4d57594f6bedb9d68c42e
@@ -102,9 +102,14 @@ class CfnNag
102
102
  violations << fatal_violation(error)
103
103
  end
104
104
 
105
+ violations = prune_fatal_violations(violations) if @config.ignore_fatal
105
106
  audit_result(violations)
106
107
  end
107
108
 
109
+ def prune_fatal_violations(violations)
110
+ violations.reject { |violation| violation.type == Violation::FAILING_VIOLATION }
111
+ end
112
+
108
113
  def render_results(aggregate_results:,
109
114
  output_format:)
110
115
  results_renderer(output_format).new.render(aggregate_results)
@@ -9,6 +9,7 @@ class CfnNagConfig
9
9
  print_suppression: false,
10
10
  isolate_custom_rule_exceptions: false,
11
11
  fail_on_warnings: false,
12
+ ignore_fatal: false,
12
13
  rule_repository_definitions: [],
13
14
  rule_arguments: {})
14
15
  @rule_directory = rule_directory
@@ -24,6 +25,7 @@ class CfnNagConfig
24
25
  @fail_on_warnings = fail_on_warnings
25
26
  @rule_repositories = rule_repositories
26
27
  @rule_arguments = rule_arguments
28
+ @ignore_fatal = ignore_fatal
27
29
  end
28
30
  # rubocop:enable Metrics/ParameterLists
29
31
 
@@ -34,4 +36,5 @@ class CfnNagConfig
34
36
  attr_reader :blacklist_definition
35
37
  attr_reader :fail_on_warnings
36
38
  attr_reader :rule_repositories
39
+ attr_reader :ignore_fatal
37
40
  end
@@ -129,6 +129,7 @@ class CfnNagExecutor
129
129
  isolate_custom_rule_exceptions: opts[:isolate_custom_rule_exceptions],
130
130
  fail_on_warnings: opts[:fail_on_warnings],
131
131
  rule_repository_definitions: @rule_repository_definitions,
132
+ ignore_fatal: opts[:ignore_fatal],
132
133
  rule_arguments: merge_rule_arguments(opts)
133
134
  )
134
135
  end
@@ -100,6 +100,11 @@ class Options
100
100
  type: :string,
101
101
  required: false,
102
102
  default: nil
103
+ opt :ignore_fatal,
104
+ 'Ignore files with fatal violations. Useful for ignoring non-Cloudformation yaml/yml/json in a path',
105
+ type: :boolean,
106
+ required: false,
107
+ default: false
103
108
  end
104
109
  end
105
110
 
@@ -193,6 +198,12 @@ class Options
193
198
  type: :string,
194
199
  required: false,
195
200
  default: nil
201
+ opt :ignore_fatal,
202
+ 'Ignore files with fatal violations. Useful for ignoring non-Cloudformation yaml/yml/json in a path',
203
+ short: 'g',
204
+ type: :boolean,
205
+ required: false,
206
+ default: false
196
207
  end
197
208
  end
198
209
  # rubocop:enable Metrics/BlockLength
@@ -18,79 +18,80 @@ class EC2NetworkAclEntryOverlappingPortsRule < BaseRule
18
18
  end
19
19
 
20
20
  def audit_impl(cfn_model)
21
+ nacl_entries = cfn_model.resources_by_type('AWS::EC2::NetworkAclEntry')
22
+
23
+ # Select nacl entries that can be evaluated
24
+ nacl_entries.select! do |nacl_entry|
25
+ tcp_or_udp_protocol?(nacl_entry) && valid_ports?(nacl_entry)
26
+ end
27
+
21
28
  violating_nacl_entries = []
22
- cfn_model.resources_by_type('AWS::EC2::NetworkAcl').each do |nacl|
23
- violating_nacl_entries += violating_nacl_entries(nacl)
29
+
30
+ # Group entries by nacl id, ip type, and egress/ingress
31
+ grouped_nacl_entries = group_nacl_entries(nacl_entries)
32
+
33
+ grouped_nacl_entries.each do |grouping|
34
+ violating_nacl_entries += overlapping_port_entries(grouping)
24
35
  end
25
36
  violating_nacl_entries.map(&:logical_resource_id)
26
37
  end
27
38
 
28
39
  private
29
40
 
30
- def overlapping_port_entries(nacl_entries)
31
- unique_pairs(nacl_entries).select do |nacl_entry_pair|
32
- tcp_or_udp_protocol?(nacl_entry_pair[0], nacl_entry_pair[1]) && overlap?(nacl_entry_pair[0], nacl_entry_pair[1])
33
- end
41
+ def tcp_or_udp_protocol?(entry)
42
+ %w[6 17].include?(entry.protocol.to_s)
34
43
  end
35
44
 
36
- def tcp_or_udp_protocol?(entry1, entry2)
37
- %w[6 17].include?(entry1.protocol.to_s) && %w[6 17].include?(entry2.protocol.to_s)
45
+ def valid_ports?(entry)
46
+ !entry.portRange.nil? && valid_port_number?(entry.portRange['From']) && valid_port_number?(entry.portRange['To'])
38
47
  end
39
48
 
40
- def unique_pairs(arr)
41
- pairs_without_dupes = arr.product(arr).select { |pair| pair[0] != pair[1] }
42
- pairs_without_dupes.reduce(Set.new) { |set_of_sets, pair| set_of_sets << Set.new(pair) }.to_a.map(&:to_a)
49
+ def valid_port_number?(port)
50
+ port.is_a?(Numeric) || (port.is_a?(String) && port.to_i(10) != 0)
43
51
  end
44
52
 
45
- def overlap?(entry1, entry2)
46
- roverlap?(entry1, entry2) || loverlap?(entry1, entry2)
47
- end
53
+ def group_nacl_entries(nacl_entries)
54
+ grouped_nacl_entries = []
48
55
 
49
- def roverlap?(entry1, entry2)
50
- entry1.portRange['From'].between?(entry2.portRange['From'], entry2.portRange['To']) ||
51
- entry1.portRange['To'].between?(entry2.portRange['From'], entry2.portRange['To'])
52
- end
56
+ # Group by NaclID
57
+ nacl_entries.group_by(&:networkAclId).each_value do |entries|
58
+ # Split entries by ip type
59
+ ipv4_entries, ipv6_entries = entries.partition { |nacl_entry| nacl_entry.ipv6CidrBlock.nil? }
53
60
 
54
- def loverlap?(entry1, entry2)
55
- entry2.portRange['From'].between?(entry1.portRange['From'], entry1.portRange['To']) ||
56
- entry2.portRange['To'].between?(entry1.portRange['From'], entry1.portRange['To'])
57
- end
61
+ # Split entries by egress/ingress
62
+ egress4, ingress4 = ipv4_entries.partition { |nacl_entry| truthy?(nacl_entry.egress) }
63
+ egress6, ingress6 = ipv6_entries.partition { |nacl_entry| truthy?(nacl_entry.egress) }
58
64
 
59
- def egress_entries(nacl_entries)
60
- nacl_entries.select do |nacl_entry|
61
- truthy?(nacl_entry.egress)
65
+ grouped_nacl_entries << egress4
66
+ grouped_nacl_entries << ingress4
67
+ grouped_nacl_entries << egress6
68
+ grouped_nacl_entries << ingress6
62
69
  end
63
- end
64
70
 
65
- def ingress_entries(nacl_entries)
66
- nacl_entries.select do |nacl_entry|
67
- not_truthy?(nacl_entry.egress)
68
- end
71
+ grouped_nacl_entries
69
72
  end
70
73
 
71
- def ip6_entries(nacl_entries)
72
- nacl_entries.select do |nacl_entry|
73
- !nacl_entry.ipv6CidrBlock.nil?
74
- end
74
+ def overlapping_port_entries(nacl_entries)
75
+ unique_pairs(nacl_entries).select do |nacl_entry_pair|
76
+ overlap?(nacl_entry_pair[0], nacl_entry_pair[1])
77
+ end.flatten.uniq
75
78
  end
76
79
 
77
- def ip4_entries(nacl_entries)
78
- nacl_entries.select do |nacl_entry|
79
- nacl_entry.ipv6CidrBlock.nil?
80
- end
80
+ def unique_pairs(arr)
81
+ pairs_without_dupes = arr.product(arr).select { |pair| pair[0] != pair[1] }
82
+ pairs_without_dupes.reduce(Set.new) { |set_of_sets, pair| set_of_sets << Set.new(pair) }.to_a.map(&:to_a)
81
83
  end
82
84
 
83
- def violating_nacl_entries(nacl)
84
- violating_ip4_nacl_entries(nacl) || violating_ip6_nacl_entries(nacl)
85
+ def overlap?(entry1, entry2)
86
+ port_overlap?(entry1.portRange, entry2.portRange) || port_overlap?(entry2.portRange, entry1.portRange)
85
87
  end
86
88
 
87
- def violating_ip4_nacl_entries(nacl)
88
- overlapping_port_entries(egress_entries(ip4_entries(nacl.network_acl_entries))).flatten.uniq &&
89
- overlapping_port_entries(ingress_entries(ip4_entries(nacl.network_acl_entries))).flatten.uniq
89
+ def port_overlap?(port_range1, port_range2)
90
+ port_number(port_range1['From']).between?(port_number(port_range2['From']), port_number(port_range2['To'])) ||
91
+ port_number(port_range1['To']).between?(port_number(port_range2['From']), port_number(port_range2['To']))
90
92
  end
91
93
 
92
- def violating_ip6_nacl_entries(nacl)
93
- overlapping_port_entries(egress_entries(ip6_entries(nacl.network_acl_entries))).flatten.uniq &&
94
- overlapping_port_entries(ingress_entries(ip6_entries(nacl.network_acl_entries))).flatten.uniq
94
+ def port_number(port)
95
+ port.to_i
95
96
  end
96
97
  end
@@ -26,7 +26,10 @@ class SPCMRule < BaseRule
26
26
  policy_documents = SPCM.new.metric_impl(cfn_model)
27
27
  rescue StandardError => catch_all_exception
28
28
  puts "Experimental SPCM rule is failing. Please report #{catch_all_exception} with the violating template"
29
- policy_documents = {}
29
+ policy_documents = {
30
+ 'AWS::IAM::Policy' => {},
31
+ 'AWS::IAM::Role' => {}
32
+ }
30
33
  end
31
34
 
32
35
  threshold = spcm_threshold.nil? ? DEFAULT_THRESHOLD : spcm_threshold.to_i
@@ -6,7 +6,6 @@ require 'set'
6
6
  class ConditionMetric
7
7
  include Weights
8
8
 
9
- # rubocop:disable Metrics/AbcSize
10
9
  def metric(statement)
11
10
  return 0 if statement.condition.nil?
12
11
 
@@ -18,7 +17,6 @@ class ConditionMetric
18
17
  aggregate += values_with_policy_tags(statement.condition)
19
18
  aggregate
20
19
  end
21
- # rubocop:enable Metrics/AbcSize
22
20
 
23
21
  private
24
22
 
@@ -6,7 +6,6 @@ require 'cfn-nag/violation'
6
6
  class ColoredStdoutResults < StdoutResults
7
7
  private
8
8
 
9
- # rubocop:disable Metrics/AbcSize
10
9
  def message(message_type:,
11
10
  color:,
12
11
  message:,
@@ -24,7 +23,6 @@ class ColoredStdoutResults < StdoutResults
24
23
  puts colorize(color, '|') unless line_numbers.empty? && logical_resource_ids.nil?
25
24
  puts colorize(color, "| #{message}")
26
25
  end
27
- # rubocop:enable Metrics/AbcSize
28
26
 
29
27
  def color_code(color_symbol)
30
28
  case color_symbol
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.4
4
+ version: 0.6.9
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-06-02 00:00:00.000000000 Z
11
+ date: 2020-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -128,14 +128,14 @@ dependencies:
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 1.60.1
131
+ version: '1.76'
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 1.60.1
138
+ version: '1.76'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: lightly
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -381,7 +381,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
381
381
  - !ruby/object:Gem::Version
382
382
  version: '0'
383
383
  requirements: []
384
- rubygems_version: 3.1.3
384
+ rubygems_version: 3.1.4
385
385
  signing_key:
386
386
  specification_version: 4
387
387
  summary: cfn-nag