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.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/bin/cfn_nag +27 -11
  3. data/bin/cfn_nag_rules +5 -4
  4. data/bin/cfn_nag_scan +29 -0
  5. data/lib/cfn-nag.rb +3 -0
  6. data/lib/cfn-nag/cfn_nag.rb +115 -0
  7. data/lib/cfn-nag/custom_rule_loader.rb +72 -0
  8. data/lib/cfn-nag/custom_rules/CloudFormationAuthenticationRule.rb +28 -0
  9. data/lib/cfn-nag/custom_rules/CloudFrontDistributionAccessLoggingRule.rb +24 -0
  10. data/lib/cfn-nag/custom_rules/EbsVolumeHasSseRule.rb +24 -0
  11. data/lib/cfn-nag/custom_rules/ElasticLoadBalancerAccessLoggingRule.rb +24 -0
  12. data/lib/cfn-nag/custom_rules/IamManagedPolicyNotActionRule.rb +25 -0
  13. data/lib/cfn-nag/custom_rules/IamManagedPolicyNotResourceRule.rb +25 -0
  14. data/lib/cfn-nag/custom_rules/IamManagedPolicyWildcardActionRule.rb +25 -0
  15. data/lib/cfn-nag/custom_rules/IamManagedPolicyWildcardResourceRule.rb +25 -0
  16. data/lib/cfn-nag/custom_rules/IamPolicyNotActionRule.rb +25 -0
  17. data/lib/cfn-nag/custom_rules/IamPolicyNotResourceRule.rb +25 -0
  18. data/lib/cfn-nag/custom_rules/IamPolicyWildcardActionRule.rb +25 -0
  19. data/lib/cfn-nag/custom_rules/IamPolicyWildcardResourceRule.rb +25 -0
  20. data/lib/cfn-nag/custom_rules/IamRoleNotActionOnPermissionsPolicyRule.rb +28 -0
  21. data/lib/cfn-nag/custom_rules/IamRoleNotActionOnTrustPolicyRule.rb +25 -0
  22. data/lib/cfn-nag/custom_rules/IamRoleNotPrincipalOnTrustPolicyRule.rb +25 -0
  23. data/lib/cfn-nag/custom_rules/IamRoleNotResourceOnPermissionsPolicyRule.rb +28 -0
  24. data/lib/cfn-nag/custom_rules/IamRoleWildcardActionOnPermissionsPolicyRule.rb +28 -0
  25. data/lib/cfn-nag/custom_rules/IamRoleWildcardActionOnTrustPolicyRule.rb +27 -0
  26. data/lib/cfn-nag/custom_rules/IamRoleWildcardResourceOnPermissionsPolicyRule.rb +28 -0
  27. data/lib/cfn-nag/custom_rules/LambdaPermissionInvokeFunctionActionRule.rb +24 -0
  28. data/lib/cfn-nag/custom_rules/LambdaPermissionWildcardPrincipalRule.rb +24 -0
  29. data/lib/cfn-nag/custom_rules/ManagedPolicyOnUserRule.rb +24 -0
  30. data/lib/cfn-nag/custom_rules/PolicyOnUserRule.rb +24 -0
  31. data/lib/cfn-nag/custom_rules/S3BucketPolicyNotActionRule.rb +25 -0
  32. data/lib/cfn-nag/custom_rules/S3BucketPolicyNotPrincipalRule.rb +25 -0
  33. data/lib/cfn-nag/custom_rules/S3BucketPolicyWildcardActionRule.rb +30 -0
  34. data/lib/cfn-nag/custom_rules/S3BucketPolicyWildcardPrincipalRule.rb +29 -0
  35. data/lib/cfn-nag/custom_rules/S3BucketPublicReadAclRule.rb +29 -0
  36. data/lib/cfn-nag/custom_rules/S3BucketPublicReadWriteAclRule.rb +29 -0
  37. data/lib/cfn-nag/custom_rules/SecurityGroupEgressOpenToWorldRule.rb +39 -0
  38. data/lib/cfn-nag/custom_rules/SecurityGroupEgressPortRangeRule.rb +38 -0
  39. data/lib/cfn-nag/custom_rules/SecurityGroupIngressCidrNon32Rule.rb +40 -0
  40. data/lib/cfn-nag/custom_rules/SecurityGroupIngressOpenToWorldRule.rb +39 -0
  41. data/lib/cfn-nag/custom_rules/SecurityGroupIngressPortRangeRule.rb +38 -0
  42. data/lib/{custom_rules/security_group_missing_egress.rb → cfn-nag/custom_rules/SecurityGroupMissingEgressRule.rb} +6 -12
  43. data/lib/cfn-nag/custom_rules/SnsTopicPolicyNotActionRule.rb +25 -0
  44. data/lib/cfn-nag/custom_rules/SnsTopicPolicyNotPrincipalRule.rb +26 -0
  45. data/lib/cfn-nag/custom_rules/SnsTopicPolicyWildcardPrincipalRule.rb +29 -0
  46. data/lib/cfn-nag/custom_rules/SqsQueuePolicyNotActionRule.rb +25 -0
  47. data/lib/cfn-nag/custom_rules/SqsQueuePolicyNotPrincipalRule.rb +25 -0
  48. data/lib/cfn-nag/custom_rules/SqsQueuePolicyWildcardActionRule.rb +30 -0
  49. data/lib/cfn-nag/custom_rules/SqsQueuePolicyWildcardPrincipalRule.rb +29 -0
  50. data/lib/cfn-nag/custom_rules/UserHasInlinePolicyRule.rb +25 -0
  51. data/lib/cfn-nag/custom_rules/UserMissingGroupRule.rb +28 -0
  52. data/lib/cfn-nag/custom_rules/WafWebAclDefaultActionRule.rb +34 -0
  53. data/lib/cfn-nag/custom_rules/base.rb +28 -0
  54. data/lib/cfn-nag/custom_rules/unencrypted_s3_put_allowed.rb +58 -0
  55. data/lib/{profile.rb → cfn-nag/profile.rb} +0 -1
  56. data/lib/{profile_loader.rb → cfn-nag/profile_loader.rb} +2 -2
  57. data/lib/{result_view → cfn-nag/result_view}/json_results.rb +0 -0
  58. data/lib/{result_view → cfn-nag/result_view}/rules_view.rb +0 -0
  59. data/lib/{result_view → cfn-nag/result_view}/simple_stdout_results.rb +5 -12
  60. data/lib/cfn-nag/rule_definition.rb +36 -0
  61. data/lib/cfn-nag/rule_dumper.rb +23 -0
  62. data/lib/cfn-nag/rule_registry.rb +43 -0
  63. data/lib/cfn-nag/template_discovery.rb +24 -0
  64. data/lib/cfn-nag/violation.rb +58 -0
  65. metadata +79 -36
  66. data/lib/cfn_nag.rb +0 -219
  67. data/lib/custom_rule_loader.rb +0 -64
  68. data/lib/custom_rules/unencrypted_s3_put_allowed.rb +0 -58
  69. data/lib/custom_rules/user_missing_group.rb +0 -34
  70. data/lib/json_rules/basic_rules.rb +0 -49
  71. data/lib/json_rules/cfn_rules.rb +0 -4
  72. data/lib/json_rules/cidr_rules.rb +0 -77
  73. data/lib/json_rules/cloudfront_rules.rb +0 -4
  74. data/lib/json_rules/ebs_rules.rb +0 -4
  75. data/lib/json_rules/iam_policy_rules.rb +0 -153
  76. data/lib/json_rules/iam_user_rules.rb +0 -15
  77. data/lib/json_rules/lambda_rules.rb +0 -9
  78. data/lib/json_rules/loadbalancer_rules.rb +0 -9
  79. data/lib/json_rules/port_rules.rb +0 -33
  80. data/lib/json_rules/s3_bucket_rules.rb +0 -51
  81. data/lib/json_rules/sns_rules.rb +0 -29
  82. data/lib/json_rules/sqs_rules.rb +0 -25
  83. data/lib/model/action_parser.rb +0 -27
  84. data/lib/model/cfn_model.rb +0 -182
  85. data/lib/model/iam_user_parser.rb +0 -34
  86. data/lib/model/parser_registry.rb +0 -31
  87. data/lib/model/s3_bucket_policy.rb +0 -25
  88. data/lib/model/s3_bucket_policy_parser.rb +0 -28
  89. data/lib/model/security_group_parser.rb +0 -59
  90. data/lib/rule.rb +0 -208
  91. data/lib/rule_registry.rb +0 -45
  92. data/lib/violation.rb +0 -41
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c77d505fee7be50a7cdc2e6b536e322752b3b9b2
4
- data.tar.gz: 33831cb14131a221d0653cdc34988e330a46d2a3
3
+ metadata.gz: 905bc16ca0d4964c17e4a532a444b174541c61a6
4
+ data.tar.gz: 5b76a420e36c46f4adeff8506cae88ff76462b83
5
5
  SHA512:
