diff --git a/docs/developer-guide/provider.mdx b/docs/developer-guide/provider.mdx index 70fd519505..3d96e41ab5 100644 --- a/docs/developer-guide/provider.mdx +++ b/docs/developer-guide/provider.mdx @@ -25,7 +25,7 @@ For providers supported by Prowler, refer to [Prowler Hub](https://hub.prowler.c Prowler supports several types of providers, each with its own implementation pattern and use case. Understanding these differences is key to designing your provider correctly. -### Classifying your Provider +### Classifying Your Provider Before implementing a new provider, you need to determine which type it belongs to. This classification will guide your implementation approach and help you choose the right patterns and libraries. @@ -1090,7 +1090,7 @@ Main registration makes your provider discoverable by Prowler's core system. It' cis.batch_write_data_to_file() ``` -#### Step 11: Register in the list of providers +#### Step 11: Register in the List of Providers **Explanation:** This is needed to be able to use the provider in the generic checks. The provider must be registered in the `init_global_provider` method to handle CLI arguments and initialization. @@ -1966,7 +1966,7 @@ Main registration makes your provider discoverable by Prowler's core system. It' This step is the same as the [SDK providers](#step-10-register-in-main). -#### Step 11: Register in the list of providers +#### Step 11: Register in the List of Providers **Explanation:** This is needed to be able to use the provider in the generic checks. The provider must be registered in the `init_global_provider` method to handle CLI arguments and initialization. @@ -2648,7 +2648,7 @@ Main registration makes your provider discoverable by Prowler's core system. It' This step is the same as the [SDK providers](#step-10-register-in-main). -#### Step 7: Register in the list of providers +#### Step 7: Register in the List of Providers **Explanation:** This is needed to be able to use the provider in the generic checks. The provider must be registered in the `init_global_provider` method to handle CLI arguments and initialization. @@ -2808,7 +2808,7 @@ def validate_your_provider_uid(value): **Provider Model:** The `Provider` model already exists and supports all provider types. Ensure your provider type is included in the choices. -### 2.2. Add the provider to the Provider Choices +### 2.2. Add the Provider to the Provider Choices Update the `return_prowler_provider` function to include your provider. This function is crucial for the API to instantiate the correct provider class. @@ -3209,7 +3209,7 @@ class YourProviderAPITestCase(APITestCase): self.assertEqual(response.status_code, 201) ``` -#### 2.6.1. Add your mocked provider to the tests +#### 2.6.1. Add Your Mocked Provider to the Tests If needed, add a named provider fixture or extend the provider factory defaults so tests can request only the provider they need. @@ -3272,7 +3272,7 @@ Your provider will be available through these endpoints: - `DELETE /api/v1/providers/{id}/` - Delete provider - `POST /api/v1/providers/secrets/` - Add provider credentials -### 2.9. Update the provider if needed +### 2.9. Update the Provider If Needed Depending on your provider's authentication requirements, you may need to add new authentication methods that are compatible with the API. This involves updating the provider class to support additional credential types beyond the basic ones. diff --git a/docs/developer-guide/security-compliance-framework.mdx b/docs/developer-guide/security-compliance-framework.mdx index 46d8d2722e..3dc84dc58c 100644 --- a/docs/developer-guide/security-compliance-framework.mdx +++ b/docs/developer-guide/security-compliance-framework.mdx @@ -18,7 +18,7 @@ A compliance framework must represent the **complete state** of the source catal Requirement coverage feeds the compliance percentage calculations and the metadata surfaces (dashboards, widgets, exports). Missing requirements skew those metrics and break the report as a faithful snapshot of the framework. -### Two supported schemas +### Two Supported Schemas | Schema | When to use | File location | Discovered as | | --- | --- | --- | --- | @@ -45,7 +45,7 @@ Before adding a new framework, complete the following checks: ## Universal Compliance Framework -### Where the file lives +### Where the File Lives Place the file at the top level of the compliance directory: @@ -57,7 +57,7 @@ Examples in the repository: `prowler/compliance/csa_ccm_4.0.json`, `prowler/comp The file is auto-discovered — there is **no** need to register it in any `__init__.py`, modify `prowler/lib/outputs/`, or update any other Python module. The framework key Prowler CLI accepts via `--compliance` is the basename of the JSON file without `.json` (`dora_2022_2554.json` → `dora_2022_2554`). -### Top-level structure +### Top-Level Structure ```json { @@ -198,7 +198,7 @@ Per requirement: For MITRE-style frameworks, additional optional fields are available on the requirement: `tactics`, `sub_techniques`, `platforms`, `technique_url` (these are populated automatically when adapting a legacy MITRE JSON to the universal model). -### Multi-provider frameworks +### Multi-Provider Frameworks A single universal file can cover any number of providers. The framework appears under each provider's `--list-compliance` output as long as **at least one** requirement has that provider key in its `checks` dict. @@ -226,7 +226,7 @@ The legacy schema spans **four layers** — a complete contribution must touch e The universal schema collapses Layers 3 and 4 into declarative configuration inside the JSON — that is the main reason it is preferred for new contributions. -### Directory structure and file naming +### Directory Structure and File Naming Compliance frameworks live at: @@ -259,7 +259,7 @@ prowler/lib/outputs/compliance// └── __init__.py ``` -### JSON schema reference +### JSON Schema Reference Every legacy compliance file is a JSON document with the following top-level keys. `Framework`, `Name` and `Provider` are validated non-empty by the root validator `framework_and_provider_must_not_be_empty` (`compliance_models.py`). @@ -362,7 +362,7 @@ For the remaining attribute classes (`AWS_Well_Architected_Requirement_Attribute The `Attributes` field is a Pydantic `Union`. The generic attribute model **must** remain the last element of that Union — otherwise Pydantic v1 silently coerces every framework into the generic shape and your specialized fields are dropped. Adding a brand-new attribute shape requires inserting the Pydantic class **before** `Generic_Compliance_Requirement_Attribute`. -#### Minimal working example +#### Minimal Working Example The following snippet is a complete, valid framework file named `my_framework_1.0_aws.json`, saved at `prowler/compliance/aws/my_framework_1.0_aws.json`. It uses the generic attribute shape for simplicity. @@ -408,7 +408,7 @@ The following snippet is a complete, valid framework file named `my_framework_1. } ``` -### Mapping checks to requirements +### Mapping Checks to Requirements Each requirement links to the Prowler checks that, together, produce a PASS or FAIL verdict for that control. @@ -425,7 +425,7 @@ To discover available checks: uv run python prowler-cli.py --list-checks ``` -### Supporting multiple providers (legacy) +### Supporting Multiple Providers (Legacy) The legacy schema binds each file to a single provider. To cover several providers with the same framework, ship one JSON file per provider: @@ -439,7 +439,7 @@ Keep the `Framework` and `Version` values identical across the files so the disp For a brand-new framework that spans several providers, **prefer the universal schema** — it covers every provider from a single file. If you must use the legacy schema, add one transformer per provider in `prowler/lib/outputs/compliance//` and extend the summary-table dispatcher accordingly. See [Output Formatter](#output-formatter). -### Output formatter +### Output Formatter Legacy frameworks render in two forms: a detailed CSV report written to disk, and a summary table printed in the CLI. Both are produced by the output formatter package for the framework. Universal frameworks do **not** need a Python output formatter — the `outputs` config inside the JSON drives rendering — so this section applies only to the legacy schema. @@ -453,19 +453,19 @@ prowler/lib/outputs/compliance/my_framework/ └── models.py # CSV row Pydantic model ``` -#### Step 1 — Define the CSV row model +#### Step 1 — Define the CSV Row Model In `models.py`, declare a Pydantic v1 model with one field per CSV column. Use existing models such as `AWSCISModel` in `prowler/lib/outputs/compliance/cis/models.py` as the reference. Fields typically include `Provider`, `Description`, `AccountId`, `Region`, `AssessmentDate`, `Requirements_Id`, `Requirements_Description`, one `Requirements_Attributes_*` field per attribute key, plus the finding fields `Status`, `StatusExtended`, `ResourceId`, `ResourceName`, `CheckId`, `Muted`, `Framework`, `Name`. -#### Step 2 — Implement the transformer +#### Step 2 — Implement the Transformer In `my_framework_aws.py`, subclass `ComplianceOutput` from `prowler.lib.outputs.compliance.compliance_output` and implement `transform(findings, compliance, compliance_name)`. Iterate over `findings`, match each finding to the requirements it satisfies through `finding.compliance.get(compliance_name, [])`, and append one row per attribute to `self._data`. -#### Step 3 — Add the summary-table dispatcher +#### Step 3 — Add the Summary-Table Dispatcher In `my_framework.py`, implement `get_my_framework_table(findings, bulk_checks_metadata, compliance_framework, output_filename, output_directory, compliance_overview)` following the pattern in `prowler/lib/outputs/compliance/cis/cis.py`. -#### Step 4 — Register the framework in the dispatchers +#### Step 4 — Register the Framework in the Dispatchers - Add the dispatcher call in `prowler/lib/outputs/compliance/compliance.py`, inside `display_compliance_table`, with a branch such as `elif "my_framework" in compliance_framework:`. - Register the CSV model and transformer in `prowler/lib/outputs/compliance/compliance_output.py` so the CSV file is emitted during the scan. @@ -474,7 +474,7 @@ In `my_framework.py`, implement `get_my_framework_table(findings, bulk_checks_me For NIST-style catalogs that use `Generic_Compliance_Requirement_Attribute`, no custom formatter is needed. The generic formatter in `prowler/lib/outputs/compliance/generic/` handles them automatically, provided the JSON validates against the generic attribute schema. -### Legacy-to-universal adapter +### Legacy-to-Universal Adapter At load time, every legacy file is transparently adapted to a `ComplianceFramework` via `adapt_legacy_to_universal()` (`compliance_models.py`), which: (a) flattens the first element of `Attributes` into a flat `attributes` dict, (b) wraps `Checks` as `{provider_lower: [...]}`, (c) infers `attributes_metadata` from the matched Pydantic class via `_infer_attribute_metadata()`. The rest of Prowler (CSV/OCSF/PDF output, CLI table) then treats both formats identically. @@ -497,7 +497,7 @@ Configuration guardrails close that gap. A requirement declares the configuratio Guardrails are an **optional** safety net for configurable checks. A requirement that maps only to non-configurable checks does not need them. When the field is absent, behavior is unchanged. -### Where guardrails are declared +### Where Guardrails Are Declared The field is attached to each requirement and exists in both schemas: @@ -506,7 +506,7 @@ The field is attached to each requirement and exists in both schemas: When a legacy file is adapted to the universal model, `adapt_legacy_to_universal()` copies `ConfigRequirements` into `config_requirements` (`compliance_models.py`), so downstream code only ever reads one shape. -### Constraint schema +### Constraint Schema Each entry in the list is a single constraint with the following fields: @@ -533,7 +533,7 @@ Each entry in the list is a single constraint with the following fields: `subset` / `superset` require both the applied value and `Value` to be lists; any other type is treated as not satisfied. For `eq` against a boolean, declare `Value` as a JSON boolean (`false`, not `0`) — the model keeps booleans distinct from integers. -### How guardrails are evaluated +### How Guardrails Are Evaluated All evaluation lives in one shared module, `prowler/lib/check/compliance_config_eval.py`, consumed by every compliance output (CSV, OCSF, and the CLI tables) and reused by the Prowler API backend so the rule is defined exactly once. @@ -547,7 +547,7 @@ All evaluation lives in one shared module, `prowler/lib/check/compliance_config_ Guardrails only ever make a result **stricter** (they can turn PASS into FAIL); they never relax a real FAIL into PASS. A requirement with no constraints, or whose keys all use defaults, is reported exactly as before. -### Example: legacy framework +### Example: Legacy Framework From `prowler/compliance/aws/cis_6.0_aws.json`, requirement 2.11 declares two guardrails — one per configurable check it maps to: @@ -590,7 +590,7 @@ A boolean guardrail from the same file: requirement 2.5 (IAM Access Analyzer) on ] ``` -### Example: universal framework +### Example: Universal Framework The universal schema uses the lowercase `config_requirements` key with the identical object shape: @@ -616,7 +616,7 @@ The universal schema uses the lowercase `config_requirements` key with the ident Each constraint declares the `Provider` it targets so the guardrail is only evaluated on scans of that provider — essential for universal frameworks like CSA CCM and DORA, where one requirement maps checks across `aws`, `azure`, `gcp` and more. Because the operator is `subset`, adding `"TLS 1.0"` to `recommended_minimal_tls_versions` widens the allowlist beyond `["TLS 1.2", "TLS 1.3"]` and the requirement is forced to FAIL. -### What the user sees +### What the User Sees With a loosened config, the affected requirement's findings report: @@ -630,7 +630,7 @@ StatusExtended: Configuration not valid for this requirement. The check The same `Configuration not valid for this requirement.` message appears identically across the CSV, OCSF, and console-table outputs. -### Authoring guidelines +### Authoring Guidelines - Declare a guardrail only for keys whose value actually changes whether the requirement is met. Most configurable checks do not need one. - Set `Value` to the **strictest** configuration the control tolerates — the same number the control text cites (CIS 45 days, NIST ≤90, and so on). @@ -639,7 +639,7 @@ The same `Configuration not valid for this requirement.` message appears identic - Pick the operator from the value's role: a max threshold is `lte`, a min threshold is `gte`, a toggle is `eq`, an allowlist is `subset`, a denylist is `superset`. - An unrecognized operator does **not** block the requirement — a malformed constraint is treated as satisfied rather than failing the whole framework. Validate your JSON with the tests below. -### Testing guardrails +### Testing Guardrails The shared evaluator and the per-output integration are covered by: @@ -670,7 +670,7 @@ Prowler matches frameworks by concatenating `Framework` and `Version`. A missing Before opening a PR, validate the JSON loads cleanly against the model and that every referenced check actually exists. -### 1. Schema validation +### 1. Schema Validation For **universal** frameworks, load the file and inspect what was parsed. The framework key inside `bulk` is the **basename of the JSON file** (without `.json`); for `prowler/compliance/dora_2022_2554.json` that key is `dora_2022_2554`, for `prowler/compliance/aws/cis_5.0_aws.json` it is `cis_5.0_aws`. @@ -688,7 +688,7 @@ bulk = get_bulk_compliance_frameworks_universal("aws") assert "" in bulk ``` -### 2. Check existence cross-check +### 2. Check Existence Cross-Check There is **no automatic check-existence validation** at load time. Cross-check that every check name in your framework maps to a real check directory: @@ -708,7 +708,7 @@ missing = referenced - real assert not missing, f"checks referenced in framework but not found in repo: {sorted(missing)}" ``` -### 3. CLI smoke test +### 3. CLI Smoke Test ```bash uv run python prowler-cli.py --list-compliance @@ -728,7 +728,7 @@ Verify that: - The CLI summary table lists every section / pillar of the framework. - Findings roll up under the expected requirements. -### 4. Inspect the CSV output +### 4. Inspect the CSV Output Open the generated CSV and confirm: diff --git a/docs/developer-guide/server-sent-events.mdx b/docs/developer-guide/server-sent-events.mdx index c91f27227f..6fb9c7a00e 100644 --- a/docs/developer-guide/server-sent-events.mdx +++ b/docs/developer-guide/server-sent-events.mdx @@ -12,7 +12,7 @@ This guide explains how to add a **Server-Sent Events (SSE)** endpoint to the Pr The platform ships the SSE **infrastructure** (`api.sse`) and wiring. No feature endpoint streams over SSE out of the box — this guide shows how to build one on top of the shared base. -## When to use SSE +## When to Use SSE | Need | Use | |------|-----| @@ -22,7 +22,7 @@ The platform ships the SSE **infrastructure** (`api.sse`) and wiring. No feature SSE is the right tool when the **client only consumes**: scan progress, long-running job checkpoints, streamed LLM tokens, cross-client resource-sync notifications. It rides on plain HTTP, reconnects automatically in the browser via the native [`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) API, and needs no extra protocol. -## How it works +## How It Works SSE is wired through [`django-eventstream`](https://github.com/fanout/django_eventstream) and a small platform layer in `api/src/backend/api/sse/`: @@ -34,11 +34,11 @@ SSE is wired through [`django-eventstream`](https://github.com/fanout/django_eve | `make_channel_name` / `tenant_id_from_channel` | `api/sse/utils.py` | Single source of truth for the channel-name format, so publishers and the channel manager agree byte-for-byte. | | Settings | `config/settings/eventstream.py` | Valkey Pub/Sub backend (dedicated DB), channel manager, allowed headers. | -### Transport: the server runs on ASGI +### Transport: The Server Runs on ASGI SSE connections are long-lived. Holding one open per synchronous worker would exhaust the worker pool, so the API runs under Gunicorn's native **`asgi` worker** (`config.asgi:application`). Streams are parked on the event loop while ordinary CRUD endpoints keep their synchronous execution (Django runs sync views in a thread-sensitive executor under ASGI). This is configured in `config/guniconf.py` and used by both the dev and production entrypoints — no separate server process is needed. -### The data flow +### The Data Flow ``` publisher (Celery task / view) subscriber (browser, CLI) @@ -53,7 +53,7 @@ publisher (Celery task / view) subscriber (browser, CLI) A publisher anywhere in the system (most often a Celery task) calls `send_event(channel, event_type, payload)`. `django-eventstream` fans it out over Valkey Pub/Sub to every connection subscribed to that channel. -## Adding an SSE endpoint to your feature +## Adding an SSE Endpoint to Your Feature The example below streams progress for a long-running **scan**. Adapt the resource, prefix, and event names to your feature. @@ -161,7 +161,7 @@ publish_end(channel, scan_id=str(scan.id)) -## Event naming convention +## Event Naming Convention Every event uses an event type of the form **`.`** (lowercased, dot-separated). The verb comes from this platform-wide vocabulary — if you need a verb that is not listed, document the addition in this guide so the catalog stays discoverable. @@ -197,7 +197,7 @@ curl -N -H "Authorization: Bearer $JWT" \ https:///api/v1/scans/$SCAN_ID/event-stream ``` -## Tenant isolation & security model +## Tenant Isolation & Security Model Authorization is enforced at two layers: @@ -206,7 +206,7 @@ Authorization is enforced at two layers: Because the tenant id lives inside the channel name, this gate works for any feature without the platform knowing anything about it. -## Reconnect & state recovery +## Reconnect & State Recovery The platform deliberately ships **without server-side replay** (`is_channel_reliable` returns `False`). When a client reconnects, it does **not** receive missed events. Instead: @@ -215,7 +215,7 @@ The platform deliberately ships **without server-side replay** (`is_channel_reli Design your event payloads accordingly: deltas are ephemeral and concatenated in-flight; the durable truth always lives behind a REST resource. -## Local development +## Local Development - The dev and production entrypoints both launch Gunicorn with the `asgi` worker (`config.asgi:application`). In dev, `DJANGO_DEBUG=True` enables hot reload; `preload_app` is automatically disabled under debug so edited code is picked up. - SSE uses a **dedicated Valkey database** (`EVENTSTREAM_VALKEY_DB`, default `2`) kept separate from the Celery broker so a noisy broker cannot crowd out streaming traffic. It reuses the same `VALKEY_*` connection settings as the rest of the platform. diff --git a/docs/getting-started/products/prowler-mcp.mdx b/docs/getting-started/products/prowler-mcp.mdx index 3deb88489c..24520ed739 100644 --- a/docs/getting-started/products/prowler-mcp.mdx +++ b/docs/getting-started/products/prowler-mcp.mdx @@ -161,7 +161,7 @@ The Prowler MCP Server enables powerful workflows through AI assistants: - "What authentication methods does Prowler support for Azure?" - "How can I contribute with a new security check to Prowler?" -### Example: Creating a custom dashboard with Prowler extracted data +### Example: Creating a Custom Dashboard with Prowler Extracted Data In the next example you can see how to create a dashboard using Prowler MCP Server and Claude Desktop. diff --git a/docs/troubleshooting.mdx b/docs/troubleshooting.mdx index 9e0c849796..8b23550c4b 100644 --- a/docs/troubleshooting.mdx +++ b/docs/troubleshooting.mdx @@ -22,7 +22,7 @@ See section [Logging](/user-guide/cli/tutorials/logging) for further information Common issues with the Docker Compose installation of Prowler Local Server. -### Problem adding AWS Provider using "Connect assuming IAM Role" in Docker +### Problem Adding AWS Provider Using "Connect assuming IAM Role" in Docker See [GitHub Issue #7745](https://github.com/prowler-cloud/prowler/issues/7745) for more details. diff --git a/docs/user-guide/cli/tutorials/fixer.mdx b/docs/user-guide/cli/tutorials/fixer.mdx index 4170b340e2..f777d64713 100644 --- a/docs/user-guide/cli/tutorials/fixer.mdx +++ b/docs/user-guide/cli/tutorials/fixer.mdx @@ -105,7 +105,7 @@ def fixer(resource_id: str) -> bool: return True ``` -## Fixer Config file +## Fixer Config File For some fixers, you can have configurable parameters depending on your use case. You can either use the default config file in `prowler/config/fixer_config.yaml` or create a custom config file and pass it to the fixer with the `--fixer-config` flag. The config file should be a YAML file with the following structure: diff --git a/docs/user-guide/cli/tutorials/misc.mdx b/docs/user-guide/cli/tutorials/misc.mdx index 0940508ed7..59f34c3660 100644 --- a/docs/user-guide/cli/tutorials/misc.mdx +++ b/docs/user-guide/cli/tutorials/misc.mdx @@ -4,7 +4,7 @@ title: 'Miscellaneous' ## Prowler Version -### Showing the Prowler version: +### Showing the Prowler Version ```console prowler -V/-v/--version @@ -22,7 +22,7 @@ To enable verbose mode in Prowler, similar to Version 2, use: prowler --verbose ``` -### Filter findings by status +### Filter Findings by Status Prowler allows filtering findings based on their status, ensuring reports and CLI display only relevant findings: diff --git a/docs/user-guide/cli/tutorials/mutelist.mdx b/docs/user-guide/cli/tutorials/mutelist.mdx index 77b710d3df..b11a41f1c9 100644 --- a/docs/user-guide/cli/tutorials/mutelist.mdx +++ b/docs/user-guide/cli/tutorials/mutelist.mdx @@ -268,7 +268,7 @@ Accounts: ## AWS Mutelist -### Muting specific AWS regions +### Muting Specific AWS Regions If you want to mute failed findings only in specific regions, create a file with the following syntax and run it with `prowler aws -w mutelist.yaml`: diff --git a/docs/user-guide/providers/alibabacloud/getting-started-alibabacloud.mdx b/docs/user-guide/providers/alibabacloud/getting-started-alibabacloud.mdx index ce9778a3b5..e887ead21e 100644 --- a/docs/user-guide/providers/alibabacloud/getting-started-alibabacloud.mdx +++ b/docs/user-guide/providers/alibabacloud/getting-started-alibabacloud.mdx @@ -144,25 +144,25 @@ prowler alibabacloud --ecs-ram-role RoleName ### Step 2: Run the First Scan -#### Scan all regions +#### Scan All Regions ```bash prowler alibabacloud ``` -#### Scan specific regions +#### Scan Specific Regions ```bash prowler alibabacloud --region cn-hangzhou cn-shanghai ``` -#### Run specific checks +#### Run Specific Checks ```bash prowler alibabacloud --checks ram_no_root_access_key ram_user_mfa_enabled_console_access ``` -#### Run a compliance framework +#### Run a Compliance Framework ```bash prowler alibabacloud --compliance cis_2.0_alibabacloud diff --git a/docs/user-guide/providers/aws/organizations.mdx b/docs/user-guide/providers/aws/organizations.mdx index 92a4faf2ae..9729a86a26 100644 --- a/docs/user-guide/providers/aws/organizations.mdx +++ b/docs/user-guide/providers/aws/organizations.mdx @@ -167,7 +167,7 @@ Include the `ExternalId` parameter in the StackSet if required by the organizati When encountering issues during deployment or needing to target specific OUs or environments (e.g., dev/staging/prod), reach out to the Prowler team via [Slack Community](https://prowler.com/slack) or [Support](mailto:support@prowler.com). -## Extra: Run Prowler across all accounts in AWS Organizations by assuming roles +## Extra: Run Prowler Across All Accounts in AWS Organizations by Assuming Roles ### Running Prowler Across All AWS Organization Accounts diff --git a/docs/user-guide/providers/mongodbatlas/getting-started-mongodbatlas.mdx b/docs/user-guide/providers/mongodbatlas/getting-started-mongodbatlas.mdx index 2fb415a11b..bf2c76447e 100644 --- a/docs/user-guide/providers/mongodbatlas/getting-started-mongodbatlas.mdx +++ b/docs/user-guide/providers/mongodbatlas/getting-started-mongodbatlas.mdx @@ -36,7 +36,7 @@ If **Require IP Access List for the Atlas Administration API** is enabled in the -### Step 1: Add the provider +### Step 1: Add the Provider 1. Navigate to **Providers** and click **Add Provider**. ![Add provider list](./img/add-provider-list.png) @@ -45,13 +45,13 @@ If **Require IP Access List for the Atlas Administration API** is enabled in the ![Add organization ID](./img/add-org-id.png) 4. (Optional) Add a friendly alias to identify this organization in dashboards. -### Step 2: Provide API credentials +### Step 2: Provide API Credentials 1. Click **Next** to open the credentials form. 2. Paste the **Atlas Public Key** and **Atlas Private Key** generated in the Atlas console. ![Add credentials](./img/add-credentials.png) -### Step 3: Test the connection and start scanning +### Step 3: Test the Connection and Start Scanning 1. Click **Test connection** to ensure Prowler Cloud can reach the Atlas API. 2. Save the credentials. The provider will appear in the list with its current connection status. @@ -66,11 +66,11 @@ If **Require IP Access List for the Atlas Administration API** is enabled in the You can also run MongoDB Atlas assessments directly from the CLI. Both command-line flags and environment variables are supported. -### Step 1: Select an authentication method +### Step 1: Select an Authentication Method Choose one of the following authentication methods: -#### Command-line arguments +#### Command-Line Arguments ```bash prowler mongodbatlas \ @@ -78,7 +78,7 @@ prowler mongodbatlas \ --atlas-private-key ``` -#### Environment variables +#### Environment Variables ```bash export ATLAS_PUBLIC_KEY= @@ -86,9 +86,9 @@ export ATLAS_PRIVATE_KEY= prowler mongodbatlas ``` -### Step 2: Run the first scan +### Step 2: Run the First Scan -#### Scan all projects and clusters +#### Scan All Projects and Clusters ```bash prowler mongodbatlas @@ -96,7 +96,7 @@ prowler mongodbatlas This command enumerates all projects accessible to the API key and scans every cluster. -#### Scan a specific project +#### Scan a Specific Project Add the `--atlas-project-id` flag when you only want to assess one project: @@ -104,7 +104,7 @@ Add the `--atlas-project-id` flag when you only want to assess one project: prowler mongodbatlas --atlas-project-id ``` -### Additional tips +### Additional Tips - Combine flags (for example, `--checks` or `--services`) just like with other providers. - Use `--output-modes` to export findings in JSON, CSV, ASFF, etc. diff --git a/docs/user-guide/providers/okta/authentication.mdx b/docs/user-guide/providers/okta/authentication.mdx index 8f664160a2..059667ee09 100644 --- a/docs/user-guide/providers/okta/authentication.mdx +++ b/docs/user-guide/providers/okta/authentication.mdx @@ -67,7 +67,7 @@ The service application must be assigned **one** of the following Okta admin rol Okta's Management API enforces a two-layer authorization model: an OAuth **scope** decides which API endpoints the token can call, and an **admin role** decides whether the call returns data. With only a scope granted, the token mint succeeds but every read returns `403 Forbidden`. Read-Only Administrator is the minimum role that lets the granted `okta.*.read` scopes return configuration data to Prowler's checks; without it, the credential probe at provider startup fails and the scan never gets to evaluate any check. -#### When Super Administrator is required +#### When Super Administrator Is Required Four checks need to resolve the Authentication Policy bound to Okta's first-party apps (Okta Admin Console, Okta Dashboard) and depend on `/api/v1/apps` returning those system apps — which Okta restricts to Super Administrator: @@ -92,17 +92,17 @@ Read-Only Administrator stays the recommended default for the least-privilege fr ## Step-by-Step Setup -### 1. Go to the admin console +### 1. Go to the Admin Console ![Okta — admin console page](/user-guide/providers/okta/images/select-admin-console.png) -### 2. [Optional] - Disable the privilege-escalation bypass (org-wide, one-time) +### 2. [Optional] - Disable the Privilege-Escalation Bypass (Org-Wide, One-Time) In the Okta Admin Console, go to **Settings → Account → Public client app admins** and ensure it is **off**. When enabled, every API Services app can be auto-assigned the Super Administrator role after scopes are granted, which would invalidate the read-only premise of this integration. ![Okta — disable Public client app admins](/user-guide/providers/okta/images/public-client-app-admins.png) -### 3. Create the API Services app +### 3. Create the API Services App 1. Go to **Applications → Applications**. @@ -118,7 +118,7 @@ In the Okta Admin Console, go to **Settings → Account → Public client app ad ![Okta — copy client id](/user-guide/providers/okta/images/copy-client-id.png) -### 4. Switch to private-key authentication and generate a keypair +### 4. Switch to Private-Key Authentication and Generate a Keypair On the new app's **General** tab, scroll to **Client Credentials**: @@ -136,13 +136,13 @@ Okta displays the private key **only once**. If you close the modal without copy ![Okta — create Public Key](/user-guide/providers/okta/images/create-public-key.png) -### 5. Grant the required OAuth scopes +### 5. Grant the Required OAuth Scopes On the app, open the **Okta API Scopes** tab and click **Grant** on every scope Prowler needs. The bundled checks require `okta.policies.read`, `okta.brands.read`, `okta.apps.read`, `okta.authenticators.read`, `okta.networkZones.read`, `okta.apiTokens.read`, `okta.roles.read`, `okta.groups.read`, `okta.logStreams.read`, and `okta.idps.read`. ![Okta — grant OAuth scopes](/user-guide/providers/okta/images/grant-permissions.png) -### 6. Assign an admin role +### 6. Assign an Admin Role On the app, open the **Admin roles** tab and click **Edit assignments → Add assignment**: @@ -155,7 +155,7 @@ To additionally evaluate the first-party application checks (Okta Admin Console ![Okta — grant Read-Only role](/user-guide/providers/okta/images/grant-roles.png) -### 7. [Optional] Verify DPoP setting +### 7. [Optional] Verify DPoP Setting Prowler sends DPoP (Demonstrating Proof of Possession) proofs on every token request. The integration works whether the **Require Demonstrating Proof of Possession (DPoP) header in token requests** setting on the service app is on or off — but enabling it is the more secure default. @@ -206,20 +206,20 @@ The org domain must be `.okta.com` (or `.oktapreview.com` / `.okta-emea.com The file at `OKTA_PRIVATE_KEY_FILE` is missing, unreadable, or empty. Confirm the path and that the file contains a non-empty PEM block or JWK JSON document. -### `OktaInvalidCredentialsError` at provider init +### `OktaInvalidCredentialsError` at Provider Init Prowler validates credentials at startup by listing one sign-on policy. This error indicates the credential material itself was rejected: - **`invalid_client`** — the public key registered in Okta does not match the private key on disk. Generate a fresh keypair and try again. -### `OktaInsufficientPermissionsError` at provider init +### `OktaInsufficientPermissionsError` at Provider Init Raised when the credential probe succeeds at the OAuth layer but the request is rejected because the service app lacks the required scope or admin role: - **`invalid_scope`** — one of the requested scopes (`okta.policies.read`, `okta.brands.read`, `okta.apps.read`, `okta.authenticators.read`, `okta.networkZones.read`, `okta.apiTokens.read`, `okta.roles.read`, `okta.groups.read`, `okta.logStreams.read`, and `okta.idps.read`) is not granted on the service app. Grant the missing scope from **Okta API Scopes**. - **`Forbidden` / `not authorized`** — no admin role is assigned to the service app. Assign **Read-Only Administrator** (or **Super Administrator** for the first-party application checks) from **Admin roles**. -### Application-service checks return MANUAL on first-party apps +### Application-Service Checks Return MANUAL on First-Party Apps When the service app runs with Read-Only Administrator, the five application-service checks targeting the Okta Admin Console and Okta Dashboard return MANUAL. This is by design — Okta restricts the underlying endpoints (`/api/v1/first-party-app-settings/{appName}` and `/api/v1/apps` for first-party app `name` values `saasure` / `okta_enduser`) to **Super Administrator**. Assign the Super Administrator role to the service app to evaluate those checks. See [Required Admin Role](#required-admin-role) for the full list. diff --git a/docs/user-guide/tutorials/prowler-app-findings-triage.mdx b/docs/user-guide/tutorials/prowler-app-findings-triage.mdx index 408f201645..ce6632dd66 100644 --- a/docs/user-guide/tutorials/prowler-app-findings-triage.mdx +++ b/docs/user-guide/tutorials/prowler-app-findings-triage.mdx @@ -141,18 +141,18 @@ Muting a finding does not fix the underlying configuration. Review the finding b ## Troubleshooting -### Triage controls do not appear +### Triage Controls Do Not Appear Make sure the row is an individual finding row. Finding Groups rows do not show triage controls. Expand a group to see affected resources and their triage controls. -### Changes cannot be saved +### Changes Cannot Be Saved Confirm that the user role has **Manage Scans** permission. Prowler Local Server does not support Findings Triage writes. -### Resolved or Reopened is missing from the selector +### Resolved or Reopened Is Missing from the Selector **Reopened** is always automatic. **Resolved** is set automatically from scan result changes and appears as a selector option only on `MANUAL` findings, where it records a [Manual Pass](#verify-a-manual-finding-as-pass). On findings with any other status, this is expected. -### Risk Accepted or False Positive muted a finding +### Risk Accepted or False Positive Muted a Finding This is expected. Those statuses create a mute rule through Mutelist. diff --git a/docs/user-guide/tutorials/prowler-app-github-action.mdx b/docs/user-guide/tutorials/prowler-app-github-action.mdx index c874a37164..faf0993e21 100644 --- a/docs/user-guide/tutorials/prowler-app-github-action.mdx +++ b/docs/user-guide/tutorials/prowler-app-github-action.mdx @@ -28,7 +28,7 @@ Source: [`prowler-cloud/prowler`](https://github.com/prowler-cloud/prowler) · M ## Usage -### AWS scan +### AWS Scan ```yaml - uses: prowler-cloud/prowler@5.25 @@ -41,7 +41,7 @@ Source: [`prowler-cloud/prowler`](https://github.com/prowler-cloud/prowler) · M AWS_SESSION_TOKEN: ${{ secrets.AWS_SESSION_TOKEN }} ``` -### Push findings to Prowler Cloud +### Push Findings to Prowler Cloud Send scan results directly to [Prowler Cloud](/user-guide/tutorials/prowler-import-findings) for centralized visibility, compliance tracking, and team collaboration. @@ -97,7 +97,7 @@ jobs: - GitHub Code Scanning is free for public repositories. Private repositories require a [GitHub Code Security](https://docs.github.com/en/get-started/learning-about-github/about-github-advanced-security) license. -### Combine push-to-cloud with SARIF upload +### Combine Push-to-Cloud with SARIF Upload ```yaml - uses: prowler-cloud/prowler@5.25 @@ -114,7 +114,7 @@ jobs: PROWLER_CLOUD_API_KEY: ${{ secrets.PROWLER_CLOUD_API_KEY }} ``` -### Scan the current repository with the GitHub provider +### Scan the Current Repository with the GitHub Provider ```yaml name: Prowler GitHub Scan @@ -142,7 +142,7 @@ jobs: `--repository` scans a single repo. Use `--organization ` instead to include org-level checks (MFA, security policies, etc.). See the [GitHub provider authentication](/user-guide/providers/github/authentication) for required token permissions. -### Fail the PR on findings +### Fail the PR on Findings By default the action tolerates findings (exit code 3) and succeeds. Set `fail-on-findings: true` to fail the workflow step when Prowler detects findings. Combine with `--severity` to control which severity levels trigger the failure: @@ -258,7 +258,7 @@ Scan results are written to `output/` in the workspace and uploaded as artifacts When `upload-sarif` is enabled, SARIF results are also uploaded to GitHub Code Scanning and appear on the repository's **Security → Code scanning** tab, filtered by the branch that ran the scan. -### Step summary +### Step Summary The action writes a summary to the run page with a per-severity breakdown of failing checks, artifact and Code Scanning links, and (when `push-to-cloud: false`) a pointer to [Prowler Cloud](https://cloud.prowler.com) for continuous monitoring. diff --git a/docs/user-guide/tutorials/prowler-app-jira-integration.mdx b/docs/user-guide/tutorials/prowler-app-jira-integration.mdx index 3621fd514c..27832352f5 100644 --- a/docs/user-guide/tutorials/prowler-app-jira-integration.mdx +++ b/docs/user-guide/tutorials/prowler-app-jira-integration.mdx @@ -159,13 +159,13 @@ Support for custom field mapping is planned for a future release. ## Troubleshooting -### Connection test fails +### Connection Test Fails * Verify Jira instance domain is correct and accessible * Confirm API token or credentials are valid * Ensure API access is enabled in Jira settings and the needed scopes are granted -### Check task status (API) +### Check Task Status (API) If the Jira issue does not appear in your Jira project, follow these steps to verify the export task status via the API. diff --git a/docs/user-guide/tutorials/prowler-app-rbac.mdx b/docs/user-guide/tutorials/prowler-app-rbac.mdx index 90ecafbcb4..f00a852f19 100644 --- a/docs/user-guide/tutorials/prowler-app-rbac.mdx +++ b/docs/user-guide/tutorials/prowler-app-rbac.mdx @@ -257,7 +257,7 @@ The **Scope** column indicates where each permission applies. **All** means the To grant all administrative permissions, select the **Grant all admin permissions** option. -### Prowler Cloud exclusive permissions +### Prowler Cloud Exclusive Permissions The following permissions are available exclusively in **Prowler Cloud**: diff --git a/docs/user-guide/tutorials/prowler-import-findings.mdx b/docs/user-guide/tutorials/prowler-import-findings.mdx index f32863b90b..0a55878988 100644 --- a/docs/user-guide/tutorials/prowler-import-findings.mdx +++ b/docs/user-guide/tutorials/prowler-import-findings.mdx @@ -444,7 +444,7 @@ For pricing details, see [Prowler Cloud Pricing](https://prowler.com/pricing). - The user associated with the API key lacks the **Manage Ingestions** permission - Contact the tenant administrator to grant the required permission -### Ingestion job status is "failed" +### Ingestion Job Status Is "failed" - Check the `/api/v1/ingestions/{id}/errors` endpoint for details - Verify the OCSF file format is valid