mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-04 19:21:51 +00:00
feat(compliance): add CIS 7.0 for the M365 provider (#11699)
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
import warnings
|
||||
|
||||
from dashboard.common_methods import get_section_containers_cis
|
||||
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
|
||||
def get_table(data):
|
||||
aux = data[
|
||||
[
|
||||
"REQUIREMENTS_ID",
|
||||
"REQUIREMENTS_DESCRIPTION",
|
||||
"REQUIREMENTS_ATTRIBUTES_SECTION",
|
||||
"CHECKID",
|
||||
"STATUS",
|
||||
"REGION",
|
||||
"ACCOUNTID",
|
||||
"RESOURCEID",
|
||||
]
|
||||
].copy()
|
||||
|
||||
return get_section_containers_cis(
|
||||
aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION"
|
||||
)
|
||||
@@ -9,6 +9,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- `entra_conditional_access_policy_explicitly_targets_azure_devops` check for M365 provider, verifying at least one enabled Conditional Access policy explicitly includes the Azure DevOps cloud application instead of relying on a broad "All cloud apps" policy [(#11182)](https://github.com/prowler-cloud/prowler/pull/11182)
|
||||
- `entra_conditional_access_policy_no_exclusion_gaps` check for M365 provider, verifying every user, group, role, or application excluded from an enabled Conditional Access policy stays in scope of another enabled policy [(#11577)](https://github.com/prowler-cloud/prowler/pull/11577)
|
||||
- `stepfunctions_statemachine_encrypted_with_cmk` check for AWS provider, verifying that each Step Functions state machine uses a customer-managed KMS key for encryption at rest rather than the default AWS-owned key [(#11538)](https://github.com/prowler-cloud/prowler/pull/11538)
|
||||
- CIS Microsoft 365 Foundations Benchmark v7.0.0 compliance framework for the M365 provider [(#11699)](https://github.com/prowler-cloud/prowler/pull/11699)
|
||||
- `waf_regional_webacl_logging_enabled` check for AWS provider, verifying that each AWS WAF Classic Regional Web ACL has logging enabled to a Kinesis Data Firehose stream [(#11539)](https://github.com/prowler-cloud/prowler/pull/11539)
|
||||
|
||||
---
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,65 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from prowler.lib.check.compliance_models import (
|
||||
CIS_Requirement_Attribute_AssessmentStatus,
|
||||
CIS_Requirement_Attribute_Profile,
|
||||
Compliance,
|
||||
)
|
||||
|
||||
PROWLER_ROOT = Path(__file__).parents[5] / "prowler"
|
||||
FRAMEWORK_PATH = PROWLER_ROOT / "compliance" / "m365" / "cis_7.0_m365.json"
|
||||
M365_SERVICES_PATH = PROWLER_ROOT / "providers" / "m365" / "services"
|
||||
|
||||
VALID_PROFILES = {p.value for p in CIS_Requirement_Attribute_Profile}
|
||||
VALID_STATUSES = {s.value for s in CIS_Requirement_Attribute_AssessmentStatus}
|
||||
|
||||
|
||||
def _existing_m365_checks() -> set:
|
||||
return {
|
||||
metadata.stem.replace(".metadata", "")
|
||||
for metadata in M365_SERVICES_PATH.rglob("*.metadata.json")
|
||||
}
|
||||
|
||||
|
||||
class TestCIS7_0_M365:
|
||||
def test_framework_is_discoverable(self):
|
||||
frameworks = Compliance.get_bulk("m365")
|
||||
assert "cis_7.0_m365" in frameworks
|
||||
|
||||
def test_framework_metadata(self):
|
||||
framework = Compliance.get_bulk("m365")["cis_7.0_m365"]
|
||||
assert framework.Framework == "CIS"
|
||||
assert framework.Provider == "M365"
|
||||
assert framework.Version == "7.0"
|
||||
assert framework.Name == "CIS Microsoft 365 Foundations Benchmark v7.0.0"
|
||||
assert len(framework.Requirements) == 160
|
||||
|
||||
def test_requirement_ids_are_unique(self):
|
||||
framework = Compliance.get_bulk("m365")["cis_7.0_m365"]
|
||||
ids = [req.Id for req in framework.Requirements]
|
||||
assert len(ids) == len(set(ids))
|
||||
|
||||
def test_each_requirement_has_one_attribute_with_section(self):
|
||||
framework = Compliance.get_bulk("m365")["cis_7.0_m365"]
|
||||
for req in framework.Requirements:
|
||||
assert len(req.Attributes) == 1, f"{req.Id} must have exactly one attribute"
|
||||
attribute = req.Attributes[0]
|
||||
assert attribute.Section, f"{req.Id} has an empty Section"
|
||||
assert attribute.Profile in VALID_PROFILES
|
||||
assert attribute.AssessmentStatus in VALID_STATUSES
|
||||
|
||||
def test_all_mapped_checks_exist(self):
|
||||
# Every check referenced by the framework must resolve to a real M365 check,
|
||||
# otherwise the requirement would never be evaluated.
|
||||
existing = _existing_m365_checks()
|
||||
framework = json.loads(FRAMEWORK_PATH.read_text())
|
||||
unknown = {
|
||||
check
|
||||
for req in framework["Requirements"]
|
||||
for check in req["Checks"]
|
||||
if check not in existing
|
||||
}
|
||||
assert (
|
||||
not unknown
|
||||
), f"Framework references unknown M365 checks: {sorted(unknown)}"
|
||||
Reference in New Issue
Block a user