mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-04-10 03:41:14 +00:00
Compare commits
6 Commits
improve-co
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31662b6e91 | ||
|
|
cccb3a4b94 | ||
|
|
ca50b24d77 | ||
|
|
7eb204fff0 | ||
|
|
56c370d3a4 | ||
|
|
b0d8534907 |
@@ -11,6 +11,7 @@ All notable changes to the **Prowler API** are documented in this file.
|
||||
- `VALKEY_SCHEME`, `VALKEY_USERNAME`, and `VALKEY_PASSWORD` environment variables to configure Celery broker TLS/auth connection details for Valkey/ElastiCache [(#10420)](https://github.com/prowler-cloud/prowler/pull/10420)
|
||||
- `Vercel` provider support [(#10190)](https://github.com/prowler-cloud/prowler/pull/10190)
|
||||
- Finding groups list and latest endpoints support `sort=delta`, ordering by `new_count` then `changed_count` so groups with the most new findings rank highest [(#10606)](https://github.com/prowler-cloud/prowler/pull/10606)
|
||||
- Handle CIS and CISA SCuBA compliance framework from google workspace [(#10629)](https://github.com/prowler-cloud/prowler/pull/10629)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
|
||||
@@ -32,9 +32,13 @@ from prowler.lib.outputs.compliance.cis.cis_aws import AWSCIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_azure import AzureCIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_gcp import GCPCIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_github import GithubCIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_googleworkspace import GoogleWorkspaceCIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_kubernetes import KubernetesCIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_m365 import M365CIS
|
||||
from prowler.lib.outputs.compliance.cis.cis_oraclecloud import OracleCloudCIS
|
||||
from prowler.lib.outputs.compliance.cisa_scuba.cisa_scuba_googleworkspace import (
|
||||
GoogleWorkspaceCISASCuBA,
|
||||
)
|
||||
from prowler.lib.outputs.compliance.csa.csa_alibabacloud import AlibabaCloudCSA
|
||||
from prowler.lib.outputs.compliance.csa.csa_aws import AWSCSA
|
||||
from prowler.lib.outputs.compliance.csa.csa_azure import AzureCSA
|
||||
@@ -93,7 +97,7 @@ COMPLIANCE_CLASS_MAP = {
|
||||
(lambda name: name.startswith("iso27001_"), AWSISO27001),
|
||||
(lambda name: name.startswith("kisa"), AWSKISAISMSP),
|
||||
(lambda name: name == "prowler_threatscore_aws", ProwlerThreatScoreAWS),
|
||||
(lambda name: name == "ccc_aws", CCC_AWS),
|
||||
(lambda name: name.startswith("ccc_"), CCC_AWS),
|
||||
(lambda name: name.startswith("c5_"), AWSC5),
|
||||
(lambda name: name.startswith("csa_"), AWSCSA),
|
||||
],
|
||||
@@ -102,7 +106,7 @@ COMPLIANCE_CLASS_MAP = {
|
||||
(lambda name: name == "mitre_attack_azure", AzureMitreAttack),
|
||||
(lambda name: name.startswith("ens_"), AzureENS),
|
||||
(lambda name: name.startswith("iso27001_"), AzureISO27001),
|
||||
(lambda name: name == "ccc_azure", CCC_Azure),
|
||||
(lambda name: name.startswith("ccc_"), CCC_Azure),
|
||||
(lambda name: name == "prowler_threatscore_azure", ProwlerThreatScoreAzure),
|
||||
(lambda name: name == "c5_azure", AzureC5),
|
||||
(lambda name: name.startswith("csa_"), AzureCSA),
|
||||
@@ -113,7 +117,7 @@ COMPLIANCE_CLASS_MAP = {
|
||||
(lambda name: name.startswith("ens_"), GCPENS),
|
||||
(lambda name: name.startswith("iso27001_"), GCPISO27001),
|
||||
(lambda name: name == "prowler_threatscore_gcp", ProwlerThreatScoreGCP),
|
||||
(lambda name: name == "ccc_gcp", CCC_GCP),
|
||||
(lambda name: name.startswith("ccc_"), CCC_GCP),
|
||||
(lambda name: name == "c5_gcp", GCPC5),
|
||||
(lambda name: name.startswith("csa_"), GCPCSA),
|
||||
],
|
||||
@@ -133,6 +137,10 @@ COMPLIANCE_CLASS_MAP = {
|
||||
"github": [
|
||||
(lambda name: name.startswith("cis_"), GithubCIS),
|
||||
],
|
||||
"googleworkspace": [
|
||||
(lambda name: name.startswith("cis_"), GoogleWorkspaceCIS),
|
||||
(lambda name: name.startswith("cisa_scuba_"), GoogleWorkspaceCISASCuBA),
|
||||
],
|
||||
"iac": [
|
||||
# IaC provider doesn't have specific compliance frameworks yet
|
||||
# Trivy handles its own compliance checks
|
||||
|
||||
@@ -163,6 +163,8 @@ These resources help ensure that AI-assisted contributions maintain consistency
|
||||
|
||||
All dependencies are listed in the `pyproject.toml` file.
|
||||
|
||||
The SDK keeps direct dependencies pinned to exact versions, while `poetry.lock` records the full resolved dependency tree and the artifact hashes for every package. Use `poetry install` from the lock file instead of ad-hoc `pip` installs when you need a reproducible environment.
|
||||
|
||||
For proper code documentation, refer to the following and follow the code documentation practices presented there: [Google Python Style Guide - Comments and Docstrings](https://github.com/google/styleguide/blob/gh-pages/pyguide.md#38-comments-and-docstrings).
|
||||
|
||||
<Note>
|
||||
|
||||
BIN
docs/images/providers/select-vercel-prowler-cloud.png
Normal file
BIN
docs/images/providers/select-vercel-prowler-cloud.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 148 KiB |
BIN
docs/images/providers/vercel-launch-scan.png
Normal file
BIN
docs/images/providers/vercel-launch-scan.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
BIN
docs/images/providers/vercel-team-id-form.png
Normal file
BIN
docs/images/providers/vercel-team-id-form.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
BIN
docs/images/providers/vercel-token-form.png
Normal file
BIN
docs/images/providers/vercel-token-form.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
@@ -21,29 +21,57 @@
|
||||
|
||||
## Supported Providers
|
||||
|
||||
The supported providers right now are:
|
||||
Prowler supports a wide range of providers organized by category:
|
||||
|
||||
| Provider | Support | Audit Scope/Entities | Interface |
|
||||
| -------------------------------------------------------------------------------- | ---------- | ---------------------------- | ------------ |
|
||||
| [AWS](/user-guide/providers/aws/getting-started-aws) | Official | Accounts | UI, API, CLI |
|
||||
| [Azure](/user-guide/providers/azure/getting-started-azure) | Official | Subscriptions | UI, API, CLI |
|
||||
| [Google Cloud](/user-guide/providers/gcp/getting-started-gcp) | Official | Projects | UI, API, CLI |
|
||||
| [Kubernetes](/user-guide/providers/kubernetes/getting-started-k8s) | Official | Clusters | UI, API, CLI |
|
||||
| [M365](/user-guide/providers/microsoft365/getting-started-m365) | Official | Tenants | UI, API, CLI |
|
||||
| [Github](/user-guide/providers/github/getting-started-github) | Official | Organizations / Repositories | UI, API, CLI |
|
||||
| [Oracle Cloud](/user-guide/providers/oci/getting-started-oci) | Official | Tenancies / Compartments | UI, API, CLI |
|
||||
| [Alibaba Cloud](/user-guide/providers/alibabacloud/getting-started-alibabacloud) | Official | Accounts | UI, API, CLI |
|
||||
| [Cloudflare](/user-guide/providers/cloudflare/getting-started-cloudflare) | Official | Accounts | UI, API, CLI |
|
||||
| [Infra as Code](/user-guide/providers/iac/getting-started-iac) | Official | Repositories | UI, API, CLI |
|
||||
| [MongoDB Atlas](/user-guide/providers/mongodbatlas/getting-started-mongodbatlas) | Official | Organizations | UI, API, CLI |
|
||||
| [OpenStack](/user-guide/providers/openstack/getting-started-openstack) | Official | Projects | UI, API, CLI |
|
||||
| [Vercel](/user-guide/providers/vercel/getting-started-vercel) | Official | Teams / Projects | CLI |
|
||||
| [LLM](/user-guide/providers/llm/getting-started-llm) | Official | Models | CLI |
|
||||
| [Image](/user-guide/providers/image/getting-started-image) | Official | Container Images | CLI, API |
|
||||
| [Google Workspace](/user-guide/providers/googleworkspace/getting-started-googleworkspace) | Official | Domains | CLI |
|
||||
| **NHN** | Unofficial | Tenants | CLI |
|
||||
### Cloud Service Providers (Infrastructure)
|
||||
|
||||
For more information about the checks and compliance of each provider visit [Prowler Hub](https://hub.prowler.com).
|
||||
| Provider | Support | Audit Scope/Entities | Interface |
|
||||
| -------------------------------------------------------------------------------- | ---------- | ------------------------ | ------------ |
|
||||
| [Alibaba Cloud](/user-guide/providers/alibabacloud/getting-started-alibabacloud) | Official | Accounts | UI, API, CLI |
|
||||
| [AWS](/user-guide/providers/aws/getting-started-aws) | Official | Accounts | UI, API, CLI |
|
||||
| [Azure](/user-guide/providers/azure/getting-started-azure) | Official | Subscriptions | UI, API, CLI |
|
||||
| [Cloudflare](/user-guide/providers/cloudflare/getting-started-cloudflare) | Official | Accounts | UI, API, CLI |
|
||||
| [Google Cloud](/user-guide/providers/gcp/getting-started-gcp) | Official | Projects | UI, API, CLI |
|
||||
| **NHN** | Unofficial | Tenants | CLI |
|
||||
| [OpenStack](/user-guide/providers/openstack/getting-started-openstack) | Official | Projects | UI, API, CLI |
|
||||
| [Oracle Cloud](/user-guide/providers/oci/getting-started-oci) | Official | Tenancies / Compartments | UI, API, CLI |
|
||||
|
||||
### Infrastructure as Code Providers
|
||||
|
||||
| Provider | Support | Audit Scope/Entities | Interface |
|
||||
| --------------------------------------------------------------------- | -------- | -------------------- | ------------ |
|
||||
| [Infra as Code](/user-guide/providers/iac/getting-started-iac) | Official | Repositories | UI, API, CLI |
|
||||
|
||||
### Software as a Service (SaaS) Providers
|
||||
|
||||
| Provider | Support | Audit Scope/Entities | Interface |
|
||||
| ----------------------------------------------------------------------------------------- | -------- | ---------------------------- | ------------ |
|
||||
| [GitHub](/user-guide/providers/github/getting-started-github) | Official | Organizations / Repositories | UI, API, CLI |
|
||||
| [Google Workspace](/user-guide/providers/googleworkspace/getting-started-googleworkspace) | Official | Domains | CLI |
|
||||
| [LLM](/user-guide/providers/llm/getting-started-llm) | Official | Models | CLI |
|
||||
| [M365](/user-guide/providers/microsoft365/getting-started-m365) | Official | Tenants | UI, API, CLI |
|
||||
| [MongoDB Atlas](/user-guide/providers/mongodbatlas/getting-started-mongodbatlas) | Official | Organizations | UI, API, CLI |
|
||||
| [Vercel](/user-guide/providers/vercel/getting-started-vercel) | Official | Teams / Projects | CLI |
|
||||
|
||||
### Kubernetes
|
||||
|
||||
| Provider | Support | Audit Scope/Entities | Interface |
|
||||
| -------------------------------------------------------------------------- | -------- | -------------------- | ------------ |
|
||||
| [Kubernetes](/user-guide/providers/kubernetes/getting-started-k8s) | Official | Clusters | UI, API, CLI |
|
||||
|
||||
### Containers
|
||||
|
||||
| Provider | Support | Audit Scope/Entities | Interface |
|
||||
| ------------------------------------------------------------------- | -------- | -------------------- | --------- |
|
||||
| [Image](/user-guide/providers/image/getting-started-image) | Official | Container Images / Registries | CLI, API |
|
||||
|
||||
### Custom Providers (Prowler Cloud Enterprise Only)
|
||||
|
||||
| Provider | Support | Audit Scope/Entities | Interface |
|
||||
| -------------------- | -------- | -------------------- | --------- |
|
||||
| VMware/Broadcom VCF | Official | Infrastructure | CLI |
|
||||
|
||||
For more information about the checks and compliance of each provider, visit [Prowler Hub](https://hub.prowler.com).
|
||||
|
||||
## Where to go next?
|
||||
|
||||
|
||||
@@ -13,9 +13,63 @@ Set up authentication for Vercel with the [Vercel Authentication](/user-guide/pr
|
||||
- Create a Vercel API Token with access to the target team
|
||||
- Identify the Team ID (optional, required to scope the scan to a single team)
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Prowler Cloud" icon="cloud" href="#prowler-cloud">
|
||||
Onboard Vercel using Prowler Cloud
|
||||
</Card>
|
||||
<Card title="Prowler CLI" icon="terminal" href="#prowler-cli">
|
||||
Onboard Vercel using Prowler CLI
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Prowler Cloud
|
||||
|
||||
<VersionBadge version="5.23.0" />
|
||||
|
||||
### Step 1: Add the Provider
|
||||
|
||||
1. Go to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app).
|
||||
2. Navigate to "Configuration" > "Cloud Providers".
|
||||
|
||||

|
||||
|
||||
3. Click "Add Cloud Provider".
|
||||
|
||||

|
||||
|
||||
4. Select "Vercel".
|
||||
|
||||

|
||||
|
||||
5. Enter the **Team ID** and an optional alias, then click "Next".
|
||||
|
||||

|
||||
|
||||
<Note>
|
||||
The Team ID can be found in the Vercel Dashboard under "Settings" > "General". It follows the format `team_xxxxxxxxxxxxxxxxxxxx`. For detailed instructions, see the [Authentication guide](/user-guide/providers/vercel/authentication).
|
||||
</Note>
|
||||
|
||||
### Step 2: Provide Credentials
|
||||
|
||||
1. Enter the **API Token** created in the Vercel Dashboard.
|
||||
|
||||

|
||||
|
||||
For the complete token creation workflow, follow the [Authentication guide](/user-guide/providers/vercel/authentication#api-token).
|
||||
|
||||
### Step 3: Launch the Scan
|
||||
|
||||
1. Review the connection summary.
|
||||
2. Choose the scan schedule: run a single scan or set up daily scans (every 24 hours).
|
||||
3. Click **Launch Scan** to start auditing Vercel.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Prowler CLI
|
||||
|
||||
<VersionBadge version="5.22.0" />
|
||||
<VersionBadge version="5.23.0" />
|
||||
|
||||
### Step 1: Set Up Authentication
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@ All notable changes to the **Prowler MCP Server** are documented in this file.
|
||||
|
||||
- Resource events tool to get timeline for a resource (who, what, when) [(#10412)](https://github.com/prowler-cloud/prowler/pull/10412)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
- Pin `httpx` dependency to exact version for reproducible installs [(#10593)](https://github.com/prowler-cloud/prowler/pull/10593)
|
||||
|
||||
### 🔐 Security
|
||||
|
||||
- `authlib` bumped from 1.6.5 to 1.6.9 to fix CVE-2026-28802 (JWT `alg: none` validation bypass) [(#10579)](https://github.com/prowler-cloud/prowler/pull/10579)
|
||||
|
||||
@@ -5,7 +5,7 @@ requires = ["setuptools>=61.0", "wheel"]
|
||||
[project]
|
||||
dependencies = [
|
||||
"fastmcp==2.14.0",
|
||||
"httpx>=0.28.0"
|
||||
"httpx==0.28.1"
|
||||
]
|
||||
description = "MCP server for Prowler ecosystem"
|
||||
name = "prowler-mcp"
|
||||
|
||||
2
mcp_server/uv.lock
generated
2
mcp_server/uv.lock
generated
@@ -727,7 +727,7 @@ dependencies = [
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "fastmcp", specifier = "==2.14.0" },
|
||||
{ name = "httpx", specifier = ">=0.28.0" },
|
||||
{ name = "httpx", specifier = "==0.28.1" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
10
poetry.lock
generated
10
poetry.lock
generated
@@ -4444,14 +4444,14 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pre-commit"
|
||||
version = "4.2.0"
|
||||
version = "4.5.1"
|
||||
description = "A framework for managing and maintaining multi-language pre-commit hooks."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
python-versions = ">=3.10"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd"},
|
||||
{file = "pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146"},
|
||||
{file = "pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77"},
|
||||
{file = "pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -6743,4 +6743,4 @@ files = [
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.10,<3.13"
|
||||
content-hash = "91739ee5e383337160f9f08b76944ab4e8629c94084c8a9d115246862557f7c5"
|
||||
content-hash = "2b72ed4419b22be8dde521c7ce1a54e44d3390ff548cc055bab177f609a3504c"
|
||||
|
||||
@@ -21,11 +21,13 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- `entra_conditional_access_policy_device_registration_mfa_required` check and `entra_intune_enrollment_sign_in_frequency_every_time` enhancement for M365 provider [(#10222)](https://github.com/prowler-cloud/prowler/pull/10222)
|
||||
- `entra_conditional_access_policy_block_elevated_insider_risk` check for M365 provider [(#10234)](https://github.com/prowler-cloud/prowler/pull/10234)
|
||||
- `Vercel` provider support with 30 checks [(#10189)](https://github.com/prowler-cloud/prowler/pull/10189)
|
||||
- CCC improvements with the latest checks and new mappings [(#10625)](https://github.com/prowler-cloud/prowler/pull/10625)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
- Added `internet-exposed` category to 13 AWS checks (CloudFront, CodeArtifact, EC2, EFS, RDS, SageMaker, Shield, VPC) [(#10502)](https://github.com/prowler-cloud/prowler/pull/10502)
|
||||
- Minimum Python version from 3.9 to 3.10 and updated classifiers to reflect supported versions (3.10, 3.11, 3.12) [(#10464)](https://github.com/prowler-cloud/prowler/pull/10464)
|
||||
- Pin direct SDK dependencies to exact versions and rely on `poetry.lock` artifact hashes for reproducible installs [(#10593)](https://github.com/prowler-cloud/prowler/pull/10593)
|
||||
- Sensitive CLI flags now warn when values are passed directly, recommending environment variables instead [(#10532)](https://github.com/prowler-cloud/prowler/pull/10532)
|
||||
|
||||
### 🐞 Fixed
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
98
prowler/lib/outputs/compliance/ccc/ccc.py
Normal file
98
prowler/lib/outputs/compliance/ccc/ccc.py
Normal file
@@ -0,0 +1,98 @@
|
||||
from colorama import Fore, Style
|
||||
from tabulate import tabulate
|
||||
|
||||
from prowler.config.config import orange_color
|
||||
|
||||
|
||||
def get_ccc_table(
|
||||
findings: list,
|
||||
bulk_checks_metadata: dict,
|
||||
compliance_framework: str,
|
||||
output_filename: str,
|
||||
output_directory: str,
|
||||
compliance_overview: bool,
|
||||
):
|
||||
section_table = {
|
||||
"Provider": [],
|
||||
"Section": [],
|
||||
"Status": [],
|
||||
"Muted": [],
|
||||
}
|
||||
pass_count = []
|
||||
fail_count = []
|
||||
muted_count = []
|
||||
sections = {}
|
||||
for index, finding in enumerate(findings):
|
||||
check = bulk_checks_metadata[finding.check_metadata.CheckID]
|
||||
check_compliances = check.Compliance
|
||||
for compliance in check_compliances:
|
||||
if compliance.Framework == "CCC":
|
||||
for requirement in compliance.Requirements:
|
||||
for attribute in requirement.Attributes:
|
||||
section = attribute.Section
|
||||
|
||||
if section not in sections:
|
||||
sections[section] = {"FAIL": 0, "PASS": 0, "Muted": 0}
|
||||
|
||||
if finding.muted:
|
||||
if index not in muted_count:
|
||||
muted_count.append(index)
|
||||
sections[section]["Muted"] += 1
|
||||
else:
|
||||
if finding.status == "FAIL" and index not in fail_count:
|
||||
fail_count.append(index)
|
||||
sections[section]["FAIL"] += 1
|
||||
elif finding.status == "PASS" and index not in pass_count:
|
||||
pass_count.append(index)
|
||||
sections[section]["PASS"] += 1
|
||||
|
||||
sections = dict(sorted(sections.items()))
|
||||
for section in sections:
|
||||
section_table["Provider"].append(compliance.Provider)
|
||||
section_table["Section"].append(section)
|
||||
if sections[section]["FAIL"] > 0:
|
||||
section_table["Status"].append(
|
||||
f"{Fore.RED}FAIL({sections[section]['FAIL']}){Style.RESET_ALL}"
|
||||
)
|
||||
else:
|
||||
if sections[section]["PASS"] > 0:
|
||||
section_table["Status"].append(
|
||||
f"{Fore.GREEN}PASS({sections[section]['PASS']}){Style.RESET_ALL}"
|
||||
)
|
||||
else:
|
||||
section_table["Status"].append(f"{Fore.GREEN}PASS{Style.RESET_ALL}")
|
||||
section_table["Muted"].append(
|
||||
f"{orange_color}{sections[section]['Muted']}{Style.RESET_ALL}"
|
||||
)
|
||||
|
||||
if (
|
||||
len(fail_count) + len(pass_count) + len(muted_count) > 1
|
||||
): # If there are no resources, don't print the compliance table
|
||||
print(
|
||||
f"\nCompliance Status of {Fore.YELLOW}{compliance_framework.upper()}{Style.RESET_ALL} Framework:"
|
||||
)
|
||||
total_findings_count = len(fail_count) + len(pass_count) + len(muted_count)
|
||||
overview_table = [
|
||||
[
|
||||
f"{Fore.RED}{round(len(fail_count) / total_findings_count * 100, 2)}% ({len(fail_count)}) FAIL{Style.RESET_ALL}",
|
||||
f"{Fore.GREEN}{round(len(pass_count) / total_findings_count * 100, 2)}% ({len(pass_count)}) PASS{Style.RESET_ALL}",
|
||||
f"{orange_color}{round(len(muted_count) / total_findings_count * 100, 2)}% ({len(muted_count)}) MUTED{Style.RESET_ALL}",
|
||||
]
|
||||
]
|
||||
print(tabulate(overview_table, tablefmt="rounded_grid"))
|
||||
if not compliance_overview:
|
||||
if len(fail_count) > 0 and len(section_table["Section"]) > 0:
|
||||
print(
|
||||
f"\nFramework {Fore.YELLOW}{compliance_framework.upper()}{Style.RESET_ALL} Results:"
|
||||
)
|
||||
print(
|
||||
tabulate(
|
||||
section_table,
|
||||
tablefmt="rounded_grid",
|
||||
headers="keys",
|
||||
)
|
||||
)
|
||||
print(f"\nDetailed results of {compliance_framework.upper()} are in:")
|
||||
print(
|
||||
f" - CSV: {output_directory}/compliance/{output_filename}_{compliance_framework}.csv\n"
|
||||
)
|
||||
@@ -3,6 +3,7 @@ import sys
|
||||
from prowler.lib.check.models import Check_Report
|
||||
from prowler.lib.logger import logger
|
||||
from prowler.lib.outputs.compliance.c5.c5 import get_c5_table
|
||||
from prowler.lib.outputs.compliance.ccc.ccc import get_ccc_table
|
||||
from prowler.lib.outputs.compliance.cis.cis import get_cis_table
|
||||
from prowler.lib.outputs.compliance.csa.csa import get_csa_table
|
||||
from prowler.lib.outputs.compliance.ens.ens import get_ens_table
|
||||
@@ -104,6 +105,15 @@ def display_compliance_table(
|
||||
output_directory,
|
||||
compliance_overview,
|
||||
)
|
||||
elif compliance_framework.startswith("ccc_"):
|
||||
get_ccc_table(
|
||||
findings,
|
||||
bulk_checks_metadata,
|
||||
compliance_framework,
|
||||
output_filename,
|
||||
output_directory,
|
||||
compliance_overview,
|
||||
)
|
||||
else:
|
||||
get_generic_compliance_table(
|
||||
findings,
|
||||
|
||||
@@ -49,11 +49,11 @@ dependencies = [
|
||||
"cryptography==46.0.6",
|
||||
"dash==3.1.1",
|
||||
"dash-bootstrap-components==2.0.3",
|
||||
"defusedxml>=0.7.1",
|
||||
"defusedxml==0.7.1",
|
||||
"detect-secrets==1.5.0",
|
||||
"dulwich==0.23.0",
|
||||
"google-api-python-client==2.163.0",
|
||||
"google-auth-httplib2>=0.1,<0.3",
|
||||
"google-auth-httplib2==0.2.0",
|
||||
"jsonschema==4.23.0",
|
||||
"kubernetes==32.0.1",
|
||||
"markdown==3.10.2",
|
||||
@@ -63,9 +63,9 @@ dependencies = [
|
||||
"openstacksdk==4.2.0",
|
||||
"pandas==2.2.3",
|
||||
"py-ocsf-models==0.8.1",
|
||||
"pydantic (>=2.0,<3.0)",
|
||||
"pydantic==2.12.5",
|
||||
"pygithub==2.8.0",
|
||||
"python-dateutil (>=2.9.0.post0,<3.0.0)",
|
||||
"python-dateutil==2.9.0.post0",
|
||||
"pytz==2025.1",
|
||||
"schema==0.7.5",
|
||||
"shodan==1.31.0",
|
||||
@@ -127,7 +127,7 @@ mock = "5.2.0"
|
||||
moto = {extras = ["all"], version = "5.1.11"}
|
||||
openapi-schema-validator = "0.6.3"
|
||||
openapi-spec-validator = "0.7.1"
|
||||
pre-commit = "4.2.0"
|
||||
pre-commit = "4.5.1"
|
||||
pylint = "3.3.4"
|
||||
pytest = "8.3.5"
|
||||
pytest-cov = "6.0.0"
|
||||
|
||||
0
tests/lib/outputs/compliance/ccc/__init__.py
Normal file
0
tests/lib/outputs/compliance/ccc/__init__.py
Normal file
138
tests/lib/outputs/compliance/ccc/ccc_aws_test.py
Normal file
138
tests/lib/outputs/compliance/ccc/ccc_aws_test.py
Normal file
@@ -0,0 +1,138 @@
|
||||
from io import StringIO
|
||||
from unittest import mock
|
||||
|
||||
from freezegun import freeze_time
|
||||
from mock import patch
|
||||
|
||||
from prowler.lib.outputs.compliance.ccc.ccc_aws import CCC_AWS
|
||||
from prowler.lib.outputs.compliance.ccc.models import CCC_AWSModel
|
||||
from tests.lib.outputs.compliance.fixtures import CCC_AWS_FIXTURE
|
||||
from tests.lib.outputs.fixtures.fixtures import generate_finding_output
|
||||
from tests.providers.aws.utils import AWS_ACCOUNT_NUMBER, AWS_REGION_EU_WEST_1
|
||||
|
||||
|
||||
class TestAWSCCC:
|
||||
def test_output_transform_evaluated_requirement(self):
|
||||
findings = [
|
||||
generate_finding_output(compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"})
|
||||
]
|
||||
|
||||
output = CCC_AWS(findings, CCC_AWS_FIXTURE)
|
||||
output_data = output.data[0]
|
||||
|
||||
assert isinstance(output_data, CCC_AWSModel)
|
||||
assert output_data.Provider == "aws"
|
||||
assert output_data.AccountId == AWS_ACCOUNT_NUMBER
|
||||
assert output_data.Region == AWS_REGION_EU_WEST_1
|
||||
assert output_data.Description == CCC_AWS_FIXTURE.Description
|
||||
assert output_data.Requirements_Id == CCC_AWS_FIXTURE.Requirements[0].Id
|
||||
assert (
|
||||
output_data.Requirements_Description
|
||||
== CCC_AWS_FIXTURE.Requirements[0].Description
|
||||
)
|
||||
attribute = CCC_AWS_FIXTURE.Requirements[0].Attributes[0]
|
||||
assert output_data.Requirements_Attributes_FamilyName == attribute.FamilyName
|
||||
assert (
|
||||
output_data.Requirements_Attributes_FamilyDescription
|
||||
== attribute.FamilyDescription
|
||||
)
|
||||
assert output_data.Requirements_Attributes_Section == attribute.Section
|
||||
assert output_data.Requirements_Attributes_SubSection == attribute.SubSection
|
||||
assert (
|
||||
output_data.Requirements_Attributes_SubSectionObjective
|
||||
== attribute.SubSectionObjective
|
||||
)
|
||||
assert (
|
||||
output_data.Requirements_Attributes_Applicability == attribute.Applicability
|
||||
)
|
||||
assert (
|
||||
output_data.Requirements_Attributes_Recommendation
|
||||
== attribute.Recommendation
|
||||
)
|
||||
assert (
|
||||
output_data.Requirements_Attributes_SectionThreatMappings
|
||||
== attribute.SectionThreatMappings
|
||||
)
|
||||
assert (
|
||||
output_data.Requirements_Attributes_SectionGuidelineMappings
|
||||
== attribute.SectionGuidelineMappings
|
||||
)
|
||||
assert output_data.Status == "PASS"
|
||||
assert output_data.StatusExtended == ""
|
||||
assert output_data.ResourceId == ""
|
||||
assert output_data.ResourceName == ""
|
||||
assert output_data.CheckId == "service_test_check_id"
|
||||
assert output_data.Muted is False
|
||||
|
||||
def test_output_transform_manual_requirement(self):
|
||||
# Use a finding for the evaluated requirement so the manual one is appended
|
||||
# by the manual-loop branch (Checks=[]).
|
||||
findings = [
|
||||
generate_finding_output(compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"})
|
||||
]
|
||||
|
||||
output = CCC_AWS(findings, CCC_AWS_FIXTURE)
|
||||
# data[0] is the evaluated PASS row, data[1] is the manual row
|
||||
manual_row = output.data[1]
|
||||
|
||||
assert isinstance(manual_row, CCC_AWSModel)
|
||||
assert manual_row.Provider == "aws"
|
||||
assert manual_row.AccountId == ""
|
||||
assert manual_row.Region == ""
|
||||
assert manual_row.Description == CCC_AWS_FIXTURE.Description
|
||||
assert manual_row.Requirements_Id == CCC_AWS_FIXTURE.Requirements[1].Id
|
||||
manual_attribute = CCC_AWS_FIXTURE.Requirements[1].Attributes[0]
|
||||
assert (
|
||||
manual_row.Requirements_Attributes_FamilyName == manual_attribute.FamilyName
|
||||
)
|
||||
assert manual_row.Requirements_Attributes_Section == manual_attribute.Section
|
||||
assert manual_row.Status == "MANUAL"
|
||||
assert manual_row.StatusExtended == "Manual check"
|
||||
assert manual_row.ResourceId == "manual_check"
|
||||
assert manual_row.ResourceName == "Manual check"
|
||||
assert manual_row.CheckId == "manual"
|
||||
assert manual_row.Muted is False
|
||||
|
||||
@freeze_time("2025-01-01 00:00:00")
|
||||
@mock.patch(
|
||||
"prowler.lib.outputs.compliance.ccc.ccc_aws.timestamp",
|
||||
"2025-01-01 00:00:00",
|
||||
)
|
||||
def test_batch_write_data_to_file(self):
|
||||
mock_file = StringIO()
|
||||
findings = [
|
||||
generate_finding_output(compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"})
|
||||
]
|
||||
output = CCC_AWS(findings, CCC_AWS_FIXTURE)
|
||||
output._file_descriptor = mock_file
|
||||
|
||||
with patch.object(mock_file, "close", return_value=None):
|
||||
output.batch_write_data_to_file()
|
||||
|
||||
mock_file.seek(0)
|
||||
content = mock_file.read()
|
||||
|
||||
# Header check: AWS-specific columns must be present
|
||||
header = content.split("\r\n", 1)[0]
|
||||
assert "ACCOUNTID" in header
|
||||
assert "REGION" in header
|
||||
assert "REQUIREMENTS_ATTRIBUTES_FAMILYNAME" in header
|
||||
assert "REQUIREMENTS_ATTRIBUTES_SECTION" in header
|
||||
assert "REQUIREMENTS_ATTRIBUTES_APPLICABILITY" in header
|
||||
assert "REQUIREMENTS_ATTRIBUTES_SECTIONTHREATMAPPINGS" in header
|
||||
# Header should NOT contain Azure or GCP-only columns
|
||||
assert "SUBSCRIPTIONID" not in header
|
||||
assert "PROJECTID" not in header
|
||||
|
||||
# Body checks: evaluated row + manual row
|
||||
rows = [r for r in content.split("\r\n") if r]
|
||||
assert len(rows) == 3 # header + evaluated + manual
|
||||
assert "CCC.Core.CN01.AR01" in rows[1]
|
||||
assert "PASS" in rows[1]
|
||||
assert AWS_ACCOUNT_NUMBER in rows[1]
|
||||
assert AWS_REGION_EU_WEST_1 in rows[1]
|
||||
assert "CCC.IAM.CN01.AR01" in rows[2]
|
||||
assert "MANUAL" in rows[2]
|
||||
assert "manual_check" in rows[2]
|
||||
# The frozen timestamp should appear
|
||||
assert "2025-01-01 00:00:00" in rows[1]
|
||||
99
tests/lib/outputs/compliance/ccc/ccc_azure_test.py
Normal file
99
tests/lib/outputs/compliance/ccc/ccc_azure_test.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from io import StringIO
|
||||
from unittest import mock
|
||||
|
||||
from freezegun import freeze_time
|
||||
from mock import patch
|
||||
|
||||
from prowler.lib.outputs.compliance.ccc.ccc_azure import CCC_Azure
|
||||
from prowler.lib.outputs.compliance.ccc.models import CCC_AzureModel
|
||||
from tests.lib.outputs.compliance.fixtures import CCC_AZURE_FIXTURE
|
||||
from tests.lib.outputs.fixtures.fixtures import generate_finding_output
|
||||
from tests.providers.azure.azure_fixtures import AZURE_SUBSCRIPTION_ID
|
||||
|
||||
AZURE_LOCATION = "westeurope"
|
||||
|
||||
|
||||
class TestAzureCCC:
|
||||
def test_output_transform_evaluated_requirement(self):
|
||||
findings = [
|
||||
generate_finding_output(
|
||||
provider="azure",
|
||||
compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"},
|
||||
account_uid=AZURE_SUBSCRIPTION_ID,
|
||||
region=AZURE_LOCATION,
|
||||
)
|
||||
]
|
||||
|
||||
output = CCC_Azure(findings, CCC_AZURE_FIXTURE)
|
||||
output_data = output.data[0]
|
||||
|
||||
assert isinstance(output_data, CCC_AzureModel)
|
||||
assert output_data.Provider == "azure"
|
||||
assert output_data.SubscriptionId == AZURE_SUBSCRIPTION_ID
|
||||
assert output_data.Location == AZURE_LOCATION
|
||||
assert output_data.Description == CCC_AZURE_FIXTURE.Description
|
||||
assert output_data.Requirements_Id == CCC_AZURE_FIXTURE.Requirements[0].Id
|
||||
attribute = CCC_AZURE_FIXTURE.Requirements[0].Attributes[0]
|
||||
assert output_data.Requirements_Attributes_FamilyName == attribute.FamilyName
|
||||
assert output_data.Requirements_Attributes_Section == attribute.Section
|
||||
assert (
|
||||
output_data.Requirements_Attributes_Applicability == attribute.Applicability
|
||||
)
|
||||
assert output_data.Status == "PASS"
|
||||
assert output_data.CheckId == "service_test_check_id"
|
||||
|
||||
def test_output_transform_manual_requirement(self):
|
||||
findings = [
|
||||
generate_finding_output(
|
||||
provider="azure",
|
||||
compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"},
|
||||
account_uid=AZURE_SUBSCRIPTION_ID,
|
||||
region=AZURE_LOCATION,
|
||||
)
|
||||
]
|
||||
output = CCC_Azure(findings, CCC_AZURE_FIXTURE)
|
||||
manual_row = output.data[1]
|
||||
|
||||
assert isinstance(manual_row, CCC_AzureModel)
|
||||
assert manual_row.Provider == "azure"
|
||||
assert manual_row.SubscriptionId == ""
|
||||
assert manual_row.Location == ""
|
||||
assert manual_row.Requirements_Id == CCC_AZURE_FIXTURE.Requirements[1].Id
|
||||
assert manual_row.Status == "MANUAL"
|
||||
assert manual_row.CheckId == "manual"
|
||||
|
||||
@freeze_time("2025-01-01 00:00:00")
|
||||
@mock.patch(
|
||||
"prowler.lib.outputs.compliance.ccc.ccc_azure.timestamp",
|
||||
"2025-01-01 00:00:00",
|
||||
)
|
||||
def test_batch_write_data_to_file(self):
|
||||
mock_file = StringIO()
|
||||
findings = [
|
||||
generate_finding_output(
|
||||
provider="azure",
|
||||
compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"},
|
||||
account_uid=AZURE_SUBSCRIPTION_ID,
|
||||
region=AZURE_LOCATION,
|
||||
)
|
||||
]
|
||||
output = CCC_Azure(findings, CCC_AZURE_FIXTURE)
|
||||
output._file_descriptor = mock_file
|
||||
|
||||
with patch.object(mock_file, "close", return_value=None):
|
||||
output.batch_write_data_to_file()
|
||||
|
||||
mock_file.seek(0)
|
||||
content = mock_file.read()
|
||||
header = content.split("\r\n", 1)[0]
|
||||
assert "SUBSCRIPTIONID" in header
|
||||
assert "LOCATION" in header
|
||||
assert "ACCOUNTID" not in header
|
||||
assert "PROJECTID" not in header
|
||||
assert "REGION" not in header
|
||||
rows = [r for r in content.split("\r\n") if r]
|
||||
assert len(rows) == 3
|
||||
assert "CCC.Core.CN01.AR01" in rows[1]
|
||||
assert AZURE_SUBSCRIPTION_ID in rows[1]
|
||||
assert "CCC.IAM.CN01.AR01" in rows[2]
|
||||
assert "MANUAL" in rows[2]
|
||||
99
tests/lib/outputs/compliance/ccc/ccc_gcp_test.py
Normal file
99
tests/lib/outputs/compliance/ccc/ccc_gcp_test.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from io import StringIO
|
||||
from unittest import mock
|
||||
|
||||
from freezegun import freeze_time
|
||||
from mock import patch
|
||||
|
||||
from prowler.lib.outputs.compliance.ccc.ccc_gcp import CCC_GCP
|
||||
from prowler.lib.outputs.compliance.ccc.models import CCC_GCPModel
|
||||
from tests.lib.outputs.compliance.fixtures import CCC_GCP_FIXTURE
|
||||
from tests.lib.outputs.fixtures.fixtures import generate_finding_output
|
||||
|
||||
GCP_PROJECT_ID = "test-project"
|
||||
GCP_LOCATION = "europe-west1"
|
||||
|
||||
|
||||
class TestGCPCCC:
|
||||
def test_output_transform_evaluated_requirement(self):
|
||||
findings = [
|
||||
generate_finding_output(
|
||||
provider="gcp",
|
||||
compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"},
|
||||
account_uid=GCP_PROJECT_ID,
|
||||
region=GCP_LOCATION,
|
||||
)
|
||||
]
|
||||
|
||||
output = CCC_GCP(findings, CCC_GCP_FIXTURE)
|
||||
output_data = output.data[0]
|
||||
|
||||
assert isinstance(output_data, CCC_GCPModel)
|
||||
assert output_data.Provider == "gcp"
|
||||
assert output_data.ProjectId == GCP_PROJECT_ID
|
||||
assert output_data.Location == GCP_LOCATION
|
||||
assert output_data.Description == CCC_GCP_FIXTURE.Description
|
||||
assert output_data.Requirements_Id == CCC_GCP_FIXTURE.Requirements[0].Id
|
||||
attribute = CCC_GCP_FIXTURE.Requirements[0].Attributes[0]
|
||||
assert output_data.Requirements_Attributes_FamilyName == attribute.FamilyName
|
||||
assert output_data.Requirements_Attributes_Section == attribute.Section
|
||||
assert (
|
||||
output_data.Requirements_Attributes_Applicability == attribute.Applicability
|
||||
)
|
||||
assert output_data.Status == "PASS"
|
||||
assert output_data.CheckId == "service_test_check_id"
|
||||
|
||||
def test_output_transform_manual_requirement(self):
|
||||
findings = [
|
||||
generate_finding_output(
|
||||
provider="gcp",
|
||||
compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"},
|
||||
account_uid=GCP_PROJECT_ID,
|
||||
region=GCP_LOCATION,
|
||||
)
|
||||
]
|
||||
output = CCC_GCP(findings, CCC_GCP_FIXTURE)
|
||||
manual_row = output.data[1]
|
||||
|
||||
assert isinstance(manual_row, CCC_GCPModel)
|
||||
assert manual_row.Provider == "gcp"
|
||||
assert manual_row.ProjectId == ""
|
||||
assert manual_row.Location == ""
|
||||
assert manual_row.Requirements_Id == CCC_GCP_FIXTURE.Requirements[1].Id
|
||||
assert manual_row.Status == "MANUAL"
|
||||
assert manual_row.CheckId == "manual"
|
||||
|
||||
@freeze_time("2025-01-01 00:00:00")
|
||||
@mock.patch(
|
||||
"prowler.lib.outputs.compliance.ccc.ccc_gcp.timestamp",
|
||||
"2025-01-01 00:00:00",
|
||||
)
|
||||
def test_batch_write_data_to_file(self):
|
||||
mock_file = StringIO()
|
||||
findings = [
|
||||
generate_finding_output(
|
||||
provider="gcp",
|
||||
compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"},
|
||||
account_uid=GCP_PROJECT_ID,
|
||||
region=GCP_LOCATION,
|
||||
)
|
||||
]
|
||||
output = CCC_GCP(findings, CCC_GCP_FIXTURE)
|
||||
output._file_descriptor = mock_file
|
||||
|
||||
with patch.object(mock_file, "close", return_value=None):
|
||||
output.batch_write_data_to_file()
|
||||
|
||||
mock_file.seek(0)
|
||||
content = mock_file.read()
|
||||
header = content.split("\r\n", 1)[0]
|
||||
assert "PROJECTID" in header
|
||||
assert "LOCATION" in header
|
||||
assert "ACCOUNTID" not in header
|
||||
assert "SUBSCRIPTIONID" not in header
|
||||
assert "REGION" not in header
|
||||
rows = [r for r in content.split("\r\n") if r]
|
||||
assert len(rows) == 3
|
||||
assert "CCC.Core.CN01.AR01" in rows[1]
|
||||
assert GCP_PROJECT_ID in rows[1]
|
||||
assert "CCC.IAM.CN01.AR01" in rows[2]
|
||||
assert "MANUAL" in rows[2]
|
||||
@@ -1,5 +1,6 @@
|
||||
from prowler.lib.check.compliance_models import (
|
||||
AWS_Well_Architected_Requirement_Attribute,
|
||||
CCC_Requirement_Attribute,
|
||||
CIS_Requirement_Attribute,
|
||||
Compliance,
|
||||
Compliance_Requirement,
|
||||
@@ -1022,3 +1023,169 @@ PROWLER_THREATSCORE_M365 = Compliance(
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
# CCC fixtures cover the three providers Prowler ships catalogs for. Each
|
||||
# fixture has one auto-evaluated requirement (with Checks) and one manual
|
||||
# requirement (Checks=[]) so test suites can exercise both paths.
|
||||
CCC_AWS_FIXTURE = Compliance(
|
||||
Framework="CCC",
|
||||
Name="Common Cloud Controls Catalog (CCC)",
|
||||
Provider="AWS",
|
||||
Version="v2025.10",
|
||||
Description="Common Cloud Controls Catalog (CCC) for AWS",
|
||||
Requirements=[
|
||||
Compliance_Requirement(
|
||||
Checks=["service_test_check_id"],
|
||||
Id="CCC.Core.CN01.AR01",
|
||||
Description="When a port is exposed for non-SSH network traffic, all traffic MUST include a TLS handshake AND be encrypted using TLS 1.3 or higher.",
|
||||
Attributes=[
|
||||
CCC_Requirement_Attribute(
|
||||
FamilyName="Data",
|
||||
FamilyDescription="The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.",
|
||||
Section="CCC.Core.CN01 Encrypt Data for Transmission",
|
||||
SubSection="",
|
||||
SubSectionObjective="Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.",
|
||||
Applicability=["tlp-green", "tlp-amber", "tlp-red"],
|
||||
Recommendation="Most cloud services enable TLS 1.3 by default.",
|
||||
SectionThreatMappings=[
|
||||
{"ReferenceId": "CCC", "Identifiers": ["CCC.Core.TH02"]}
|
||||
],
|
||||
SectionGuidelineMappings=[
|
||||
{"ReferenceId": "CCM", "Identifiers": ["CEK-03", "CEK-04"]}
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
Compliance_Requirement(
|
||||
Checks=[],
|
||||
Id="CCC.IAM.CN01.AR01",
|
||||
Description="When an identity policy for a non-administrative principal is evaluated, it MUST NOT grant permissions for creating credentials or generating temporary session tokens.",
|
||||
Attributes=[
|
||||
CCC_Requirement_Attribute(
|
||||
FamilyName="Identity and Access Management",
|
||||
FamilyDescription="Controls that restrict who can access and modify IAM resources.",
|
||||
Section="CCC.IAM.CN01 Restrict IAM User Credentials Creation",
|
||||
SubSection="",
|
||||
SubSectionObjective="Prevent non-administrative principals from creating new long-lived credentials.",
|
||||
Applicability=["tlp-clear", "tlp-green", "tlp-amber", "tlp-red"],
|
||||
Recommendation="",
|
||||
SectionThreatMappings=[
|
||||
{"ReferenceId": "CCC", "Identifiers": ["CCC.IAM.TH03"]}
|
||||
],
|
||||
SectionGuidelineMappings=[
|
||||
{"ReferenceId": "NIST-CSF", "Identifiers": ["PR.AA-05"]}
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
CCC_AZURE_FIXTURE = Compliance(
|
||||
Framework="CCC",
|
||||
Name="Common Cloud Controls Catalog (CCC)",
|
||||
Provider="Azure",
|
||||
Version="v2025.10",
|
||||
Description="Common Cloud Controls Catalog (CCC) for Azure",
|
||||
Requirements=[
|
||||
Compliance_Requirement(
|
||||
Checks=["service_test_check_id"],
|
||||
Id="CCC.Core.CN01.AR01",
|
||||
Description="When a port is exposed for non-SSH network traffic, all traffic MUST include a TLS handshake AND be encrypted using TLS 1.3 or higher.",
|
||||
Attributes=[
|
||||
CCC_Requirement_Attribute(
|
||||
FamilyName="Data",
|
||||
FamilyDescription="The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.",
|
||||
Section="CCC.Core.CN01 Encrypt Data for Transmission",
|
||||
SubSection="",
|
||||
SubSectionObjective="Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.",
|
||||
Applicability=["tlp-green", "tlp-amber", "tlp-red"],
|
||||
Recommendation="Most cloud services enable TLS 1.3 by default.",
|
||||
SectionThreatMappings=[
|
||||
{"ReferenceId": "CCC", "Identifiers": ["CCC.Core.TH02"]}
|
||||
],
|
||||
SectionGuidelineMappings=[
|
||||
{"ReferenceId": "CCM", "Identifiers": ["CEK-03", "CEK-04"]}
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
Compliance_Requirement(
|
||||
Checks=[],
|
||||
Id="CCC.IAM.CN01.AR01",
|
||||
Description="When an identity policy for a non-administrative principal is evaluated, it MUST NOT grant permissions for creating credentials.",
|
||||
Attributes=[
|
||||
CCC_Requirement_Attribute(
|
||||
FamilyName="Identity and Access Management",
|
||||
FamilyDescription="Controls that restrict who can access and modify IAM resources.",
|
||||
Section="CCC.IAM.CN01 Restrict IAM User Credentials Creation",
|
||||
SubSection="",
|
||||
SubSectionObjective="Prevent non-administrative principals from creating new long-lived credentials.",
|
||||
Applicability=["tlp-clear", "tlp-green", "tlp-amber", "tlp-red"],
|
||||
Recommendation="",
|
||||
SectionThreatMappings=[
|
||||
{"ReferenceId": "CCC", "Identifiers": ["CCC.IAM.TH03"]}
|
||||
],
|
||||
SectionGuidelineMappings=[
|
||||
{"ReferenceId": "NIST-CSF", "Identifiers": ["PR.AA-05"]}
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
CCC_GCP_FIXTURE = Compliance(
|
||||
Framework="CCC",
|
||||
Name="Common Cloud Controls Catalog (CCC)",
|
||||
Provider="GCP",
|
||||
Version="v2025.10",
|
||||
Description="Common Cloud Controls Catalog (CCC) for GCP",
|
||||
Requirements=[
|
||||
Compliance_Requirement(
|
||||
Checks=["service_test_check_id"],
|
||||
Id="CCC.Core.CN01.AR01",
|
||||
Description="When a port is exposed for non-SSH network traffic, all traffic MUST include a TLS handshake AND be encrypted using TLS 1.3 or higher.",
|
||||
Attributes=[
|
||||
CCC_Requirement_Attribute(
|
||||
FamilyName="Data",
|
||||
FamilyDescription="The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.",
|
||||
Section="CCC.Core.CN01 Encrypt Data for Transmission",
|
||||
SubSection="",
|
||||
SubSectionObjective="Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.",
|
||||
Applicability=["tlp-green", "tlp-amber", "tlp-red"],
|
||||
Recommendation="Most cloud services enable TLS 1.3 by default.",
|
||||
SectionThreatMappings=[
|
||||
{"ReferenceId": "CCC", "Identifiers": ["CCC.Core.TH02"]}
|
||||
],
|
||||
SectionGuidelineMappings=[
|
||||
{"ReferenceId": "CCM", "Identifiers": ["CEK-03", "CEK-04"]}
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
Compliance_Requirement(
|
||||
Checks=[],
|
||||
Id="CCC.IAM.CN01.AR01",
|
||||
Description="When an identity policy for a non-administrative principal is evaluated, it MUST NOT grant permissions for creating credentials.",
|
||||
Attributes=[
|
||||
CCC_Requirement_Attribute(
|
||||
FamilyName="Identity and Access Management",
|
||||
FamilyDescription="Controls that restrict who can access and modify IAM resources.",
|
||||
Section="CCC.IAM.CN01 Restrict IAM User Credentials Creation",
|
||||
SubSection="",
|
||||
SubSectionObjective="Prevent non-administrative principals from creating new long-lived credentials.",
|
||||
Applicability=["tlp-clear", "tlp-green", "tlp-amber", "tlp-red"],
|
||||
Recommendation="",
|
||||
SectionThreatMappings=[
|
||||
{"ReferenceId": "CCC", "Identifiers": ["CCC.IAM.TH03"]}
|
||||
],
|
||||
SectionGuidelineMappings=[
|
||||
{"ReferenceId": "NIST-CSF", "Identifiers": ["PR.AA-05"]}
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user