From ff915d0e9fcf169368a04453608f1f09af0e7d58 Mon Sep 17 00:00:00 2001 From: Jonathan Lassoff Date: Mon, 11 Dec 2023 14:55:18 -0800 Subject: [PATCH] DMZ Tagging: Support multiple tags, move to panther_config --- global_helpers/panther_base_helpers.py | 13 ++++++------- global_helpers/panther_config_defaults.py | 7 +++++++ ..._only_dmz_security_groups_publicly_accessible.py | 12 ++++++++++-- ...only_dmz_security_groups_publicly_accessible.yml | 9 +++++++++ 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/global_helpers/panther_base_helpers.py b/global_helpers/panther_base_helpers.py index 8ebeb2a27..97d88caee 100644 --- a/global_helpers/panther_base_helpers.py +++ b/global_helpers/panther_base_helpers.py @@ -7,6 +7,7 @@ from functools import reduce from ipaddress import ip_address, ip_network from typing import Any, List, Optional, Sequence, Union +from panther_config import config # # # # # # # # # # # # # # # Exceptions # @@ -59,23 +60,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..b754323b2 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 + if isinstance(DMZ_TAGS, MagicMock): + DMZ_TAGS = set([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",