mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-04 02:04:06 +00:00
docs: brand tone and writing style fixes (#12671)
Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
This commit is contained in:
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
</Warning>
|
||||
|
||||
### 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/<framework>/
|
||||
└── __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`.
|
||||
</Note>
|
||||
|
||||
#### 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 <provider> --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/<framework>/` 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.
|
||||
</Note>
|
||||
|
||||
### 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.
|
||||
</Note>
|
||||
|
||||
### 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.
|
||||
</Note>
|
||||
|
||||
### 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.
|
||||
</Warning>
|
||||
|
||||
### 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 "<your_framework_filename_without_json>" 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 <provider> --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:
|
||||
|
||||
|
||||
@@ -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.
|
||||
</Info>
|
||||
|
||||
## 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))
|
||||
|
||||
</Steps>
|
||||
|
||||
## Event naming convention
|
||||
## Event Naming Convention
|
||||
|
||||
Every event uses an event type of the form **`<resource>.<verb>`** (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://<host>/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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ title: 'Miscellaneous'
|
||||
|
||||
## Prowler Version
|
||||
|
||||
### Showing the Prowler version:
|
||||
### Showing the Prowler Version
|
||||
|
||||
```console
|
||||
prowler <provider> -V/-v/--version
|
||||
@@ -22,7 +22,7 @@ To enable verbose mode in Prowler, similar to Version 2, use:
|
||||
prowler <provider> --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:
|
||||
|
||||
|
||||
@@ -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`:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ If **Require IP Access List for the Atlas Administration API** is enabled in the
|
||||
|
||||
<VersionBadge version="5.15.0" />
|
||||
|
||||
### Step 1: Add the provider
|
||||
### Step 1: Add the Provider
|
||||
|
||||
1. Navigate to **Providers** and click **Add Provider**.
|
||||

|
||||
@@ -45,13 +45,13 @@ If **Require IP Access List for the Atlas Administration API** is enabled in the
|
||||

|
||||
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.
|
||||

|
||||
|
||||
### 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 <private_key>
|
||||
```
|
||||
|
||||
#### Environment variables
|
||||
#### Environment Variables
|
||||
|
||||
```bash
|
||||
export ATLAS_PUBLIC_KEY=<public_key>
|
||||
@@ -86,9 +86,9 @@ export ATLAS_PRIVATE_KEY=<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 <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.
|
||||
|
||||
@@ -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
|
||||
|
||||

|
||||
|
||||
### 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.
|
||||
|
||||

|
||||
|
||||
### 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
|
||||
|
||||

|
||||
|
||||
### 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
|
||||
|
||||

|
||||
|
||||
### 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`.
|
||||
|
||||

|
||||
|
||||
### 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
|
||||
|
||||

|
||||
|
||||
### 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 `<org>.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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
</Warning>
|
||||
|
||||
### 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 <name>` instead to include org-level checks (MFA, security policies, etc.). See the [GitHub provider authentication](/user-guide/providers/github/authentication) for required token permissions.
|
||||
</Info>
|
||||
|
||||
### 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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ The **Scope** column indicates where each permission applies. **All** means the
|
||||
</Note>
|
||||
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**:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user