-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feat(sdk): replace detect-secrets library with kingfisher #11694
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
danibarranqueroo
wants to merge
22
commits into
master
Choose a base branch
from
PROWLER-2083-replace-detect-secrets-library-with-a-new-one
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,896
−846
Open
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
439a0df
feat(sdk): replace detect-secrets with kingfisher for secret scanning
danibarranqueroo 018c58d
feat(sdk): add opt-in secret validation with critical escalation for …
danibarranqueroo 2600402
test(sdk): update secret checks tests and fixtures for kingfisher
danibarranqueroo 8eec932
docs: document kingfisher secret scanning and validation
danibarranqueroo a0f4472
Merge branch 'master' into PROWLER-2083-replace-detect-secrets-librar…
danibarranqueroo 6f418cb
chore: add secrets flag into aws schema
danibarranqueroo 5e54451
chore(sdk): remove deprecated detect_secrets_plugins config option
danibarranqueroo 5e4ddf4
fix(sdk): skip secret re-validation in cloudwatch line-number rescan
danibarranqueroo 26d9f61
docs: complete secret-scanning check list and note provider-wide vali…
danibarranqueroo 21e07b1
feat(sdk): add batched secret scanning to amortize kingfisher subproc…
danibarranqueroo 7bd6884
perf(sdk): batch secret scanning across cloudwatch, lambda and ecs re…
danibarranqueroo 741cc94
refactor(sdk): batch secret scanning across all remaining secret checks
danibarranqueroo 92262a6
docs: document the batched secret-scanning check structure
danibarranqueroo 6be7e01
perf(sdk): batch the cloudwatch multiline-event rescan
danibarranqueroo 388e471
refactor(sdk): remove unused single-payload detect_secrets_scan helper
danibarranqueroo c01297a
fix(sdk): bound the kingfisher subprocess with a timeout and type the…
danibarranqueroo 0e9731a
test(sdk): cover the verified-secret escalation path across secret ch…
danibarranqueroo b13b3f0
docs(sdk): correct secret-scanning docs, changelog and OpenStack chec…
danibarranqueroo d9b9bd7
docs(sdk): add version badge and engine-history note to secret-scanni…
danibarranqueroo faa50ee
fix(sdk): apply ignore patterns to the cloudwatch multiline-event rescan
danibarranqueroo 869a08e
fix(sdk): report undecodable user data as MANUAL instead of dropping …
danibarranqueroo 2004494
Merge branch 'master' into PROWLER-2083-replace-detect-secrets-librar…
danibarranqueroo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| --- | ||
| title: 'Secret-Scanning Checks' | ||
| --- | ||
|
|
||
| import { VersionBadge } from "/snippets/version-badge.mdx" | ||
|
|
||
| <VersionBadge version="5.32.0" /> | ||
|
|
||
| Prowler scans audited resources for plaintext secrets using [Kingfisher](https://github.com/mongodb/kingfisher), an open-source secret-scanning engine that Prowler invokes as a subprocess. This guide explains the structure every secret-scanning check must follow to keep scanning correct and efficient on large accounts. | ||
|
|
||
| <Note> | ||
| Since Prowler 5.32.0 the secret-scanning checks scan with Kingfisher. Earlier versions used the `detect-secrets` library. | ||
| </Note> | ||
|
|
||
| ## Overview | ||
|
|
||
| Secret detection runs through a single helper in `prowler/lib/utils/utils.py`: | ||
|
|
||
| - **`detect_secrets_scan_batch(payloads, excluded_secrets=..., validate=...)`** scans many payloads in chunked subprocess invocations and returns a `{key: [findings]}` dictionary. To scan a single payload, pass a one-entry mapping (for example, `{0: data}`). | ||
|
|
||
| Every Kingfisher invocation carries a fixed process-startup cost (around 100 ms). Scanning once per resource would spawn thousands of subprocesses on large accounts (for example, thousands of CloudWatch log groups). `detect_secrets_scan_batch` amortizes that cost: it writes each payload to a temporary file as it consumes them, runs one subprocess per chunk (500 payloads by default), and maps the findings back to each payload by key. | ||
|
|
||
| ## The Batched Structure | ||
|
|
||
| Every secret-scanning check follows three phases. | ||
|
|
||
| ### Phase 1: Collect | ||
|
|
||
| Define a generator that yields `(key, payload)` for each scannable unit. The generator builds payload strings only — it does not call Kingfisher. Lazy yielding keeps memory and temporary-disk usage bounded to a single chunk, which matters when an account holds thousands of resources. | ||
|
|
||
| ### Phase 2: Batch | ||
|
|
||
| Call `detect_secrets_scan_batch` once with the generator. The helper consumes it in chunks, runs Kingfisher per chunk, and returns the keys that produced findings mapped to their finding lists. | ||
|
|
||
| ### Phase 3: Report | ||
|
|
||
| Iterate the resources, look up the findings by key, and build one report per resource. Emit a finding for **every** iterated resource — never drop one silently. When a resource's payload cannot be prepared for scanning (for example, user data that fails to base64-decode or decompress), report it as `MANUAL` with a status explaining the scan could not inspect it, rather than omitting it or claiming `PASS`. | ||
|
|
||
| ```python | ||
| from prowler.lib.check.models import Check, Check_Report_AWS | ||
| from prowler.lib.utils.utils import ( | ||
| annotate_verified_secrets, | ||
| detect_secrets_scan_batch, | ||
| ) | ||
| from prowler.providers.aws.services.example.example_client import example_client | ||
|
|
||
|
|
||
| class example_resource_no_secrets(Check): | ||
| def execute(self): | ||
| findings = [] | ||
| excluded = example_client.audit_config.get("secrets_ignore_patterns", []) | ||
| validate = example_client.audit_config.get("secrets_validate", False) | ||
| resources = list(example_client.resources) | ||
|
|
||
| # Phase 1: collect — builds strings only, no scan. | ||
| def payloads(): | ||
| for index, resource in enumerate(resources): | ||
| if resource.scannable_data: | ||
| yield index, serialize(resource) | ||
|
|
||
| # Phase 2: batch — one call, chunked subprocesses. | ||
| batch_results = detect_secrets_scan_batch( | ||
| payloads(), excluded_secrets=excluded, validate=validate | ||
| ) | ||
|
|
||
| # Phase 3: report — look up findings by key. | ||
| for index, resource in enumerate(resources): | ||
| report = Check_Report_AWS(metadata=self.metadata(), resource=resource) | ||
| report.status = "PASS" | ||
| report.status_extended = f"No secrets found in {resource.name}." | ||
| detect_secrets_output = batch_results.get(index) | ||
| if detect_secrets_output: | ||
| report.status = "FAIL" | ||
| report.status_extended = ( | ||
| f"Potential secret found in {resource.name} -> ..." | ||
| ) | ||
| annotate_verified_secrets(report, detect_secrets_output) | ||
| findings.append(report) | ||
|
|
||
| return findings | ||
| ``` | ||
|
|
||
| ## Choosing the Key | ||
|
|
||
| The key maps each finding back to its source. Two shapes cover every check: | ||
|
|
||
| - **One payload per resource:** use the resource index. This fits checks that serialize a single payload per resource, such as launch configurations, CloudFormation outputs, SSM documents, Step Functions definitions, and OpenStack metadata. | ||
| - **Several payloads per resource:** use a `(resource_index, fragment)` tuple, where the fragment identifies the variable, log stream, container, file, or version. Phase 3 groups the per-fragment findings to build the resource report. This fits CloudWatch log streams, ECS containers, CodeBuild variables, Glue arguments, and Lambda code files. | ||
|
|
||
| Derive the indices from the same `list(...)` of resources in both Phase 1 and Phase 3 so the order stays stable and the keys align. | ||
|
|
||
| ## Preserving Per-Payload Results | ||
|
|
||
| `detect_secrets_scan_batch` runs Kingfisher with `--no-dedup`, so a secret that appears in more than one payload is reported for each one. This reproduces the result of scanning each payload individually. Build payload strings exactly as a single scan would: serialize the same data and keep line ordering, because messages often map a finding's `line_number` back to a variable name or metadata key. | ||
|
|
||
| ## Validation and Severity | ||
|
|
||
| `detect_secrets_scan_batch` accepts `validate`, read from `secrets_validate` in the provider configuration or the `--scan-secrets-validate` flag. When enabled, Kingfisher confirms whether each secret is live, and confirmed secrets carry `is_verified: True`. | ||
|
|
||
| After marking a report as `FAIL`, pass the findings to `annotate_verified_secrets(report, findings)`. When any secret is verified, the helper escalates the finding to critical severity and appends a note that the secret was confirmed live. Validation stays off by default because it sends the discovered secret to the provider API. | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| ## Excluded Secrets | ||
|
|
||
| `detect_secrets_scan_batch` applies `secrets_ignore_patterns` — regular expressions from the provider configuration — against each finding's source line and drops the matches, mirroring single-scan behavior. | ||
|
|
||
| ## Testing | ||
|
|
||
| To assert on the verified-secret path, mock `detect_secrets_scan_batch` in the check module and return the keyed dictionary. For a single resource scanned at index `0`: | ||
|
|
||
| ```python | ||
| mock.patch( | ||
| "prowler.providers.aws.services.example.example_resource_no_secrets.example_resource_no_secrets.detect_secrets_scan_batch", | ||
| return_value={ | ||
| 0: [{"type": "...", "line_number": 1, "is_verified": True}] | ||
| }, | ||
| ) | ||
| ``` | ||
|
|
||
| Most tests need no mock at all: they seed resources that contain example secrets and assert on the `FAIL` status and message, which exercises the real batched path. Refer to the [Testing](/developer-guide/unit-testing) documentation for the general structure. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.