diff --git a/.circleci/config.yml b/.circleci/config.yml index 98a1182..24156ca 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -57,7 +57,7 @@ jobs: name: Running unit tests command: | . venv/bin/activate - pytest -s -vv tests/unit + pytest -s -vv --cov=src/rules/ package: executor: python37-executor diff --git a/build.sh b/build.sh index 149fe83..236742e 100755 --- a/build.sh +++ b/build.sh @@ -5,13 +5,13 @@ set -e echo "" echo "Running unit tests..." -pytest -s -vv tests/unit +pytest -s -vv echo "" echo "Copying dependencies..." for i in rules/*; do - cp -r src tests requirements.txt $i + cp -r src requirements.txt $i done echo "" diff --git a/requirements-test.txt b/requirements-test.txt index ed78557..ac5baf0 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,3 +1,5 @@ pytest==5.0.1 +pytest-cov==2.7.1 boto3==1.9.199 xmltodict==0.10.1 +jsonpickle==1.2 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..7f6f4ae --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,59 @@ +import json +import jsonpickle +import os + +from unittest.mock import MagicMock +from pytest import fixture + + +def load_json(file_path): + dir_name = os.path.dirname(os.path.abspath(__file__)) + file_name = os.path.join(dir_name, file_path) + with open(file_name) as f: + data = json.load(f) + return data + + +@fixture +def event(): + return load_json('resources/event.json') + + +@fixture +def event_policy(): + return load_json('resources/event_with_policy.json') + + +@fixture +def event_control(): + return load_json('resources/event_with_control.json') + + +@fixture +def config_response(): + return load_json('resources/config_response.json') + + +@fixture +def config_service(config_response): + service = MagicMock() + service.put_evaluations.return_value = config_response + return service + + +@fixture +def computers(monkeypatch): + data = load_json('resources/computers.json') + computers = jsonpickle.decode(json.dumps(data)) + monkeypatch.setattr(computers, 'get', lambda: None) + return computers + + +@fixture +def manager(computers): + manager = MagicMock() + manager._request.return_value = None + manager.sign_in.return_value = None + manager.sign_out.return_value = None + manager.computers = computers + return manager diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/resources/computers.json b/tests/resources/computers.json new file mode 100644 index 0000000..c1c4f9a --- /dev/null +++ b/tests/resources/computers.json @@ -0,0 +1,150 @@ +{ + "2": { + "anti_malware_classic_pattern_version": "15.279.00", + "anti_malware_engine_version": "N/A", + "anti_malware_intelli_trap_exception_version": "1.631.00", + "anti_malware_intelli_trap_version": "0.251.00", + "anti_malware_smart_scan_pattern_version": "15.277.00", + "anti_malware_spyware_pattern_version": "2.199.00", + "cloud_object_image_id": "ami-0c7a4976cb6fafd3a", + "cloud_object_instance_id": "i-03f48756b2e392fca", + "cloud_object_internal_unique_id": "i-03f48756b2e392fca", + "cloud_object_security_group_ids": null, + "cloud_object_type": "AMAZON_VM", + "component_klasses": null, + "component_names": null, + "component_types": null, + "component_versions": null, + "computer_group_id": "35", + "computer_group_name": "Computers > stelligentlabs - 000000000000 > EU (Ireland) > kubernetes-vpc-VPC (vpc-0f9ca9cd8f25a420e) > kubernetes-vpc-Subnet02 (subnet-016c57baf66a86747)", + "computer_light": "GREEN", + "computer_type": "STANDARD", + "description": null, + "display_name": "kube-twistlock-nodegroup-Node", + "external": "true", + "external_id": null, + "hostInterfaces": null, + "id": 2, + "last_anit_malware_scheduled_scan": null, + "last_anti_malware_event": null, + "last_anti_malware_manual_scan": null, + "last_firewall_event": null, + "last_integrity_monitoring_event": null, + "last_intrusion_prevention_event": null, + "last_ipused": null, + "last_log_inspection_event": null, + "last_web_reputation_event": null, + "light": "0", + "locked": "false", + "manager": { + "API_TYPE_REST": "REST", + "API_TYPE_SOAP": "SOAP", + "_hostname": "0.0.0.0", + "_log_at_level": 30, + "_password": "xxxxxx", + "_port": "443", + "_prefix": "", + "_rest_api_endpoint": "https://0.0.0.0:443/rest", + "_soap_api_endpoint": "https://0.0.0.0:443/webservice/Manager", + "_tenant": null, + "_username": "xxxxxx", + "cloud_accounts": { + "__dict__": { + "_exempt_from_find": [], + "manager": { + "py/id": 2 + } + }, + "py/object": "environments.CloudAccounts" + }, + "computer_groups": { + "__dict__": { + "_exempt_from_find": [ + "computers" + ], + "computers": { + "__dict__": { + "_exempt_from_find": [] + }, + "py/object": "core.CoreDict" + }, + "manager": { + "py/id": 2 + } + }, + "py/object": "computers.ComputerGroups" + }, + "computers": { + "py/id": 0 + }, + "ignore_ssl_validation": 1, + "ip_lists": { + "__dict__": { + "_exempt_from_find": [], + "manager": { + "py/id": 2 + } + }, + "py/object": "policies.IPLists" + }, + "logger": { + "py/reduce": [ + { + "py/function": "logging.getLogger" + }, + { + "py/tuple": [ + "DeepSecurity.API" + ] + } + ] + }, + "policies": { + "__dict__": { + "_exempt_from_find": [], + "manager": { + "py/id": 2 + } + }, + "py/object": "policies.Policies" + }, + "py/object": "src.deepsecurity.dsm.Manager", + "rules": { + "__dict__": { + "_exempt_from_find": [], + "manager": { + "py/id": 2 + } + }, + "py/object": "policies.Rules" + } + }, + "name": "ec2-0-0-0-0.eu-west-1.compute.amazonaws.com", + "overall_anti_malware_status": "Anti-Malware: On, Real Time", + "overall_firewall_status": "Firewall: On, 8 rules", + "overall_integrity_monitoring_status": "Integrity Monitoring: Not Licensed", + "overall_intrusion_prevention_status": "Intrusion Prevention: Not Licensed", + "overall_last_recommendation_scan": null, + "overall_last_successful_communication": null, + "overall_last_successful_update": null, + "overall_last_update_required": "2019-08-06T13:39:28.800Z", + "overall_log_inspection_status": "Log Inspection: Off, not installed, no rules", + "overall_status": "Managed (Online)", + "overall_version": "N/A", + "overall_web_reputation_status": "Web Reputation: Off, not installed", + "platform": "Unknown (64 bit)", + "policy_id": null, + "policy_name": "Linux Server", + "py/object": "computers.Computer", + "recommended_rules": null, + "virtual_name": null, + "virtual_uuid": null + }, + "__dict__": { + "_exempt_from_find": [], + "manager": { + "py/id": 2 + } + }, + "py/object": "computers.Computers" +} \ No newline at end of file diff --git a/tests/resources/config_response.json b/tests/resources/config_response.json new file mode 100644 index 0000000..f0417ca --- /dev/null +++ b/tests/resources/config_response.json @@ -0,0 +1,15 @@ +{ + "FailedEvaluations": [], + "ResponseMetadata": { + "RequestId": "7964b119-ea29-46d1-86c5-b5def3e85b13", + "HTTPStatusCode": 200, + "HTTPHeaders": { + "x-amzn-requestid": "7964b119-ea29-46d1-86c5-b5def3e85b13", + "strict-transport-security": "max-age=86400", + "content-type": "application/x-amz-json-1.1", + "content-length": "24", + "date": "Tue, 06 Aug 2019 16:54:08 GMT" + }, + "RetryAttempts": 0 + } +} \ No newline at end of file diff --git a/tests/resources/event.json b/tests/resources/event.json new file mode 100644 index 0000000..294900f --- /dev/null +++ b/tests/resources/event.json @@ -0,0 +1,12 @@ +{ + "configRuleId": "config-rule-rop19i", + "version": "1.0", + "configRuleName": "dsIsInstanceClear", + "configRuleArn": "arn:aws:config:us-west-1:000000000000:config-rule/config-rule-rop19i", + "invokingEvent": "{\"configurationItemDiff\":null,\"configurationItem\":{\"relatedEvents\":[],\"relationships\":[{\"resourceId\":\"eni-0ac7c43ee76a7009c\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::NetworkInterface\",\"name\":\"Contains NetworkInterface\"},{\"resourceId\":\"sg-020755897c0825901\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::SecurityGroup\",\"name\":\"Is associated with SecurityGroup\"},{\"resourceId\":\"sg-09caa2f0b560c1f7d\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::SecurityGroup\",\"name\":\"Is associated with SecurityGroup\"},{\"resourceId\":\"subnet-07d982e574e75f3e5\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::Subnet\",\"name\":\"Is contained in Subnet\"},{\"resourceId\":\"vol-067a98804f50c6932\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::Volume\",\"name\":\"Is attached to Volume\"},{\"resourceId\":\"vol-08cf33b707496abec\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::Volume\",\"name\":\"Is attached to Volume\"},{\"resourceId\":\"vpc-014188d7689bcf41f\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::VPC\",\"name\":\"Is contained in Vpc\"}],\"configuration\":{\"amiLaunchIndex\":0,\"imageId\":\"ami-0041a7cbd48160980\",\"instanceId\":\"i-03f48756b2e392fca\",\"instanceType\":\"m5.large\",\"kernelId\":null,\"keyName\":\"dsm\",\"launchTime\":\"2019-07-18T17:46:24.000Z\",\"monitoring\":{\"state\":\"disabled\"},\"placement\":{\"availabilityZone\":\"us-west-1a\",\"affinity\":null,\"groupName\":\"\",\"partitionNumber\":null,\"hostId\":null,\"tenancy\":\"default\",\"spreadDomain\":null},\"platform\":null,\"privateDnsName\":\"ip-172-30-0-180.us-west-1.compute.internal\",\"privateIpAddress\":\"172.30.0.180\",\"productCodes\":[{\"productCodeId\":\"xxxxxxxx\",\"productCodeType\":\"marketplace\"}],\"publicDnsName\":\"\",\"publicIpAddress\":\"0.0.0.0\",\"ramdiskId\":null,\"state\":{\"code\":16,\"name\":\"running\"},\"stateTransitionReason\":\"\",\"subnetId\":\"subnet-07d982e574e75f3e5\",\"vpcId\":\"vpc-014188d7689bcf41f\",\"architecture\":\"x86_64\",\"blockDeviceMappings\":[{\"deviceName\":\"/dev/xvda\",\"ebs\":{\"attachTime\":\"2019-07-18T17:46:24.000Z\",\"deleteOnTermination\":true,\"status\":\"attached\",\"volumeId\":\"vol-067a98804f50c6932\"}},{\"deviceName\":\"/dev/sdf\",\"ebs\":{\"attachTime\":\"2019-07-18T17:46:24.000Z\",\"deleteOnTermination\":true,\"status\":\"attached\",\"volumeId\":\"vol-08cf33b707496abec\"}}],\"clientToken\":\"156347198056481272\",\"ebsOptimized\":true,\"enaSupport\":true,\"hypervisor\":\"xen\",\"iamInstanceProfile\":null,\"instanceLifecycle\":null,\"elasticGpuAssociations\":[],\"elasticInferenceAcceleratorAssociations\":[],\"networkInterfaces\":[{\"association\":{\"ipOwnerId\":\"amazon\",\"publicDnsName\":\"\",\"publicIp\":\"0.0.0.0\"},\"attachment\":{\"attachTime\":\"2019-07-18T17:46:24.000Z\",\"attachmentId\":\"eni-attach-0e08f46622bc60e1d\",\"deleteOnTermination\":true,\"deviceIndex\":0,\"status\":\"attached\"},\"description\":\"Primary network interface\",\"groups\":[{\"groupName\":\"Trend Micro Deep Security -BYOL--Deep Security 12-0-300-AutogenByAWSMP-\",\"groupId\":\"sg-09caa2f0b560c1f7d\"},{\"groupName\":\"default\",\"groupId\":\"sg-020755897c0825901\"}],\"ipv6Addresses\":[],\"macAddress\":\"00:00:00:00:00:00\",\"networkInterfaceId\":\"eni-0ac7c43ee76a7009c\",\"ownerId\":\"000000000000\",\"privateDnsName\":null,\"privateIpAddress\":\"172.30.0.180\",\"privateIpAddresses\":[{\"association\":{\"ipOwnerId\":\"amazon\",\"publicDnsName\":\"\",\"publicIp\":\"0.0.0.0\"},\"primary\":true,\"privateDnsName\":null,\"privateIpAddress\":\"172.30.0.180\"}],\"sourceDestCheck\":true,\"status\":\"in-use\",\"subnetId\":\"subnet-07d982e574e75f3e5\",\"vpcId\":\"vpc-014188d7689bcf41f\",\"interfaceType\":\"interface\"}],\"rootDeviceName\":\"/dev/xvda\",\"rootDeviceType\":\"ebs\",\"securityGroups\":[{\"groupName\":\"Trend Micro Deep Security -BYOL--Deep Security 12-0-300-AutogenByAWSMP-\",\"groupId\":\"sg-09caa2f0b560c1f7d\"},{\"groupName\":\"default\",\"groupId\":\"sg-020755897c0825901\"}],\"sourceDestCheck\":true,\"spotInstanceRequestId\":null,\"sriovNetSupport\":null,\"stateReason\":null,\"tags\":[{\"key\":\"Name\",\"value\":\"Deep Security Manager\"}],\"virtualizationType\":\"hvm\",\"cpuOptions\":{\"coreCount\":1,\"threadsPerCore\":2},\"capacityReservationId\":null,\"capacityReservationSpecification\":{\"capacityReservationPreference\":\"open\",\"capacityReservationTarget\":null},\"hibernationOptions\":{\"configured\":false},\"licenses\":[]},\"supplementaryConfiguration\":{},\"tags\":{\"Name\":\"Deep Security Manager\"},\"configurationItemVersion\":\"1.3\",\"configurationItemCaptureTime\":\"2019-07-18T19:24:11.679Z\",\"configurationStateId\":1563477851679,\"awsAccountId\":\"000000000000\",\"configurationItemStatus\":\"OK\",\"resourceType\":\"AWS::EC2::Instance\",\"resourceId\":\"i-03f48756b2e392fca\",\"resourceName\":null,\"ARN\":\"arn:aws:ec2:us-west-1:000000000000:instance/i-03f48756b2e392fca\",\"awsRegion\":\"us-west-1\",\"availabilityZone\":\"us-west-1a\",\"configurationStateMd5Hash\":\"\",\"resourceCreationTime\":\"2019-07-18T17:46:24.000Z\"},\"notificationCreationTime\":\"2019-07-18T21:34:41.397Z\",\"messageType\":\"ConfigurationItemChangeNotification\",\"recordVersion\":\"1.3\"}", + "resultToken": "xxxxxxxxxxxxxxx", + "eventLeftScope": false, + "ruleParameters": "{\"dsUsernameKey\":\"/ds/api_user\",\"dsPasswordKey\":\"/ds/api_password\",\"dsHostname\":\"0.0.0.0\",\"dsPort\":\"443\",\"dsIgnoreSslValidation\":\"true\"}", + "executionRoleArn": "arn:aws:iam::000000000000:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig", + "accountId": "000000000000" +} \ No newline at end of file diff --git a/tests/resources/event_with_control.json b/tests/resources/event_with_control.json new file mode 100644 index 0000000..7ef0f7e --- /dev/null +++ b/tests/resources/event_with_control.json @@ -0,0 +1,12 @@ +{ + "configRuleId": "config-rule-rop19i", + "version": "1.0", + "configRuleName": "dsIsInstanceClear", + "configRuleArn": "arn:aws:config:us-west-1:000000000000:config-rule/config-rule-rop19i", + "invokingEvent": "{\"configurationItemDiff\":null,\"configurationItem\":{\"relatedEvents\":[],\"relationships\":[{\"resourceId\":\"eni-0ac7c43ee76a7009c\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::NetworkInterface\",\"name\":\"Contains NetworkInterface\"},{\"resourceId\":\"sg-020755897c0825901\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::SecurityGroup\",\"name\":\"Is associated with SecurityGroup\"},{\"resourceId\":\"sg-09caa2f0b560c1f7d\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::SecurityGroup\",\"name\":\"Is associated with SecurityGroup\"},{\"resourceId\":\"subnet-07d982e574e75f3e5\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::Subnet\",\"name\":\"Is contained in Subnet\"},{\"resourceId\":\"vol-067a98804f50c6932\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::Volume\",\"name\":\"Is attached to Volume\"},{\"resourceId\":\"vol-08cf33b707496abec\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::Volume\",\"name\":\"Is attached to Volume\"},{\"resourceId\":\"vpc-014188d7689bcf41f\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::VPC\",\"name\":\"Is contained in Vpc\"}],\"configuration\":{\"amiLaunchIndex\":0,\"imageId\":\"ami-0041a7cbd48160980\",\"instanceId\":\"i-03f48756b2e392fca\",\"instanceType\":\"m5.large\",\"kernelId\":null,\"keyName\":\"dsm\",\"launchTime\":\"2019-07-18T17:46:24.000Z\",\"monitoring\":{\"state\":\"disabled\"},\"placement\":{\"availabilityZone\":\"us-west-1a\",\"affinity\":null,\"groupName\":\"\",\"partitionNumber\":null,\"hostId\":null,\"tenancy\":\"default\",\"spreadDomain\":null},\"platform\":null,\"privateDnsName\":\"ip-172-30-0-180.us-west-1.compute.internal\",\"privateIpAddress\":\"172.30.0.180\",\"productCodes\":[{\"productCodeId\":\"xxxxxxxx\",\"productCodeType\":\"marketplace\"}],\"publicDnsName\":\"\",\"publicIpAddress\":\"0.0.0.0\",\"ramdiskId\":null,\"state\":{\"code\":16,\"name\":\"running\"},\"stateTransitionReason\":\"\",\"subnetId\":\"subnet-07d982e574e75f3e5\",\"vpcId\":\"vpc-014188d7689bcf41f\",\"architecture\":\"x86_64\",\"blockDeviceMappings\":[{\"deviceName\":\"/dev/xvda\",\"ebs\":{\"attachTime\":\"2019-07-18T17:46:24.000Z\",\"deleteOnTermination\":true,\"status\":\"attached\",\"volumeId\":\"vol-067a98804f50c6932\"}},{\"deviceName\":\"/dev/sdf\",\"ebs\":{\"attachTime\":\"2019-07-18T17:46:24.000Z\",\"deleteOnTermination\":true,\"status\":\"attached\",\"volumeId\":\"vol-08cf33b707496abec\"}}],\"clientToken\":\"156347198056481272\",\"ebsOptimized\":true,\"enaSupport\":true,\"hypervisor\":\"xen\",\"iamInstanceProfile\":null,\"instanceLifecycle\":null,\"elasticGpuAssociations\":[],\"elasticInferenceAcceleratorAssociations\":[],\"networkInterfaces\":[{\"association\":{\"ipOwnerId\":\"amazon\",\"publicDnsName\":\"\",\"publicIp\":\"0.0.0.0\"},\"attachment\":{\"attachTime\":\"2019-07-18T17:46:24.000Z\",\"attachmentId\":\"eni-attach-0e08f46622bc60e1d\",\"deleteOnTermination\":true,\"deviceIndex\":0,\"status\":\"attached\"},\"description\":\"Primary network interface\",\"groups\":[{\"groupName\":\"Trend Micro Deep Security -BYOL--Deep Security 12-0-300-AutogenByAWSMP-\",\"groupId\":\"sg-09caa2f0b560c1f7d\"},{\"groupName\":\"default\",\"groupId\":\"sg-020755897c0825901\"}],\"ipv6Addresses\":[],\"macAddress\":\"00:00:00:00:00:00\",\"networkInterfaceId\":\"eni-0ac7c43ee76a7009c\",\"ownerId\":\"000000000000\",\"privateDnsName\":null,\"privateIpAddress\":\"172.30.0.180\",\"privateIpAddresses\":[{\"association\":{\"ipOwnerId\":\"amazon\",\"publicDnsName\":\"\",\"publicIp\":\"0.0.0.0\"},\"primary\":true,\"privateDnsName\":null,\"privateIpAddress\":\"172.30.0.180\"}],\"sourceDestCheck\":true,\"status\":\"in-use\",\"subnetId\":\"subnet-07d982e574e75f3e5\",\"vpcId\":\"vpc-014188d7689bcf41f\",\"interfaceType\":\"interface\"}],\"rootDeviceName\":\"/dev/xvda\",\"rootDeviceType\":\"ebs\",\"securityGroups\":[{\"groupName\":\"Trend Micro Deep Security -BYOL--Deep Security 12-0-300-AutogenByAWSMP-\",\"groupId\":\"sg-09caa2f0b560c1f7d\"},{\"groupName\":\"default\",\"groupId\":\"sg-020755897c0825901\"}],\"sourceDestCheck\":true,\"spotInstanceRequestId\":null,\"sriovNetSupport\":null,\"stateReason\":null,\"tags\":[{\"key\":\"Name\",\"value\":\"Deep Security Manager\"}],\"virtualizationType\":\"hvm\",\"cpuOptions\":{\"coreCount\":1,\"threadsPerCore\":2},\"capacityReservationId\":null,\"capacityReservationSpecification\":{\"capacityReservationPreference\":\"open\",\"capacityReservationTarget\":null},\"hibernationOptions\":{\"configured\":false},\"licenses\":[]},\"supplementaryConfiguration\":{},\"tags\":{\"Name\":\"Deep Security Manager\"},\"configurationItemVersion\":\"1.3\",\"configurationItemCaptureTime\":\"2019-07-18T19:24:11.679Z\",\"configurationStateId\":1563477851679,\"awsAccountId\":\"000000000000\",\"configurationItemStatus\":\"OK\",\"resourceType\":\"AWS::EC2::Instance\",\"resourceId\":\"i-03f48756b2e392fca\",\"resourceName\":null,\"ARN\":\"arn:aws:ec2:us-west-1:000000000000:instance/i-03f48756b2e392fca\",\"awsRegion\":\"us-west-1\",\"availabilityZone\":\"us-west-1a\",\"configurationStateMd5Hash\":\"\",\"resourceCreationTime\":\"2019-07-18T17:46:24.000Z\"},\"notificationCreationTime\":\"2019-07-18T21:34:41.397Z\",\"messageType\":\"ConfigurationItemChangeNotification\",\"recordVersion\":\"1.3\"}", + "resultToken": "xxxxxxxxxxxxxxx", + "eventLeftScope": false, + "ruleParameters": "{\"dsUsernameKey\":\"/ds/api_user\",\"dsPasswordKey\":\"/ds/api_password\",\"dsHostname\":\"0.0.0.0\",\"dsPort\":\"443\",\"dsIgnoreSslValidation\":\"true\",\"dsControl\":\"firewall\"}", + "executionRoleArn": "arn:aws:iam::000000000000:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig", + "accountId": "000000000000" +} \ No newline at end of file diff --git a/tests/resources/event_with_policy.json b/tests/resources/event_with_policy.json new file mode 100644 index 0000000..9a707f8 --- /dev/null +++ b/tests/resources/event_with_policy.json @@ -0,0 +1,12 @@ +{ + "configRuleId": "config-rule-rop19i", + "version": "1.0", + "configRuleName": "dsIsInstanceClear", + "configRuleArn": "arn:aws:config:us-west-1:000000000000:config-rule/config-rule-rop19i", + "invokingEvent": "{\"configurationItemDiff\":null,\"configurationItem\":{\"relatedEvents\":[],\"relationships\":[{\"resourceId\":\"eni-0ac7c43ee76a7009c\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::NetworkInterface\",\"name\":\"Contains NetworkInterface\"},{\"resourceId\":\"sg-020755897c0825901\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::SecurityGroup\",\"name\":\"Is associated with SecurityGroup\"},{\"resourceId\":\"sg-09caa2f0b560c1f7d\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::SecurityGroup\",\"name\":\"Is associated with SecurityGroup\"},{\"resourceId\":\"subnet-07d982e574e75f3e5\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::Subnet\",\"name\":\"Is contained in Subnet\"},{\"resourceId\":\"vol-067a98804f50c6932\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::Volume\",\"name\":\"Is attached to Volume\"},{\"resourceId\":\"vol-08cf33b707496abec\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::Volume\",\"name\":\"Is attached to Volume\"},{\"resourceId\":\"vpc-014188d7689bcf41f\",\"resourceName\":null,\"resourceType\":\"AWS::EC2::VPC\",\"name\":\"Is contained in Vpc\"}],\"configuration\":{\"amiLaunchIndex\":0,\"imageId\":\"ami-0041a7cbd48160980\",\"instanceId\":\"i-03f48756b2e392fca\",\"instanceType\":\"m5.large\",\"kernelId\":null,\"keyName\":\"dsm\",\"launchTime\":\"2019-07-18T17:46:24.000Z\",\"monitoring\":{\"state\":\"disabled\"},\"placement\":{\"availabilityZone\":\"us-west-1a\",\"affinity\":null,\"groupName\":\"\",\"partitionNumber\":null,\"hostId\":null,\"tenancy\":\"default\",\"spreadDomain\":null},\"platform\":null,\"privateDnsName\":\"ip-172-30-0-180.us-west-1.compute.internal\",\"privateIpAddress\":\"172.30.0.180\",\"productCodes\":[{\"productCodeId\":\"xxxxxxxx\",\"productCodeType\":\"marketplace\"}],\"publicDnsName\":\"\",\"publicIpAddress\":\"0.0.0.0\",\"ramdiskId\":null,\"state\":{\"code\":16,\"name\":\"running\"},\"stateTransitionReason\":\"\",\"subnetId\":\"subnet-07d982e574e75f3e5\",\"vpcId\":\"vpc-014188d7689bcf41f\",\"architecture\":\"x86_64\",\"blockDeviceMappings\":[{\"deviceName\":\"/dev/xvda\",\"ebs\":{\"attachTime\":\"2019-07-18T17:46:24.000Z\",\"deleteOnTermination\":true,\"status\":\"attached\",\"volumeId\":\"vol-067a98804f50c6932\"}},{\"deviceName\":\"/dev/sdf\",\"ebs\":{\"attachTime\":\"2019-07-18T17:46:24.000Z\",\"deleteOnTermination\":true,\"status\":\"attached\",\"volumeId\":\"vol-08cf33b707496abec\"}}],\"clientToken\":\"156347198056481272\",\"ebsOptimized\":true,\"enaSupport\":true,\"hypervisor\":\"xen\",\"iamInstanceProfile\":null,\"instanceLifecycle\":null,\"elasticGpuAssociations\":[],\"elasticInferenceAcceleratorAssociations\":[],\"networkInterfaces\":[{\"association\":{\"ipOwnerId\":\"amazon\",\"publicDnsName\":\"\",\"publicIp\":\"0.0.0.0\"},\"attachment\":{\"attachTime\":\"2019-07-18T17:46:24.000Z\",\"attachmentId\":\"eni-attach-0e08f46622bc60e1d\",\"deleteOnTermination\":true,\"deviceIndex\":0,\"status\":\"attached\"},\"description\":\"Primary network interface\",\"groups\":[{\"groupName\":\"Trend Micro Deep Security -BYOL--Deep Security 12-0-300-AutogenByAWSMP-\",\"groupId\":\"sg-09caa2f0b560c1f7d\"},{\"groupName\":\"default\",\"groupId\":\"sg-020755897c0825901\"}],\"ipv6Addresses\":[],\"macAddress\":\"00:00:00:00:00:00\",\"networkInterfaceId\":\"eni-0ac7c43ee76a7009c\",\"ownerId\":\"000000000000\",\"privateDnsName\":null,\"privateIpAddress\":\"172.30.0.180\",\"privateIpAddresses\":[{\"association\":{\"ipOwnerId\":\"amazon\",\"publicDnsName\":\"\",\"publicIp\":\"0.0.0.0\"},\"primary\":true,\"privateDnsName\":null,\"privateIpAddress\":\"172.30.0.180\"}],\"sourceDestCheck\":true,\"status\":\"in-use\",\"subnetId\":\"subnet-07d982e574e75f3e5\",\"vpcId\":\"vpc-014188d7689bcf41f\",\"interfaceType\":\"interface\"}],\"rootDeviceName\":\"/dev/xvda\",\"rootDeviceType\":\"ebs\",\"securityGroups\":[{\"groupName\":\"Trend Micro Deep Security -BYOL--Deep Security 12-0-300-AutogenByAWSMP-\",\"groupId\":\"sg-09caa2f0b560c1f7d\"},{\"groupName\":\"default\",\"groupId\":\"sg-020755897c0825901\"}],\"sourceDestCheck\":true,\"spotInstanceRequestId\":null,\"sriovNetSupport\":null,\"stateReason\":null,\"tags\":[{\"key\":\"Name\",\"value\":\"Deep Security Manager\"}],\"virtualizationType\":\"hvm\",\"cpuOptions\":{\"coreCount\":1,\"threadsPerCore\":2},\"capacityReservationId\":null,\"capacityReservationSpecification\":{\"capacityReservationPreference\":\"open\",\"capacityReservationTarget\":null},\"hibernationOptions\":{\"configured\":false},\"licenses\":[]},\"supplementaryConfiguration\":{},\"tags\":{\"Name\":\"Deep Security Manager\"},\"configurationItemVersion\":\"1.3\",\"configurationItemCaptureTime\":\"2019-07-18T19:24:11.679Z\",\"configurationStateId\":1563477851679,\"awsAccountId\":\"000000000000\",\"configurationItemStatus\":\"OK\",\"resourceType\":\"AWS::EC2::Instance\",\"resourceId\":\"i-03f48756b2e392fca\",\"resourceName\":null,\"ARN\":\"arn:aws:ec2:us-west-1:000000000000:instance/i-03f48756b2e392fca\",\"awsRegion\":\"us-west-1\",\"availabilityZone\":\"us-west-1a\",\"configurationStateMd5Hash\":\"\",\"resourceCreationTime\":\"2019-07-18T17:46:24.000Z\"},\"notificationCreationTime\":\"2019-07-18T21:34:41.397Z\",\"messageType\":\"ConfigurationItemChangeNotification\",\"recordVersion\":\"1.3\"}", + "resultToken": "xxxxxxxxxxxxxxx", + "eventLeftScope": false, + "ruleParameters": "{\"dsUsernameKey\":\"/ds/api_user\",\"dsPasswordKey\":\"/ds/api_password\",\"dsHostname\":\"0.0.0.0\",\"dsPort\":\"443\",\"dsIgnoreSslValidation\":\"true\",\"dsPolicy\":\"Linux Server\"}", + "executionRoleArn": "arn:aws:iam::000000000000:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig", + "accountId": "000000000000" +} \ No newline at end of file diff --git a/tests/unit/test_credentials.py b/tests/test_credentials.py similarity index 100% rename from tests/unit/test_credentials.py rename to tests/test_credentials.py diff --git a/tests/test_rule.py b/tests/test_rule.py new file mode 100644 index 0000000..e5f3efd --- /dev/null +++ b/tests/test_rule.py @@ -0,0 +1,31 @@ +from unittest.mock import patch, MagicMock +from src.rules.rule import Rule + + +def test_requirement(event): + rule = Rule(event) + assert rule.username_key + assert rule.password_key + assert rule.hostname + + +@patch('src.deepsecurity.credentials.Credentials.get_password') +@patch('src.deepsecurity.credentials.Credentials.get_username') +def test_get_credentials(mock_get_username, mock_get_password, event): + mock_get_username.return_value = 'user' + mock_get_password.return_value = 'pass' + + rule = Rule(event) + creds = rule._get_credentials() + assert creds == ('user', 'pass') + + +@patch('boto3.client') +def test_respond_to_config(mock_client, config_response, event): + config = MagicMock() + config.put_evaluations.return_value = config_response + mock_client.return_value = config + + rule = Rule(event) + response = rule._respond_to_config() + assert response == config_response diff --git a/tests/test_rule_does_instance_have_policy.py b/tests/test_rule_does_instance_have_policy.py new file mode 100644 index 0000000..c02ceaf --- /dev/null +++ b/tests/test_rule_does_instance_have_policy.py @@ -0,0 +1,23 @@ +from unittest.mock import patch +from src.rules.rule_does_instance_have_policy import RuleDoesInstanceHavePolicy + + +def test_requirement(event_policy): + rule = RuleDoesInstanceHavePolicy(event_policy) + assert rule.username_key + assert rule.password_key + assert rule.hostname + assert rule.policy + + +@patch('boto3.client') +@patch('src.rules.rule.Manager') +def test_execute(mock_dsm, mock_client, manager, config_service, event_policy): + mock_dsm.return_value = manager + mock_client.return_value = config_service + + rule = RuleDoesInstanceHavePolicy(event_policy) + rule.execute() + + assert rule.compliance == 'COMPLIANT' + assert rule.compliance_msg == 'Current policy: Linux Server' diff --git a/tests/test_rule_is_instance_clear.py b/tests/test_rule_is_instance_clear.py new file mode 100644 index 0000000..5fb0718 --- /dev/null +++ b/tests/test_rule_is_instance_clear.py @@ -0,0 +1,15 @@ +from unittest.mock import patch +from src.rules.rule_is_instance_clear import RuleIsInstanceClear + + +@patch('boto3.client') +@patch('src.rules.rule.Manager') +def test_execute(mock_dsm, mock_client, manager, config_service, event): + mock_dsm.return_value = manager + mock_client.return_value = config_service + + rule = RuleIsInstanceClear(event) + rule.execute() + + assert rule.compliance == 'COMPLIANT' + assert rule.compliance_msg == 'Current status: GREEN' diff --git a/tests/test_rule_is_instance_protected_by.py b/tests/test_rule_is_instance_protected_by.py new file mode 100644 index 0000000..2c93770 --- /dev/null +++ b/tests/test_rule_is_instance_protected_by.py @@ -0,0 +1,23 @@ +from unittest.mock import patch +from src.rules.rule_is_instance_protected_by import RuleIsInstanceProtectedBy + + +def test_requirement(event_control): + rule = RuleIsInstanceProtectedBy(event_control) + assert rule.username_key + assert rule.password_key + assert rule.hostname + assert rule.control + + +@patch('boto3.client') +@patch('src.rules.rule.Manager') +def test_execute(mock_dsm, mock_client, manager, config_service, event_control): + mock_dsm.return_value = manager + mock_client.return_value = config_service + + rule = RuleIsInstanceProtectedBy(event_control) + rule.execute() + + assert rule.compliance == 'COMPLIANT' + assert rule.compliance_msg == 'Firewall status: Firewall: On, 8 rules' diff --git a/tests/test_rule_is_instance_protected_by_anti_malware.py b/tests/test_rule_is_instance_protected_by_anti_malware.py new file mode 100644 index 0000000..61d051d --- /dev/null +++ b/tests/test_rule_is_instance_protected_by_anti_malware.py @@ -0,0 +1,15 @@ +from unittest.mock import patch +from src.rules.rule_is_instance_protected_by_anti_malware import RuleIsInstanceProtectedByAntiMalware + + +@patch('boto3.client') +@patch('src.rules.rule.Manager') +def test_execute(mock_dsm, mock_client, manager, config_service, event): + mock_dsm.return_value = manager + mock_client.return_value = config_service + + rule = RuleIsInstanceProtectedByAntiMalware(event) + rule.execute() + + assert rule.compliance == 'COMPLIANT' + assert rule.compliance_msg == 'Anti-Malware status: Anti-Malware: On, Real Time' diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py deleted file mode 100644 index e69de29..0000000