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
@@ -0,0 +1,26 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class SnsTopicPolicyNotPrincipalRule < BaseRule
5
+
6
+ def rule_text
7
+ 'SNS Topic policy should not allow Allow+NotPrincipal'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::FAILING_VIOLATION
12
+ end
13
+
14
+ def rule_id
15
+ 'F8'
16
+ end
17
+
18
+ def audit_impl(cfn_model)
19
+ violating_policies = cfn_model.resources_by_type('AWS::SNS::TopicPolicy').select do |policy|
20
+ !policy.policyDocument.allows_not_principal.empty?
21
+ end
22
+
23
+ violating_policies.map { |policy| policy.logical_resource_id }
24
+ end
25
+ end
26
+
@@ -0,0 +1,29 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class SnsTopicPolicyWildcardPrincipalRule < BaseRule
5
+
6
+ def rule_text
7
+ 'SNS topic policy should not allow * principal'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::FAILING_VIOLATION
12
+ end
13
+
14
+ def rule_id
15
+ 'F18'
16
+ end
17
+
18
+ def audit_impl(cfn_model)
19
+ logical_resource_ids = []
20
+
21
+ cfn_model.resources_by_type('AWS::SNS::TopicPolicy').each do |topic_policy|
22
+ if !topic_policy.policyDocument.wildcard_allowed_principals.empty?
23
+ logical_resource_ids << topic_policy.logical_resource_id
24
+ end
25
+ end
26
+
27
+ logical_resource_ids
28
+ end
29
+ end
@@ -0,0 +1,25 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class SqsQueuePolicyNotActionRule < BaseRule
5
+
6
+ def rule_text
7
+ 'SQS Queue policy should not allow Allow+NotAction'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::WARNING
12
+ end
13
+
14
+ def rule_id
15
+ 'W18'
16
+ end
17
+
18
+ def audit_impl(cfn_model)
19
+ violating_policies = cfn_model.resources_by_type('AWS::SQS::QueuePolicy').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
@@ -0,0 +1,25 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class SqsQueuePolicyNotPrincipalRule < BaseRule
5
+
6
+ def rule_text
7
+ 'SQS Queue policy should not allow Allow+NotPrincipal'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::FAILING_VIOLATION
12
+ end
13
+
14
+ def rule_id
15
+ 'F7'
16
+ end
17
+
18
+ def audit_impl(cfn_model)
19
+ violating_policies = cfn_model.resources_by_type('AWS::SQS::QueuePolicy').select do |policy|
20
+ !policy.policyDocument.allows_not_principal.empty?
21
+ end
22
+
23
+ violating_policies.map { |policy| policy.logical_resource_id }
24
+ end
25
+ end
@@ -0,0 +1,30 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class SqsQueuePolicyWildcardActionRule < BaseRule
5
+
6
+ def rule_text
7
+ 'SQS Queue policy should not allow * action'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::FAILING_VIOLATION
12
+ end
13
+
14
+ def rule_id
15
+ 'F20'
16
+ end
17
+
18
+ def audit_impl(cfn_model)
19
+ logical_resource_ids = []
20
+
21
+ cfn_model.resources_by_type('AWS::SQS::QueuePolicy').each do |queue_policy|
22
+
23
+ if !queue_policy.policyDocument.wildcard_allowed_actions.empty?
24
+ logical_resource_ids << queue_policy.logical_resource_id
25
+ end
26
+ end
27
+
28
+ logical_resource_ids
29
+ end
30
+ end
@@ -0,0 +1,29 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class SqsQueuePolicyWildcardPrincipalRule < BaseRule
5
+
6
+ def rule_text
7
+ 'SQS Queue policy should not allow * principal'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::FAILING_VIOLATION
12
+ end
13
+
14
+ def rule_id
15
+ 'F21'
16
+ end
17
+
18
+ def audit_impl(cfn_model)
19
+ logical_resource_ids = []
20
+
21
+ cfn_model.resources_by_type('AWS::SQS::QueuePolicy').each do |topic_policy|
22
+ if !topic_policy.policyDocument.wildcard_allowed_principals.empty?
23
+ logical_resource_ids << topic_policy.logical_resource_id
24
+ end
25
+ end
26
+
27
+ logical_resource_ids
28
+ end
29
+ end
@@ -0,0 +1,25 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class UserHasInlinePolicyRule < BaseRule
5
+
6
+ def rule_text
7
+ 'IAM user should not have any inline policies. Should be centralized Policy object on group'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::FAILING_VIOLATION
12
+ end
13
+
14
+ def rule_id
15
+ 'F10'
16
+ end
17
+
18
+ def audit_impl(cfn_model)
19
+ violating_users = cfn_model.iam_users.select do |iam_user|
20
+ iam_user.policies.size > 0
21
+ end
22
+
23
+ violating_users.map { |violating_user| violating_user.logical_resource_id }
24
+ end
25
+ end
@@ -0,0 +1,28 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class UserMissingGroupRule < BaseRule
5
+
6
+ def rule_text
7
+ 'User is not assigned to a group'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::FAILING_VIOLATION
12
+ end
13
+
14
+ def rule_id
15
+ 'F2000'
16
+ end
17
+
18
+ def audit_impl(cfn_model)
19
+ logical_resource_ids = []
20
+ cfn_model.iam_users.each do |iam_user|
21
+ if iam_user.groups.empty?
22
+ logical_resource_ids << iam_user.logical_resource_id
23
+ end
24
+ end
25
+
26
+ logical_resource_ids
27
+ end
28
+ end
@@ -0,0 +1,34 @@
1
+ # Copy
2
+ # "MyWebACL": {
3
+ # "Type": "AWS::WAF::WebACL",
4
+ # "Properties": {
5
+ # "Name": "WebACL to with three rules",
6
+ # "DefaultAction": {
7
+ # "Type": "ALLOW"
8
+ # },
9
+
10
+ require 'cfn-nag/violation'
11
+ require_relative 'base'
12
+
13
+ class WafWebAclDefaultActionRule < BaseRule
14
+
15
+ def rule_text
16
+ 'WebAcl DefaultAction should not be ALLOW'
17
+ end
18
+
19
+ def rule_type
20
+ Violation::FAILING_VIOLATION
21
+ end
22
+
23
+ def rule_id
24
+ 'F665'
25
+ end
26
+
27
+ def audit_impl(cfn_model)
28
+ violating_web_acls = cfn_model.resources_by_type('AWS::WAF::WebACL').select do |web_acl|
29
+ web_acl.defaultAction['Type'] == 'ALLOW'
30
+ end
31
+
32
+ violating_web_acls.map { |web_acl| web_acl.logical_resource_id }
33
+ end
34
+ end
@@ -0,0 +1,28 @@
1
+ require 'cfn-nag/violation'
2
+
3
+ class BaseRule
4
+
5
+ ##
6
+ # Returns a collection of logical resource ids
7
+ #
8
+ def audit_impl(cfn_model)
9
+ raise 'must implement in subclass'
10
+ end
11
+
12
+ ##
13
+ # Returns nil when there are no violations
14
+ # Returns a Violation object otherwise
15
+ #
16
+ def audit(cfn_model)
17
+ logical_resource_ids = audit_impl(cfn_model)
18
+
19
+ if !logical_resource_ids.empty?
20
+ Violation.new(id: rule_id,
21
+ type: rule_type,
22
+ message: rule_text,
23
+ logical_resource_ids: logical_resource_ids)
24
+ else
25
+ nil
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,58 @@
1
+ # require 'cfn-nag/violation'
2
+ # require 'model/action_parser'
3
+ #
4
+ # class UnencryptedS3PutObjectAllowedRule
5
+ #
6
+ # def rule_text
7
+ # 'It appears that the S3 Bucket Policy allows s3:PutObject without server-side encryption'
8
+ # end
9
+ #
10
+ # def rule_type
11
+ # Violation::WARNING
12
+ # end
13
+ #
14
+ # def rule_id
15
+ # 'W1000'
16
+ # end
17
+ #
18
+ # def audit(cfn_model)
19
+ # logical_resource_ids = []
20
+ # cfn_model.bucket_policies.each do |bucket_policy|
21
+ # found_statement = bucket_policy.statements.find do |statement|
22
+ # blocks_put_object_without_encryption(statement)
23
+ # end
24
+ # if found_statement.nil?
25
+ # logical_resource_ids << bucket_policy.logical_resource_id
26
+ # end
27
+ # end
28
+ #
29
+ # if logical_resource_ids.size > 0
30
+ # Violation.new(id: rule_id,
31
+ # type: rule_type,
32
+ # message: rule_text,
33
+ # logical_resource_ids: logical_resource_ids)
34
+ # else
35
+ # nil
36
+ # end
37
+ # end
38
+ #
39
+ # private
40
+ #
41
+ # def blocks_put_object_without_encryption(statement)
42
+ # encryption_condition = {
43
+ # 'StringNotEquals' => {
44
+ # 's3:x-amz-server-side-encryption' => 'AES256'
45
+ # }
46
+ # }
47
+ #
48
+ # # this isn't quite complete. parsing the Resource field can be tricky
49
+ # # looking for a trailing wildcard will likely be right most of the time
50
+ # # but there are a lot of string manipulations to confuse things so...
51
+ # # just warn when we can't find at least the Deny+encryption - they may have an
52
+ # # incomplete Deny (for encryption) and that will slip through
53
+ # statement['Effect'] == 'Deny' and
54
+ # ActionParser.new.include?(actual_action: statement['Action'], action_to_look_for: 's3:PutObject') and
55
+ # S3BucketPolicy::condition_includes?(statement, encryption_condition) and
56
+ # statement['Principal'] == '*'
57
+ # end
58
+ # end
@@ -1,7 +1,6 @@
1
1
  require 'set'
