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,24 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class PolicyOnUserRule < BaseRule
5
+ def rule_text
6
+ 'IAM policy should not apply directly to users. Should be on group'
7
+ end
8
+
9
+ def rule_type
10
+ Violation::FAILING_VIOLATION
11
+ end
12
+
13
+ def rule_id
14
+ 'F11'
15
+ end
16
+
17
+ def audit_impl(cfn_model)
18
+ violating_policies = cfn_model.resources_by_type('AWS::IAM::Policy').select do |policy|
19
+ policy.users.size > 0
20
+ end
21
+
22
+ violating_policies.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 S3BucketPolicyNotActionRule < BaseRule
5
+
6
+ def rule_text
7
+ 'S3 Bucket policy should not allow Allow+NotAction'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::WARNING
12
+ end
13
+
14
+ def rule_id
15
+ 'W20'
16
+ end
17
+
18
+ def audit_impl(cfn_model)
19
+ violating_policies = cfn_model.resources_by_type('AWS::S3::BucketPolicy').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 S3BucketPolicyNotPrincipalRule < BaseRule
5
+
6
+ def rule_text
7
+ 'S3 Bucket 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
+ 'F9'
16
+ end
17
+
18
+ def audit_impl(cfn_model)
19
+ violating_policies = cfn_model.resources_by_type('AWS::S3::BucketPolicy').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 S3BucketPolicyWildcardActionRule < BaseRule
5
+
6
+ def rule_text
7
+ 'S3 Bucket policy should not allow * action'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::FAILING_VIOLATION
12
+ end
13
+
14
+ def rule_id
15
+ 'F15'
16
+ end
17
+
18
+ def audit_impl(cfn_model)
19
+ logical_resource_ids = []
20
+
21
+ cfn_model.resources_by_type('AWS::S3::BucketPolicy').each do |bucket_policy|
22
+
23
+ if !bucket_policy.policyDocument.wildcard_allowed_actions.empty?
24
+ logical_resource_ids << bucket_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 S3BucketPolicyWildcardPrincipalRule < BaseRule
5
+
6
+ def rule_text
7
+ 'S3 Bucket policy should not allow * principal'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::FAILING_VIOLATION
12
+ end
13
+
14
+ def rule_id
15
+ 'F16'
16
+ end
17
+
18
+ def audit_impl(cfn_model)
19
+ logical_resource_ids = []
20
+
21
+ cfn_model.resources_by_type('AWS::S3::BucketPolicy').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,29 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class S3BucketPublicReadAclRule < BaseRule
5
+
6
+ def rule_text
7
+ 'S3 Bucket likely should not have a public read acl'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::WARNING
12
+ end
13
+
14
+ def rule_id
15
+ 'W31'
16
+ end
17
+
18
+ def audit_impl(cfn_model)
19
+ logical_resource_ids = []
20
+
21
+ cfn_model.resources_by_type('AWS::S3::Bucket').each do |bucket|
22
+ if bucket.accessControl == 'PublicRead'
23
+ logical_resource_ids << bucket.logical_resource_id
24
+ end
25
+ end
26
+
27
+ logical_resource_ids
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class S3BucketPublicReadWriteAclRule < BaseRule
5
+
6
+ def rule_text
7
+ 'S3 Bucket should not have a public read-write acl'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::FAILING_VIOLATION
12
+ end
13
+
14
+ def rule_id
15
+ 'F14'
16
+ end
17
+
18
+ def audit_impl(cfn_model)
19
+ logical_resource_ids = []
20
+
21
+ cfn_model.resources_by_type('AWS::S3::Bucket').each do |bucket|
22
+ if bucket.accessControl == 'PublicReadWrite'
23
+ logical_resource_ids << bucket.logical_resource_id
24
+ end
25
+ end
26
+
27
+ logical_resource_ids
28
+ end
29
+ end
@@ -0,0 +1,39 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class SecurityGroupEgressOpenToWorldRule < BaseRule
5
+
6
+ def rule_text
7
+ 'Security Groups found with cidr open to world on egress'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::WARNING
12
+ end
13
+
14
+ def rule_id
15
+ 'W5'
16
+ end
17
+
18
+ ##
19
+ # This will behave slightly different than the legacy jq based rule which was targeted against inline ingress only
20
+ def audit_impl(cfn_model)
21
+ logical_resource_ids = []
22
+ cfn_model.security_groups.each do |security_group|
23
+ violating_egresses = security_group.securityGroupEgress.select do |egress|
24
+ # only care about literals. if a Hash/Ref not going to chase it down given likely a Parameter with external val
25
+ egress.cidrIp.is_a?(String) && egress.cidrIp == '0.0.0.0/0'
26
+ end
27
+
28
+ unless violating_egresses.empty?
29
+ logical_resource_ids << security_group.logical_resource_id
30
+ end
31
+ end
32
+
33
+ violating_egresses = cfn_model.standalone_egress.select do |standalone_egress|
34
+ standalone_egress.cidrIp.is_a?(String) && standalone_egress.cidrIp == '0.0.0.0/0'
35
+ end
36
+
37
+ logical_resource_ids + violating_egresses.map { |egress| egress.logical_resource_id}
38
+ end
39
+ end
@@ -0,0 +1,38 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class SecurityGroupEgressPortRangeRule < BaseRule
5
+
6
+ def rule_text
7
+ 'Security Groups found egress with port range instead of just a single port'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::WARNING
12
+ end
13
+
14
+ def rule_id
15
+ 'W29'
16
+ end
17
+
18
+ ##
19
+ # This will behave slightly different than the legacy jq based rule which was targeted against inline ingress only
20
+ def audit_impl(cfn_model)
21
+ logical_resource_ids = []
22
+ cfn_model.security_groups.each do |security_group|
23
+ violating_egresses = security_group.securityGroupEgress.select do |egress|
24
+ egress.fromPort != egress.toPort
25
+ end
26
+
27
+ unless violating_egresses.empty?
28
+ logical_resource_ids << security_group.logical_resource_id
29
+ end
30
+ end
31
+
32
+ violating_egresses = cfn_model.standalone_egress.select do |standalone_egress|
33
+ standalone_egress.fromPort != standalone_egress.toPort
34
+ end
35
+
36
+ logical_resource_ids + violating_egresses.map { |egress| egress.logical_resource_id}
37
+ end
38
+ end
@@ -0,0 +1,40 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class SecurityGroupIngressCidrNon32Rule < BaseRule
5
+
6
+ def rule_text
7
+ 'Security Groups found with ingress cidr that is not /32'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::WARNING
12
+ end
13
+
14
+ def rule_id
15
+ 'W9'
16
+ end
17
+
18
+ ##
19
+ # This will behave slightly different than the legacy jq based rule which was targeted against inline ingress only
20
+ def audit_impl(cfn_model)
21
+ logical_resource_ids = []
22
+ cfn_model.security_groups.each do |security_group|
23
+ violating_ingresses = security_group.securityGroupIngress.select do |ingress|
24
+ # only care about literals. if a Hash/Ref not going to chase it down given likely a Parameter with external val
25
+ ingress.cidrIp.is_a?(String) && !ingress.cidrIp.end_with?('/32')
26
+ end
27
+
28
+ unless violating_ingresses.empty?
29
+ logical_resource_ids << security_group.logical_resource_id
30
+ end
31
+ end
32
+
33
+ violating_ingresses = cfn_model.standalone_ingress.select do |standalone_ingress|
34
+ standalone_ingress.cidrIp.is_a?(String) && !standalone_ingress.cidrIp.end_with?('/32')
35
+ end
36
+
37
+ logical_resource_ids + violating_ingresses.map { |ingress| ingress.logical_resource_id}
38
+ end
39
+ end
40
+
@@ -0,0 +1,39 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class SecurityGroupIngressOpenToWorldRule < BaseRule
5
+
6
+ def rule_text
7
+ 'Security Groups found with cidr open to world on ingress. This should never be true on instance. Permissible on ELB'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::WARNING
12
+ end
13
+
14
+ def rule_id
15
+ 'W2'
16
+ end
17
+
18
+ ##
19
+ # This will behave slightly different than the legacy jq based rule which was targeted against inline ingress only
20
+ def audit_impl(cfn_model)
21
+ logical_resource_ids = []
22
+ cfn_model.security_groups.each do |security_group|
23
+ violating_ingresses = security_group.securityGroupIngress.select do |ingress|
24
+ # only care about literals. if a Hash/Ref not going to chase it down given likely a Parameter with external val
25
+ ingress.cidrIp.is_a?(String) && ingress.cidrIp == '0.0.0.0/0'
26
+ end
27
+
28
+ unless violating_ingresses.empty?
29
+ logical_resource_ids << security_group.logical_resource_id
30
+ end
31
+ end
32
+
33
+ violating_ingresses = cfn_model.standalone_ingress.select do |standalone_ingress|
34
+ standalone_ingress.cidrIp.is_a?(String) && standalone_ingress.cidrIp == '0.0.0.0/0'
35
+ end
36
+
37
+ logical_resource_ids + violating_ingresses.map { |ingress| ingress.logical_resource_id}
38
+ end
39
+ end
@@ -0,0 +1,38 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class SecurityGroupIngressPortRangeRule < BaseRule
5
+
6
+ def rule_text
7
+ 'Security Groups found ingress with port range instead of just a single port'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::WARNING
12
+ end
13
+
14
+ def rule_id
15
+ 'W27'
16
+ end
17
+
18
+ ##
19
+ # This will behave slightly different than the legacy jq based rule which was targeted against inline ingress only
20
+ def audit_impl(cfn_model)
21
+ logical_resource_ids = []
22
+ cfn_model.security_groups.each do |security_group|
23
+ violating_ingresses = security_group.securityGroupIngress.select do |ingress|
24
+ ingress.fromPort != ingress.toPort
25
+ end
26
+
27
+ unless violating_ingresses.empty?
28
+ logical_resource_ids << security_group.logical_resource_id
29
+ end
30
+ end
31
+
32
+ violating_ingresses = cfn_model.standalone_ingress.select do |standalone_ingress|
33
+ standalone_ingress.fromPort != standalone_ingress.toPort
34
+ end
35
+
36
+ logical_resource_ids + violating_ingresses.map { |ingress| ingress.logical_resource_id}
37
+ end
38
+ end
@@ -1,6 +1,7 @@
1
- require_relative '../violation'
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
2
3
 
