cfn-nag 0.6.9 → 0.6.14
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/lib/cfn-nag/cfn_nag.rb +1 -2
- data/lib/cfn-nag/cfn_nag_config.rb +2 -8
- data/lib/cfn-nag/custom_rule_loader.rb +1 -1
- data/lib/cfn-nag/custom_rules/DynamoDBBackupRule.rb +28 -0
- data/lib/cfn-nag/custom_rules/ECRRepositoryScanOnPushRule.rb +28 -0
- data/lib/cfn-nag/custom_rules/ElasticLoadBalancerV2AccessLoggingRule.rb +1 -2
- data/lib/cfn-nag/custom_rules/ElasticsearchDomainEncryptionAtRestOptionsRule.rb +0 -1
- data/lib/cfn-nag/custom_rules/IamRolePassRoleWildcardResourceRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/RDSInstanceDeletionProtectionRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/SPCMRule.rb +1 -0
- data/lib/cfn-nag/custom_rules/SecurityGroupEgressOpenToWorldRule.rb +8 -2
- data/lib/cfn-nag/custom_rules/SecurityGroupIngressCidrNon32Rule.rb +8 -2
- data/lib/cfn-nag/custom_rules/SecurityGroupIngressOpenToWorldRule.rb +8 -2
- data/lib/cfn-nag/custom_rules/SecurityGroupRuleDescriptionRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/boolean_base_rule.rb +1 -1
- data/lib/cfn-nag/custom_rules/passrole_base_rule.rb +1 -1
- data/lib/cfn-nag/iam_complexity_metric/condition_metric.rb +3 -2
- data/lib/cfn-nag/ip_addr.rb +3 -2
- data/lib/cfn-nag/metadata.rb +2 -2
- data/lib/cfn-nag/result_view/stdout_results.rb +2 -2
- data/lib/cfn-nag/rule_repos/gem_based_rule_repo.rb +1 -1
- data/lib/cfn-nag/rule_repository_loader.rb +1 -1
- data/lib/cfn-nag/util/enforce_reference_parameter.rb +1 -1
- data/lib/cfn-nag/util/enforce_string_or_dynamic_reference.rb +5 -6
- metadata +8 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 834f2a3fa72ba8263f6c1c6602da439ffd63f2e5dbdff3c5ca7828d08e805e7b
|
4
|
+
data.tar.gz: 805de39301a8a7972ceb6acb27911e0e551d3cd236501d54608af9ec84210ddb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45a8a649e813676a3299a69292981065b3f41b0aed19377b4c84b20876aa6f84e0473721967d4c689207b90ba5c51d70816e9226af89962409c4dad960de8227
|
7
|
+
data.tar.gz: 86c3bd27996e14a73a26a4e5fb8bb16360da8caf9a320c00517a61ba42eff7ce257643a7e7ed86a3661ea7c406604484ef915198e40d57b0031150d490e6fa6c
|
data/lib/cfn-nag/cfn_nag.rb
CHANGED
@@ -135,12 +135,11 @@ class CfnNag
|
|
135
135
|
)
|
136
136
|
|
137
137
|
# this must come after - blacklist should always win
|
138
|
-
|
138
|
+
filter_violations_by_blacklist(
|
139
139
|
blacklist_definition: @config.blacklist_definition,
|
140
140
|
rule_definitions: @config.custom_rule_loader.rule_definitions,
|
141
141
|
violations: violations
|
142
142
|
)
|
143
|
-
violations
|
144
143
|
rescue StandardError => blacklist_or_profile_parse_error
|
145
144
|
violations << fatal_violation(blacklist_or_profile_parse_error.to_s)
|
146
145
|
violations
|
@@ -29,12 +29,6 @@ class CfnNagConfig
|
|
29
29
|
end
|
30
30
|
# rubocop:enable Metrics/ParameterLists
|
31
31
|
|
32
|
-
attr_reader :rule_arguments
|
33
|
-
|
34
|
-
attr_reader :custom_rule_loader
|
35
|
-
attr_reader :profile_definition
|
36
|
-
attr_reader :blacklist_definition
|
37
|
-
attr_reader :fail_on_warnings
|
38
|
-
attr_reader :rule_repositories
|
39
|
-
attr_reader :ignore_fatal
|
32
|
+
attr_reader :rule_arguments, :rule_directory, :custom_rule_loader, :profile_definition, :blacklist_definition, \
|
33
|
+
:fail_on_warnings, :rule_repositories, :ignore_fatal
|
40
34
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cfn-nag/violation'
|
4
|
+
require 'cfn-nag/util/truthy'
|
5
|
+
require_relative 'base'
|
6
|
+
|
7
|
+
class DynamoDBBackupRule < BaseRule
|
8
|
+
def rule_text
|
9
|
+
'DynamoDB table should have backup enabled, should be set using PointInTimeRecoveryEnabled'
|
10
|
+
end
|
11
|
+
|
12
|
+
def rule_type
|
13
|
+
Violation::WARNING
|
14
|
+
end
|
15
|
+
|
16
|
+
def rule_id
|
17
|
+
'W78'
|
18
|
+
end
|
19
|
+
|
20
|
+
def audit_impl(cfn_model)
|
21
|
+
violating_ddb_tables = cfn_model.resources_by_type('AWS::DynamoDB::Table').select do |table|
|
22
|
+
table.pointInTimeRecoverySpecification.nil? ||
|
23
|
+
!truthy?(table.pointInTimeRecoverySpecification['PointInTimeRecoveryEnabled'].to_s)
|
24
|
+
end
|
25
|
+
|
26
|
+
violating_ddb_tables.map(&:logical_resource_id)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cfn-nag/violation'
|
4
|
+
require 'cfn-nag/util/truthy'
|
5
|
+
require_relative 'base'
|
6
|
+
|
7
|
+
class ECRRepositoryScanOnPushRule < BaseRule
|
8
|
+
def rule_text
|
9
|
+
'ECR Repository should have scanOnPush enabled'
|
10
|
+
end
|
11
|
+
|
12
|
+
def rule_type
|
13
|
+
Violation::WARNING
|
14
|
+
end
|
15
|
+
|
16
|
+
def rule_id
|
17
|
+
'W79'
|
18
|
+
end
|
19
|
+
|
20
|
+
def audit_impl(cfn_model)
|
21
|
+
violating_ecr_registries = cfn_model.resources_by_type('AWS::ECR::Repository').select do |registry|
|
22
|
+
registry.imageScanningConfiguration.nil? ||
|
23
|
+
!truthy?(registry.imageScanningConfiguration['scanOnPush'].to_s)
|
24
|
+
end
|
25
|
+
|
26
|
+
violating_ecr_registries.map(&:logical_resource_id)
|
27
|
+
end
|
28
|
+
end
|
@@ -29,10 +29,9 @@ class ElasticLoadBalancerV2AccessLoggingRule < BaseRule
|
|
29
29
|
private
|
30
30
|
|
31
31
|
def access_logging_is_false?(load_balancer)
|
32
|
-
|
32
|
+
load_balancer.loadBalancerAttributes.find do |load_balancer_attribute|
|
33
33
|
load_balancer_attribute['Key'] == 'access_logs.s3.enabled' && not_truthy?(load_balancer_attribute['Value'])
|
34
34
|
end
|
35
|
-
false_access_log_attribute
|
36
35
|
end
|
37
36
|
|
38
37
|
def missing_access_logs?(load_balancer)
|
@@ -5,7 +5,7 @@ require_relative 'base'
|
|
5
5
|
require 'cfn-nag/util/wildcard_patterns'
|
6
6
|
|
7
7
|
class IamRolePassRoleWildcardResourceRule < BaseRule
|
8
|
-
IAM_ACTION_PATTERNS = wildcard_patterns('PassRole').map! { |x|
|
8
|
+
IAM_ACTION_PATTERNS = wildcard_patterns('PassRole').map! { |x| "iam:#{x}" } + ['*']
|
9
9
|
|
10
10
|
def rule_text
|
11
11
|
'IAM role should not allow * resource with PassRole action on its permissions policy'
|
@@ -25,16 +25,22 @@ class SecurityGroupEgressOpenToWorldRule < BaseRule
|
|
25
25
|
def audit_impl(cfn_model)
|
26
26
|
violating_security_groups = cfn_model.security_groups.select do |security_group|
|
27
27
|
violating_egresses = security_group.egresses.select do |egress|
|
28
|
-
|
28
|
+
violating_egress(egress)
|
29
29
|
end
|
30
30
|
|
31
31
|
!violating_egresses.empty?
|
32
32
|
end
|
33
33
|
|
34
34
|
violating_egresses = cfn_model.standalone_egress.select do |standalone_egress|
|
35
|
-
|
35
|
+
violating_egress(standalone_egress)
|
36
36
|
end
|
37
37
|
|
38
38
|
violating_security_groups.map(&:logical_resource_id) + violating_egresses.map(&:logical_resource_id)
|
39
39
|
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def violating_egress(egress)
|
44
|
+
ip4_open?(egress) || ip6_open?(egress)
|
45
|
+
end
|
40
46
|
end
|
@@ -25,16 +25,22 @@ class SecurityGroupIngressCidrNon32Rule < BaseRule
|
|
25
25
|
def audit_impl(cfn_model)
|
26
26
|
violating_security_groups = cfn_model.security_groups.select do |security_group|
|
27
27
|
violating_ingresses = security_group.ingresses.select do |ingress|
|
28
|
-
|
28
|
+
violating_ingress(ingress)
|
29
29
|
end
|
30
30
|
|
31
31
|
!violating_ingresses.empty?
|
32
32
|
end
|
33
33
|
|
34
34
|
violating_ingresses = cfn_model.standalone_ingress.select do |standalone_ingress|
|
35
|
-
|
35
|
+
violating_ingress(standalone_ingress)
|
36
36
|
end
|
37
37
|
|
38
38
|
violating_security_groups.map(&:logical_resource_id) + violating_ingresses.map(&:logical_resource_id)
|
39
39
|
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def violating_ingress(ingress)
|
44
|
+
ip4_cidr_range?(ingress) || ip6_cidr_range?(ingress)
|
45
|
+
end
|
40
46
|
end
|
@@ -26,16 +26,22 @@ class SecurityGroupIngressOpenToWorldRule < BaseRule
|
|
26
26
|
def audit_impl(cfn_model)
|
27
27
|
violating_security_groups = cfn_model.security_groups.select do |security_group|
|
28
28
|
violating_ingresses = security_group.ingresses.select do |ingress|
|
29
|
-
|
29
|
+
violating_ingress(ingress)
|
30
30
|
end
|
31
31
|
|
32
32
|
!violating_ingresses.empty?
|
33
33
|
end
|
34
34
|
|
35
35
|
violating_ingresses = cfn_model.standalone_ingress.select do |standalone_ingress|
|
36
|
-
|
36
|
+
violating_ingress(standalone_ingress)
|
37
37
|
end
|
38
38
|
|
39
39
|
violating_security_groups.map(&:logical_resource_id) + violating_ingresses.map(&:logical_resource_id)
|
40
40
|
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def violating_ingress(ingress)
|
45
|
+
ip4_open?(ingress) || ip6_open?(ingress)
|
46
|
+
end
|
41
47
|
end
|
@@ -5,7 +5,7 @@ require_relative 'base'
|
|
5
5
|
require 'cfn-nag/util/wildcard_patterns'
|
6
6
|
|
7
7
|
class PassRoleBaseRule < BaseRule
|
8
|
-
IAM_ACTION_PATTERNS = wildcard_patterns('PassRole').map { |pattern|
|
8
|
+
IAM_ACTION_PATTERNS = wildcard_patterns('PassRole').map { |pattern| "iam:#{pattern}" } + ['*']
|
9
9
|
|
10
10
|
def policy_type
|
11
11
|
raise 'must implement in subclass'
|
@@ -41,9 +41,10 @@ class ConditionMetric
|
|
41
41
|
result = []
|
42
42
|
conditions.each do |_, expression|
|
43
43
|
expression.each do |_, value|
|
44
|
-
|
44
|
+
case value
|
45
|
+
when String
|
45
46
|
result << value
|
46
|
-
|
47
|
+
when Array
|
47
48
|
result += value
|
48
49
|
end
|
49
50
|
end
|
data/lib/cfn-nag/ip_addr.rb
CHANGED
@@ -47,9 +47,10 @@ module IpAddr
|
|
47
47
|
# anything with it
|
48
48
|
#
|
49
49
|
def normalize_cidr_ip6(ingress)
|
50
|
-
|
50
|
+
case ingress.cidrIpv6
|
51
|
+
when Symbol
|
51
52
|
":#{ingress.cidrIpv6}"
|
52
|
-
|
53
|
+
when String
|
53
54
|
ingress.cidrIpv6
|
54
55
|
end
|
55
56
|
end
|
data/lib/cfn-nag/metadata.rb
CHANGED
@@ -13,7 +13,7 @@ module Metadata
|
|
13
13
|
logical_resource_id = mangled_metadata.first
|
14
14
|
mangled_rules = mangled_metadata[1]
|
15
15
|
|
16
|
-
|
16
|
+
$stderr.puts "#{logical_resource_id} has missing cfn_nag suppression rule id: #{mangled_rules}"
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
@@ -46,7 +46,7 @@ module Metadata
|
|
46
46
|
end
|
47
47
|
if found_suppression_rule && print_suppression
|
48
48
|
message = "Suppressing #{rule_id} on #{logical_resource_id} for reason: #{found_suppression_rule['reason']}"
|
49
|
-
|
49
|
+
$stderr.puts message
|
50
50
|
end
|
51
51
|
!found_suppression_rule.nil?
|
52
52
|
end
|
@@ -27,7 +27,7 @@ class StdoutResults
|
|
27
27
|
def render(results)
|
28
28
|
results.each do |result|
|
29
29
|
60.times { print '-' }
|
30
|
-
puts "\n
|
30
|
+
puts "\n#{result[:filename]}"
|
31
31
|
60.times { print '-' }
|
32
32
|
|
33
33
|
violations = result[:file_results][:violations]
|
@@ -45,6 +45,6 @@ class StdoutResults
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def indent_multiline_string_with_prefix(prefix, multiline_string)
|
48
|
-
prefix
|
48
|
+
"#{prefix} #{multiline_string.gsub(/\n/, "\n#{prefix} ")}"
|
49
49
|
end
|
50
50
|
end
|
@@ -53,7 +53,7 @@ class GemBasedRuleRepo
|
|
53
53
|
require rule_gem_name
|
54
54
|
true
|
55
55
|
rescue LoadError
|
56
|
-
|
56
|
+
$stderr.puts "Could not require #{rule_gem_name} - does the rule gem have a top level entry point?"
|
57
57
|
false
|
58
58
|
end
|
59
59
|
|
@@ -33,7 +33,7 @@ class RuleRepositoryLoader
|
|
33
33
|
end
|
34
34
|
|
35
35
|
repo_class = class_from_name(rule_repository_definition['repo_class_name'])
|
36
|
-
if rule_repository_definition['repo_arguments']
|
36
|
+
if rule_repository_definition['repo_arguments'].is_a?(Hash)
|
37
37
|
repo_class.new(**to_sym_keys(rule_repository_definition['repo_arguments']))
|
38
38
|
else
|
39
39
|
repo_class.new
|
@@ -9,17 +9,16 @@ def insecure_string_or_dynamic_reference?(_cfn_model, key_to_check)
|
|
9
9
|
|
10
10
|
# Check if string starts with a Dynamic Reference pointing to SecretsManager
|
11
11
|
# or SSM Secure
|
12
|
+
# &&
|
13
|
+
# Verify that the secure string ends properly with the double curly braces
|
12
14
|
if key_to_check.start_with?(
|
13
15
|
'{{resolve:secretsmanager:',
|
14
16
|
'{{resolve:ssm-secure:'
|
15
|
-
)
|
16
|
-
|
17
|
-
if key_to_check.end_with? '}}'
|
18
|
-
return false
|
19
|
-
end
|
17
|
+
) && key_to_check.end_with?('}}')
|
18
|
+
return false
|
20
19
|
end
|
21
20
|
|
22
|
-
#
|
21
|
+
# Return true if key_to_check is a string and is not calling a secured
|
23
22
|
# dynamic reference pattern (Secrets Manager or SSM-Secure)
|
24
23
|
true
|
25
24
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cfn-nag
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Kascic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -72,14 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - '='
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 0.5.
|
75
|
+
version: 0.5.4
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - '='
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 0.5.
|
82
|
+
version: 0.5.4
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: logging
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -203,6 +203,7 @@ files:
|
|
203
203
|
- lib/cfn-nag/custom_rules/DirectoryServiceMicrosoftADPasswordRule.rb
|
204
204
|
- lib/cfn-nag/custom_rules/DirectoryServiceSimpleADPasswordRule.rb
|
205
205
|
- lib/cfn-nag/custom_rules/DocDBDBClusterMasterUserPasswordRule.rb
|
206
|
+
- lib/cfn-nag/custom_rules/DynamoDBBackupRule.rb
|
206
207
|
- lib/cfn-nag/custom_rules/DynamoDBBillingModeRule.rb
|
207
208
|
- lib/cfn-nag/custom_rules/DynamoDBEncryptionRule.rb
|
208
209
|
- lib/cfn-nag/custom_rules/EC2NetworkAclEntryDuplicateRule.rb
|
@@ -211,6 +212,7 @@ files:
|
|
211
212
|
- lib/cfn-nag/custom_rules/EC2NetworkAclEntryPortRangeRule.rb
|
212
213
|
- lib/cfn-nag/custom_rules/EC2NetworkAclEntryProtocolRule.rb
|
213
214
|
- lib/cfn-nag/custom_rules/EC2SubnetMapPublicIpOnLaunchRule.rb
|
215
|
+
- lib/cfn-nag/custom_rules/ECRRepositoryScanOnPushRule.rb
|
214
216
|
- lib/cfn-nag/custom_rules/EFSFileSystemEncryptedRule.rb
|
215
217
|
- lib/cfn-nag/custom_rules/EMRClusterKerberosAttributesADDomainJoinPasswordRule.rb
|
216
218
|
- lib/cfn-nag/custom_rules/EMRClusterKerberosAttributesCrossRealmTrustPrincipalPasswordRule.rb
|
@@ -381,7 +383,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
381
383
|
- !ruby/object:Gem::Version
|
382
384
|
version: '0'
|
383
385
|
requirements: []
|
384
|
-
|
386
|
+
rubyforge_project:
|
387
|
+
rubygems_version: 2.7.6
|
385
388
|
signing_key:
|
386
389
|
specification_version: 4
|
387
390
|
summary: cfn-nag
|