2
2
 
3
3
  class Profile
4
-
5
4
  attr_reader :rule_ids
6
5
 
7
6
  def initialize
@@ -16,8 +16,8 @@ class ProfileLoader
16
16
 
17
17
  profile_definition.each_line do |line|
18
18
  rule_id = line.chomp
19
- if @rules_registry.by_id(rule_id) == []
20
- raise "#{rule_id} is not a legal rule identifier from: #{@rules_registry.rules}"
19
+ if @rules_registry.by_id(rule_id) == nil
20
+ raise "#{rule_id} is not a legal rule identifier from: #{@rules_registry.rules.map { |rule| rule.id }}"
21
21
  else
22
22
  new_profile.add_rule rule_id
23
23
  end
@@ -1,4 +1,4 @@
1
- require 'rule'
1
+ require 'cfn-nag/violation'
2
2
 
3
3
  class SimpleStdoutResults
4
4
 
@@ -11,11 +11,10 @@ class SimpleStdoutResults
11
11
  result[:file_results][:violations].each do |violation|
12
12
  message message_type: "#{violation.type} #{violation.id}",
13
13
  message: violation.message,
14
- logical_resource_ids: violation.logical_resource_ids,
15
- violating_code: violation.violating_code
14
+ logical_resource_ids: violation.logical_resource_ids
16
15
  end
