cfn-nag 0.3.50 → 0.3.51
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|