mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-01-25 02:08:11 +00:00
feat(aws): add new check for Codebuild projects visibility (#8127)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
This commit is contained in:
@@ -44,6 +44,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- `monitor_alert_service_health_exists` check for Azure provider [(#8067)](https://github.com/prowler-cloud/prowler/pull/8067)
|
||||
- Replace `Domain.Read.All` with `Directory.Read.All` in Azure and M365 docs [(#8075)](https://github.com/prowler-cloud/prowler/pull/8075)
|
||||
- Refactor IaC provider to use Checkov as Python library [(#8093)](https://github.com/prowler-cloud/prowler/pull/8093)
|
||||
- New check `codebuild_project_not_publicly_accessible` for AWS provider [(#8127)](https://github.com/prowler-cloud/prowler/pull/8127)
|
||||
|
||||
### Fixed
|
||||
- Consolidate Azure Storage file service properties to the account level, improving the accuracy of the `storage_ensure_file_shares_soft_delete_is_enabled` check [(#8087)](https://github.com/prowler-cloud/prowler/pull/8087)
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "codebuild_project_not_publicly_accessible",
|
||||
"CheckTitle": "Ensure AWS CodeBuild projects are not public",
|
||||
"CheckType": [],
|
||||
"ServiceName": "codebuild",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:aws:codebuild:region:account-id:project:project-name",
|
||||
"Severity": "high",
|
||||
"ResourceType": "AwsCodeBuildProject",
|
||||
"Description": "Check for CodeBuild projects ensuring that the project visibility is appropriate",
|
||||
"Risk": "Public CodeBuild Project ensures all build logs and artifacts are available to the public. Environment variables, source code, and other sensitive information may have been output to the build logs and artifacts. You must be careful about what information is output to the build logs.",
|
||||
"RelatedUrl": "",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"NativeIaC": "",
|
||||
"Terraform": "",
|
||||
"CLI": "aws codebuild update-project --name <project-name> --project-visibility PRIVATE",
|
||||
"Other": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Ensure that all CodeBuild projects are private to avoid fact gathering about builds from an Attacker.",
|
||||
"Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/public-builds.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
from typing import List
|
||||
|
||||
from prowler.lib.check.models import Check, Check_Report_AWS
|
||||
from prowler.providers.aws.services.codebuild.codebuild_client import codebuild_client
|
||||
|
||||
|
||||
class codebuild_project_not_publicly_accessible(Check):
|
||||
def execute(self) -> List[Check_Report_AWS]:
|
||||
findings = []
|
||||
|
||||
projects = codebuild_client.projects
|
||||
for arn, project in projects.items():
|
||||
report = Check_Report_AWS(self.metadata(), resource=project)
|
||||
report.resource_id = project.name
|
||||
report.resource_arn = arn
|
||||
report.region = project.region
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"CodeBuild project {project.name} is public."
|
||||
|
||||
if project.project_visibility == "PRIVATE":
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"CodeBuild project {project.name} is private."
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -121,6 +121,7 @@ class Codebuild(AWSService):
|
||||
)
|
||||
project.tags = project_info.get("tags", [])
|
||||
project.service_role_arn = project_info.get("serviceRole", "")
|
||||
project.project_visibility = project_info.get("projectVisibility", "")
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
@@ -222,6 +223,7 @@ class Project(BaseModel):
|
||||
s3_logs: Optional[s3Logs]
|
||||
cloudwatch_logs: Optional[CloudWatchLogs]
|
||||
tags: Optional[list]
|
||||
project_visibility: Optional[str] = None
|
||||
|
||||
|
||||
class ExportConfig(BaseModel):
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.aws.services.codebuild.codebuild_service import Project
|
||||
|
||||
AWS_REGION = "eu-west-1"
|
||||
AWS_ACCOUNT_NUMBER = "123456789012"
|
||||
|
||||
|
||||
class Test_codebuild_project_not_publicly_accessible:
|
||||
def test_project_public(self):
|
||||
codebuild_client = mock.MagicMock
|
||||
project_name = "test-project"
|
||||
project_arn = f"arn:aws:codebuild:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:project/{project_name}"
|
||||
codebuild_client.projects = {
|
||||
project_arn: Project(
|
||||
name=project_name,
|
||||
arn=project_arn,
|
||||
region="eu-west-1",
|
||||
project_visibility="PUBLIC",
|
||||
tags=[],
|
||||
)
|
||||
}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_service.Codebuild",
|
||||
codebuild_client,
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_not_publicly_accessible.codebuild_project_not_publicly_accessible.codebuild_client",
|
||||
codebuild_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_not_publicly_accessible.codebuild_project_not_publicly_accessible import (
|
||||
codebuild_project_not_publicly_accessible,
|
||||
)
|
||||
|
||||
check = codebuild_project_not_publicly_accessible()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"CodeBuild project {project_name} is public."
|
||||
)
|
||||
assert result[0].resource_id == project_name
|
||||
assert result[0].resource_arn == project_arn
|
||||
assert result[0].resource_tags == []
|
||||
assert result[0].region == AWS_REGION
|
||||
|
||||
def test_project_private(self):
|
||||
codebuild_client = mock.MagicMock
|
||||
project_name = "test-project"
|
||||
project_arn = f"arn:aws:codebuild:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:project/{project_name}"
|
||||
codebuild_client.projects = {
|
||||
project_arn: Project(
|
||||
name=project_name,
|
||||
arn=project_arn,
|
||||
region="eu-west-1",
|
||||
project_visibility="PRIVATE",
|
||||
tags=[],
|
||||
)
|
||||
}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_service.Codebuild",
|
||||
codebuild_client,
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_not_publicly_accessible.codebuild_project_not_publicly_accessible.codebuild_client",
|
||||
codebuild_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_not_publicly_accessible.codebuild_project_not_publicly_accessible import (
|
||||
codebuild_project_not_publicly_accessible,
|
||||
)
|
||||
|
||||
check = codebuild_project_not_publicly_accessible()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"CodeBuild project {project_name} is private."
|
||||
)
|
||||
assert result[0].resource_id == project_name
|
||||
assert result[0].resource_arn == project_arn
|
||||
assert result[0].resource_tags == []
|
||||
assert result[0].region == AWS_REGION
|
||||
|
||||
def test_project_no_visibility_set(self):
|
||||
codebuild_client = mock.MagicMock
|
||||
project_name = "test-project"
|
||||
project_arn = f"arn:aws:codebuild:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:project/{project_name}"
|
||||
codebuild_client.projects = {
|
||||
project_arn: Project(
|
||||
name=project_name,
|
||||
arn=project_arn,
|
||||
region="eu-west-1",
|
||||
project_visibility=None,
|
||||
tags=[],
|
||||
)
|
||||
}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_service.Codebuild",
|
||||
codebuild_client,
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_not_publicly_accessible.codebuild_project_not_publicly_accessible.codebuild_client",
|
||||
codebuild_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_not_publicly_accessible.codebuild_project_not_publicly_accessible import (
|
||||
codebuild_project_not_publicly_accessible,
|
||||
)
|
||||
|
||||
check = codebuild_project_not_publicly_accessible()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"CodeBuild project {project_name} is public."
|
||||
)
|
||||
assert result[0].resource_id == project_name
|
||||
assert result[0].resource_arn == project_arn
|
||||
assert result[0].resource_tags == []
|
||||
assert result[0].region == AWS_REGION
|
||||
|
||||
def test_project_empty_visibility(self):
|
||||
codebuild_client = mock.MagicMock
|
||||
project_name = "test-project"
|
||||
project_arn = f"arn:aws:codebuild:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:project/{project_name}"
|
||||
codebuild_client.projects = {
|
||||
project_arn: Project(
|
||||
name=project_name,
|
||||
arn=project_arn,
|
||||
region="eu-west-1",
|
||||
project_visibility="",
|
||||
tags=[],
|
||||
)
|
||||
}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_service.Codebuild",
|
||||
codebuild_client,
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_not_publicly_accessible.codebuild_project_not_publicly_accessible.codebuild_client",
|
||||
codebuild_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_not_publicly_accessible.codebuild_project_not_publicly_accessible import (
|
||||
codebuild_project_not_publicly_accessible,
|
||||
)
|
||||
|
||||
check = codebuild_project_not_publicly_accessible()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"CodeBuild project {project_name} is public."
|
||||
)
|
||||
assert result[0].resource_id == project_name
|
||||
assert result[0].resource_arn == project_arn
|
||||
assert result[0].resource_tags == []
|
||||
assert result[0].region == AWS_REGION
|
||||
@@ -28,6 +28,7 @@ build_id = "test:93f838a7-cd20-48ae-90e5-c10fbbc78ca6"
|
||||
last_invoked_time = datetime.now() - timedelta(days=2)
|
||||
bitbucket_url = "https://bitbucket.org/example/repo.git"
|
||||
secondary_bitbucket_url = "https://bitbucket.org/example/secondary-repo.git"
|
||||
project_visibility = "PRIVATE"
|
||||
|
||||
report_group_arn = f"arn:{AWS_COMMERCIAL_PARTITION}:codebuild:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:report-group/{project_name}"
|
||||
|
||||
@@ -71,6 +72,7 @@ def mock_make_api_call(self, operation_name, kwarg):
|
||||
},
|
||||
},
|
||||
"tags": [{"key": "Name", "value": project_name}],
|
||||
"projectVisibility": project_visibility,
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -152,6 +154,7 @@ class Test_Codebuild_Service:
|
||||
)
|
||||
assert codebuild.projects[project_arn].tags[0]["key"] == "Name"
|
||||
assert codebuild.projects[project_arn].tags[0]["value"] == project_name
|
||||
assert codebuild.projects[project_arn].project_visibility == project_visibility
|
||||
# Asserttions related with report groups
|
||||
assert len(codebuild.report_groups) == 1
|
||||
assert isinstance(codebuild.report_groups, dict)
|
||||
|
||||
Reference in New Issue
Block a user