Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(codebuild): add new check codebuild_project_logging_enabled #5365

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
128adbb
feat(codebuild): add s3Logs to Project
puchy22 Oct 10, 2024
751de04
test(codebuild): test S3Logs attribute
puchy22 Oct 10, 2024
0d43d2a
feat(codebuild): add new check to ensure S3 Logs are encrypted at rest
puchy22 Oct 10, 2024
a84cb7d
test(codebuild): test check with logs encrypted and not encrypted
puchy22 Oct 10, 2024
9310169
fix(codebuild): fix tests
puchy22 Oct 10, 2024
a8461d4
chore(codebuild): not check if logs are enabled
puchy22 Oct 10, 2024
bcd07e6
feat(codebuild): add CloudWatchLogs to Projects
puchy22 Oct 10, 2024
bfd3b38
feat(codebuild): add new check to ensure logging is enabled
puchy22 Oct 10, 2024
8ff1bff
test(codebuild): test check with logging enabled and disabled
puchy22 Oct 10, 2024
ba091f7
test(codebuild): test cloudwatch_logs attribute
puchy22 Oct 10, 2024
613c9d6
chore(codebuild): add tags to report
puchy22 Oct 10, 2024
665b231
chore(codebuild): add other remediation
puchy22 Oct 10, 2024
7554ee9
chore(codebuild): change metadata fields order
puchy22 Oct 14, 2024
d3e085f
Merge branch 'PRWLR-4460-ensure-code-build-s-3-logs-are-encrypted' in…
puchy22 Oct 14, 2024
080dc79
chore(codebuild): change metadata fields order
puchy22 Oct 14, 2024
6dfff4b
Merge branch 'master' into PRWLR-4462-ensure-code-build-project-envir…
sergargar Oct 14, 2024
22b81d8
chore(codebuild): improve description and risk
puchy22 Oct 15, 2024
67b2736
chore(codebuild): add different status extended for each case
puchy22 Oct 15, 2024
b1d70d7
test(codebuild): add a test case for each status_extended
puchy22 Oct 15, 2024
ea5cf3a
Merge branch 'PRWLR-4462-ensure-code-build-project-environments-have-…
puchy22 Oct 15, 2024
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
Original file line number Diff line number Diff line change
@@ -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": ""
}
Original file line number Diff line number Diff line change
@@ -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
19 changes: 19 additions & 0 deletions prowler/providers/aws/services/codebuild/codebuild_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,18 @@ def _batch_get_projects(self, project):
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(
Expand Down Expand Up @@ -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
Expand All @@ -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]
Original file line number Diff line number Diff line change
@@ -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
Loading