cfn-nag 0.7.15 → 0.8.2
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_rules +3 -3
- data/bin/spcm_scan +1 -1
- data/lib/cfn-nag/base_rule.rb +7 -1
- data/lib/cfn-nag/cfn_nag.rb +16 -20
- data/lib/cfn-nag/cfn_nag_config.rb +3 -3
- data/lib/cfn-nag/cfn_nag_executor.rb +7 -7
- data/lib/cfn-nag/cli_options.rb +19 -8
- data/lib/cfn-nag/custom_rules/AlexaASKSkillAuthenticationConfigurationClientSecretRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/AlexaASKSkillAuthenticationConfigurationRefreshTokenRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/AmazonMQBrokerUsersPasswordRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/AmplifyAppAccessTokenRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/AmplifyAppBasicAuthConfigPasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/AmplifyAppOauthTokenRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/AmplifyBranchBasicAuthConfigPasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/ApiGatewayAccessLoggingRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/ApiGatewayCacheEncryptedRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/ApiGatewayMethodAuthorizationTypeRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/AppStreamDirectoryConfigServiceAccountCredentialsAccountPasswordRule.rb +3 -3
- data/lib/cfn-nag/custom_rules/CodePipelineWebhookAuthenticationConfigurationSecretTokenRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/CognitoIdentityPoolAllowUnauthenticatedIdentitiesRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/DMSEndpointMongoDbSettingsPasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/DMSEndpointPasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/DirectoryServiceMicrosoftADPasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/DirectoryServiceSimpleADPasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/DocDBDBClusterMasterUserPasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/EC2NetworkAclEntryProtocolRule.rb +3 -7
- data/lib/cfn-nag/custom_rules/EKSClusterEncryptionRule.rb +1 -3
- data/lib/cfn-nag/custom_rules/EMRClusterKerberosAttributesADDomainJoinPasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/EMRClusterKerberosAttributesCrossRealmTrustPrincipalPasswordRule.rb +3 -3
- data/lib/cfn-nag/custom_rules/EMRClusterKerberosAttributesKdcAdminPasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/ElastiCacheReplicationGroupAuthTokenRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/GameLiftFleetInboundPortRangeRule.rb +2 -0
- data/lib/cfn-nag/custom_rules/IAMUserLoginProfilePasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/IamUserLoginProfilePasswordResetRule.rb +4 -6
- data/lib/cfn-nag/custom_rules/KMSKeyWildcardPrincipalRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/KinesisFirehoseDeliveryStreamRedshiftDestinationConfigurationPasswordRule.rb +3 -3
- data/lib/cfn-nag/custom_rules/KinesisFirehoseDeliveryStreamSplunkDestinationConfigurationHECTokenRule.rb +3 -3
- data/lib/cfn-nag/custom_rules/KinesisStreamStreamEncryptionRule.rb +3 -5
- data/lib/cfn-nag/custom_rules/LambdaPermissionEventSourceTokenRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/LambdaPermissionInvokeFunctionActionRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/ManagedBlockchainMemberMemberFabricConfigurationAdminPasswordRule.rb +4 -7
- data/lib/cfn-nag/custom_rules/OpsWorksAppAppSourcePasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/OpsWorksAppSslConfigurationPrivateKeyRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/OpsWorksStackCustomCookbooksSourcePasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/OpsWorksStackRdsDbInstancesDbPasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/PinpointAPNSChannelPrivateKeyRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/PinpointAPNSChannelTokenKeyRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/PinpointAPNSSandboxChannelPrivateKeyRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/PinpointAPNSSandboxChannelTokenKeyRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/PinpointAPNSVoipChannelPrivateKeyRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/PinpointAPNSVoipChannelTokenKeyRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/PinpointAPNSVoipSandboxChannelPrivateKeyRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/PinpointAPNSVoipSandboxChannelTokenKeyRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/RDSDBClusterMasterUserPasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/RDSDBInstanceMasterUserPasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/RDSDBInstanceMasterUsernameRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/RedshiftClusterMasterUserPasswordRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/ResourceWithExplicitNameRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/SecretsManagerSecretKmsKeyIdRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/SecurityGroupIngressOpenToWorldRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/SecurityGroupIngressPortRangeRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/SecurityGroupMissingEgressRule.rb +1 -1
- data/lib/cfn-nag/custom_rules/SecurityGroupRuleDescriptionRule.rb +2 -2
- data/lib/cfn-nag/custom_rules/base.rb +7 -1
- data/lib/cfn-nag/deny_list_loader.rb +43 -0
- data/lib/cfn-nag/iam_complexity_metric/spcm.rb +3 -3
- data/lib/cfn-nag/result_view/json_results.rb +1 -1
- data/lib/cfn-nag/result_view/sarif_results.rb +103 -0
- data/lib/cfn-nag/result_view/stdout_results.rb +1 -1
- data/lib/cfn-nag/rule_definition.rb +6 -3
- data/lib/cfn-nag/rule_registry.rb +1 -0
- data/lib/cfn-nag/util/enforce_reference_parameter.rb +1 -1
- data/lib/cfn-nag/version.rb +6 -0
- data/lib/cfn-nag/violation.rb +11 -0
- data/lib/cfn-nag/violation_filtering.rb +9 -9
- metadata +7 -5
- data/lib/cfn-nag/blacklist_loader.rb +0 -43
|
@@ -29,9 +29,7 @@ class IamUserLoginProfilePasswordResetRule < BaseRule
|
|
|
29
29
|
|
|
30
30
|
def iam_user_password_reset_required_key?(login_profile)
|
|
31
31
|
if login_profile.key? 'PasswordResetRequired'
|
|
32
|
-
if login_profile['PasswordResetRequired'].nil?
|
|
33
|
-
true
|
|
34
|
-
elsif not_truthy?(login_profile['PasswordResetRequired'])
|
|
32
|
+
if login_profile['PasswordResetRequired'].nil? || not_truthy?(login_profile['PasswordResetRequired'])
|
|
35
33
|
true
|
|
36
34
|
end
|
|
37
35
|
else
|
|
@@ -40,10 +38,10 @@ class IamUserLoginProfilePasswordResetRule < BaseRule
|
|
|
40
38
|
end
|
|
41
39
|
|
|
42
40
|
def violating_iam_users?(iam_user)
|
|
43
|
-
if
|
|
44
|
-
iam_user_password_reset_required_key?(iam_user.loginProfile)
|
|
45
|
-
else
|
|
41
|
+
if iam_user.loginProfile.nil?
|
|
46
42
|
false
|
|
43
|
+
else
|
|
44
|
+
iam_user_password_reset_required_key?(iam_user.loginProfile)
|
|
47
45
|
end
|
|
48
46
|
end
|
|
49
47
|
end
|
|
@@ -6,7 +6,7 @@ require_relative 'base'
|
|
|
6
6
|
class KMSKeyWildcardPrincipalRule < BaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'KMS key should not allow * principal ' \
|
|
9
|
-
|
|
9
|
+
'(https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html)'
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def rule_type
|
|
@@ -6,9 +6,9 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class KinesisFirehoseDeliveryStreamRedshiftDestinationConfigurationPasswordRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'Kinesis Firehose DeliveryStream RedshiftDestinationConfiguration Password ' \
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
'must not be a plaintext string or a Ref to a Parameter with a ' \
|
|
10
|
+
'Default value. ' \
|
|
11
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager/ssm-secure value.'
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def rule_type
|
|
@@ -6,9 +6,9 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class KinesisFirehoseDeliveryStreamSplunkDestinationConfigurationHECTokenRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'Kinesis Firehose DeliveryStream SplunkDestinationConfiguration HECToken ' \
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
'must not be a plaintext string or a Ref to a Parameter with a ' \
|
|
10
|
+
'Default value. ' \
|
|
11
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager value.'
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def rule_type
|
|
@@ -27,11 +27,9 @@ class KinesisStreamStreamEncryptionRule < BaseRule
|
|
|
27
27
|
private
|
|
28
28
|
|
|
29
29
|
def violating_kinesis_streams?(kinesis_stream)
|
|
30
|
-
if kinesis_stream.streamEncryption.nil?
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
true
|
|
34
|
-
elsif kinesis_stream.streamEncryption['KeyId'].nil?
|
|
30
|
+
if kinesis_stream.streamEncryption.nil? ||
|
|
31
|
+
kinesis_stream.streamEncryption['EncryptionType'].nil? ||
|
|
32
|
+
kinesis_stream.streamEncryption['KeyId'].nil?
|
|
35
33
|
true
|
|
36
34
|
else
|
|
37
35
|
kinesis_stream.streamEncryption['EncryptionType'] == 'NONE'
|
|
@@ -6,8 +6,8 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class LambdaPermissionEventSourceTokenRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'Lambda Permission EventSourceToken must not be a plaintext string ' \
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
data/lib/cfn-nag/custom_rules/ManagedBlockchainMemberMemberFabricConfigurationAdminPasswordRule.rb
CHANGED
|
@@ -8,7 +8,7 @@ require_relative 'base'
|
|
|
8
8
|
class ManagedBlockchainMemberMemberFabricConfigurationAdminPasswordRule < BaseRule
|
|
9
9
|
def rule_text
|
|
10
10
|
'ManagedBlockchain Member MemberFabricConfiguration AdminPasswordRule must ' \
|
|
11
|
-
|
|
11
|
+
'not be a plaintext string or a Ref to a NoEcho Parameter with a Default value.'
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def rule_type
|
|
@@ -42,14 +42,11 @@ class ManagedBlockchainMemberMemberFabricConfigurationAdminPasswordRule < BaseRu
|
|
|
42
42
|
# 'MemberFabricConfiguration'
|
|
43
43
|
# 'AdminPassword'
|
|
44
44
|
def password_property_does_not_exist(member)
|
|
45
|
-
if member.memberConfiguration['MemberFrameworkConfiguration'].nil?
|
|
46
|
-
|
|
47
|
-
elsif member.memberConfiguration['MemberFrameworkConfiguration']['MemberFabricConfiguration'].nil?
|
|
48
|
-
true
|
|
49
|
-
elsif member.memberConfiguration['MemberFrameworkConfiguration']['MemberFabricConfiguration']['AdminPassword'].nil?
|
|
45
|
+
if member.memberConfiguration['MemberFrameworkConfiguration'].nil? ||
|
|
46
|
+
member.memberConfiguration['MemberFrameworkConfiguration']['MemberFabricConfiguration'].nil?
|
|
50
47
|
true
|
|
51
48
|
else
|
|
52
|
-
|
|
49
|
+
member.memberConfiguration['MemberFrameworkConfiguration']['MemberFabricConfiguration']['AdminPassword'].nil?
|
|
53
50
|
end
|
|
54
51
|
end
|
|
55
52
|
end
|
|
@@ -6,8 +6,8 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class OpsWorksAppAppSourcePasswordRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'OpsWorks App AppSource Password must not be a plaintext ' \
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'string or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager/ssm-secure value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
|
@@ -6,8 +6,8 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class OpsWorksAppSslConfigurationPrivateKeyRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'OpsWorks App SslConfiguration PrivateKey must not be a plaintext ' \
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'string or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
|
@@ -6,8 +6,8 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class OpsWorksStackCustomCookbooksSourcePasswordRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'OpsWorks Stack CustomCookbooksSource Password must not be a plaintext ' \
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'string or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager/ssm-secure value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
|
@@ -6,8 +6,8 @@ require_relative 'sub_property_with_list_password_base_rule'
|
|
|
6
6
|
class OpsWorksStackRdsDbInstancesDbPasswordRule < SubPropertyWithListPasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'OpsWorks Stack RDS DbInstance DbPassword must not be a plaintext string '\
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager/ssm-secure value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
|
@@ -6,8 +6,8 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class PinpointAPNSChannelPrivateKeyRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'Pinpoint APNSChannel PrivateKey must not be a plaintext string ' \
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
|
@@ -6,8 +6,8 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class PinpointAPNSChannelTokenKeyRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'Pinpoint APNSChannel TokenKey must not be a plaintext string ' \
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
|
@@ -6,8 +6,8 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class PinpointAPNSSandboxChannelPrivateKeyRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'Pinpoint APNSSandboxChannel PrivateKey must not be a plaintext string ' \
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
|
@@ -6,8 +6,8 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class PinpointAPNSSandboxChannelTokenKeyRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'Pinpoint APNSSandboxChannel TokenKey must not be a plaintext string ' \
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
|
@@ -6,8 +6,8 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class PinpointAPNSVoipChannelPrivateKeyRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'Pinpoint APNSVoipChannel PrivateKey must not be a plaintext string ' \
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
|
@@ -6,8 +6,8 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class PinpointAPNSVoipChannelTokenKeyRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'Pinpoint APNSChannel TokenKey must not be a plaintext string ' \
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
|
@@ -6,8 +6,8 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class PinpointAPNSVoipSandboxChannelPrivateKeyRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'Pinpoint APNSVoipSandboxChannel PrivateKey must not be a plaintext ' \
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'string or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
|
@@ -6,8 +6,8 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class PinpointAPNSVoipSandboxChannelTokenKeyRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'Pinpoint APNSVoipSandboxChannel TokenKey must not be a plaintext string ' \
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
|
@@ -6,8 +6,8 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class RDSDBClusterMasterUserPasswordRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'RDS DB Cluster master user password must not be a plaintext string ' \
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager/ssm-secure value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
|
@@ -6,8 +6,8 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class RDSDBInstanceMasterUserPasswordRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'RDS instance master user password must not be a plaintext string ' \
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager/ssm-secure value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
|
@@ -7,8 +7,8 @@ require_relative 'password_base_rule'
|
|
|
7
7
|
class RDSDBInstanceMasterUsernameRule < PasswordBaseRule
|
|
8
8
|
def rule_text
|
|
9
9
|
'RDS instance master username must not be a plaintext string ' \
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
'or a Ref to a Parameter with a Default value. ' \
|
|
11
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager value.'
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def rule_type
|
|
@@ -6,8 +6,8 @@ require_relative 'password_base_rule'
|
|
|
6
6
|
class RedshiftClusterMasterUserPasswordRule < PasswordBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'Redshift Cluster master user password must not be a plaintext string ' \
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
'or a Ref to a Parameter with a Default value. ' \
|
|
10
|
+
'Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager/ssm-secure value.'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def rule_type
|
|
@@ -6,7 +6,7 @@ require_relative 'boolean_base_rule'
|
|
|
6
6
|
class SecretsManagerSecretKmsKeyIdRule < BooleanBaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'Secrets Manager Secret should explicitly specify KmsKeyId.' \
|
|
9
|
-
|
|
9
|
+
' Besides control of the key this will allow the secret to be shared cross-account'
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def rule_type
|
|
@@ -9,7 +9,7 @@ class SecurityGroupIngressOpenToWorldRule < BaseRule
|
|
|
9
9
|
|
|
10
10
|
def rule_text
|
|
11
11
|
'Security Groups found with cidr open to world on ingress. This should ' \
|
|
12
|
-
|
|
12
|
+
'never be true on instance. Permissible on ELB'
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def rule_type
|
|
@@ -6,7 +6,7 @@ require_relative 'base'
|
|
|
6
6
|
class SecurityGroupMissingEgressRule < BaseRule
|
|
7
7
|
def rule_text
|
|
8
8
|
'Missing egress rule means all traffic is allowed outbound. Make this ' \
|
|
9
|
-
|
|
9
|
+
'explicit if it is desired configuration'
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def rule_type
|
|
@@ -8,8 +8,8 @@ require 'cfn-nag/util/blank'
|
|
|
8
8
|
class SecurityGroupRuleDescriptionRule < BaseRule
|
|
9
9
|
def rule_text
|
|
10
10
|
'Security group rules without a description obscure their purpose and may '\
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
'lead to bad practices in ensuring they only allow traffic from the ports '\
|
|
12
|
+
'and sources/destinations required.'
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def rule_type
|
|
@@ -19,9 +19,15 @@ class BaseRule
|
|
|
19
19
|
logical_resource_ids = audit_impl(cfn_model)
|
|
20
20
|
return if logical_resource_ids.empty?
|
|
21
21
|
|
|
22
|
+
violation(logical_resource_ids)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def violation(logical_resource_ids, line_numbers = [])
|
|
22
26
|
Violation.new(id: rule_id,
|
|
27
|
+
name: self.class.name,
|
|
23
28
|
type: rule_type,
|
|
24
29
|
message: rule_text,
|
|
25
|
-
logical_resource_ids: logical_resource_ids
|
|
30
|
+
logical_resource_ids: logical_resource_ids,
|
|
31
|
+
line_numbers: line_numbers)
|
|
26
32
|
end
|
|
27
33
|
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
|
|
5
|
+
class DenyListLoader
|
|
6
|
+
def initialize(rules_registry)
|
|
7
|
+
@rules_registry = rules_registry
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def load(deny_list_definition:)
|
|
11
|
+
raise 'Empty profile' if deny_list_definition.strip == ''
|
|
12
|
+
|
|
13
|
+
deny_list_ruleset = RuleIdSet.new
|
|
14
|
+
|
|
15
|
+
deny_list_hash = load_deny_list_yaml(deny_list_definition)
|
|
16
|
+
raise 'Deny list is malformed' unless deny_list_hash.is_a? Hash
|
|
17
|
+
|
|
18
|
+
rules_to_suppress = deny_list_hash.fetch('RulesToSuppress', {})
|
|
19
|
+
raise 'Missing RulesToSuppress key in deny list' if rules_to_suppress.empty?
|
|
20
|
+
|
|
21
|
+
rule_ids_to_suppress = rules_to_suppress.map { |rule| rule['id'] }
|
|
22
|
+
rule_ids_to_suppress.each do |rule_id|
|
|
23
|
+
check_valid_rule_id rule_id
|
|
24
|
+
deny_list_ruleset.add_rule rule_id
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
deny_list_ruleset
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def load_deny_list_yaml(deny_list_definition)
|
|
33
|
+
YAML.safe_load(deny_list_definition)
|
|
34
|
+
rescue StandardError => yaml_parse_error
|
|
35
|
+
raise "YAML parse of deny list failed: #{yaml_parse_error}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def check_valid_rule_id(rule_id)
|
|
39
|
+
return true unless @rules_registry.by_id(rule_id).nil?
|
|
40
|
+
|
|
41
|
+
raise "#{rule_id} is not a legal rule identifier from: #{@rules_registry.ids}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -11,8 +11,8 @@ class SPCM
|
|
|
11
11
|
parameter_values_path: nil,
|
|
12
12
|
condition_values_path: nil,
|
|
13
13
|
template_pattern: DEFAULT_TEMPLATE_PATTERN)
|
|
14
|
-
parameter_values_string = parameter_values_path.nil? ? nil :
|
|
15
|
-
condition_values_string = condition_values_path.nil? ? nil :
|
|
14
|
+
parameter_values_string = parameter_values_path.nil? ? nil : File.read(parameter_values_path)
|
|
15
|
+
condition_values_string = condition_values_path.nil? ? nil : File.read(condition_values_path)
|
|
16
16
|
|
|
17
17
|
templates = TemplateDiscovery.new.discover_templates(input_json_path: input_path,
|
|
18
18
|
template_pattern: template_pattern)
|
|
@@ -21,7 +21,7 @@ class SPCM
|
|
|
21
21
|
aggregate_results << {
|
|
22
22
|
filename: template,
|
|
23
23
|
file_results: metric(
|
|
24
|
-
cloudformation_string:
|
|
24
|
+
cloudformation_string: File.read(template),
|
|
25
25
|
parameter_values_string: parameter_values_string,
|
|
26
26
|
condition_values_string: condition_values_string
|
|
27
27
|
)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'pathname'
|
|
5
|
+
|
|
6
|
+
class SarifResults
|
|
7
|
+
def render(results, rule_registry)
|
|
8
|
+
sarif_results = []
|
|
9
|
+
results.each do |file|
|
|
10
|
+
# For each file in the results, review the violations
|
|
11
|
+
file[:file_results][:violations].each do |violation|
|
|
12
|
+
# For each violation, generate a sarif result for each logical resource id in the violation
|
|
13
|
+
violation.logical_resource_ids.each_with_index do |_logical_resource_id, index|
|
|
14
|
+
sarif_results << sarif_result(file_name: file[:filename], violation: violation, index: index)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
sarif_report = {
|
|
20
|
+
version: '2.1.0',
|
|
21
|
+
'$schema': 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json',
|
|
22
|
+
runs: [
|
|
23
|
+
tool: {
|
|
24
|
+
driver: driver(rule_registry.rules)
|
|
25
|
+
},
|
|
26
|
+
results: sarif_results
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
puts JSON.pretty_generate(sarif_report)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Generates a SARIF driver object, which describes the tool and the rules used
|
|
34
|
+
def driver(rules)
|
|
35
|
+
{
|
|
36
|
+
name: 'cfn_nag',
|
|
37
|
+
informationUri: 'https://github.com/stelligent/cfn_nag',
|
|
38
|
+
semanticVersion: CfnNagVersion::VERSION,
|
|
39
|
+
rules: rules.map do |rule_definition|
|
|
40
|
+
{
|
|
41
|
+
id: "CFN_NAG_#{rule_definition.id}",
|
|
42
|
+
name: rule_definition.name,
|
|
43
|
+
fullDescription: {
|
|
44
|
+
text: rule_definition.message
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
end
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Given a cfn_nag Violation object, and index, generates a SARIF result object for the finding
|
|
52
|
+
def sarif_result(file_name:, violation:, index:)
|
|
53
|
+
{
|
|
54
|
+
ruleId: "CFN_NAG_#{violation.id}",
|
|
55
|
+
level: sarif_level(violation.type),
|
|
56
|
+
message: {
|
|
57
|
+
text: violation.message
|
|
58
|
+
},
|
|
59
|
+
locations: [
|
|
60
|
+
{
|
|
61
|
+
physicalLocation: {
|
|
62
|
+
artifactLocation: {
|
|
63
|
+
uri: relative_path(file_name),
|
|
64
|
+
uriBaseId: '%SRCROOT%'
|
|
65
|
+
},
|
|
66
|
+
region: {
|
|
67
|
+
startLine: sarif_line_number(violation.line_numbers[index])
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
logicalLocations: [
|
|
71
|
+
{
|
|
72
|
+
name: violation.logical_resource_ids[index]
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Line number defaults to 1 unless provided with valid number
|
|
81
|
+
def sarif_line_number(line_number)
|
|
82
|
+
line_number.nil? || line_number.to_i < 1 ? 1 : line_number.to_i
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def sarif_level(violation_type)
|
|
86
|
+
case violation_type
|
|
87
|
+
when RuleDefinition::WARNING
|
|
88
|
+
'warning'
|
|
89
|
+
else
|
|
90
|
+
'error'
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def relative_path(file_name)
|
|
95
|
+
file_pathname = Pathname.new(file_name)
|
|
96
|
+
|
|
97
|
+
if file_pathname.relative?
|
|
98
|
+
file_pathname.to_s
|
|
99
|
+
else
|
|
100
|
+
file_pathname.relative_path_from(Pathname.pwd).to_s
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -4,27 +4,30 @@ class RuleDefinition
|
|
|
4
4
|
WARNING = 'WARN'
|
|
5
5
|
FAILING_VIOLATION = 'FAIL'
|
|
6
6
|
|
|
7
|
-
attr_reader :id, :type, :message
|
|
7
|
+
attr_reader :id, :name, :type, :message
|
|
8
8
|
|
|
9
9
|
def initialize(id:,
|
|
10
|
+
name:,
|
|
10
11
|
type:,
|
|
11
12
|
message:)
|
|
12
13
|
@id = id
|
|
14
|
+
@name = name
|
|
13
15
|
@type = type
|
|
14
16
|
@message = message
|
|
15
17
|
|
|
16
|
-
[@id, @type, @message].each do |required|
|
|
18
|
+
[@id, @type, @name, @message].each do |required|
|
|
17
19
|
raise 'No parameters to Violation constructor can be nil' if required.nil?
|
|
18
20
|
end
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
def to_s
|
|
22
|
-
"#{@id} #{@type} #{@message}"
|
|
24
|
+
"#{@id} #{name} #{@type} #{@message}"
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
def to_h
|
|
26
28
|
{
|
|
27
29
|
id: @id,
|
|
30
|
+
name: @name,
|
|
28
31
|
type: @type,
|
|
29
32
|
message: @message
|
|
30
33
|
}
|