Repository: bridgecrewio/checkov

Issue:
Add new check: Ensure Session Manager data is encrypted in transit and at rest 
If document_type = Session, then check for the following within the document: 

	kmsKeyId	- This enabled encryption in transit
	s3EncryptionEnabled - Encryption at rest… only if s3BucketName had a value
	cloudWatchEncryptionEnabled - Encryption at rest… only if cloudWatchLogGroupName has a value

An example of the SSM document is here: https://docs.aws.amazon.com/systems-manager/latest/userguide/getting-started-sessiondocumentaccesscheck.html


https://www.terraform.io/docs/providers/aws/r/ssm_document.html
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-document.html


Discussion:

Resolving patch:
diff --git a/checkov/terraform/checks/resource/aws/SSMSessionManagerDocumentEncryption.py b/checkov/terraform/checks/resource/aws/SSMSessionManagerDocumentEncryption.py
--- a/checkov/terraform/checks/resource/aws/SSMSessionManagerDocumentEncryption.py
+++ b/checkov/terraform/checks/resource/aws/SSMSessionManagerDocumentEncryption.py
@@ -1,4 +1,6 @@
 import json
+import logging
+
 import yaml
 
 from checkov.common.models.enums import CheckResult, CheckCategories
@@ -38,6 +40,7 @@ def is_json(data):
     try:
         json.loads(data)
     except ValueError:
+        logging.debug(f"could not parse json data: {data}")
         return False
     return True
 
@@ -46,6 +49,7 @@ def is_yaml(data):
     try:
         yaml.safe_load(data)
     except yaml.YAMLError:
+        logging.debug(f"could not parse yaml data: {data}")
         return False
     return True
 
diff --git a/checkov/terraform/checks/resource/aws/SSMSessionManagerDocumentLogging.py b/checkov/terraform/checks/resource/aws/SSMSessionManagerDocumentLogging.py
new file mode 100644
--- /dev/null
+++ b/checkov/terraform/checks/resource/aws/SSMSessionManagerDocumentLogging.py
@@ -0,0 +1,62 @@
+import json
+import logging
+
+import yaml
+
+from checkov.common.models.enums import CheckResult, CheckCategories
+from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
+
+
+class SSMSessionManagerDocumentLogging(BaseResourceCheck):
+    def __init__(self):
+        name = "Ensure Session Manager logs are enabled and encrypted"
+        id = "CKV_AWS_113"
+        supported_resources = ["aws_ssm_document"]
+        categories = [CheckCategories.ENCRYPTION, CheckCategories.LOGGING]
+        super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)
+
+    def scan_resource_conf(self, conf):
+        if conf.get("document_type") == ["Session"]:
+            doc_format = conf.get("document_format", ["JSON"])
+
+            if "content" in conf.keys():
+                content = conf["content"][0]
+                inputs = None
+
+                if doc_format == ["JSON"] and is_json(content):
+                    inputs = json.loads(content).get("inputs", {})
+                elif doc_format == ["YAML"] and is_yaml(content):
+                    inputs = yaml.safe_load(content).get("inputs", {})
+
+                if inputs:
+                    if inputs.get("s3BucketName") and inputs.get("s3EncryptionEnabled"):
+                        return CheckResult.PASSED
+                    elif inputs.get("cloudWatchLogGroupName") and inputs.get("cloudWatchEncryptionEnabled"):
+                        return CheckResult.PASSED
+
+                    return CheckResult.FAILED
+
+                return CheckResult.UNKNOWN
+
+        return CheckResult.UNKNOWN
+
+
+def is_json(data):
+    try:
+        json.loads(data)
+    except ValueError:
+        logging.debug(f"could not parse json data: {data}")
+        return False
+    return True
+
+
+def is_yaml(data):
+    try:
+        yaml.safe_load(data)
+    except yaml.YAMLError:
+        logging.debug(f"could not parse yaml data: {data}")
+        return False
+    return True
+
+
+check = SSMSessionManagerDocumentLogging()


