feat(allowlist): Support regexes in Tags to allow "or"-like conditional matching (#2300)

Co-authored-by: Kevin Pullin <kevinp@nexttrucking.com>
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
This commit is contained in:
Kevin Pullin
2023-05-05 05:56:27 -07:00
committed by GitHub
parent 05e4911d6f
commit c22bf01003
4 changed files with 85 additions and 46 deletions

View File

@@ -7,9 +7,10 @@ You can use `-w`/`--allowlist-file` with the path of your allowlist yaml file, b
## Allowlist Yaml File Syntax ## Allowlist Yaml File Syntax
### Account, Check and/or Region can be * to apply for all the cases ### Account, Check and/or Region can be * to apply for all the cases.
### Resources is a list that can have either Regex or Keywords ### Resources and tags are lists that can have either Regex or Keywords.
### Tags is an optional list containing tuples of 'key=value' ### Tags is an optional list that matches on tuples of 'key=value' and are "ANDed" together.
### Use an alternation Regex to match one of multiple tags with "ORed" logic.
########################### ALLOWLIST EXAMPLE ########################### ########################### ALLOWLIST EXAMPLE ###########################
Allowlist: Allowlist:
Accounts: Accounts:
@@ -25,10 +26,10 @@ You can use `-w`/`--allowlist-file` with the path of your allowlist yaml file, b
Regions: Regions:
- "*" - "*"
Resources: Resources:
- "test" # Will ignore every resource containing the string "test" and the tags 'test=test' and 'project=test' in account 123456789012 and every region - "test"
Tags: Tags:
- "test=test" # Will ignore every resource containing the string "test" and the tags 'test=test' and 'project=test' in account 123456789012 and every region - "test=test" # Will ignore every resource containing the string "test" and the tags 'test=test' and
- "project=test" - "project=test|project=stage" # either of ('project=test' OR project=stage) in account 123456789012 and every region
"*": "*":
Checks: Checks:

View File

@@ -1,6 +1,7 @@
### Account, Check and/or Region can be * to apply for all the cases ### Account, Check and/or Region can be * to apply for all the cases.
### Resources is a list that can have either Regex or Keywords ### Resources and tags are lists that can have either Regex or Keywords.
### Tags is an optional list containing tuples of 'key=value' ### Tags is an optional list that matches on tuples of 'key=value' and are "ANDed" together.
### Use an alternation Regex to match one of multiple tags with "ORed" logic.
########################### ALLOWLIST EXAMPLE ########################### ########################### ALLOWLIST EXAMPLE ###########################
Allowlist: Allowlist:
Accounts: Accounts:
@@ -16,10 +17,10 @@ Allowlist:
Regions: Regions:
- "*" - "*"
Resources: Resources:
- "test" # Will ignore every resource containing the string "test" and the tags 'test=test' and 'project=test' in account 123456789012 and every region - "test"
Tags: Tags:
- "test=test" # Will ignore every resource containing the string "test" and the tags 'test=test' and 'project=test' in account 123456789012 and every region - "test=test" # Will ignore every resource containing the string "test" and the tags 'test=test' and
- "project=test" - "project=test|project=stage" # either of ('project=test' OR project=stage) in account 123456789012 and every region
"*": "*":
Checks: Checks:

View File

@@ -192,13 +192,21 @@ def is_allowlisted_in_tags(check_allowlist, elem, resource, tags):
# Check if there are allowlisted tags # Check if there are allowlisted tags
if "Tags" in check_allowlist: if "Tags" in check_allowlist:
# Check if there are resource tags # Check if there are resource tags
if tags: if not tags or not re.search(elem, resource):
tags_in_resource_tags = True return False
for tag in check_allowlist["Tags"]:
if tag not in tags: all_allowed_tags_in_resource_tags = True
tags_in_resource_tags = False for allowed_tag in check_allowlist["Tags"]:
if tags_in_resource_tags and re.search(elem, resource): found_allowed_tag = False
return True for resource_tag in tags:
if re.search(allowed_tag, resource_tag):
found_allowed_tag = True
break
if not found_allowed_tag:
all_allowed_tags_in_resource_tags = False
return all_allowed_tags_in_resource_tags
else: else:
if re.search(elem, resource): if re.search(elem, resource):
return True return True

View File

@@ -165,15 +165,15 @@ class Test_Allowlist:
} }
assert is_allowlisted( assert is_allowlisted(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler", []
) )
assert is_allowlisted( assert is_allowlisted(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler-test", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler-test", []
) )
assert is_allowlisted( assert is_allowlisted(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "test-prowler", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "test-prowler", []
) )
assert is_allowlisted( assert is_allowlisted(
@@ -187,7 +187,7 @@ class Test_Allowlist:
assert not ( assert not (
is_allowlisted( is_allowlisted(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", "us-east-2", "test", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", "us-east-2", "test", []
) )
) )
@@ -207,20 +207,20 @@ class Test_Allowlist:
} }
assert is_allowlisted( assert is_allowlisted(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler", []
) )
assert is_allowlisted( assert is_allowlisted(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler-test", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler-test", []
) )
assert is_allowlisted( assert is_allowlisted(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "test-prowler", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "test-prowler", []
) )
assert not ( assert not (
is_allowlisted( is_allowlisted(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", "us-east-2", "test", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", "us-east-2", "test", []
) )
) )
@@ -240,20 +240,20 @@ class Test_Allowlist:
} }
assert is_allowlisted( assert is_allowlisted(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler", []
) )
assert is_allowlisted( assert is_allowlisted(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler-test", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler-test", []
) )
assert is_allowlisted( assert is_allowlisted(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "test-prowler", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "test-prowler", []
) )
assert not ( assert not (
is_allowlisted( is_allowlisted(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", "us-east-2", "test", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", "us-east-2", "test", []
) )
) )
@@ -273,20 +273,20 @@ class Test_Allowlist:
} }
assert is_allowlisted_in_region( assert is_allowlisted_in_region(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler", []
) )
assert is_allowlisted_in_region( assert is_allowlisted_in_region(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler-test", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler-test", []
) )
assert is_allowlisted_in_region( assert is_allowlisted_in_region(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "test-prowler", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "test-prowler", []
) )
assert not ( assert not (
is_allowlisted_in_region( is_allowlisted_in_region(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", "us-east-2", "test", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", "us-east-2", "test", []
) )
) )
@@ -306,20 +306,20 @@ class Test_Allowlist:
} }
assert is_allowlisted_in_check( assert is_allowlisted_in_check(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler", []
) )
assert is_allowlisted_in_check( assert is_allowlisted_in_check(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler-test", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "prowler-test", []
) )
assert is_allowlisted_in_check( assert is_allowlisted_in_check(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "test-prowler", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", AWS_REGION, "test-prowler", []
) )
assert not ( assert not (
is_allowlisted_in_check( is_allowlisted_in_check(
allowlist, AWS_ACCOUNT_NUMBER, "check_test", "us-east-2", "test", "" allowlist, AWS_ACCOUNT_NUMBER, "check_test", "us-east-2", "test", []
) )
) )
@@ -332,7 +332,7 @@ class Test_Allowlist:
"check_test": { "check_test": {
"Regions": ["us-east-1", "eu-west-1"], "Regions": ["us-east-1", "eu-west-1"],
"Resources": ["*"], "Resources": ["*"],
"Tags": ["environment=dev", "project=prowler"], "Tags": ["environment=dev", "project=.*"],
} }
} }
} }
@@ -345,7 +345,7 @@ class Test_Allowlist:
"check_test", "check_test",
AWS_REGION, AWS_REGION,
"prowler", "prowler",
"environment=dev", ["environment=dev"],
) )
assert is_allowlisted( assert is_allowlisted(
@@ -354,7 +354,7 @@ class Test_Allowlist:
"check_test", "check_test",
AWS_REGION, AWS_REGION,
"prowler-test", "prowler-test",
"environment=dev project=prowler", ["environment=dev", "project=prowler"],
) )
assert not ( assert not (
@@ -364,7 +364,7 @@ class Test_Allowlist:
"check_test", "check_test",
"us-east-2", "us-east-2",
"test", "test",
"environment=pro", ["environment=pro"],
) )
) )
@@ -380,14 +380,14 @@ class Test_Allowlist:
check_allowlist, check_allowlist,
check_allowlist["Resources"][0], check_allowlist["Resources"][0],
"prowler", "prowler",
"environment=dev", ["environment=dev"],
) )
assert is_allowlisted_in_tags( assert is_allowlisted_in_tags(
check_allowlist, check_allowlist,
check_allowlist["Resources"][0], check_allowlist["Resources"][0],
"prowler-test", "prowler-test",
"environment=dev project=prowler", ["environment=dev", "project=prowler"],
) )
assert not ( assert not (
@@ -395,6 +395,35 @@ class Test_Allowlist:
check_allowlist, check_allowlist,
check_allowlist["Resources"][0], check_allowlist["Resources"][0],
"test", "test",
"environment=pro", ["environment=pro"],
) )
) )
def test_is_allowlisted_in_tags_regex(self):
# Allowlist example
check_allowlist = {
"Regions": ["us-east-1", "eu-west-1"],
"Resources": ["*"],
"Tags": ["environment=(dev|test)", ".*=prowler"],
}
assert is_allowlisted_in_tags(
check_allowlist,
check_allowlist["Resources"][0],
"prowler-test",
["environment=test", "proj=prowler"],
)
assert not is_allowlisted_in_tags(
check_allowlist,
check_allowlist["Resources"][0],
"prowler-test",
["env=prod", "project=prowler"],
)
assert not is_allowlisted_in_tags(
check_allowlist,
check_allowlist["Resources"][0],
"prowler-test",
["environment=prod", "project=myproj"],
)