fix(aws): handle AccessDenied when retrieving resource policy (#6912)

Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
This commit is contained in:
Prowler Bot
2025-02-13 01:15:51 +01:00
committed by GitHub
parent 91b74822e9
commit 48cb45b7a8
19 changed files with 150 additions and 83 deletions
@@ -7,6 +7,8 @@ class awslambda_function_not_publicly_accessible(Check):
def execute(self):
findings = []
for function in awslambda_client.functions.values():
if function.policy is None:
continue
report = Check_Report_AWS(metadata=self.metadata(), resource=function)
report.status = "PASS"
@@ -7,6 +7,8 @@ class dynamodb_table_cross_account_access(Check):
def execute(self):
findings = []
for table in dynamodb_client.tables.values():
if table.policy is None:
continue
report = Check_Report_AWS(metadata=self.metadata(), resource=table)
report.status = "PASS"
report.status_extended = (
@@ -8,6 +8,8 @@ class ecr_repositories_not_publicly_accessible(Check):
findings = []
for registry in ecr_client.registries.values():
for repository in registry.repositories:
if repository.policy is None:
continue
report = Check_Report_AWS(metadata=self.metadata(), resource=repository)
report.status = "PASS"
report.status_extended = (
@@ -87,6 +87,7 @@ class ECR(AWSService):
logger.warning(
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
repository.policy = {}
except Exception as error:
if "RepositoryPolicyNotFoundException" not in str(error):
@@ -7,6 +7,8 @@ class efs_not_publicly_accessible(Check):
def execute(self):
findings = []
for fs in efs_client.filesystems.values():
if fs.policy is None:
continue
report = Check_Report_AWS(metadata=self.metadata(), resource=fs)
report.status = "PASS"
report.status_extended = f"EFS {fs.id} has a policy which does not allow access to any client within the VPC."
@@ -164,7 +164,7 @@ class FileSystem(BaseModel):
id: str
arn: str
region: str
policy: Optional[dict] = {}
policy: Optional[dict]
backup_policy: Optional[str] = "DISABLED"
encrypted: bool
availability_zone_id: Optional[str]
@@ -9,6 +9,8 @@ class eventbridge_bus_cross_account_access(Check):
def execute(self):
findings = []
for bus in eventbridge_client.buses.values():
if bus.policy is None:
continue
report = Check_Report_AWS(metadata=self.metadata(), resource=bus)
report.status = "PASS"
report.status_extended = (
@@ -9,6 +9,8 @@ class eventbridge_bus_exposed(Check):
def execute(self):
findings = []
for bus in eventbridge_client.buses.values():
if bus.policy is None:
continue
report = Check_Report_AWS(metadata=self.metadata(), resource=bus)
report.status = "PASS"
report.status_extended = (
@@ -7,6 +7,8 @@ class eventbridge_schema_registry_cross_account_access(Check):
def execute(self):
findings = []
for registry in schema_client.registries.values():
if registry.policy is None:
continue
report = Check_Report_AWS(metadata=self.metadata(), resource=registry)
report.status = "PASS"
report.status_extended = f"EventBridge schema registry {registry.name} does not allow cross-account access."
@@ -7,6 +7,8 @@ class glue_data_catalogs_not_publicly_accessible(Check):
def execute(self):
findings = []
for data_catalog in glue_client.data_catalogs.values():
if data_catalog.policy is None:
continue
report = Check_Report_AWS(metadata=self.metadata(), resource=data_catalog)
report.resource_id = glue_client.audited_account
report.resource_arn = glue_client._get_data_catalog_arn_template(
@@ -17,7 +17,7 @@ class opensearch_service_domains_not_publicly_accessible(Check):
if domain.vpc_id:
report.status_extended = f"Opensearch domain {domain.name} is in a VPC, then it is not publicly accessible."
elif domain.access_policy and is_policy_public(
elif domain.access_policy is not None and is_policy_public(
domain.access_policy, opensearch_client.audited_account
):
report.status = "FAIL"
@@ -7,6 +7,8 @@ class s3_bucket_cross_account_access(Check):
def execute(self):
findings = []
for bucket in s3_client.buckets.values():
if bucket.policy is None:
continue
report = Check_Report_AWS(metadata=self.metadata(), resource=bucket)
report.status = "PASS"
report.status_extended = f"S3 Bucket {bucket.name} has a bucket policy but it does not allow cross account access."
@@ -8,6 +8,8 @@ class s3_bucket_policy_public_write_access(Check):
def execute(self):
findings = []
for bucket in s3_client.buckets.values():
if bucket.policy is None:
continue
report = Check_Report_AWS(metadata=self.metadata(), resource=bucket)
# Check if bucket policy allow public write access
if not bucket.policy:
@@ -45,7 +45,9 @@ class s3_bucket_public_access(Check):
report.status_extended = f"S3 Bucket {bucket.name} has public access due to bucket ACL."
# 4. Check bucket policy
if is_policy_public(bucket.policy, s3_client.audited_account):
if bucket.policy is not None and is_policy_public(
bucket.policy, s3_client.audited_account
):
report.status = "FAIL"
report.status_extended = f"S3 Bucket {bucket.name} has public access due to bucket policy."
findings.append(report)
@@ -681,7 +681,7 @@ class Bucket(BaseModel):
logging: bool = False
public_access_block: Optional[PublicAccessBlock]
acl_grantees: List[ACL_Grantee] = Field(default_factory=list)
policy: Dict = Field(default_factory=dict)
policy: Optional[dict]
encryption: Optional[str]
region: str
logging_target_bucket: Optional[str]
@@ -9,6 +9,8 @@ class secretsmanager_not_publicly_accessible(Check):
def execute(self):
findings = []
for secret in secretsmanager_client.secrets.values():
if secret.policy is None:
continue
report = Check_Report_AWS(metadata=self.metadata(), resource=secret)
report.status = "PASS"
report.status_extended = (
@@ -7,6 +7,8 @@ class ses_identity_not_publicly_accessible(Check):
def execute(self):
findings = []
for identity in ses_client.email_identities.values():
if identity.policy is None:
continue
report = Check_Report_AWS(metadata=self.metadata(), resource=identity)
report.status = "PASS"
report.status_extended = (
@@ -104,12 +104,15 @@ class Test_dynamodb_table_cross_account_access:
def test_no_tables(self):
dynamodb_client = mock.MagicMock
dynamodb_client.tables = {}
with mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
), mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
with (
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
),
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
),
):
from prowler.providers.aws.services.dynamodb.dynamodb_table_cross_account_access.dynamodb_table_cross_account_access import (
dynamodb_table_cross_account_access,
@@ -131,15 +134,19 @@ class Test_dynamodb_table_cross_account_access:
arn=arn,
name=test_table_name,
region=AWS_REGION_EU_WEST_1,
policy={},
)
}
with mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
), mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
with (
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
),
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
),
):
from prowler.providers.aws.services.dynamodb.dynamodb_table_cross_account_access.dynamodb_table_cross_account_access import (
dynamodb_table_cross_account_access,
@@ -172,12 +179,15 @@ class Test_dynamodb_table_cross_account_access:
policy=test_restricted_policy,
)
}
with mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
), mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
with (
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
),
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
),
):
from prowler.providers.aws.services.dynamodb.dynamodb_table_cross_account_access.dynamodb_table_cross_account_access import (
dynamodb_table_cross_account_access,
@@ -211,12 +221,15 @@ class Test_dynamodb_table_cross_account_access:
)
}
with mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
), mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
with (
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
),
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
),
):
from prowler.providers.aws.services.dynamodb.dynamodb_table_cross_account_access.dynamodb_table_cross_account_access import (
dynamodb_table_cross_account_access,
@@ -251,12 +264,15 @@ class Test_dynamodb_table_cross_account_access:
)
}
with mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
), mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
with (
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
),
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
),
):
from prowler.providers.aws.services.dynamodb.dynamodb_table_cross_account_access.dynamodb_table_cross_account_access import (
dynamodb_table_cross_account_access,
@@ -291,12 +307,15 @@ class Test_dynamodb_table_cross_account_access:
)
}
with mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
), mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
with (
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
),
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
),
):
from prowler.providers.aws.services.dynamodb.dynamodb_table_cross_account_access.dynamodb_table_cross_account_access import (
dynamodb_table_cross_account_access,
@@ -330,12 +349,15 @@ class Test_dynamodb_table_cross_account_access:
)
}
with mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
), mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
with (
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
),
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
),
):
from prowler.providers.aws.services.dynamodb.dynamodb_table_cross_account_access.dynamodb_table_cross_account_access import (
dynamodb_table_cross_account_access,
@@ -369,12 +391,15 @@ class Test_dynamodb_table_cross_account_access:
)
}
with mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
), mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
with (
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_service.DynamoDB",
new=dynamodb_client,
),
mock.patch(
"prowler.providers.aws.services.dynamodb.dynamodb_client.dynamodb_client",
new=dynamodb_client,
),
):
from prowler.providers.aws.services.dynamodb.dynamodb_table_cross_account_access.dynamodb_table_cross_account_access import (
dynamodb_table_cross_account_access,
@@ -43,12 +43,15 @@ class Test_ecr_repositories_not_publicly_accessible:
ecr_client = mock.MagicMock
ecr_client.registries = {}
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_aws_provider(),
), mock.patch(
"prowler.providers.aws.services.ecr.ecr_repositories_not_publicly_accessible.ecr_repositories_not_publicly_accessible.ecr_client",
ecr_client,
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_aws_provider(),
),
mock.patch(
"prowler.providers.aws.services.ecr.ecr_repositories_not_publicly_accessible.ecr_repositories_not_publicly_accessible.ecr_client",
ecr_client,
),
):
from prowler.providers.aws.services.ecr.ecr_repositories_not_publicly_accessible.ecr_repositories_not_publicly_accessible import (
ecr_repositories_not_publicly_accessible,
@@ -70,12 +73,15 @@ class Test_ecr_repositories_not_publicly_accessible:
rules=[],
)
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_aws_provider(),
), mock.patch(
"prowler.providers.aws.services.ecr.ecr_repositories_not_publicly_accessible.ecr_repositories_not_publicly_accessible.ecr_client",
ecr_client,
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_aws_provider(),
),
mock.patch(
"prowler.providers.aws.services.ecr.ecr_repositories_not_publicly_accessible.ecr_repositories_not_publicly_accessible.ecr_client",
ecr_client,
),
):
from prowler.providers.aws.services.ecr.ecr_repositories_not_publicly_accessible.ecr_repositories_not_publicly_accessible import (
ecr_repositories_not_publicly_accessible,
@@ -109,12 +115,15 @@ class Test_ecr_repositories_not_publicly_accessible:
rules=[],
)
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_aws_provider(),
), mock.patch(
"prowler.providers.aws.services.ecr.ecr_repositories_not_publicly_accessible.ecr_repositories_not_publicly_accessible.ecr_client",
ecr_client,
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_aws_provider(),
),
mock.patch(
"prowler.providers.aws.services.ecr.ecr_repositories_not_publicly_accessible.ecr_repositories_not_publicly_accessible.ecr_client",
ecr_client,
),
):
from prowler.providers.aws.services.ecr.ecr_repositories_not_publicly_accessible.ecr_repositories_not_publicly_accessible import (
ecr_repositories_not_publicly_accessible,
@@ -145,7 +154,7 @@ class Test_ecr_repositories_not_publicly_accessible:
arn=repository_arn,
region=AWS_REGION_EU_WEST_1,
scan_on_push=True,
policy=None,
policy={},
images_details=None,
lifecycle_policy=None,
)
@@ -153,12 +162,15 @@ class Test_ecr_repositories_not_publicly_accessible:
rules=[],
)
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_aws_provider(),
), mock.patch(
"prowler.providers.aws.services.ecr.ecr_repositories_not_publicly_accessible.ecr_repositories_not_publicly_accessible.ecr_client",
ecr_client,
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_aws_provider(),
),
mock.patch(
"prowler.providers.aws.services.ecr.ecr_repositories_not_publicly_accessible.ecr_repositories_not_publicly_accessible.ecr_client",
ecr_client,
),
):
from prowler.providers.aws.services.ecr.ecr_repositories_not_publicly_accessible.ecr_repositories_not_publicly_accessible import (
ecr_repositories_not_publicly_accessible,
@@ -199,12 +211,15 @@ class Test_ecr_repositories_not_publicly_accessible:
rules=[],
)
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_aws_provider(),
), mock.patch(
"prowler.providers.aws.services.ecr.ecr_repositories_not_publicly_accessible.ecr_repositories_not_publicly_accessible.ecr_client",
ecr_client,
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_aws_provider(),
),
mock.patch(
"prowler.providers.aws.services.ecr.ecr_repositories_not_publicly_accessible.ecr_repositories_not_publicly_accessible.ecr_client",
ecr_client,
),
):
from prowler.providers.aws.services.ecr.ecr_repositories_not_publicly_accessible.ecr_repositories_not_publicly_accessible import (
ecr_repositories_not_publicly_accessible,