Test patch:
diff --git a/tests/terraform/checks/resource/aws/example_SSMSessionManagerDocumentLogging/main.tf b/tests/terraform/checks/resource/aws/example_SSMSessionManagerDocumentLogging/main.tf
new file mode 100644
--- /dev/null
+++ b/tests/terraform/checks/resource/aws/example_SSMSessionManagerDocumentLogging/main.tf
@@ -0,0 +1,283 @@
+# pass
+
+resource "aws_ssm_document" "s3_enabled_encrypted" {
+  name          = "SSM-SessionManagerRunShell"
+  document_type = "Session"
+
+  content = <<DOC
+  {
+    "schemaVersion": "1.0",
+    "description": "Document to hold regional settings for Session Manager",
+    "sessionType": "Standard_Stream",
+    "inputs": {
+      "s3BucketName": "example",
+      "s3KeyPrefix": "",
+      "s3EncryptionEnabled": true,
+      "cloudWatchLogGroupName": "",
+      "cloudWatchEncryptionEnabled": true,
+      "idleSessionTimeout": "20",
+      "cloudWatchStreamingEnabled": true,
+      "kmsKeyId": "",
+      "runAsEnabled": false,
+      "runAsDefaultUser": "",
+      "shellProfile": {
+        "windows": "",
+        "linux": ""
+      }
+    }
+  }
+DOC
+}
+
+resource "aws_ssm_document" "s3_enabled_encrypted_yaml" {
+  name          = "SSM-SessionManagerRunShell"
+  document_type = "Session"
+
+  document_format = "YAML"
+
+  content = <<DOC
+  schemaVersion: '1.0'
+  description: Document to hold regional settings for Session Manager
+  sessionType: Standard_Stream
+  inputs:
+    s3BucketName: 'example'
+    s3KeyPrefix: ''
+    s3EncryptionEnabled: true
+    cloudWatchLogGroupName: ''
+    cloudWatchEncryptionEnabled: true
+    cloudWatchStreamingEnabled: true
+    kmsKeyId: ''
+    runAsEnabled: true
+    runAsDefaultUser: ''
+    idleSessionTimeout: '20'
+    shellProfile:
+      windows: ''
+      linux: ''
+DOC
+}
+
+resource "aws_ssm_document" "cw_enabled_encrypted" {
+  name          = "SSM-SessionManagerRunShell"
+  document_type = "Session"
+
+  content = <<DOC
+  {
+    "schemaVersion": "1.0",
+    "description": "Document to hold regional settings for Session Manager",
+    "sessionType": "Standard_Stream",
+    "inputs": {
+      "s3BucketName": "",
+      "s3KeyPrefix": "",
+      "s3EncryptionEnabled": true,
+      "cloudWatchLogGroupName": "example",
+      "cloudWatchEncryptionEnabled": true,
+      "idleSessionTimeout": "20",
+      "cloudWatchStreamingEnabled": true,
+      "kmsKeyId": "",
+      "runAsEnabled": false,
+      "runAsDefaultUser": "",
+      "shellProfile": {
+        "windows": "",
+        "linux": ""
+      }
+    }
+  }
+DOC
+}
+
+resource "aws_ssm_document" "cw_enabled_encrypted_yaml" {
+  name          = "SSM-SessionManagerRunShell"
+  document_type = "Session"
+
+  document_format = "YAML"
+
+  content = <<DOC
+  schemaVersion: '1.0'
+  description: Document to hold regional settings for Session Manager
+  sessionType: Standard_Stream
+  inputs:
+    s3BucketName: ''
+    s3KeyPrefix: ''
+    s3EncryptionEnabled: true
+    cloudWatchLogGroupName: 'example'
+    cloudWatchEncryptionEnabled: true
+    cloudWatchStreamingEnabled: true
+    kmsKeyId: ''
+    runAsEnabled: true
+    runAsDefaultUser: ''
+    idleSessionTimeout: '20'
+    shellProfile:
+      windows: ''
+      linux: ''
+DOC
+}
+
+# failure
+
+resource "aws_ssm_document" "disabled" {
+  name          = "SSM-SessionManagerRunShell"
+  document_type = "Session"
+
+  content = <<DOC
+  {
+    "schemaVersion": "1.0",
+    "description": "Document to hold regional settings for Session Manager",
+    "sessionType": "Standard_Stream",
+    "inputs": {
+      "s3BucketName": "",
+      "s3KeyPrefix": "",
+      "s3EncryptionEnabled": true,
+      "cloudWatchLogGroupName": "",
+      "cloudWatchEncryptionEnabled": true,
+      "idleSessionTimeout": "20",
+      "cloudWatchStreamingEnabled": true,
+      "kmsKeyId": "",
+      "runAsEnabled": false,
+      "runAsDefaultUser": "",
+      "shellProfile": {
+        "windows": "",
+        "linux": ""
+      }
+    }
+  }
+DOC
+}
+
+resource "aws_ssm_document" "disabled_yaml" {
+  name          = "SSM-SessionManagerRunShell"
+  document_type = "Session"
+
+  document_format = "YAML"
+
+  content = <<DOC
+  schemaVersion: '1.0'
+  description: Document to hold regional settings for Session Manager
+  sessionType: Standard_Stream
+  inputs:
+    s3BucketName: ''
+    s3KeyPrefix: ''
+    s3EncryptionEnabled: true
+    cloudWatchLogGroupName: ''
+    cloudWatchEncryptionEnabled: true
+    cloudWatchStreamingEnabled: true
+    kmsKeyId: ''
+    runAsEnabled: true
+    runAsDefaultUser: ''
+    idleSessionTimeout: '20'
+    shellProfile:
+      windows: ''
+      linux: ''
+DOC
+}
+
+resource "aws_ssm_document" "s3_enabled_not_encrypted" {
+  name          = "SSM-SessionManagerRunShell"
+  document_type = "Session"
+
+  content = <<DOC
+  {
+    "schemaVersion": "1.0",
+    "description": "Document to hold regional settings for Session Manager",
+    "sessionType": "Standard_Stream",
+    "inputs": {
+      "s3BucketName": "example",
+      "s3KeyPrefix": "",
+      "s3EncryptionEnabled": false,
+      "cloudWatchLogGroupName": "",
+      "cloudWatchEncryptionEnabled": true,
+      "idleSessionTimeout": "20",
+      "cloudWatchStreamingEnabled": true,
+      "kmsKeyId": "",
+      "runAsEnabled": false,
+      "runAsDefaultUser": "",
+      "shellProfile": {
+        "windows": "",
+        "linux": ""
+      }
+    }
+  }
+DOC
+}
+
+resource "aws_ssm_document" "s3_enabled_not_encrypted_yaml" {
+  name          = "SSM-SessionManagerRunShell"
+  document_type = "Session"
+
+  document_format = "YAML"
+
+  content = <<DOC
+  schemaVersion: '1.0'
+  description: Document to hold regional settings for Session Manager
+  sessionType: Standard_Stream
+  inputs:
+    s3BucketName: 'example'
+    s3KeyPrefix: ''
+    s3EncryptionEnabled: false
+    cloudWatchLogGroupName: ''
+    cloudWatchEncryptionEnabled: true
+    cloudWatchStreamingEnabled: true
+    kmsKeyId: ''
+    runAsEnabled: true
+    runAsDefaultUser: ''
+    idleSessionTimeout: '20'
+    shellProfile:
+      windows: ''
+      linux: ''
+DOC
+}
+
+resource "aws_ssm_document" "cw_enabled_not_encrypted" {
+  name          = "SSM-SessionManagerRunShell"
+  document_type = "Session"
+
+  content = <<DOC
+  {
+    "schemaVersion": "1.0",
+    "description": "Document to hold regional settings for Session Manager",
+    "sessionType": "Standard_Stream",
+    "inputs": {
+      "s3BucketName": "",
+      "s3KeyPrefix": "",
+      "s3EncryptionEnabled": true,
+      "cloudWatchLogGroupName": "example",
+      "cloudWatchEncryptionEnabled": false,
+      "idleSessionTimeout": "20",
+      "cloudWatchStreamingEnabled": true,
+      "kmsKeyId": "",
+      "runAsEnabled": false,
+      "runAsDefaultUser": "",
+      "shellProfile": {
+        "windows": "",
+        "linux": ""
+      }
+    }
+  }
+DOC
+}
+
+resource "aws_ssm_document" "cw_enabled_not_encrypted_yaml" {
+  name          = "SSM-SessionManagerRunShell"
+  document_type = "Session"
+
+  document_format = "YAML"
+
+  content = <<DOC
+  schemaVersion: '1.0'
+  description: Document to hold regional settings for Session Manager
+  sessionType: Standard_Stream
+  inputs:
+    s3BucketName: ''
+    s3KeyPrefix: ''
+    s3EncryptionEnabled: false
+    cloudWatchLogGroupName: 'example'
+    cloudWatchEncryptionEnabled: false
+    cloudWatchStreamingEnabled: true
+    kmsKeyId: ''
+    runAsEnabled: true
+    runAsDefaultUser: ''
+    idleSessionTimeout: '20'
+    shellProfile:
+      windows: ''
+      linux: ''
+DOC
+}
diff --git a/tests/terraform/checks/resource/aws/test_SSMSessionManagerDocument.py b/tests/terraform/checks/resource/aws/test_SSMSessionManagerDocumentEncryption.py
similarity index 100%
rename from tests/terraform/checks/resource/aws/test_SSMSessionManagerDocument.py
rename to tests/terraform/checks/resource/aws/test_SSMSessionManagerDocumentEncryption.py
diff --git a/tests/terraform/checks/resource/aws/test_SSMSessionManagerDocumentLogging.py b/tests/terraform/checks/resource/aws/test_SSMSessionManagerDocumentLogging.py
new file mode 100644
--- /dev/null
+++ b/tests/terraform/checks/resource/aws/test_SSMSessionManagerDocumentLogging.py
@@ -0,0 +1,46 @@
+import os
+import unittest
+
+from checkov.runner_filter import RunnerFilter
+from checkov.terraform.checks.resource.aws.SSMSessionManagerDocumentLogging import check
+from checkov.terraform.runner import Runner
+
+
+class TestSSMSessionManagerDocumentLogging(unittest.TestCase):
+    def test(self):
+        runner = Runner()
+        current_dir = os.path.dirname(os.path.realpath(__file__))
+
+        test_files_dir = current_dir + "/example_SSMSessionManagerDocumentLogging"
+        report = runner.run(root_folder=test_files_dir, runner_filter=RunnerFilter(checks=[check.id]))
+        summary = report.get_summary()
+
+        passing_resources = {
+            "aws_ssm_document.s3_enabled_encrypted",
+            "aws_ssm_document.s3_enabled_encrypted_yaml",
+            "aws_ssm_document.cw_enabled_encrypted",
+            "aws_ssm_document.cw_enabled_encrypted_yaml",
+        }
+        failing_resources = {
+            "aws_ssm_document.disabled",
+            "aws_ssm_document.disabled_yaml",
+            "aws_ssm_document.s3_enabled_not_encrypted",
+            "aws_ssm_document.s3_enabled_not_encrypted_yaml",
+            "aws_ssm_document.cw_enabled_not_encrypted",
+            "aws_ssm_document.cw_enabled_not_encrypted_yaml",
+        }
+
+        passed_check_resources = set([c.resource for c in report.passed_checks])
+        failed_check_resources = set([c.resource for c in report.failed_checks])
+
+        self.assertEqual(summary["passed"], 4)
+        self.assertEqual(summary["failed"], 6)
+        self.assertEqual(summary["skipped"], 0)
+        self.assertEqual(summary["parsing_errors"], 0)
+
+        self.assertEqual(passing_resources, passed_check_resources)
+        self.assertEqual(failing_resources, failed_check_resources)
+
+
+if __name__ == "__main__":
+    unittest.main()