6
- metadata.gz: b460866e5500b58d732f33d6f8433b891a5fc4024c54aad491120ac460f224ae1270cf3862cbbd092bb54cdcfa4936a443dbb2e2e184d86045ed910779ad572a
7
- data.tar.gz: e2b6a603ceaeab42441dfe9e97e9954e965e5c6d4cd66a249865605d1d8d89acf1e51a52f3fc77af3078177544e0ad6616b50e2accfbf8a5a449fdfc38358370
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 'cfn_nag'
3
+ require 'cfn-nag'
4
4
  require 'logging'
5
+ require 'json'
5
6
 
6
7
  opts = Trollop::options do
7
- opt :input_json_path, 'CloudFormation template to nag on or directory of templates - all *.json and *.template recursively', type: :io, required: true
8
- opt :output_format, 'Format of results: [txt, json]', type: :string, default: 'txt'
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 directories', type: :strings, required: false, default: [], multi: true
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 'cfn_nag'
3
+ require 'cfn-nag'
4
4
 
5
5
  opts = Trollop::options do
6
- opt :rule_directory, 'Extra rule directories', type: :strings, required: false, default: [], multi: true
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
- cfn_nag = CfnNag.new(profile_definition: profile_definition)
15
+ rule_dumper = CfnNagRuleDumper.new(profile_definition: profile_definition,
16
+ rule_directory: opts[:rule_directory])
16
17
 
17
- cfn_nag.dump_rules(rule_directories: opts[:rule_directory])
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,3 @@
1
+ require 'cfn-nag/cfn_nag'
2
+ require 'cfn-nag/violation'
3
+ require 'cfn-nag/rule_dumper'
@@ -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