From b8f37bd07111655694830cc92edc089f620d3b96 Mon Sep 17 00:00:00 2001 From: Jonathan Lassoff Date: Mon, 11 Dec 2023 14:55:18 -0800 Subject: [PATCH 1/2] DMZ Tagging: Support multiple tags, move to panther_config --- global_helpers/panther_base_helpers.py | 12 +++++------- global_helpers/panther_config_defaults.py | 7 +++++++ ...s_only_dmz_security_groups_publicly_accessible.py | 12 ++++++++++-- ..._only_dmz_security_groups_publicly_accessible.yml | 9 +++++++++ 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/global_helpers/panther_base_helpers.py b/global_helpers/panther_base_helpers.py index 8ebeb2a27..9e6e921dd 100644 --- a/global_helpers/panther_base_helpers.py +++ b/global_helpers/panther_base_helpers.py @@ -59,23 +59,21 @@ def is_dmz_cidr(ip_range): return any(ip_network(ip_range).overlaps(dmz_network) for dmz_network in DMZ_NETWORKS) -DMZ_TAG_KEY = "environment" -DMZ_TAG_VALUE = "dmz" - - # Defaults to False to assume something is not a DMZ if it is not tagged -def is_dmz_tags(resource): +def is_dmz_tags(resource, dmz_tags): """This function determines whether a given resource is tagged as existing in a DMZ.""" if resource["Tags"] is None: return False - return resource["Tags"].get(DMZ_TAG_KEY) == DMZ_TAG_VALUE + for key, value in dmz_tags: + if resource["Tags"].get(key) == value: + return True + return False # Function variables here so that implementation details of these functions can be changed without # having to rename the function in all locations its used, or having an outdated name on the actual # function being used, etc. IN_PCI_SCOPE = in_pci_scope_tags -IS_DMZ = is_dmz_tags # # # # # # # # # # # # # # # GSuite Helpers # diff --git a/global_helpers/panther_config_defaults.py b/global_helpers/panther_config_defaults.py index 87a8f01bb..cacf232e3 100644 --- a/global_helpers/panther_config_defaults.py +++ b/global_helpers/panther_config_defaults.py @@ -13,3 +13,10 @@ MS_EXCHANGE_ALLOWED_FORWARDING_DESTINATION_DOMAINS = ORGANIZATION_DOMAINS MS_EXCHANGE_ALLOWED_FORWARDING_DESTINATION_EMAILS = ["postmaster@" + ORGANIZATION_DOMAINS[0]] TELEPORT_ORGANIZATION_DOMAINS = ORGANIZATION_DOMAINS + +# Key/value pairs of tags used to denote resources that are intentionally exposed +DMZ_TAGS = set( + [ + ("environment", "dmz"), + ] +) diff --git a/policies/aws_vpc_policies/aws_only_dmz_security_groups_publicly_accessible.py b/policies/aws_vpc_policies/aws_only_dmz_security_groups_publicly_accessible.py index deb985053..1c8e209a7 100644 --- a/policies/aws_vpc_policies/aws_only_dmz_security_groups_publicly_accessible.py +++ b/policies/aws_vpc_policies/aws_only_dmz_security_groups_publicly_accessible.py @@ -1,6 +1,11 @@ +import json from ipaddress import ip_network +from unittest.mock import MagicMock -from panther_base_helpers import IS_DMZ +from panther_base_helpers import is_dmz_tags +from panther_config import config + +DMZ_TAGS = config.DMZ_TAGS def policy(resource): @@ -9,7 +14,10 @@ def policy(resource): return True # DMZ security groups can have inbound permissions from the internet - if IS_DMZ(resource): + global DMZ_TAGS # pylint: disable=global-statement + if isinstance(DMZ_TAGS, MagicMock): + DMZ_TAGS = {tuple(kv) for kv in json.loads(DMZ_TAGS())} + if is_dmz_tags(resource, DMZ_TAGS): return True for permission in resource["IpPermissions"]: diff --git a/policies/aws_vpc_policies/aws_only_dmz_security_groups_publicly_accessible.yml b/policies/aws_vpc_policies/aws_only_dmz_security_groups_publicly_accessible.yml index 38495c771..b6e86c30f 100644 --- a/policies/aws_vpc_policies/aws_only_dmz_security_groups_publicly_accessible.yml +++ b/policies/aws_vpc_policies/aws_only_dmz_security_groups_publicly_accessible.yml @@ -25,6 +25,9 @@ Tests: - Name: DMZ Security Group Does Allows Public Access ExpectedResult: true + Mocks: + - objectName: DMZ_TAGS + returnValue: '[["environment", "dmz"]]' Resource: { "Description": "example VPC security group", @@ -88,6 +91,9 @@ Tests: - Name: Non DMZ Security Group Allows Public Access ExpectedResult: false + Mocks: + - objectName: DMZ_TAGS + returnValue: '[["environment", "dmz"]]' Resource: { "Description": "example VPC security group", @@ -151,6 +157,9 @@ Tests: - Name: Non DMZ Security Group Does Not Allow Public Access ExpectedResult: true + Mocks: + - objectName: DMZ_TAGS + returnValue: '[["environment", "dmz"]]' Resource: { "Description": "example VPC security group", From dff52be3e5fbbaf84de3d30d32c45b9cecf1e3de Mon Sep 17 00:00:00 2001 From: egibs Date: Tue, 12 Dec 2023 16:19:54 -0600 Subject: [PATCH 2/2] Appease the linter --- global_helpers/panther_config_defaults.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global_helpers/panther_config_defaults.py b/global_helpers/panther_config_defaults.py index 8a333b74b..d98ac2f3a 100644 --- a/global_helpers/panther_config_defaults.py +++ b/global_helpers/panther_config_defaults.py @@ -26,4 +26,4 @@ PCI_NETWORKS = [ # ip_network("10.0.0.0/24"), -] \ No newline at end of file +]