17
- puts "\nFailures count: #{Rule::count_failures(result[:file_results][:violations])}"
18
- puts "Warnings count: #{Rule::count_warnings(result[:file_results][:violations])}"
16
+ puts "\nFailures count: #{Violation.count_failures(result[:file_results][:violations])}"
17
+ puts "Warnings count: #{Violation.count_warnings(result[:file_results][:violations])}"
19
18
  end
20
19
  end
21
20
 
@@ -23,8 +22,7 @@ class SimpleStdoutResults
23
22
 
24
23
  def message(message_type:,
25
24
  message:,
26
- logical_resource_ids: nil,
27
- violating_code: nil)
25
+ logical_resource_ids: nil)
28
26
 
29
27
  if logical_resource_ids == []
30
28
  logical_resource_ids = nil
@@ -37,11 +35,6 @@ class SimpleStdoutResults
37
35
  puts "| Resources: #{logical_resource_ids}" unless logical_resource_ids.nil?
38
36
  puts '|' unless logical_resource_ids.nil?
39
37
  puts "| #{message}"
40
-
41
- unless violating_code.nil?
42
- puts '|'
43
- puts indent_multiline_string_with_prefix('|', violating_code.to_s)
44
- end
45
38
  end
46
39
 
47
40
  def indent_multiline_string_with_prefix(prefix, multiline_string)
@@ -0,0 +1,36 @@
1
+ class RuleDefinition
2
+ WARNING = 'WARN'
3
+ FAILING_VIOLATION = 'FAIL'
4
+
5
+ attr_reader :id, :type, :message
6
+
7
+ def initialize(id:,
8
+ type:,
9
+ message:)
10
+ @id = id
11
+ @type = type
12
+ @message = message
13
+
14
+ [@id, @type, @message].each do |required|
15
+ if required.nil?
16
+ raise 'No parameters to Violation constructor can be nil'
17
+ end
18
+ end
19
+ end
20
+
21
+ def to_s
22
+ "#{@id} #{@type} #{@message}"
23
+ end
24
+
25
+ def to_h
26
+ {
27
+ id: @id,
28
+ type: @type,
29
+ message: @message
30
+ }
31
+ end
32
+
33
+ def ==(other_violation)
34
+ other_violation.class == self.class && other_violation.to_h == to_h
35
+ end
36
+ end