mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-10 21:44:16 +00:00
feat(providers/huaweicloud): add functiongraph_function_vpc_configured check
This commit is contained in:
1 parent
1218b0920f
commit
ec6878c824
7 files changed
+328
No files matched your search
Whitespace-only changes.
@@ -0,0 +1,6 @@
|
||||
from prowler.providers.common.provider import Provider
|
||||
from prowler.providers.huaweicloud.services.functiongraph.functiongraph_service import (
|
||||
FunctionGraph,
|
||||
)
|
||||
|
||||
functiongraph_client = FunctionGraph(Provider.get_global_provider())
|
||||
Whitespace-only changes.
+34
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"Provider": "huaweicloud",
|
||||
"CheckID": "functiongraph_function_vpc_configured",
|
||||
"CheckTitle": "FunctionGraph functions are configured within a VPC",
|
||||
"CheckType": [],
|
||||
"ServiceName": "functiongraph",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "function/{function_id}",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "FunctionGraphFunction",
|
||||
"ResourceGroup": "serverless",
|
||||
"Description": "Ensure FunctionGraph functions are associated with a VPC to restrict network access",
|
||||
"Risk": "Functions not associated with a VPC have direct internet access without network restrictions, increasing the attack surface",
|
||||
"RelatedUrl": "",
|
||||
"AdditionalURLs": [],
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Associate the FunctionGraph function with a VPC to restrict network access",
|
||||
"Url": "https://hub.prowler.com/check/functiongraph_function_vpc_configured"
|
||||
}
|
||||
},
|
||||
"Categories": [
|
||||
"trust-boundaries"
|
||||
],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
from prowler.lib.check.models import Check, CheckReportHuaweiCloud
|
||||
from prowler.providers.huaweicloud.services.functiongraph.functiongraph_client import (
|
||||
functiongraph_client,
|
||||
)
|
||||
|
||||
|
||||
class functiongraph_function_vpc_configured(Check):
|
||||
"""Check if FunctionGraph functions are configured within a VPC."""
|
||||
|
||||
def execute(self) -> list[CheckReportHuaweiCloud]:
|
||||
findings = []
|
||||
for function in functiongraph_client.functions:
|
||||
report = CheckReportHuaweiCloud(
|
||||
metadata=self.metadata(),
|
||||
resource=function,
|
||||
)
|
||||
report.region = function.region
|
||||
report.resource_id = function.function_id
|
||||
report.resource_arn = f"huaweicloud:functiongraph:{function.region}:{functiongraph_client.audited_account}:function/{function.function_id}"
|
||||
|
||||
if function.func_vpc_id:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Function '{function.name}' is configured within VPC '{function.func_vpc_id}'."
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Function '{function.name}' is not associated with a VPC and has direct internet access without network restrictions."
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,95 @@
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic.v1 import BaseModel
|
||||
|
||||
from prowler.lib.logger import logger
|
||||
from prowler.providers.huaweicloud.lib.service.service import HuaweiCloudService
|
||||
|
||||
|
||||
class FunctionGraph(HuaweiCloudService):
|
||||
"""
|
||||
FunctionGraph service class for Huawei Cloud.
|
||||
|
||||
This class provides methods to interact with Huawei Cloud FunctionGraph service
|
||||
to retrieve serverless functions and their security configuration.
|
||||
"""
|
||||
|
||||
def __init__(self, provider):
|
||||
super().__init__(__class__.__name__, provider)
|
||||
|
||||
self.functions: List[FunctionGraphFunction] = []
|
||||
|
||||
if self.session.is_mock:
|
||||
self._load_mock_data()
|
||||
return
|
||||
|
||||
self._list_functions()
|
||||
|
||||
def _load_mock_data(self):
|
||||
"""Load mock data for testing."""
|
||||
region = "la-south-2"
|
||||
self.functions = [
|
||||
FunctionGraphFunction(
|
||||
function_id="fg-mock-001",
|
||||
name="function-secure",
|
||||
runtime="Python3.9",
|
||||
timeout=30,
|
||||
memory_size=128,
|
||||
func_vpc_id="vpc-12345",
|
||||
region=region,
|
||||
),
|
||||
FunctionGraphFunction(
|
||||
function_id="fg-mock-002",
|
||||
name="function-insecure",
|
||||
runtime="Python3.9",
|
||||
timeout=30,
|
||||
memory_size=128,
|
||||
func_vpc_id=None,
|
||||
region=region,
|
||||
),
|
||||
]
|
||||
|
||||
def _list_functions(self):
|
||||
"""List all FunctionGraph functions across regions."""
|
||||
if not self.regional_clients:
|
||||
return
|
||||
|
||||
for region, client in self.regional_clients.items():
|
||||
logger.info(f"FunctionGraph - Listing Functions in {region}...")
|
||||
|
||||
try:
|
||||
from huaweicloudsdkfunctiongraph.v2 import ListFunctionsRequest
|
||||
|
||||
request = ListFunctionsRequest()
|
||||
response = self._call_with_retries(client.list_functions, request)
|
||||
|
||||
if response and response.functions:
|
||||
for func in response.functions:
|
||||
self.functions.append(
|
||||
FunctionGraphFunction(
|
||||
function_id=getattr(func, "resource_id", ""),
|
||||
name=getattr(func, "func_name", ""),
|
||||
runtime=getattr(func, "runtime", ""),
|
||||
timeout=getattr(func, "timeout", 0),
|
||||
memory_size=getattr(func, "memory_size", 0),
|
||||
func_vpc_id=getattr(func, "func_vpc_id", None),
|
||||
region=region,
|
||||
)
|
||||
)
|
||||
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
|
||||
class FunctionGraphFunction(BaseModel):
|
||||
"""FunctionGraph function model."""
|
||||
|
||||
function_id: str
|
||||
name: str = ""
|
||||
runtime: str = ""
|
||||
timeout: int = 0
|
||||
memory_size: int = 0
|
||||
func_vpc_id: Optional[str] = None
|
||||
region: str = ""
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
from unittest import mock
|
||||
|
||||
from tests.providers.huaweicloud.huaweicloud_fixtures import (
|
||||
set_mocked_huaweicloud_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_functiongraph_function_vpc_configured:
|
||||
def test_functiongraph_vpc_configured_pass(self):
|
||||
functiongraph_client = mock.MagicMock()
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_huaweicloud_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.huaweicloud.services.functiongraph.functiongraph_function_vpc_configured.functiongraph_function_vpc_configured.functiongraph_client",
|
||||
new=functiongraph_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.huaweicloud.services.functiongraph.functiongraph_function_vpc_configured.functiongraph_function_vpc_configured import (
|
||||
functiongraph_function_vpc_configured,
|
||||
)
|
||||
from prowler.providers.huaweicloud.services.functiongraph.functiongraph_service import (
|
||||
FunctionGraphFunction,
|
||||
)
|
||||
|
||||
functiongraph_client.functions = [
|
||||
FunctionGraphFunction(
|
||||
function_id="fg-001",
|
||||
name="function-secure",
|
||||
runtime="Python3.9",
|
||||
timeout=30,
|
||||
memory_size=128,
|
||||
func_vpc_id="vpc-12345",
|
||||
region="la-south-2",
|
||||
),
|
||||
]
|
||||
functiongraph_client.audited_account = "123456789012"
|
||||
|
||||
check = functiongraph_function_vpc_configured()
|
||||
results = check.execute()
|
||||
|
||||
assert len(results) == 1
|
||||
assert results[0].status == "PASS"
|
||||
assert results[0].resource_id == "fg-001"
|
||||
assert "configured within VPC" in results[0].status_extended
|
||||
|
||||
def test_functiongraph_vpc_configured_fail(self):
|
||||
functiongraph_client = mock.MagicMock()
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_huaweicloud_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.huaweicloud.services.functiongraph.functiongraph_function_vpc_configured.functiongraph_function_vpc_configured.functiongraph_client",
|
||||
new=functiongraph_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.huaweicloud.services.functiongraph.functiongraph_function_vpc_configured.functiongraph_function_vpc_configured import (
|
||||
functiongraph_function_vpc_configured,
|
||||
)
|
||||
from prowler.providers.huaweicloud.services.functiongraph.functiongraph_service import (
|
||||
FunctionGraphFunction,
|
||||
)
|
||||
|
||||
functiongraph_client.functions = [
|
||||
FunctionGraphFunction(
|
||||
function_id="fg-002",
|
||||
name="function-insecure",
|
||||
runtime="Python3.9",
|
||||
timeout=30,
|
||||
memory_size=128,
|
||||
func_vpc_id=None,
|
||||
region="la-south-2",
|
||||
),
|
||||
]
|
||||
functiongraph_client.audited_account = "123456789012"
|
||||
|
||||
check = functiongraph_function_vpc_configured()
|
||||
results = check.execute()
|
||||
|
||||
assert len(results) == 1
|
||||
assert results[0].status == "FAIL"
|
||||
assert results[0].resource_id == "fg-002"
|
||||
assert "not associated with a VPC" in results[0].status_extended
|
||||
|
||||
def test_functiongraph_vpc_configured_mixed(self):
|
||||
functiongraph_client = mock.MagicMock()
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_huaweicloud_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.huaweicloud.services.functiongraph.functiongraph_function_vpc_configured.functiongraph_function_vpc_configured.functiongraph_client",
|
||||
new=functiongraph_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.huaweicloud.services.functiongraph.functiongraph_function_vpc_configured.functiongraph_function_vpc_configured import (
|
||||
functiongraph_function_vpc_configured,
|
||||
)
|
||||
from prowler.providers.huaweicloud.services.functiongraph.functiongraph_service import (
|
||||
FunctionGraphFunction,
|
||||
)
|
||||
|
||||
functiongraph_client.functions = [
|
||||
FunctionGraphFunction(
|
||||
function_id="fg-001",
|
||||
name="function-secure",
|
||||
runtime="Python3.9",
|
||||
timeout=30,
|
||||
memory_size=128,
|
||||
func_vpc_id="vpc-12345",
|
||||
region="la-south-2",
|
||||
),
|
||||
FunctionGraphFunction(
|
||||
function_id="fg-002",
|
||||
name="function-insecure",
|
||||
runtime="Python3.9",
|
||||
timeout=30,
|
||||
memory_size=128,
|
||||
func_vpc_id=None,
|
||||
region="la-south-2",
|
||||
),
|
||||
]
|
||||
functiongraph_client.audited_account = "123456789012"
|
||||
|
||||
check = functiongraph_function_vpc_configured()
|
||||
results = check.execute()
|
||||
|
||||
assert len(results) == 2
|
||||
assert results[0].status == "PASS"
|
||||
assert results[1].status == "FAIL"
|
||||
|
||||
def test_functiongraph_vpc_configured_empty(self):
|
||||
functiongraph_client = mock.MagicMock()
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_huaweicloud_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.huaweicloud.services.functiongraph.functiongraph_function_vpc_configured.functiongraph_function_vpc_configured.functiongraph_client",
|
||||
new=functiongraph_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.huaweicloud.services.functiongraph.functiongraph_function_vpc_configured.functiongraph_function_vpc_configured import (
|
||||
functiongraph_function_vpc_configured,
|
||||
)
|
||||
|
||||
functiongraph_client.functions = []
|
||||
functiongraph_client.audited_account = "123456789012"
|
||||
|
||||
check = functiongraph_function_vpc_configured()
|
||||
results = check.execute()
|
||||
|
||||
assert len(results) == 0
|
||||
Reference in new issue
Block a user