3
- class SecurityGroupMissingEgressRule
4
+ class SecurityGroupMissingEgressRule < BaseRule
4
5
 
5
6
  def rule_text
6
7
  'Missing egress rule means all traffic is allowed outbound. Make this explicit if it is desired configuration'
@@ -14,21 +15,14 @@ class SecurityGroupMissingEgressRule
14
15
  'F1000'
15
16
  end
16
17
 
17
- def audit(cfn_model)
18
+ def audit_impl(cfn_model)
18
19
  logical_resource_ids = []
19
20
  cfn_model.security_groups.each do |security_group|
20
- if security_group.egress_rules.size == 0
21
+ if security_group.securityGroupEgress.empty?
21
22
  logical_resource_ids << security_group.logical_resource_id
22
23
  end
23
24
  end
24
25
 
25
- if logical_resource_ids.size > 0
26
- Violation.new(id: rule_id,
27
- type: rule_type,
28
- message: rule_text,
29
- logical_resource_ids: logical_resource_ids)
30
- else
31
- nil
32
- end
26
+ logical_resource_ids
33
27
  end
34
28
  end
@@ -0,0 +1,25 @@
1
+ require 'cfn-nag/violation'
2
+ require_relative 'base'
3
+
4
+ class SnsTopicPolicyNotActionRule < BaseRule
5
+
6
+ def rule_text
7
+ 'SNS Topic policy should not allow Allow+NotAction'
8
+ end
9
+
10
+ def rule_type
11
+ Violation::WARNING
12
+ end
13
+
14
+ def rule_id
15
+ 'W19'
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_action.empty?
21
+ end
22
+
23
+ violating_policies.map { |policy| policy.logical_resource_id }
24
+ end
25
+ end