Repository: bridgecrewio/checkov

Issue:
CloudFormation: S3 default encryption check should look for ServerSideEncryptionByDefault
The CloudFormation check for CKV_AWS_19 only looks for `ServerSideEncryptionRule`, not `ServerSideEncryptionByDefault`:

https://github.com/bridgecrewio/checkov/blob/864d12ad0dfc6ca898dbacf7dc16fdc20f702733/checkov/cloudformation/checks/resource/aws/S3Encryption.py

The syntax used in the S3 template does not appear to be used anywhere else in GitHub:

https://github.com/bridgecrewio/checkov/blob/864d12ad0dfc6ca898dbacf7dc16fdc20f702733/tests/cloudformation/checks/resource/aws/S3Templates/ExampleS3.yaml#L13 

All of the working CloudFormation templates which I've seen look like this:

https://github.com/cloudconformity/documentation-api/blob/cba56c057d42c19db606f7d72ca197ee52d97848/examples/cloudformation-snippets/S3Bucket.yml#L8-L11

Checkov version: 1.0.312

Discussion:

Patch:
diff --git a/checkov/cloudformation/checks/resource/aws/S3Encryption.py b/checkov/cloudformation/checks/resource/aws/S3Encryption.py
index 511a8f760..f9562a8f0 100644
--- a/checkov/cloudformation/checks/resource/aws/S3Encryption.py
+++ b/checkov/cloudformation/checks/resource/aws/S3Encryption.py
@@ -11,8 +11,11 @@ class S3Encryption(BaseResourceCheck):
         super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)
 
     def scan_resource_conf(self, conf):
-        if conf.get('Properties') and conf['Properties'].get('ServerSideEncryptionRule'):
-            return CheckResult.PASSED
+        if conf.get('Properties'):
+            if conf['Properties'].get('ServerSideEncryptionRule') or \
+                (conf['Properties'].get('BucketEncryption') and
+                 len(conf['Properties']['BucketEncryption'].get('ServerSideEncryptionConfiguration', [])) > 0):
+                return CheckResult.PASSED
         return CheckResult.FAILED
 
 


Test patch:
diff --git a/tests/cloudformation/checks/resource/aws/S3Templates/ExampleS3.yaml b/tests/cloudformation/checks/resource/aws/S3Templates/ExampleS3.yaml
index 9ee8427c5..850bc2bf8 100644
--- a/tests/cloudformation/checks/resource/aws/S3Templates/ExampleS3.yaml
+++ b/tests/cloudformation/checks/resource/aws/S3Templates/ExampleS3.yaml
@@ -6,6 +6,10 @@ Resources:
     Type: AWS::S3::Bucket
     Properties:
       AccessControl: PublicRead
+      BucketEncryption:
+        ServerSideEncryptionConfiguration:
+          - ServerSideEncryptionByDefault:
+              SSEAlgorithm: AES256
   S3Bucket:
     Type: AWS::S3::Bucket
     Properties:
@@ -26,7 +30,7 @@ Resources:
         Status: Enabled
       ServerSideEncryptionRule:
         ServerSideEncryptionByDefault:
-          SSEAlgorithm: AWS256
+          SSEAlgorithm: AES256
       LoggingConfiguration:
         DestinationBucketName: String
         LogFilePrefix: String
diff --git a/tests/cloudformation/checks/resource/aws/test_S3Encryption.py b/tests/cloudformation/checks/resource/aws/test_S3Encryption.py
index 013c905e7..f8f1caf56 100644
--- a/tests/cloudformation/checks/resource/aws/test_S3Encryption.py
+++ b/tests/cloudformation/checks/resource/aws/test_S3Encryption.py
@@ -16,8 +16,8 @@ class TestS3Versioning(unittest.TestCase):
         report = runner.run(root_folder=test_files_dir, runner_filter=RunnerFilter(checks=[check.id]))
         summary = report.get_summary()
 
-        self.assertEqual(summary['passed'], 2)
-        self.assertEqual(summary['failed'], 3)
+        self.assertEqual(summary['passed'], 3)
+        self.assertEqual(summary['failed'], 2)
         self.assertEqual(summary['skipped'], 0)
         self.assertEqual(summary['parsing_errors'], 0)