mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 12:31:54 +00:00
feat(aws): add check to ensure Codebuild Github projects are only use allowed Github orgs (#7595)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
This commit is contained in:
@@ -31,6 +31,7 @@ The following list includes all the AWS checks with configurable variables that
|
||||
| `cloudtrail_threat_detection_privilege_escalation` | `threat_detection_privilege_escalation_minutes` | Integer |
|
||||
| `cloudwatch_log_group_no_secrets_in_logs` | `secrets_ignore_patterns` | List of Strings |
|
||||
| `cloudwatch_log_group_retention_policy_specific_days_enabled` | `log_group_retention_days` | Integer |
|
||||
| `codebuild_github_allowed_organizations` | `github_allowed_organizations` | List of Strings |
|
||||
| `codebuild_project_no_secrets_in_variables` | `excluded_sensitive_environment_variables` | List of Strings |
|
||||
| `codebuild_project_no_secrets_in_variables` | `secrets_ignore_patterns` | List of Strings |
|
||||
| `config_recorder_all_regions_enabled` | `mute_non_default_regions` | Boolean |
|
||||
|
||||
@@ -29,6 +29,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- Avoid bypassing IAM check using wildcards [(#7708)](https://github.com/prowler-cloud/prowler/pull/7708)
|
||||
- New method to authenticate in AppInsights in check `app_function_application_insights_enabled` [(#7763)](https://github.com/prowler-cloud/prowler/pull/7763)
|
||||
- ISO 27001 2022 for M365 provider. [(#7985)](https://github.com/prowler-cloud/prowler/pull/7985)
|
||||
- `codebuild_project_uses_allowed_github_organizations` check for AWS provider [(#7595)](https://github.com/prowler-cloud/prowler/pull/7595)
|
||||
- IaC provider [(#7852)](https://github.com/prowler-cloud/prowler/pull/7852)
|
||||
|
||||
---
|
||||
|
||||
@@ -417,6 +417,11 @@ aws:
|
||||
{"name": "TwilioKeyDetector"},
|
||||
]
|
||||
|
||||
# AWS CodeBuild Configuration
|
||||
# aws.codebuild_project_uses_allowed_github_organizations
|
||||
codebuild_github_allowed_organizations:
|
||||
[
|
||||
]
|
||||
|
||||
# Azure Configuration
|
||||
azure:
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "codebuild_project_uses_allowed_github_organizations",
|
||||
"CheckTitle": "Ensure AWS CodeBuild projects using GitHub connect only to allowed organizations",
|
||||
"CheckType": [],
|
||||
"ServiceName": "codebuild",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:aws:codebuild:region:account-id:project:project-name",
|
||||
"Severity": "high",
|
||||
"ResourceType": "AwsCodeBuildProject",
|
||||
"Description": "Check for CodeBuild projects using GitHub repositories from untrusted organizations that could lead to backdoored IAM roles",
|
||||
"Risk": "Attackers can use GitHub Actions in untrusted repositories to backdoor IAM roles used by CodeBuild projects, gaining persistent access to AWS accounts.",
|
||||
"RelatedUrl": "https://medium.com/@adan.alvarez/gaining-long-term-aws-access-with-codebuild-and-github-873324638784",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"NativeIaC": "",
|
||||
"Terraform": "",
|
||||
"CLI": "",
|
||||
"Other": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Only use GitHub repositories from trusted organizations with CodeBuild projects. Configure the allowed GitHub organizations in your Prowler configuration.",
|
||||
"Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/auth-and-access-control-iam-identity-based-access-control.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_AWS
|
||||
from prowler.providers.aws.services.codebuild.codebuild_client import codebuild_client
|
||||
from prowler.providers.aws.services.iam.iam_client import iam_client
|
||||
from prowler.providers.aws.services.iam.lib.policy import (
|
||||
has_codebuild_trusted_principal,
|
||||
is_codebuild_using_allowed_github_org,
|
||||
)
|
||||
|
||||
|
||||
class codebuild_project_uses_allowed_github_organizations(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
allowed_organizations = codebuild_client.audit_config.get(
|
||||
"codebuild_github_allowed_organizations", []
|
||||
)
|
||||
|
||||
for project in codebuild_client.projects.values():
|
||||
if project.source and project.source.type in (
|
||||
"GITHUB",
|
||||
"GITHUB_ENTERPRISE",
|
||||
):
|
||||
project_github_repo_url = project.source.location
|
||||
project_role = next(
|
||||
(
|
||||
role
|
||||
for role in iam_client.roles
|
||||
if role.arn == project.service_role_arn
|
||||
),
|
||||
None,
|
||||
)
|
||||
project_iam_trust_policy = (
|
||||
project_role.assume_role_policy if project_role else None
|
||||
)
|
||||
|
||||
if not project_iam_trust_policy or not has_codebuild_trusted_principal(
|
||||
project_iam_trust_policy
|
||||
):
|
||||
continue
|
||||
|
||||
report = Check_Report_AWS(metadata=self.metadata(), resource=project)
|
||||
report.status = "PASS"
|
||||
|
||||
is_allowed, org_name = is_codebuild_using_allowed_github_org(
|
||||
project_iam_trust_policy,
|
||||
project_github_repo_url,
|
||||
allowed_organizations,
|
||||
)
|
||||
if org_name is not None:
|
||||
if is_allowed:
|
||||
report.status_extended = f"CodeBuild project {project.name} uses GitHub organization '{org_name}', which is in the allowed organizations."
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"CodeBuild project {project.name} uses GitHub organization '{org_name}', which is not in the allowed organizations."
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -120,6 +120,7 @@ class Codebuild(AWSService):
|
||||
stream_name=cloudwatch_logs.get("streamName", ""),
|
||||
)
|
||||
project.tags = project_info.get("tags", [])
|
||||
project.service_role_arn = project_info.get("serviceRole", "")
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
@@ -216,10 +217,11 @@ class Project(BaseModel):
|
||||
buildspec: Optional[str] = None
|
||||
source: Optional[Source] = None
|
||||
secondary_sources: Optional[list[Source]] = []
|
||||
environment_variables: Optional[List[EnvironmentVariable]] = []
|
||||
s3_logs: Optional[s3Logs] = None
|
||||
cloudwatch_logs: Optional[CloudWatchLogs] = None
|
||||
tags: Optional[list] = []
|
||||
service_role_arn: Optional[str] = None
|
||||
environment_variables: Optional[List[EnvironmentVariable]]
|
||||
s3_logs: Optional[s3Logs]
|
||||
cloudwatch_logs: Optional[CloudWatchLogs]
|
||||
tags: Optional[list]
|
||||
|
||||
|
||||
class ExportConfig(BaseModel):
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import re
|
||||
from ipaddress import ip_address, ip_network
|
||||
from typing import Optional, Tuple
|
||||
|
||||
from py_iam_expand.actions import InvalidActionHandling, expand_actions
|
||||
|
||||
@@ -738,3 +739,75 @@ def is_valid_aws_service(service):
|
||||
if service in read_aws_regions_file()["services"]:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_codebuild_using_allowed_github_org(
|
||||
trust_policy: dict, github_repo_url: str, allowed_organizations: list
|
||||
) -> Tuple[bool, Optional[str]]:
|
||||
"""
|
||||
Checks if the trust policy allows codebuild.amazonaws.com as a trusted principal and if the GitHub organization
|
||||
in the repo URL is in the allowed organizations list.
|
||||
Returns (is_allowed: bool, org_name: str or None)
|
||||
"""
|
||||
try:
|
||||
if not trust_policy or not github_repo_url:
|
||||
return False, None
|
||||
|
||||
if not has_codebuild_trusted_principal(trust_policy):
|
||||
return False, None
|
||||
|
||||
# Extract org name from GitHub repo URL
|
||||
org_name = (
|
||||
github_repo_url.split("/")[3]
|
||||
if len(github_repo_url.split("/")) > 3
|
||||
else None
|
||||
)
|
||||
if not org_name:
|
||||
raise ValueError(f"Malformed GitHub repo URL: {github_repo_url}")
|
||||
if org_name in allowed_organizations:
|
||||
return True, org_name
|
||||
return False, org_name
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
return False, None
|
||||
|
||||
|
||||
def has_codebuild_trusted_principal(trust_policy: dict) -> bool:
|
||||
"""
|
||||
Returns True if the trust policy allows codebuild.amazonaws.com as a trusted principal, otherwise False.
|
||||
"""
|
||||
if not trust_policy:
|
||||
return False
|
||||
statements = trust_policy.get("Statement", [])
|
||||
if not isinstance(statements, list):
|
||||
statements = [statements]
|
||||
return any(
|
||||
s.get("Effect") == "Allow"
|
||||
and "Principal" in s
|
||||
and (
|
||||
(
|
||||
isinstance(s["Principal"], dict)
|
||||
and (
|
||||
(
|
||||
isinstance(s["Principal"].get("Service"), str)
|
||||
and s["Principal"].get("Service") == "codebuild.amazonaws.com"
|
||||
)
|
||||
or (
|
||||
isinstance(s["Principal"].get("Service"), list)
|
||||
and "codebuild.amazonaws.com" in s["Principal"].get("Service")
|
||||
)
|
||||
)
|
||||
)
|
||||
or (
|
||||
isinstance(s["Principal"], str)
|
||||
and s["Principal"] == "codebuild.amazonaws.com"
|
||||
)
|
||||
or (
|
||||
isinstance(s["Principal"], list)
|
||||
and "codebuild.amazonaws.com" in s["Principal"]
|
||||
)
|
||||
)
|
||||
for s in statements
|
||||
)
|
||||
|
||||
+393
@@ -0,0 +1,393 @@
|
||||
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
|
||||
|
||||
AWS_ACCOUNT_NUMBER = "123456789012"
|
||||
|
||||
|
||||
class Test_codebuild_project_uses_allowed_github_organizations:
|
||||
@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_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.codebuild_client",
|
||||
new=Codebuild(aws_provider),
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.codebuild_client.audit_config",
|
||||
{"codebuild_github_allowed_organizations": ["allowed-org"]},
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations import (
|
||||
codebuild_project_uses_allowed_github_organizations,
|
||||
)
|
||||
|
||||
check = codebuild_project_uses_allowed_github_organizations()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
@mock_aws
|
||||
def test_project_github_allowed_organization(self):
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
|
||||
codebuild_client = client("codebuild", region_name=AWS_REGION_EU_WEST_1)
|
||||
iam_client = client("iam", region_name=AWS_REGION_EU_WEST_1)
|
||||
project_name = "test-project-github-allowed"
|
||||
role_name = "codebuild-test-role"
|
||||
role_arn = iam_client.create_role(
|
||||
RoleName=role_name,
|
||||
AssumeRolePolicyDocument="""{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": "codebuild.amazonaws.com"},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}""",
|
||||
)["Role"]["Arn"]
|
||||
project_arn = codebuild_client.create_project(
|
||||
name=project_name,
|
||||
source={
|
||||
"type": "GITHUB",
|
||||
"location": "https://github.com/allowed-org/repo",
|
||||
},
|
||||
artifacts={"type": "NO_ARTIFACTS"},
|
||||
environment={
|
||||
"type": "LINUX_CONTAINER",
|
||||
"image": "aws/codebuild/standard:4.0",
|
||||
"computeType": "BUILD_GENERAL1_SMALL",
|
||||
"environmentVariables": [],
|
||||
},
|
||||
serviceRole=role_arn,
|
||||
tags=[{"key": "Name", "value": "test"}],
|
||||
)["project"]["arn"]
|
||||
|
||||
from prowler.providers.aws.services.codebuild.codebuild_service import Codebuild
|
||||
from prowler.providers.aws.services.iam.iam_service import IAM
|
||||
|
||||
with (
|
||||
patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.codebuild_client",
|
||||
new=Codebuild(aws_provider),
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.iam_client",
|
||||
new=IAM(aws_provider),
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.codebuild_client.audit_config",
|
||||
{"codebuild_github_allowed_organizations": ["allowed-org"]},
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations import (
|
||||
codebuild_project_uses_allowed_github_organizations,
|
||||
)
|
||||
|
||||
check = codebuild_project_uses_allowed_github_organizations()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert result[0].resource_id == project_name
|
||||
assert result[0].resource_arn == project_arn
|
||||
assert "which is in the allowed organizations" in result[0].status_extended
|
||||
assert result[0].region == AWS_REGION_EU_WEST_1
|
||||
|
||||
@mock_aws
|
||||
def test_project_github_not_allowed_organization(self):
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
|
||||
codebuild_client = client("codebuild", region_name=AWS_REGION_EU_WEST_1)
|
||||
iam_client = client("iam", region_name=AWS_REGION_EU_WEST_1)
|
||||
project_name = "test-project-github-not-allowed"
|
||||
role_name = "codebuild-test-role"
|
||||
role_arn = iam_client.create_role(
|
||||
RoleName=role_name,
|
||||
AssumeRolePolicyDocument="""{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": "codebuild.amazonaws.com"},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}""",
|
||||
)["Role"]["Arn"]
|
||||
project_arn = codebuild_client.create_project(
|
||||
name=project_name,
|
||||
source={
|
||||
"type": "GITHUB",
|
||||
"location": "https://github.com/not-allowed-org/repo",
|
||||
},
|
||||
artifacts={"type": "NO_ARTIFACTS"},
|
||||
environment={
|
||||
"type": "LINUX_CONTAINER",
|
||||
"image": "aws/codebuild/standard:4.0",
|
||||
"computeType": "BUILD_GENERAL1_SMALL",
|
||||
"environmentVariables": [],
|
||||
},
|
||||
serviceRole=role_arn,
|
||||
tags=[{"key": "Name", "value": "test"}],
|
||||
)["project"]["arn"]
|
||||
|
||||
from prowler.providers.aws.services.codebuild.codebuild_service import Codebuild
|
||||
from prowler.providers.aws.services.iam.iam_service import IAM
|
||||
|
||||
with (
|
||||
patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.codebuild_client",
|
||||
new=Codebuild(aws_provider),
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.iam_client",
|
||||
new=IAM(aws_provider),
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.codebuild_client.audit_config",
|
||||
{"codebuild_github_allowed_organizations": ["allowed-org"]},
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations import (
|
||||
codebuild_project_uses_allowed_github_organizations,
|
||||
)
|
||||
|
||||
check = codebuild_project_uses_allowed_github_organizations()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].resource_id == project_name
|
||||
assert result[0].resource_arn == project_arn
|
||||
assert (
|
||||
"which is not in the allowed organizations" in result[0].status_extended
|
||||
)
|
||||
assert result[0].region == AWS_REGION_EU_WEST_1
|
||||
|
||||
@mock_aws
|
||||
def test_project_github_no_codebuild_trusted_principal(self):
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
|
||||
|
||||
from prowler.providers.aws.services.codebuild.codebuild_service import Codebuild
|
||||
from prowler.providers.aws.services.iam.iam_service import IAM
|
||||
|
||||
with (
|
||||
patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.codebuild_client",
|
||||
new=Codebuild(aws_provider),
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.iam_client",
|
||||
new=IAM(aws_provider),
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.codebuild_client.audit_config",
|
||||
{"codebuild_github_allowed_organizations": ["allowed-org"]},
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations import (
|
||||
codebuild_project_uses_allowed_github_organizations,
|
||||
)
|
||||
|
||||
check = codebuild_project_uses_allowed_github_organizations()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
@mock_aws
|
||||
def test_project_github_enterprise_allowed_organization(self):
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
|
||||
codebuild_client = client("codebuild", region_name=AWS_REGION_EU_WEST_1)
|
||||
iam_client = client("iam", region_name=AWS_REGION_EU_WEST_1)
|
||||
project_name = "test-project-github-enterprise-allowed"
|
||||
role_name = "codebuild-test-role"
|
||||
role_arn = iam_client.create_role(
|
||||
RoleName=role_name,
|
||||
AssumeRolePolicyDocument="""{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": "codebuild.amazonaws.com"},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}""",
|
||||
)["Role"]["Arn"]
|
||||
project_arn = codebuild_client.create_project(
|
||||
name=project_name,
|
||||
source={
|
||||
"type": "GITHUB_ENTERPRISE",
|
||||
"location": "https://github.enterprise.com/allowed-org/repo",
|
||||
},
|
||||
artifacts={"type": "NO_ARTIFACTS"},
|
||||
environment={
|
||||
"type": "LINUX_CONTAINER",
|
||||
"image": "aws/codebuild/standard:4.0",
|
||||
"computeType": "BUILD_GENERAL1_SMALL",
|
||||
"environmentVariables": [],
|
||||
},
|
||||
serviceRole=role_arn,
|
||||
tags=[{"key": "Name", "value": "test"}],
|
||||
)["project"]["arn"]
|
||||
|
||||
from prowler.providers.aws.services.codebuild.codebuild_service import Codebuild
|
||||
from prowler.providers.aws.services.iam.iam_service import IAM
|
||||
|
||||
with (
|
||||
patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.codebuild_client",
|
||||
new=Codebuild(aws_provider),
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.iam_client",
|
||||
new=IAM(aws_provider),
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.codebuild_client.audit_config",
|
||||
{"codebuild_github_allowed_organizations": ["allowed-org"]},
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations import (
|
||||
codebuild_project_uses_allowed_github_organizations,
|
||||
)
|
||||
|
||||
check = codebuild_project_uses_allowed_github_organizations()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert result[0].resource_id == project_name
|
||||
assert result[0].resource_arn == project_arn
|
||||
assert "which is in the allowed organizations" in result[0].status_extended
|
||||
assert result[0].region == AWS_REGION_EU_WEST_1
|
||||
|
||||
@mock_aws
|
||||
def test_project_github_enterprise_not_allowed_organization(self):
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
|
||||
codebuild_client = client("codebuild", region_name=AWS_REGION_EU_WEST_1)
|
||||
iam_client = client("iam", region_name=AWS_REGION_EU_WEST_1)
|
||||
project_name = "test-project-github-enterprise-not-allowed"
|
||||
role_name = "codebuild-test-role"
|
||||
role_arn = iam_client.create_role(
|
||||
RoleName=role_name,
|
||||
AssumeRolePolicyDocument="""{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": "codebuild.amazonaws.com"},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}""",
|
||||
)["Role"]["Arn"]
|
||||
project_arn = codebuild_client.create_project(
|
||||
name=project_name,
|
||||
source={
|
||||
"type": "GITHUB_ENTERPRISE",
|
||||
"location": "https://github.enterprise.com/not-allowed-org/repo",
|
||||
},
|
||||
artifacts={"type": "NO_ARTIFACTS"},
|
||||
environment={
|
||||
"type": "LINUX_CONTAINER",
|
||||
"image": "aws/codebuild/standard:4.0",
|
||||
"computeType": "BUILD_GENERAL1_SMALL",
|
||||
"environmentVariables": [],
|
||||
},
|
||||
serviceRole=role_arn,
|
||||
tags=[{"key": "Name", "value": "test"}],
|
||||
)["project"]["arn"]
|
||||
|
||||
from prowler.providers.aws.services.codebuild.codebuild_service import Codebuild
|
||||
from prowler.providers.aws.services.iam.iam_service import IAM
|
||||
|
||||
with (
|
||||
patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.codebuild_client",
|
||||
new=Codebuild(aws_provider),
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.iam_client",
|
||||
new=IAM(aws_provider),
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.codebuild_client.audit_config",
|
||||
{"codebuild_github_allowed_organizations": ["allowed-org"]},
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations import (
|
||||
codebuild_project_uses_allowed_github_organizations,
|
||||
)
|
||||
|
||||
check = codebuild_project_uses_allowed_github_organizations()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].resource_id == project_name
|
||||
assert result[0].resource_arn == project_arn
|
||||
assert (
|
||||
"which is not in the allowed organizations" in result[0].status_extended
|
||||
)
|
||||
assert result[0].region == AWS_REGION_EU_WEST_1
|
||||
|
||||
@mock_aws
|
||||
def test_project_github_enterprise_no_codebuild_trusted_principal(self):
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
|
||||
|
||||
from prowler.providers.aws.services.codebuild.codebuild_service import Codebuild
|
||||
from prowler.providers.aws.services.iam.iam_service import IAM
|
||||
|
||||
with (
|
||||
patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.codebuild_client",
|
||||
new=Codebuild(aws_provider),
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.iam_client",
|
||||
new=IAM(aws_provider),
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations.codebuild_client.audit_config",
|
||||
{"codebuild_github_allowed_organizations": ["allowed-org"]},
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.codebuild.codebuild_project_uses_allowed_github_organizations.codebuild_project_uses_allowed_github_organizations import (
|
||||
codebuild_project_uses_allowed_github_organizations,
|
||||
)
|
||||
|
||||
check = codebuild_project_uses_allowed_github_organizations()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
@@ -5,6 +5,8 @@ from prowler.providers.aws.services.iam.lib.policy import (
|
||||
check_admin_access,
|
||||
check_full_service_access,
|
||||
get_effective_actions,
|
||||
has_codebuild_trusted_principal,
|
||||
is_codebuild_using_allowed_github_org,
|
||||
is_condition_block_restrictive,
|
||||
is_condition_block_restrictive_organization,
|
||||
is_condition_block_restrictive_sns_endpoint,
|
||||
@@ -2268,3 +2270,184 @@ class Test_Policy:
|
||||
],
|
||||
}
|
||||
assert check_admin_access(policy)
|
||||
|
||||
|
||||
def test_is_codebuild_using_allowed_github_org_allows():
|
||||
trust_policy = {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": "codebuild.amazonaws.com"},
|
||||
"Action": "sts:AssumeRole",
|
||||
}
|
||||
],
|
||||
}
|
||||
github_repo_url = "https://github.com/allowed-org/repo"
|
||||
allowed_organizations = ["allowed-org"]
|
||||
is_allowed, org_name = is_codebuild_using_allowed_github_org(
|
||||
trust_policy, github_repo_url, allowed_organizations
|
||||
)
|
||||
assert is_allowed is True
|
||||
assert org_name == "allowed-org"
|
||||
|
||||
|
||||
def test_is_codebuild_using_allowed_github_org_denies():
|
||||
trust_policy = {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": "codebuild.amazonaws.com"},
|
||||
"Action": "sts:AssumeRole",
|
||||
}
|
||||
],
|
||||
}
|
||||
github_repo_url = "https://github.com/not-allowed-org/repo"
|
||||
allowed_organizations = ["allowed-org"]
|
||||
is_allowed, org_name = is_codebuild_using_allowed_github_org(
|
||||
trust_policy, github_repo_url, allowed_organizations
|
||||
)
|
||||
assert is_allowed is False
|
||||
assert org_name == "not-allowed-org"
|
||||
|
||||
|
||||
def test_is_codebuild_using_allowed_github_org_no_codebuild_principal():
|
||||
trust_policy = {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": "lambda.amazonaws.com"},
|
||||
"Action": "sts:AssumeRole",
|
||||
}
|
||||
],
|
||||
}
|
||||
github_repo_url = "https://github.com/allowed-org/repo"
|
||||
allowed_organizations = ["allowed-org"]
|
||||
is_allowed, org_name = is_codebuild_using_allowed_github_org(
|
||||
trust_policy, github_repo_url, allowed_organizations
|
||||
)
|
||||
assert is_allowed is False
|
||||
assert org_name is None
|
||||
|
||||
|
||||
def test_is_codebuild_using_allowed_github_org_invalid_url():
|
||||
trust_policy = {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": "codebuild.amazonaws.com"},
|
||||
"Action": "sts:AssumeRole",
|
||||
}
|
||||
],
|
||||
}
|
||||
github_repo_url = "https://github.com//test" # Malformed, no org
|
||||
allowed_organizations = ["allowed-org"]
|
||||
is_allowed, org_name = is_codebuild_using_allowed_github_org(
|
||||
trust_policy, github_repo_url, allowed_organizations
|
||||
)
|
||||
assert is_allowed is False
|
||||
assert org_name is None
|
||||
|
||||
|
||||
def test_has_codebuild_trusted_principal_true():
|
||||
trust_policy = {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": "codebuild.amazonaws.com"},
|
||||
"Action": "sts:AssumeRole",
|
||||
}
|
||||
],
|
||||
}
|
||||
assert has_codebuild_trusted_principal(trust_policy) is True
|
||||
|
||||
|
||||
def test_has_codebuild_trusted_principal_false():
|
||||
trust_policy = {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": "lambda.amazonaws.com"},
|
||||
"Action": "sts:AssumeRole",
|
||||
}
|
||||
],
|
||||
}
|
||||
assert has_codebuild_trusted_principal(trust_policy) is False
|
||||
|
||||
|
||||
def test_has_codebuild_trusted_principal_empty():
|
||||
trust_policy = {}
|
||||
assert has_codebuild_trusted_principal(trust_policy) is False
|
||||
|
||||
|
||||
def test_is_codebuild_using_allowed_github_org_principal_string():
|
||||
trust_policy = {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": "codebuild.amazonaws.com",
|
||||
"Action": "sts:AssumeRole",
|
||||
}
|
||||
],
|
||||
}
|
||||
github_repo_url = "https://github.com/allowed-org/repo"
|
||||
allowed_organizations = ["allowed-org"]
|
||||
is_allowed, org_name = is_codebuild_using_allowed_github_org(
|
||||
trust_policy, github_repo_url, allowed_organizations
|
||||
)
|
||||
assert is_allowed is True
|
||||
assert org_name == "allowed-org"
|
||||
|
||||
|
||||
def test_is_codebuild_using_allowed_github_org_principal_list():
|
||||
trust_policy = {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": ["codebuild.amazonaws.com", "lambda.amazonaws.com"],
|
||||
"Action": "sts:AssumeRole",
|
||||
}
|
||||
],
|
||||
}
|
||||
github_repo_url = "https://github.com/allowed-org/repo"
|
||||
allowed_organizations = ["allowed-org"]
|
||||
is_allowed, org_name = is_codebuild_using_allowed_github_org(
|
||||
trust_policy, github_repo_url, allowed_organizations
|
||||
)
|
||||
assert is_allowed is True
|
||||
assert org_name == "allowed-org"
|
||||
|
||||
|
||||
def test_has_codebuild_trusted_principal_string():
|
||||
trust_policy = {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": "codebuild.amazonaws.com",
|
||||
"Action": "sts:AssumeRole",
|
||||
}
|
||||
],
|
||||
}
|
||||
assert has_codebuild_trusted_principal(trust_policy) is True
|
||||
|
||||
|
||||
def test_has_codebuild_trusted_principal_list():
|
||||
trust_policy = {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": ["codebuild.amazonaws.com", "lambda.amazonaws.com"],
|
||||
"Action": "sts:AssumeRole",
|
||||
}
|
||||
],
|
||||
}
|
||||
assert has_codebuild_trusted_principal(trust_policy) is True
|
||||
|
||||
Reference in New Issue
Block a user