cfn-nag 0.0.44 → 0.1.0
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 +27 -11
- data/bin/cfn_nag_rules +5 -4
- data/bin/cfn_nag_scan +29 -0
- data/lib/cfn-nag.rb +3 -0
- data/lib/cfn-nag/cfn_nag.rb +115 -0
- data/lib/cfn-nag/custom_rule_loader.rb +72 -0
- data/lib/cfn-nag/custom_rules/CloudFormationAuthenticationRule.rb +28 -0
- data/lib/cfn-nag/custom_rules/CloudFrontDistributionAccessLoggingRule.rb +24 -0
- data/lib/cfn-nag/custom_rules/EbsVolumeHasSseRule.rb +24 -0
- data/lib/cfn-nag/custom_rules/ElasticLoadBalancerAccessLoggingRule.rb +24 -0
- data/lib/cfn-nag/custom_rules/IamManagedPolicyNotActionRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/IamManagedPolicyNotResourceRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/IamManagedPolicyWildcardActionRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/IamManagedPolicyWildcardResourceRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/IamPolicyNotActionRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/IamPolicyNotResourceRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/IamPolicyWildcardActionRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/IamPolicyWildcardResourceRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/IamRoleNotActionOnPermissionsPolicyRule.rb +28 -0
- data/lib/cfn-nag/custom_rules/IamRoleNotActionOnTrustPolicyRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/IamRoleNotPrincipalOnTrustPolicyRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/IamRoleNotResourceOnPermissionsPolicyRule.rb +28 -0
- data/lib/cfn-nag/custom_rules/IamRoleWildcardActionOnPermissionsPolicyRule.rb +28 -0
- data/lib/cfn-nag/custom_rules/IamRoleWildcardActionOnTrustPolicyRule.rb +27 -0
- data/lib/cfn-nag/custom_rules/IamRoleWildcardResourceOnPermissionsPolicyRule.rb +28 -0
- data/lib/cfn-nag/custom_rules/LambdaPermissionInvokeFunctionActionRule.rb +24 -0
- data/lib/cfn-nag/custom_rules/LambdaPermissionWildcardPrincipalRule.rb +24 -0
- data/lib/cfn-nag/custom_rules/ManagedPolicyOnUserRule.rb +24 -0
- data/lib/cfn-nag/custom_rules/PolicyOnUserRule.rb +24 -0
- data/lib/cfn-nag/custom_rules/S3BucketPolicyNotActionRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/S3BucketPolicyNotPrincipalRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/S3BucketPolicyWildcardActionRule.rb +30 -0
- data/lib/cfn-nag/custom_rules/S3BucketPolicyWildcardPrincipalRule.rb +29 -0
- data/lib/cfn-nag/custom_rules/S3BucketPublicReadAclRule.rb +29 -0
- data/lib/cfn-nag/custom_rules/S3BucketPublicReadWriteAclRule.rb +29 -0
- data/lib/cfn-nag/custom_rules/SecurityGroupEgressOpenToWorldRule.rb +39 -0
- data/lib/cfn-nag/custom_rules/SecurityGroupEgressPortRangeRule.rb +38 -0
- data/lib/cfn-nag/custom_rules/SecurityGroupIngressCidrNon32Rule.rb +40 -0
- data/lib/cfn-nag/custom_rules/SecurityGroupIngressOpenToWorldRule.rb +39 -0
- data/lib/cfn-nag/custom_rules/SecurityGroupIngressPortRangeRule.rb +38 -0
- data/lib/{custom_rules/security_group_missing_egress.rb → cfn-nag/custom_rules/SecurityGroupMissingEgressRule.rb} +6 -12
- data/lib/cfn-nag/custom_rules/SnsTopicPolicyNotActionRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/SnsTopicPolicyNotPrincipalRule.rb +26 -0
- data/lib/cfn-nag/custom_rules/SnsTopicPolicyWildcardPrincipalRule.rb +29 -0
- data/lib/cfn-nag/custom_rules/SqsQueuePolicyNotActionRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/SqsQueuePolicyNotPrincipalRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/SqsQueuePolicyWildcardActionRule.rb +30 -0
- data/lib/cfn-nag/custom_rules/SqsQueuePolicyWildcardPrincipalRule.rb +29 -0
- data/lib/cfn-nag/custom_rules/UserHasInlinePolicyRule.rb +25 -0
- data/lib/cfn-nag/custom_rules/UserMissingGroupRule.rb +28 -0
- data/lib/cfn-nag/custom_rules/WafWebAclDefaultActionRule.rb +34 -0
- data/lib/cfn-nag/custom_rules/base.rb +28 -0
- data/lib/cfn-nag/custom_rules/unencrypted_s3_put_allowed.rb +58 -0
- data/lib/{profile.rb → cfn-nag/profile.rb} +0 -1
- data/lib/{profile_loader.rb → cfn-nag/profile_loader.rb} +2 -2
- data/lib/{result_view → cfn-nag/result_view}/json_results.rb +0 -0
- data/lib/{result_view → cfn-nag/result_view}/rules_view.rb +0 -0
- data/lib/{result_view → cfn-nag/result_view}/simple_stdout_results.rb +5 -12
- data/lib/cfn-nag/rule_definition.rb +36 -0
- data/lib/cfn-nag/rule_dumper.rb +23 -0
- data/lib/cfn-nag/rule_registry.rb +43 -0
- data/lib/cfn-nag/template_discovery.rb +24 -0
- data/lib/cfn-nag/violation.rb +58 -0
- metadata +79 -36
- data/lib/cfn_nag.rb +0 -219
- data/lib/custom_rule_loader.rb +0 -64
- data/lib/custom_rules/unencrypted_s3_put_allowed.rb +0 -58
- data/lib/custom_rules/user_missing_group.rb +0 -34
- data/lib/json_rules/basic_rules.rb +0 -49
- data/lib/json_rules/cfn_rules.rb +0 -4
- data/lib/json_rules/cidr_rules.rb +0 -77
- data/lib/json_rules/cloudfront_rules.rb +0 -4
- data/lib/json_rules/ebs_rules.rb +0 -4
- data/lib/json_rules/iam_policy_rules.rb +0 -153
- data/lib/json_rules/iam_user_rules.rb +0 -15
- data/lib/json_rules/lambda_rules.rb +0 -9
- data/lib/json_rules/loadbalancer_rules.rb +0 -9
- data/lib/json_rules/port_rules.rb +0 -33
- data/lib/json_rules/s3_bucket_rules.rb +0 -51
- data/lib/json_rules/sns_rules.rb +0 -29
- data/lib/json_rules/sqs_rules.rb +0 -25
- data/lib/model/action_parser.rb +0 -27
- data/lib/model/cfn_model.rb +0 -182
- data/lib/model/iam_user_parser.rb +0 -34
- data/lib/model/parser_registry.rb +0 -31
- data/lib/model/s3_bucket_policy.rb +0 -25
- data/lib/model/s3_bucket_policy_parser.rb +0 -28
- data/lib/model/security_group_parser.rb +0 -59
- data/lib/rule.rb +0 -208
- data/lib/rule_registry.rb +0 -45
- data/lib/violation.rb +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 905bc16ca0d4964c17e4a532a444b174541c61a6
|
4
|
+
data.tar.gz: 5b76a420e36c46f4adeff8506cae88ff76462b83
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da46ac982d9a672b38b8161dbb7b123763fb88f34a0a196c6059cee52157076796c18973a385525cc9f00c50b4bf6ab8abcf992b6ddf6cd08e201c6482efce9d
|
7
|
+
data.tar.gz: da78b9bf29944292f4221ab5dd0dd4cca0c03d0398f164f03b391cf29164b29fc1fbb437851b822411e24297ca31473f6feebf7e175ff83a582d5b191badf4a2
|
data/bin/cfn_nag
CHANGED
@@ -1,19 +1,17 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'trollop'
|
3
|
-
require '
|
3
|
+
require 'cfn-nag'
|
4
4
|
require 'logging'
|
5
|
+
require 'json'
|
5
6
|
|
6
7
|
opts = Trollop::options do
|
7
|
-
|
8
|
-
|
8
|
+
usage '[options] <cloudformation template path ...>|<cloudformation template in STDIN>'
|
9
|
+
|
9
10
|
opt :debug, 'Enable debug output', type: :boolean, required: false, default: false
|
10
|
-
opt :rule_directory, 'Extra rule
|
11
|
+
opt :rule_directory, 'Extra rule directory', type: :io, required: false, default: nil
|
11
12
|
opt :profile_path, 'Path to a profile file', type: :io, required: false, default: nil
|
12
13
|
end
|
13
14
|
|
14
|
-
Trollop::die(:output_format,
|
15
|
-
'Must be txt or json') unless %w(txt json).include?(opts[:output_format])
|
16
|
-
|
17
15
|
CfnNag::configure_logging(opts)
|
18
16
|
|
19
17
|
profile_definition = nil
|
@@ -21,8 +19,26 @@ unless opts[:profile_path].nil?
|
|
21
19
|
profile_definition = IO.read(opts[:profile_path])
|
22
20
|
end
|
23
21
|
|
24
|
-
cfn_nag = CfnNag.new(profile_definition: profile_definition
|
22
|
+
cfn_nag = CfnNag.new(profile_definition: profile_definition,
|
23
|
+
rule_directory: opts[:rule_directory])
|
24
|
+
|
25
|
+
# trollop appears to pop args off of ARGV
|
26
|
+
# ARGF concatenates which we don't want
|
27
|
+
if ARGV.size == 0
|
28
|
+
results = cfn_nag.audit(cloudformation_string: STDIN.read)
|
29
|
+
|
30
|
+
results[:violations] = results[:violations].map { |violation| violation.to_h }
|
31
|
+
puts JSON.pretty_generate(results)
|
32
|
+
exit results[:failure_count]
|
33
|
+
else
|
34
|
+
total_failure_count = 0
|
35
|
+
ARGV.each do |file_name|
|
36
|
+
results = cfn_nag.audit(cloudformation_string: IO.read(file_name))
|
37
|
+
|
38
|
+
total_failure_count += results[:failure_count]
|
39
|
+
results[:violations] = results[:violations].map { |violation| violation.to_h }
|
40
|
+
puts JSON.pretty_generate(results)
|
41
|
+
end
|
42
|
+
exit total_failure_count
|
43
|
+
end
|
25
44
|
|
26
|
-
exit cfn_nag.audit(input_json_path: opts[:input_json_path],
|
27
|
-
output_format: opts[:output_format],
|
28
|
-
rule_directories: opts[:rule_directory])
|
data/bin/cfn_nag_rules
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'trollop'
|
3
|
-
require '
|
3
|
+
require 'cfn-nag'
|
4
4
|
|
5
5
|
opts = Trollop::options do
|
6
|
-
opt :rule_directory, 'Extra rule directories', type: :
|
6
|
+
opt :rule_directory, 'Extra rule directories', type: :io, required: false, default: nil
|
7
7
|
opt :profile_path, 'Path to a profile file', type: :io, required: false, default: nil
|
8
8
|
end
|
9
9
|
|
@@ -12,6 +12,7 @@ unless opts[:profile_path].nil?
|
|
12
12
|
profile_definition = IO.read(opts[:profile_path])
|
13
13
|
end
|
14
14
|
|
15
|
-
|
15
|
+
rule_dumper = CfnNagRuleDumper.new(profile_definition: profile_definition,
|
16
|
+
rule_directory: opts[:rule_directory])
|
16
17
|
|
17
|
-
|
18
|
+
rule_dumper.dump_rules
|
data/bin/cfn_nag_scan
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'trollop'
|
3
|
+
require 'cfn-nag'
|
4
|
+
require 'logging'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
opts = Trollop::options do
|
8
|
+
opt :input_path, 'CloudFormation template to nag on or directory of templates - all *.json, *.yaml, *.yml and *.template recursively', type: :io, required: true
|
9
|
+
opt :output_format, 'Format of results: [txt, json]', type: :string, default: 'txt'
|
10
|
+
opt :debug, 'Enable debug output', type: :boolean, required: false, default: false
|
11
|
+
opt :rule_directory, 'Extra rule directory', type: :io, required: false, default: nil
|
12
|
+
opt :profile_path, 'Path to a profile file', type: :io, required: false, default: nil
|
13
|
+
end
|
14
|
+
|
15
|
+
Trollop::die(:output_format,
|
16
|
+
'Must be txt or json') unless %w(txt json).include?(opts[:output_format])
|
17
|
+
|
18
|
+
CfnNag::configure_logging(opts)
|
19
|
+
|
20
|
+
profile_definition = nil
|
21
|
+
unless opts[:profile_path].nil?
|
22
|
+
profile_definition = IO.read(opts[:profile_path])
|
23
|
+
end
|
24
|
+
|
25
|
+
cfn_nag = CfnNag.new(profile_definition: profile_definition,
|
26
|
+
rule_directory: opts[:rule_directory])
|
27
|
+
|
28
|
+
exit cfn_nag.audit_aggregate_across_files_and_render_results(input_path: opts[:input_path],
|
29
|
+
output_format: opts[:output_format])
|
data/lib/cfn-nag.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
require_relative 'custom_rule_loader'
|
2
|
+
require_relative 'rule_registry'
|
3
|
+
require_relative 'profile_loader'
|
4
|
+
require_relative 'template_discovery'
|
5
|
+
require_relative 'result_view/simple_stdout_results'
|
6
|
+
require_relative 'result_view/json_results'
|
7
|
+
require 'cfn-model'
|
8
|
+
require 'logging'
|
9
|
+
|
10
|
+
class CfnNag
|
11
|
+
def initialize(profile_definition: nil,
|
12
|
+
rule_directory: nil)
|
13
|
+
@rule_directory = rule_directory
|
14
|
+
@custom_rule_loader = CustomRuleLoader.new(rule_directory: rule_directory)
|
15
|
+
@profile_definition = profile_definition
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Given a file or directory path, emit aggregate results to stdout
|
20
|
+
#
|
21
|
+
# Return an aggregate failure count (for exit code usage)
|
22
|
+
#
|
23
|
+
def audit_aggregate_across_files_and_render_results(input_path:,
|
24
|
+
output_format:'txt')
|
25
|
+
aggregate_results = audit_aggregate_across_files input_path: input_path
|
26
|
+
|
27
|
+
render_results(aggregate_results: aggregate_results,
|
28
|
+
output_format: output_format)
|
29
|
+
|
30
|
+
aggregate_results.inject(0) do |total_failure_count, results|
|
31
|
+
total_failure_count + results[:file_results][:failure_count]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Given a file or directory path, return aggregate results
|
37
|
+
#
|
38
|
+
def audit_aggregate_across_files(input_path:)
|
39
|
+
templates = TemplateDiscovery.new.discover_templates(input_path)
|
40
|
+
|
41
|
+
aggregate_results = []
|
42
|
+
templates.each do |template|
|
43
|
+
aggregate_results << {
|
44
|
+
filename: template,
|
45
|
+
file_results: audit(cloudformation_string: IO.read(template))
|
46
|
+
}
|
47
|
+
end
|
48
|
+
aggregate_results
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Given cloudformation json/yml, run all the rules against it
|
53
|
+
#
|
54
|
+
# Return a hash with failure count
|
55
|
+
#
|
56
|
+
def audit(cloudformation_string:)
|
57
|
+
stop_processing = false
|
58
|
+
violations = []
|
59
|
+
|
60
|
+
begin
|
61
|
+
cfn_model = CfnParser.new.parse cloudformation_string
|
62
|
+
rescue ParserError => parser_error
|
63
|
+
violations << Violation.new(id: 'FATAL',
|
64
|
+
type: Violation::FAILING_VIOLATION,
|
65
|
+
message: parser_error.to_s)
|
66
|
+
stop_processing = true
|
67
|
+
end
|
68
|
+
|
69
|
+
violations += @custom_rule_loader.execute_custom_rules(cfn_model) unless stop_processing == true
|
70
|
+
|
71
|
+
violations = filter_violations_by_profile violations unless stop_processing == true
|
72
|
+
|
73
|
+
{
|
74
|
+
failure_count: Violation.count_failures(violations),
|
75
|
+
violations: violations
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.configure_logging(opts)
|
80
|
+
logger = Logging.logger['log']
|
81
|
+
if opts[:debug]
|
82
|
+
logger.level = :debug
|
83
|
+
else
|
84
|
+
logger.level = :info
|
85
|
+
end
|
86
|
+
|
87
|
+
logger.add_appenders Logging.appenders.stdout
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def filter_violations_by_profile(violations)
|
93
|
+
profile = nil
|
94
|
+
unless @profile_definition.nil?
|
95
|
+
profile = ProfileLoader.new(@custom_rule_loader.rule_definitions).load(profile_definition: @profile_definition)
|
96
|
+
end
|
97
|
+
|
98
|
+
violations.reject do |violation|
|
99
|
+
not profile.nil? and not profile.execute_rule?(violation.id)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def render_results(aggregate_results:,
|
104
|
+
output_format:)
|
105
|
+
results_renderer(output_format).new.render(aggregate_results)
|
106
|
+
end
|
107
|
+
|
108
|
+
def results_renderer(output_format)
|
109
|
+
registry = {
|
110
|
+
'txt' => SimpleStdoutResults,
|
111
|
+
'json' => JsonResults
|
112
|
+
}
|
113
|
+
registry[output_format]
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'cfn-model'
|
2
|
+
require 'logging'
|
3
|
+
require_relative 'rule_registry'
|
4
|
+
|
5
|
+
##
|
6
|
+
# This object can discover the internal and custom user-provided rules and
|
7
|
+
# apply these rules to a CfnModel object
|
8
|
+
#
|
9
|
+
class CustomRuleLoader
|
10
|
+
def initialize(rule_directory: nil)
|
11
|
+
@rule_directory = rule_directory
|
12
|
+
validate_extra_rule_directory rule_directory
|
13
|
+
end
|
14
|
+
|
15
|
+
def rule_definitions
|
16
|
+
rule_registry = RuleRegistry.new
|
17
|
+
|
18
|
+
discover_rule_classes(@rule_directory).each do |rule_class|
|
19
|
+
rule = rule_class.new
|
20
|
+
rule_registry.definition(id: rule.rule_id,
|
21
|
+
type: rule.rule_type,
|
22
|
+
message: rule.rule_text)
|
23
|
+
end
|
24
|
+
rule_registry
|
25
|
+
end
|
26
|
+
|
27
|
+
def execute_custom_rules(cfn_model)
|
28
|
+
Logging.logger['log'].debug "cfn_model: #{cfn_model}"
|
29
|
+
|
30
|
+
violations = []
|
31
|
+
|
32
|
+
discover_rule_classes(@rule_directory).each do |rule_class|
|
33
|
+
audit_result = rule_class.new.audit(cfn_model)
|
34
|
+
violations << audit_result unless audit_result.nil?
|
35
|
+
end
|
36
|
+
violations
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def validate_extra_rule_directory(rule_directory)
|
42
|
+
unless rule_directory.nil?
|
43
|
+
fail "Not a real directory #{rule_directory}" unless File.directory? rule_directory
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def discover_rule_filenames(rule_directory)
|
48
|
+
rule_filenames = []
|
49
|
+
unless rule_directory.nil?
|
50
|
+
rule_filenames += Dir[File.join(rule_directory, '*Rule.rb')].sort
|
51
|
+
end
|
52
|
+
rule_filenames += Dir[File.join(__dir__, 'custom_rules', '*Rule.rb')].sort
|
53
|
+
Logging.logger['log'].debug "rule_filenames: #{rule_filenames}"
|
54
|
+
rule_filenames
|
55
|
+
end
|
56
|
+
|
57
|
+
def discover_rule_classes(rule_directory)
|
58
|
+
rule_classes = []
|
59
|
+
|
60
|
+
rule_filenames = discover_rule_filenames(rule_directory)
|
61
|
+
|
62
|
+
rule_filenames.each do |rule_filename|
|
63
|
+
require(rule_filename)
|
64
|
+
rule_classname = File.basename(rule_filename, '.rb')
|
65
|
+
|
66
|
+
rule_classes << Object.const_get(rule_classname)
|
67
|
+
end
|
68
|
+
Logging.logger['log'].debug "rule_classes: #{rule_classes}"
|
69
|
+
|
70
|
+
rule_classes
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'cfn-nag/violation'
|
2
|
+
require_relative 'base'
|
3
|
+
|
4
|
+
class CloudFormationAuthenticationRule < BaseRule
|
5
|
+
def rule_text
|
6
|
+
'Specifying credentials in the template itself is probably not the safest thing'
|
7
|
+
end
|
8
|
+
|
9
|
+
def rule_type
|
10
|
+
Violation::WARNING
|
11
|
+
end
|
12
|
+
|
13
|
+
def rule_id
|
14
|
+
'W1'
|
15
|
+
end
|
16
|
+
|
17
|
+
def audit_impl(cfn_model)
|
18
|
+
logical_resource_ids = []
|
19
|
+
cfn_model.raw_model['Resources'].each do |resource_name, resource|
|
20
|
+
unless resource['Metadata'].nil?
|
21
|
+
if !resource['Metadata']['AWS::CloudFormation::Authentication'].nil?
|
22
|
+
logical_resource_ids << resource_name
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
logical_resource_ids
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'cfn-nag/violation'
|
2
|
+
require_relative 'base'
|
3
|
+
|
4
|
+
class CloudFrontDistributionAccessLoggingRule < BaseRule
|
5
|
+
def rule_text
|
6
|
+
'CloudFront Distribution should enable access logging'
|
7
|
+
end
|
8
|
+
|
9
|
+
def rule_type
|
10
|
+
Violation::WARNING
|
11
|
+
end
|
12
|
+
|
13
|
+
def rule_id
|
14
|
+
'W10'
|
15
|
+
end
|
16
|
+
|
17
|
+
def audit_impl(cfn_model)
|
18
|
+
violating_distributions = cfn_model.resources_by_type('AWS::CloudFront::Distribution').select do |distribution|
|
19
|
+
distribution.distributionConfig['Logging'].nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
violating_distributions.map { |distribution| distribution.logical_resource_id }
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'cfn-nag/violation'
|
2
|
+
require_relative 'base'
|
3
|
+
|
4
|
+
class EbsVolumeHasSseRule < BaseRule
|
5
|
+
def rule_text
|
6
|
+
'EBS volume should have server-side encryption enabled'
|
7
|
+
end
|
8
|
+
|
9
|
+
def rule_type
|
10
|
+
Violation::FAILING_VIOLATION
|
11
|
+
end
|
12
|
+
|
13
|
+
def rule_id
|
14
|
+
'F1'
|
15
|
+
end
|
16
|
+
|
17
|
+
def audit_impl(cfn_model)
|
18
|
+
violating_volumes = cfn_model.resources_by_type('AWS::EC2::Volume').select do |volume|
|
19
|
+
volume.encrypted.nil? || volume.encrypted == false
|
20
|
+
end
|
21
|
+
|
22
|
+
violating_volumes.map { |violating_user| violating_user.logical_resource_id }
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'cfn-nag/violation'
|
2
|
+
require_relative 'base'
|
3
|
+
|
4
|
+
class ElasticLoadBalancerAccessLoggingRule < BaseRule
|
5
|
+
def rule_text
|
6
|
+
'Elastic Load Balancer should have access logging enabled'
|
7
|
+
end
|
8
|
+
|
9
|
+
def rule_type
|
10
|
+
Violation::WARNING
|
11
|
+
end
|
12
|
+
|
13
|
+
def rule_id
|
14
|
+
'W26'
|
15
|
+
end
|
16
|
+
|
17
|
+
def audit_impl(cfn_model)
|
18
|
+
violating_elbs = cfn_model.resources_by_type('AWS::ElasticLoadBalancing::LoadBalancer').select do |elb|
|
19
|
+
elb.accessLoggingPolicy.nil? || elb.accessLoggingPolicy['Enabled'] != true
|
20
|
+
end
|
21
|
+
|
22
|
+
violating_elbs.map { |violating_user| violating_user.logical_resource_id }
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'cfn-nag/violation'
|
2
|
+
require_relative 'base'
|
3
|
+
|
4
|
+
class IamManagedPolicyNotActionRule < BaseRule
|
5
|
+
|
6
|
+
def rule_text
|
7
|
+
'IAM managed policy should not allow Allow+NotAction'
|
8
|
+
end
|
9
|
+
|
10
|
+
def rule_type
|
11
|
+
Violation::WARNING
|
12
|
+
end
|
13
|
+
|
14
|
+
def rule_id
|
15
|
+
'W17'
|
16
|
+
end
|
17
|
+
|
18
|
+
def audit_impl(cfn_model)
|
19
|
+
violating_policies = cfn_model.resources_by_type('AWS::IAM::ManagedPolicy').select do |policy|
|
20
|
+
!policy.policyDocument.allows_not_action.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
violating_policies.map { |policy| policy.logical_resource_id }
|
24
|
+
end
|
25
|
+
end
|