mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-01-25 02:08:11 +00:00
feat(codebuild): add new check codebuild_project_logging_enabled (#5365)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
0449d6372c
commit
aac6038565
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "codebuild_project_logging_enabled",
|
||||
"CheckTitle": "Ensure that CodeBuild projects have S3 or CloudWatch logging enabled",
|
||||
"CheckType": [],
|
||||
"ServiceName": "codebuild",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AwsCodeBuildProject",
|
||||
"Description": "Ensure that CodeBuild projects have S3 or CloudWatch logging enabled.",
|
||||
"Risk": "Without logging, tracking and investigating security incidents in CodeBuild projects becomes challenging, reducing confidence in threat detections.",
|
||||
"RelatedUrl": "https://docs.aws.amazon.com/codebuild/latest/userguide/change-project.html#change-project-console-logs",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "aws codebuild update-project --name <project-name> --logs-config \"cloudWatchLogs={status=ENABLED},s3Logs={status=ENABLED\"}",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/codebuild-controls.html#codebuild-4",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Enable logging for CodeBuild projects to capture build events and logs for future analysis and incident response.",
|
||||
"Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/change-project.html#change-project-console-logs"
|
||||
}
|
||||
},
|
||||
"Categories": [
|
||||
"logging"
|
||||
],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_AWS
|
||||
from prowler.providers.aws.services.codebuild.codebuild_client import codebuild_client
|
||||
|
||||
|
||||
class codebuild_project_logging_enabled(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for project in codebuild_client.projects.values():
|
||||
report = Check_Report_AWS(self.metadata())
|
||||
report.resource_id = project.name
|
||||
report.resource_arn = project.arn
|
||||
report.region = project.region
|
||||
report.resource_tags = project.tags
|
||||
report.status = "PASS"
|
||||
|
||||
if project.cloudwatch_logs.enabled and project.s3_logs.enabled:
|
||||
report.status_extended = f"CodeBuild project {project.name} has enabled CloudWartch logs in log group {project.cloudwatch_logs.group_name} and S3 logs in bucket {project.s3_logs.bucket_location}."
|
||||
elif project.cloudwatch_logs.enabled:
|
||||
report.status_extended = f"CodeBuild project {project.name} has CloudWatch logging enabled in log group {project.cloudwatch_logs.group_name}."
|
||||
elif project.s3_logs.enabled:
|
||||
report.status_extended = f"CodeBuild project {project.name} has S3 logging enabled in bucket {project.s3_logs.bucket_location}."
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"CodeBuild project {project.name} does not have logging enabled."
|
||||
)
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -101,6 +101,18 @@ class Codebuild(AWSService):
|
||||
bucket_location=s3_logs.get("location", ""),
|
||||
encrypted=(not s3_logs.get("encryptionDisabled", False)),
|
||||
)
|
||||
cloudwatch_logs = project_info.get("logsConfig", {}).get(
|
||||
"cloudWatchLogs", {}
|
||||
)
|
||||
project.cloudwatch_logs = CloudWatchLogs(
|
||||
enabled=(
|
||||
True
|
||||
if cloudwatch_logs.get("status", "DISABLED") == "ENABLED"
|
||||
else False
|
||||
),
|
||||
group_name=cloudwatch_logs.get("groupName", ""),
|
||||
stream_name=cloudwatch_logs.get("streamName", ""),
|
||||
)
|
||||
project.tags = project_info.get("tags", [])
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
@@ -129,6 +141,12 @@ class s3Logs(BaseModel):
|
||||
encrypted: bool
|
||||
|
||||
|
||||
class CloudWatchLogs(BaseModel):
|
||||
enabled: bool
|
||||
group_name: str
|
||||
stream_name: str
|
||||
|
||||
|
||||
class Project(BaseModel):
|
||||
name: str
|
||||
arn: str
|
||||
@@ -140,4 +158,5 @@ class Project(BaseModel):
|
||||
secondary_sources: Optional[list[Source]] = []
|
||||
environment_variables: Optional[List[EnvironmentVariable]]
|
||||
s3_logs: Optional[s3Logs]
|
||||
cloudwatch_logs: Optional[CloudWatchLogs]
|
||||
tags: Optional[list]
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
from unittest.mock import patch
|
||||
|
||||
from boto3 import client
|
||||
from moto import mock_aws
|
||||
|
||||
from tests.providers.aws.utils import AWS_REGION_EU_WEST_1, set_mocked_aws_provider
|
||||
|
||||
|
||||
class Test_codebuild_project_logging_enabled:
|
||||
@mock_aws
|
||||
def test_no_projects(self):
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
|
||||
|
||||
from prowler.providers.aws.services.codebuild.codebuild_service import Codebuild
|
||||
|
||||
with patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
), patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_logging_enabled.codebuild_project_logging_enabled.codebuild_client",
|
||||
new=Codebuild(aws_provider),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_logging_enabled.codebuild_project_logging_enabled import (
|
||||
codebuild_project_logging_enabled,
|
||||
)
|
||||
|
||||
check = codebuild_project_logging_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
@mock_aws
|
||||
def test_project_cloudwatch_logging_enabled(self):
|
||||
codebuild_client = client("codebuild", region_name=AWS_REGION_EU_WEST_1)
|
||||
|
||||
project_name = "test-project-logging-enabled"
|
||||
|
||||
project_arn = codebuild_client.create_project(
|
||||
name=project_name,
|
||||
source={
|
||||
"type": "S3",
|
||||
"location": "test-bucket",
|
||||
},
|
||||
artifacts={
|
||||
"type": "NO_ARTIFACTS",
|
||||
},
|
||||
environment={
|
||||
"type": "LINUX_CONTAINER",
|
||||
"image": "aws/codebuild/standard:4.0",
|
||||
"computeType": "BUILD_GENERAL1_SMALL",
|
||||
"environmentVariables": [],
|
||||
},
|
||||
serviceRole="arn:aws:iam::123456789012:role/service-role/codebuild-role",
|
||||
logsConfig={
|
||||
"cloudWatchLogs": {
|
||||
"status": "ENABLED",
|
||||
"groupName": "cw-test-group",
|
||||
}
|
||||
},
|
||||
tags=[
|
||||
{"key": "Name", "value": "test"},
|
||||
],
|
||||
)["project"]["arn"]
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
|
||||
|
||||
from prowler.providers.aws.services.codebuild.codebuild_service import Codebuild
|
||||
|
||||
with patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
), patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_logging_enabled.codebuild_project_logging_enabled.codebuild_client",
|
||||
new=Codebuild(aws_provider),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_logging_enabled.codebuild_project_logging_enabled import (
|
||||
codebuild_project_logging_enabled,
|
||||
)
|
||||
|
||||
check = codebuild_project_logging_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"CodeBuild project {project_name} has CloudWatch logging enabled in log group cw-test-group."
|
||||
)
|
||||
assert result[0].resource_id == project_name
|
||||
assert result[0].resource_arn == project_arn
|
||||
assert result[0].resource_tags == [{"key": "Name", "value": "test"}]
|
||||
assert result[0].region == AWS_REGION_EU_WEST_1
|
||||
|
||||
@mock_aws
|
||||
def test_project_s3_logging_enabled(self):
|
||||
codebuild_client = client("codebuild", region_name=AWS_REGION_EU_WEST_1)
|
||||
|
||||
project_name = "test-project-logging-enabled"
|
||||
|
||||
project_arn = codebuild_client.create_project(
|
||||
name=project_name,
|
||||
source={
|
||||
"type": "S3",
|
||||
"location": "test-bucket",
|
||||
},
|
||||
artifacts={
|
||||
"type": "NO_ARTIFACTS",
|
||||
},
|
||||
environment={
|
||||
"type": "LINUX_CONTAINER",
|
||||
"image": "aws/codebuild/standard:4.0",
|
||||
"computeType": "BUILD_GENERAL1_SMALL",
|
||||
"environmentVariables": [],
|
||||
},
|
||||
serviceRole="arn:aws:iam::123456789012:role/service-role/codebuild-role",
|
||||
logsConfig={
|
||||
"s3Logs": {
|
||||
"status": "ENABLED",
|
||||
"location": "s3://test-bucket/logs",
|
||||
}
|
||||
},
|
||||
tags=[
|
||||
{"key": "Name", "value": "test"},
|
||||
],
|
||||
)["project"]["arn"]
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
|
||||
|
||||
from prowler.providers.aws.services.codebuild.codebuild_service import Codebuild
|
||||
|
||||
with patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
), patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_logging_enabled.codebuild_project_logging_enabled.codebuild_client",
|
||||
new=Codebuild(aws_provider),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_logging_enabled.codebuild_project_logging_enabled import (
|
||||
codebuild_project_logging_enabled,
|
||||
)
|
||||
|
||||
check = codebuild_project_logging_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"CodeBuild project {project_name} has S3 logging enabled in bucket s3://test-bucket/logs."
|
||||
)
|
||||
assert result[0].resource_id == project_name
|
||||
assert result[0].resource_arn == project_arn
|
||||
assert result[0].resource_tags == [{"key": "Name", "value": "test"}]
|
||||
assert result[0].region == AWS_REGION_EU_WEST_1
|
||||
|
||||
@mock_aws
|
||||
def test_project_both_logging_enabled(self):
|
||||
codebuild_client = client("codebuild", region_name=AWS_REGION_EU_WEST_1)
|
||||
|
||||
project_name = "test-project-logging-enabled"
|
||||
|
||||
project_arn = codebuild_client.create_project(
|
||||
name=project_name,
|
||||
source={
|
||||
"type": "S3",
|
||||
"location": "test-bucket",
|
||||
},
|
||||
artifacts={
|
||||
"type": "NO_ARTIFACTS",
|
||||
},
|
||||
environment={
|
||||
"type": "LINUX_CONTAINER",
|
||||
"image": "aws/codebuild/standard:4.0",
|
||||
"computeType": "BUILD_GENERAL1_SMALL",
|
||||
"environmentVariables": [],
|
||||
},
|
||||
serviceRole="arn:aws:iam::123456789012:role/service-role/codebuild-role",
|
||||
logsConfig={
|
||||
"cloudWatchLogs": {
|
||||
"status": "ENABLED",
|
||||
"groupName": "cw-test-group",
|
||||
},
|
||||
"s3Logs": {
|
||||
"status": "ENABLED",
|
||||
"location": "s3://test-bucket/logs",
|
||||
},
|
||||
},
|
||||
tags=[
|
||||
{"key": "Name", "value": "test"},
|
||||
],
|
||||
)["project"]["arn"]
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
|
||||
|
||||
from prowler.providers.aws.services.codebuild.codebuild_service import Codebuild
|
||||
|
||||
with patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
), patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_logging_enabled.codebuild_project_logging_enabled.codebuild_client",
|
||||
new=Codebuild(aws_provider),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_logging_enabled.codebuild_project_logging_enabled import (
|
||||
codebuild_project_logging_enabled,
|
||||
)
|
||||
|
||||
check = codebuild_project_logging_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"CodeBuild project {project_name} has enabled CloudWartch logs in log group cw-test-group and S3 logs in bucket s3://test-bucket/logs."
|
||||
)
|
||||
assert result[0].resource_id == project_name
|
||||
assert result[0].resource_arn == project_arn
|
||||
assert result[0].resource_tags == [{"key": "Name", "value": "test"}]
|
||||
assert result[0].region == AWS_REGION_EU_WEST_1
|
||||
|
||||
@mock_aws
|
||||
def test_project_logging_disabled(self):
|
||||
codebuild_client = client("codebuild", region_name=AWS_REGION_EU_WEST_1)
|
||||
|
||||
project_name = "test-project-logging-disabled"
|
||||
|
||||
project_arn = codebuild_client.create_project(
|
||||
name=project_name,
|
||||
source={
|
||||
"type": "S3",
|
||||
"location": "test-bucket",
|
||||
},
|
||||
artifacts={
|
||||
"type": "NO_ARTIFACTS",
|
||||
},
|
||||
environment={
|
||||
"type": "LINUX_CONTAINER",
|
||||
"image": "aws/codebuild/standard:4.0",
|
||||
"computeType": "BUILD_GENERAL1_SMALL",
|
||||
"environmentVariables": [],
|
||||
},
|
||||
serviceRole="arn:aws:iam::123456789012:role/service-role/codebuild-role",
|
||||
logsConfig={
|
||||
"cloudWatchLogs": {
|
||||
"status": "DISABLED",
|
||||
}
|
||||
},
|
||||
tags=[
|
||||
{"key": "Name", "value": "test"},
|
||||
],
|
||||
)["project"]["arn"]
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
|
||||
|
||||
from prowler.providers.aws.services.codebuild.codebuild_service import Codebuild
|
||||
|
||||
with patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
), patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_logging_enabled.codebuild_project_logging_enabled.codebuild_client",
|
||||
new=Codebuild(aws_provider),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_logging_enabled.codebuild_project_logging_enabled import (
|
||||
codebuild_project_logging_enabled,
|
||||
)
|
||||
|
||||
check = codebuild_project_logging_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"CodeBuild project {project_name} does not have logging enabled."
|
||||
)
|
||||
assert result[0].resource_id == project_name
|
||||
assert result[0].resource_arn == project_arn
|
||||
assert result[0].resource_tags == [{"key": "Name", "value": "test"}]
|
||||
assert result[0].region == AWS_REGION_EU_WEST_1
|
||||
@@ -5,6 +5,7 @@ import botocore
|
||||
|
||||
from prowler.providers.aws.services.codebuild.codebuild_service import (
|
||||
Build,
|
||||
CloudWatchLogs,
|
||||
Codebuild,
|
||||
Project,
|
||||
s3Logs,
|
||||
@@ -53,11 +54,16 @@ def mock_make_api_call(self, operation_name, kwarg):
|
||||
}
|
||||
],
|
||||
"logsConfig": {
|
||||
"cloudWatchLogs": {
|
||||
"status": "ENABLED",
|
||||
"groupName": project_name,
|
||||
"streamName": project_name,
|
||||
},
|
||||
"s3Logs": {
|
||||
"status": "ENABLED",
|
||||
"location": "test-bucket",
|
||||
"encryptionDisabled": False,
|
||||
}
|
||||
},
|
||||
},
|
||||
"tags": [{"key": "Name", "value": project_name}],
|
||||
}
|
||||
@@ -105,5 +111,15 @@ class Test_Codebuild_Service:
|
||||
assert codebuild.projects[project_arn].s3_logs.enabled
|
||||
assert codebuild.projects[project_arn].s3_logs.bucket_location == "test-bucket"
|
||||
assert codebuild.projects[project_arn].s3_logs.encrypted
|
||||
assert isinstance(
|
||||
codebuild.projects[project_arn].cloudwatch_logs, CloudWatchLogs
|
||||
)
|
||||
assert codebuild.projects[project_arn].cloudwatch_logs.enabled
|
||||
assert (
|
||||
codebuild.projects[project_arn].cloudwatch_logs.group_name == project_name
|
||||
)
|
||||
assert (
|
||||
codebuild.projects[project_arn].cloudwatch_logs.stream_name == project_name
|
||||
)
|
||||
assert codebuild.projects[project_arn].tags[0]["key"] == "Name"
|
||||
assert codebuild.projects[project_arn].tags[0]["value"] == project_name
|
||||
|
||||
Reference in New Issue
Block a user