Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions prowler/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
- `--list-checks` and `--list-checks-json` now include `threat-detection` category checks in their output [(#10578)](https://github.com/prowler-cloud/prowler/pull/10578)
- Missing `__init__.py` in `codebuild_project_uses_allowed_github_organizations` check preventing discovery by `--list-checks` [(#10584)](https://github.com/prowler-cloud/prowler/pull/10584)
- Azure Key Vault checks emitting incorrect findings for keys, secrets, and vault logging [(#10332)](https://github.com/prowler-cloud/prowler/pull/10332)
- `is_policy_public` now recognizes `kms:CallerAccount`, `kms:ViaService`, `aws:CalledVia`, `aws:CalledViaFirst`, and `aws:CalledViaLast` as restrictive condition keys, fixing false positives in `kms_key_policy_is_not_public` and other checks that use `is_condition_block_restrictive` [(#10600)](https://github.com/prowler-cloud/prowler/pull/10600)
- `_enabled_regions` empty-set bug in `AwsProvider.generate_regional_clients` creating boto3 clients for all 36 AWS regions instead of the audited ones, causing random CI timeouts and slow test runs [(#10598)](https://github.com/prowler-cloud/prowler/pull/10598)

### 🔐 Security
Expand Down
10 changes: 10 additions & 0 deletions prowler/providers/aws/services/iam/lib/policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,11 @@ def is_condition_block_restrictive(
"aws:sourceorgpaths",
"aws:userid",
"aws:username",
"aws:calledvia",
"aws:calledviafirst",
"aws:calledvialast",
"kms:calleraccount",
"kms:viaservice",
"s3:resourceaccount",
"lambda:eventsourcetoken", # For Alexa Home functions, a token that the invoker must supply.
],
Expand All @@ -635,6 +640,11 @@ def is_condition_block_restrictive(
"aws:sourceorgpaths",
"aws:userid",
"aws:username",
"aws:calledvia",
"aws:calledviafirst",
"aws:calledvialast",
"kms:calleraccount",
"kms:viaservice",
"s3:resourceaccount",
"lambda:eventsourcetoken",
],
Expand Down
174 changes: 174 additions & 0 deletions tests/providers/aws/services/iam/lib/policy_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,115 @@ def test_condition_parser_string_like_AWS_ResourceAccount_str_not_valid(self):
condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
)

def test_condition_parser_string_equals_aws_CalledVia_str(self):
condition_statement = {
"StringEquals": {"aws:CalledVia": "cloudformation.amazonaws.com"}
}
assert is_condition_block_restrictive(
condition_statement,
TRUSTED_AWS_ACCOUNT_NUMBER,
is_cross_account_allowed=True,
)

def test_condition_parser_string_equals_aws_CalledViaFirst_str(self):
condition_statement = {
"StringEquals": {"aws:CalledViaFirst": "cloudformation.amazonaws.com"}
}
assert is_condition_block_restrictive(
condition_statement,
TRUSTED_AWS_ACCOUNT_NUMBER,
is_cross_account_allowed=True,
)

def test_condition_parser_string_equals_aws_CalledViaLast_str(self):
condition_statement = {
"StringEquals": {"aws:CalledViaLast": "glue.amazonaws.com"}
}
assert is_condition_block_restrictive(
condition_statement,
TRUSTED_AWS_ACCOUNT_NUMBER,
is_cross_account_allowed=True,
)

def test_condition_parser_string_like_aws_CalledVia_str(self):
condition_statement = {"StringLike": {"aws:CalledVia": "*.amazonaws.com"}}
assert is_condition_block_restrictive(
condition_statement,
TRUSTED_AWS_ACCOUNT_NUMBER,
is_cross_account_allowed=True,
)

def test_condition_parser_string_equals_kms_CallerAccount_str(self):
condition_statement = {
"StringEquals": {"kms:CallerAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
}
assert is_condition_block_restrictive(
condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
)

def test_condition_parser_string_equals_kms_CallerAccount_str_not_valid(self):
condition_statement = {
"StringEquals": {"kms:CallerAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
}
assert not is_condition_block_restrictive(
condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
)

def test_condition_parser_string_equals_kms_CallerAccount_list(self):
condition_statement = {
"StringEquals": {"kms:CallerAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
}
assert is_condition_block_restrictive(
condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
)

def test_condition_parser_string_equals_kms_CallerAccount_list_not_valid(self):
condition_statement = {
"StringEquals": {
"kms:CallerAccount": [
TRUSTED_AWS_ACCOUNT_NUMBER,
NON_TRUSTED_AWS_ACCOUNT_NUMBER,
]
}
}
assert not is_condition_block_restrictive(
condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
)

def test_condition_parser_string_equals_kms_ViaService_str(self):
condition_statement = {
"StringEquals": {"kms:ViaService": "glue.eu-central-1.amazonaws.com"}
}
assert is_condition_block_restrictive(
condition_statement,
TRUSTED_AWS_ACCOUNT_NUMBER,
is_cross_account_allowed=True,
)

def test_condition_parser_string_like_kms_CallerAccount_str(self):
condition_statement = {
"StringLike": {"kms:CallerAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
}
assert is_condition_block_restrictive(
condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
)

def test_condition_parser_string_like_kms_CallerAccount_str_not_valid(self):
condition_statement = {
"StringLike": {"kms:CallerAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
}
assert not is_condition_block_restrictive(
condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
)

def test_condition_parser_string_like_kms_ViaService_str(self):
condition_statement = {"StringLike": {"kms:ViaService": "glue.*.amazonaws.com"}}
assert is_condition_block_restrictive(
condition_statement,
TRUSTED_AWS_ACCOUNT_NUMBER,
is_cross_account_allowed=True,
)

def test_condition_parser_two_lists_unrestrictive(self):
condition_statement = {
"StringLike": {
Expand Down Expand Up @@ -2357,6 +2466,71 @@ def test_is_policy_public_with_trusted_ips_partial_match(self):
trusted_ips=["1.2.3.4", "5.6.7.8"],
)

def test_is_policy_public_kms_caller_account_and_via_service(self):
policy = {
"Version": "2008-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {"AWS": "*"},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:CreateGrant",
"kms:DescribeKey",
],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:ViaService": "glue.eu-central-1.amazonaws.com",
"kms:CallerAccount": TRUSTED_AWS_ACCOUNT_NUMBER,
}
},
},
],
}
assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

def test_is_policy_public_kms_caller_account_only(self):
policy = {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {"AWS": "*"},
"Action": ["kms:Decrypt"],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:CallerAccount": TRUSTED_AWS_ACCOUNT_NUMBER,
}
},
},
],
}
assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

def test_is_policy_public_kms_via_service_without_account_restriction(self):
policy = {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {"AWS": "*"},
"Action": ["kms:Decrypt"],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:ViaService": "glue.eu-central-1.amazonaws.com",
}
},
},
],
}
assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

def test_check_admin_access(self):
policy = {
"Version": "2012-10-17",
Expand Down
Loading