cfn-nag 0.3.50 → 0.3.51
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 +32 -20
- data/bin/cfn_nag_scan +40 -19
- data/lib/cfn-nag/cfn_nag.rb +3 -5
- data/lib/cfn-nag/custom_rule_loader.rb +5 -7
- data/lib/cfn-nag/custom_rules/CloudFormationAuthenticationRule.rb +1 -2
- data/lib/cfn-nag/custom_rules/CloudFrontDistributionAccessLoggingRule.rb +4 -5
- data/lib/cfn-nag/custom_rules/EbsVolumeHasSseRule.rb +4 -4
- data/lib/cfn-nag/custom_rules/ElasticLoadBalancerAccessLoggingRule.rb +4 -6
- data/lib/cfn-nag/custom_rules/IamManagedPolicyNotActionRule.rb +4 -5
- data/lib/cfn-nag/custom_rules/IamManagedPolicyNotResourceRule.rb +4 -5
- data/lib/cfn-nag/custom_rules/IamManagedPolicyWildcardActionRule.rb +4 -5
- data/lib/cfn-nag/custom_rules/IamManagedPolicyWildcardResourceRule.rb +4 -5
- data/lib/cfn-nag/custom_rules/IamPolicyNotActionRule.rb +4 -5
- data/lib/cfn-nag/custom_rules/IamPolicyNotResourceRule.rb +4 -5
- data/lib/cfn-nag/custom_rules/RDSInstanceMasterUsernameRule.rb +1 -2
- data/lib/cfn-nag/custom_rules/SecurityGroupIngressOpenToWorldRule.rb +1 -2
- data/lib/cfn-nag/result_view/json_results.rb +1 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e764bdbe8170764ddbcc2c6ed6030e2626300ef312af2284f6ba52d32158a75
|
4
|
+
data.tar.gz: b90488a204b909cf5decba7db589c0dc570231354a686f3713e33b056484fdb7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 242bdde3f47c84cb12246b0c54305df8751ad927bd90a75bebf46fdf1e4ec3e6d93405906d234c2ad1f44b137fd7257a7b22969a867078a1120370d03d9818df
|
7
|
+
data.tar.gz: 0f87bcb3a3c6e404b972c2219b4ca93118ce30a9f2e06f792aed6c75d07b36071e3649df5b58968f54f61286606975bfeae89a87d45785abafbb8d934658fdd6
|
data/bin/cfn_nag
CHANGED
@@ -6,32 +6,44 @@ require 'json'
|
|
6
6
|
require 'rubygems/specification'
|
7
7
|
|
8
8
|
opts = Trollop.options do
|
9
|
-
usage '[options] <cloudformation template path
|
10
|
-
'<cloudformation template in STDIN>'
|
9
|
+
usage '[options] <cloudformation template path ...>|<cloudformation template in STDIN>'
|
11
10
|
version Gem::Specification.find_by_name('cfn-nag').version
|
12
11
|
|
13
|
-
opt :debug,
|
14
|
-
|
12
|
+
opt :debug,
|
13
|
+
'Enable debug output',
|
14
|
+
type: :boolean,
|
15
|
+
required: false,
|
16
|
+
default: false
|
15
17
|
opt :allow_suppression,
|
16
18
|
'Allow using Metadata to suppress violations',
|
17
|
-
type: :boolean,
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
19
|
+
type: :boolean,
|
20
|
+
required: false,
|
21
|
+
default: true
|
22
|
+
opt :print_suppression,
|
23
|
+
'Emit suppressions to stderr',
|
24
|
+
type: :boolean,
|
25
|
+
required: false,
|
26
|
+
default: false
|
27
|
+
opt :rule_directory,
|
28
|
+
'Extra rule directory',
|
29
|
+
type: :io,
|
30
|
+
required: false,
|
31
|
+
default: nil
|
32
|
+
opt :profile_path,
|
33
|
+
'Path to a profile file',
|
34
|
+
type: :io,
|
35
|
+
required: false,
|
36
|
+
default: nil
|
27
37
|
opt :parameter_values_path,
|
28
|
-
'Path to a JSON file to pull Parameter values from',
|
29
|
-
|
30
|
-
|
38
|
+
'Path to a JSON file to pull Parameter values from',
|
39
|
+
type: :io,
|
40
|
+
required: false,
|
41
|
+
default: nil
|
31
42
|
opt :isolate_custom_rule_exceptions,
|
32
|
-
'Isolate custom rule exceptions - just emit the exception '
|
33
|
-
|
34
|
-
|
43
|
+
'Isolate custom rule exceptions - just emit the exception without stack trace and keep chugging',
|
44
|
+
type: :boolean,
|
45
|
+
required: false,
|
46
|
+
default: false
|
35
47
|
end
|
36
48
|
|
37
49
|
CfnNag.configure_logging(opts)
|
data/bin/cfn_nag_scan
CHANGED
@@ -8,28 +8,49 @@ require 'rubygems/specification'
|
|
8
8
|
opts = Trollop.options do
|
9
9
|
version Gem::Specification.find_by_name('cfn-nag').version
|
10
10
|
|
11
|
-
opt :input_path,
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
type: :
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
type: :
|
11
|
+
opt :input_path,
|
12
|
+
'CloudFormation template to nag on or directory of templates - all *.json, *.yaml, *.yml and *.template recursively',
|
13
|
+
type: :io,
|
14
|
+
required: true
|
15
|
+
opt :output_format,
|
16
|
+
'Format of results: [txt, json]',
|
17
|
+
type: :string,
|
18
|
+
default: 'txt'
|
19
|
+
opt :debug,
|
20
|
+
'Enable debug output',
|
21
|
+
type: :boolean,
|
22
|
+
required: false,
|
23
|
+
default: false
|
24
|
+
opt :rule_directory,
|
25
|
+
'Extra rule directory',
|
26
|
+
type: :io,
|
27
|
+
required: false,
|
28
|
+
default: nil
|
29
|
+
opt :profile_path,
|
30
|
+
'Path to a profile file',
|
31
|
+
type: :io,
|
32
|
+
required: false,
|
33
|
+
default: nil
|
22
34
|
opt :parameter_values_path,
|
23
35
|
'Path to a JSON file to pull Parameter values from',
|
24
|
-
type: :io,
|
25
|
-
|
26
|
-
|
27
|
-
opt :
|
28
|
-
|
36
|
+
type: :io,
|
37
|
+
required: false,
|
38
|
+
default: nil
|
39
|
+
opt :allow_suppression,
|
40
|
+
'Allow using Metadata to suppress violations',
|
41
|
+
type: :boolean,
|
42
|
+
required: false,
|
43
|
+
default: true
|
44
|
+
opt :print_suppression,
|
45
|
+
'Emit suppressions to stderr',
|
46
|
+
type: :boolean,
|
47
|
+
required: false,
|
48
|
+
default: false
|
29
49
|
opt :isolate_custom_rule_exceptions,
|
30
|
-
'Isolate custom rule exceptions - just emit the exception without '
|
31
|
-
|
32
|
-
|
50
|
+
'Isolate custom rule exceptions - just emit the exception without stack trace and keep chugging',
|
51
|
+
type: :boolean,
|
52
|
+
required: false,
|
53
|
+
default: false
|
33
54
|
end
|
34
55
|
|
35
56
|
unless %w[txt json].include?(opts[:output_format])
|
data/lib/cfn-nag/cfn_nag.rb
CHANGED
@@ -31,9 +31,8 @@ class CfnNag
|
|
31
31
|
def audit_aggregate_across_files_and_render_results(
|
32
32
|
input_path:, output_format: 'txt', parameter_values_path: nil
|
33
33
|
)
|
34
|
-
aggregate_results =
|
35
|
-
|
36
|
-
parameter_values_path: parameter_values_path
|
34
|
+
aggregate_results = audit_aggregate_across_files input_path: input_path,
|
35
|
+
parameter_values_path: parameter_values_path
|
37
36
|
|
38
37
|
render_results(aggregate_results: aggregate_results,
|
39
38
|
output_format: output_format)
|
@@ -49,8 +48,7 @@ class CfnNag
|
|
49
48
|
# Given a file or directory path, return aggregate results
|
50
49
|
#
|
51
50
|
def audit_aggregate_across_files(input_path:, parameter_values_path: nil)
|
52
|
-
parameter_values_string =
|
53
|
-
parameter_values_path.nil? ? nil : IO.read(parameter_values_path)
|
51
|
+
parameter_values_string = parameter_values_path.nil? ? nil : IO.read(parameter_values_path)
|
54
52
|
templates = TemplateDiscovery.new.discover_templates(input_path)
|
55
53
|
aggregate_results = []
|
56
54
|
templates.each do |template|
|
@@ -74,9 +74,9 @@ class CustomRuleLoader
|
|
74
74
|
def filter_rule_classes(cfn_model, violations)
|
75
75
|
discover_rule_classes(@rule_directory).each do |rule_class|
|
76
76
|
begin
|
77
|
-
filtered_cfn_model = cfn_model_with_suppressed_resources_removed
|
78
|
-
|
79
|
-
|
77
|
+
filtered_cfn_model = cfn_model_with_suppressed_resources_removed cfn_model: cfn_model,
|
78
|
+
rule_id: rule_class.new.rule_id,
|
79
|
+
allow_suppression: @allow_suppression
|
80
80
|
audit_result = rule_class.new.audit(filtered_cfn_model)
|
81
81
|
violations << audit_result unless audit_result.nil?
|
82
82
|
rescue Exception => exception
|
@@ -113,8 +113,7 @@ class CustomRuleLoader
|
|
113
113
|
logical_resource_id = mangled_metadata.first
|
114
114
|
mangled_rules = mangled_metadata[1]
|
115
115
|
|
116
|
-
STDERR.puts "#{logical_resource_id} has missing cfn_nag "
|
117
|
-
"suppression rule id: #{mangled_rules}"
|
116
|
+
STDERR.puts "#{logical_resource_id} has missing cfn_nag suppression rule id: #{mangled_rules}"
|
118
117
|
end
|
119
118
|
end
|
120
119
|
|
@@ -124,8 +123,7 @@ class CustomRuleLoader
|
|
124
123
|
rule_to_suppress['id'] == rule_id
|
125
124
|
end
|
126
125
|
if found_suppression_rule && @print_suppression
|
127
|
-
STDERR.puts "Suppressing #{rule_id} on #{logical_resource_id} "
|
128
|
-
"for reason: #{found_suppression_rule['reason']}"
|
126
|
+
STDERR.puts "Suppressing #{rule_id} on #{logical_resource_id} for reason: #{found_suppression_rule['reason']}"
|
129
127
|
end
|
130
128
|
!found_suppression_rule.nil?
|
131
129
|
end
|
@@ -4,8 +4,7 @@ require_relative 'base'
|
|
4
4
|
# Rule to ensure credentials are not specified in template
|
5
5
|
class CloudFormationAuthenticationRule < BaseRule
|
6
6
|
def rule_text
|
7
|
-
'Specifying credentials in the template itself '
|
8
|
-
'is probably not the safest thing'
|
7
|
+
'Specifying credentials in the template itself is probably not the safest thing'
|
9
8
|
end
|
10
9
|
|
11
10
|
def rule_type
|
@@ -16,11 +16,10 @@ class CloudFrontDistributionAccessLoggingRule < BaseRule
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def audit_impl(cfn_model)
|
19
|
-
violating_distributions =
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
19
|
+
violating_distributions = cfn_model.resources_by_type('AWS::CloudFront::Distribution')
|
20
|
+
.select do |distribution|
|
21
|
+
distribution.distributionConfig['Logging'].nil?
|
22
|
+
end
|
24
23
|
|
25
24
|
violating_distributions.map(&:logical_resource_id)
|
26
25
|
end
|
@@ -15,10 +15,10 @@ class EbsVolumeHasSseRule < BaseRule
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def audit_impl(cfn_model)
|
18
|
-
violating_volumes =
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
violating_volumes = cfn_model.resources_by_type('AWS::EC2::Volume')
|
19
|
+
.select do |volume|
|
20
|
+
volume.encrypted.nil? || volume.encrypted.to_s.casecmp('false').zero?
|
21
|
+
end
|
22
22
|
|
23
23
|
violating_volumes.map(&:logical_resource_id)
|
24
24
|
end
|
@@ -15,12 +15,10 @@ class ElasticLoadBalancerAccessLoggingRule < BaseRule
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def audit_impl(cfn_model)
|
18
|
-
violating_elbs =
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
elb.accessLoggingPolicy['Enabled'] != true
|
23
|
-
end
|
18
|
+
violating_elbs = cfn_model.resources_by_type('AWS::ElasticLoadBalancing::LoadBalancer')
|
19
|
+
.select do |elb|
|
20
|
+
elb.accessLoggingPolicy.nil? || elb.accessLoggingPolicy['Enabled'] != true
|
21
|
+
end
|
24
22
|
|
25
23
|
violating_elbs.map(&:logical_resource_id)
|
26
24
|
end
|
@@ -15,11 +15,10 @@ class IamManagedPolicyNotActionRule < BaseRule
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def audit_impl(cfn_model)
|
18
|
-
violating_policies =
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
18
|
+
violating_policies = cfn_model.resources_by_type('AWS::IAM::ManagedPolicy')
|
19
|
+
.select do |policy|
|
20
|
+
!policy.policy_document.allows_not_action.empty?
|
21
|
+
end
|
23
22
|
|
24
23
|
violating_policies.map(&:logical_resource_id)
|
25
24
|
end
|
@@ -15,11 +15,10 @@ class IamManagedPolicyNotResourceRule < BaseRule
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def audit_impl(cfn_model)
|
18
|
-
violating_policies =
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
18
|
+
violating_policies = cfn_model.resources_by_type('AWS::IAM::ManagedPolicy')
|
19
|
+
.select do |policy|
|
20
|
+
!policy.policy_document.allows_not_resource.empty?
|
21
|
+
end
|
23
22
|
|
24
23
|
violating_policies.map(&:logical_resource_id)
|
25
24
|
end
|
@@ -15,11 +15,10 @@ class IamManagedPolicyWildcardActionRule < BaseRule
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def audit_impl(cfn_model)
|
18
|
-
violating_policies =
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
18
|
+
violating_policies = cfn_model.resources_by_type('AWS::IAM::ManagedPolicy')
|
19
|
+
.select do |policy|
|
20
|
+
!policy.policy_document.wildcard_allowed_actions.empty?
|
21
|
+
end
|
23
22
|
|
24
23
|
violating_policies.map(&:logical_resource_id)
|
25
24
|
end
|
@@ -15,11 +15,10 @@ class IamManagedPolicyWildcardResourceRule < BaseRule
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def audit_impl(cfn_model)
|
18
|
-
violating_policies =
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
18
|
+
violating_policies = cfn_model.resources_by_type('AWS::IAM::ManagedPolicy')
|
19
|
+
.select do |policy|
|
20
|
+
!policy.policy_document.wildcard_allowed_resources.empty?
|
21
|
+
end
|
23
22
|
|
24
23
|
violating_policies.map(&:logical_resource_id)
|
25
24
|
end
|
@@ -15,11 +15,10 @@ class IamPolicyNotActionRule < BaseRule
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def audit_impl(cfn_model)
|
18
|
-
violating_policies =
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
18
|
+
violating_policies = cfn_model.resources_by_type('AWS::IAM::Policy')
|
19
|
+
.select do |policy|
|
20
|
+
!policy.policy_document.allows_not_action.empty?
|
21
|
+
end
|
23
22
|
|
24
23
|
violating_policies.map(&:logical_resource_id)
|
25
24
|
end
|
@@ -15,11 +15,10 @@ class IamPolicyNotResourceRule < BaseRule
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def audit_impl(cfn_model)
|
18
|
-
violating_policies =
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
18
|
+
violating_policies = cfn_model.resources_by_type('AWS::IAM::Policy')
|
19
|
+
.select do |policy|
|
20
|
+
!policy.policy_document.allows_not_resource.empty?
|
21
|
+
end
|
23
22
|
|
24
23
|
violating_policies.map(&:logical_resource_id)
|
25
24
|
end
|
@@ -4,8 +4,7 @@ require_relative 'base'
|
|
4
4
|
# cfn_nag rules related to RDS Instance master username
|
5
5
|
class RDSInstanceMasterUsernameRule < BaseRule
|
6
6
|
def rule_text
|
7
|
-
'RDS instance master username must be Ref to NoEcho Parameter. '
|
8
|
-
'Default credentials are not recommended'
|
7
|
+
'RDS instance master username must be Ref to NoEcho Parameter. Default credentials are not recommended'
|
9
8
|
end
|
10
9
|
|
11
10
|
def rule_type
|
@@ -6,8 +6,7 @@ class SecurityGroupIngressOpenToWorldRule < BaseRule
|
|
6
6
|
include IpAddr
|
7
7
|
|
8
8
|
def rule_text
|
9
|
-
'Security Groups found with cidr open to world on ingress. '
|
10
|
-
'This should never be true on instance. Permissible on ELB'
|
9
|
+
'Security Groups found with cidr open to world on ingress. This should never be true on instance. Permissible on ELB'
|
11
10
|
end
|
12
11
|
|
13
12
|
def rule_type
|
@@ -3,8 +3,7 @@ require 'json'
|
|
3
3
|
class JsonResults
|
4
4
|
def render(results)
|
5
5
|
hashified_results = results.each do |result|
|
6
|
-
result[:file_results][:violations] =
|
7
|
-
result[:file_results][:violations].map(&:to_h)
|
6
|
+
result[:file_results][:violations] = result[:file_results][:violations].map(&:to_h)
|
8
7
|
end
|
9
8
|
|
10
9
|
puts JSON.pretty_generate(hashified_results)
|