Skip to content
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

platform(secrets): Support custom detectors from the platform #3926

Merged
merged 54 commits into from
Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
3ec2a61
add env PRESENT_CACHED_RESULTS to gat report for save image sca
lirshindalman Aug 18, 2022
c8e7f5d
Revert "add env PRESENT_CACHED_RESULTS to gat report for save image sca"
lirshindalman Aug 18, 2022
d816a0e
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Aug 18, 2022
e9fb902
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Aug 18, 2022
28a20e2
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Aug 21, 2022
c8cb12d
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Aug 21, 2022
c64e546
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Aug 24, 2022
b8f16e0
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Sep 1, 2022
7c4bf61
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Sep 4, 2022
75a39e3
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Sep 6, 2022
1d78072
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Sep 6, 2022
6c4b707
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Sep 6, 2022
56130a8
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Oct 24, 2022
9786bb2
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Nov 2, 2022
a5d890c
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Nov 6, 2022
8e597ca
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Nov 21, 2022
cc279ef
add
lirshindalman Nov 22, 2022
48f17fc
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Nov 22, 2022
996849e
Merge branch 'master' into Move_CustomRegexDetector_to_checkov
lirshindalman Nov 22, 2022
5bba575
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Nov 23, 2022
de77963
add CustomRegexDetector
lirshindalman Nov 23, 2022
674a355
add CustomRegexDetector
lirshindalman Nov 23, 2022
9c0b115
UT
lirshindalman Nov 23, 2022
8850e50
UT
lirshindalman Nov 23, 2022
cf46f25
UT
lirshindalman Nov 24, 2022
ae95a40
UT
lirshindalman Nov 24, 2022
5363909
UT
lirshindalman Nov 24, 2022
ab33113
UT
lirshindalman Nov 24, 2022
8868125
UT
lirshindalman Nov 24, 2022
db8a243
UT
lirshindalman Nov 24, 2022
d2f6f30
UT
lirshindalman Nov 24, 2022
8e7c734
UT
lirshindalman Nov 24, 2022
e45def3
UT
lirshindalman Nov 24, 2022
51b0281
Update checkov/secrets/plugins/custom_regex_detector.py
lirshindalman Nov 24, 2022
3b4cadb
test
lirshindalman Nov 24, 2022
49fd441
test
lirshindalman Nov 24, 2022
3f4567c
test
lirshindalman Nov 24, 2022
3d045be
test
lirshindalman Nov 24, 2022
3e13b9b
test
lirshindalman Nov 24, 2022
bf48cba
Merge branch 'master' into Move_CustomRegexDetector_to_checkov
lirshindalman Nov 24, 2022
522779f
Merge branch 'master' of https://github.com/bridgecrewio/checkov
lirshindalman Nov 24, 2022
4070f04
Merge branch 'master' into Move_CustomRegexDetector_to_checkov
lirshindalman Nov 24, 2022
d05784e
test
lirshindalman Nov 24, 2022
20c1fb5
test
lirshindalman Nov 24, 2022
20b27fa
test
lirshindalman Nov 24, 2022
28f7204
add enable_secret_scan_all_files as FF for CustomRegexDetector
lirshindalman Nov 24, 2022
fadc1e5
add enable_secret_scan_all_files as FF for CustomRegexDetector
lirshindalman Nov 24, 2022
0712f08
add enable_secret_scan_all_files as FF for CustomRegexDetector
lirshindalman Nov 24, 2022
f683a04
add enable_secret_scan_all_files as FF for CustomRegexDetector
lirshindalman Nov 24, 2022
31bf29e
add enable_secret_scan_all_files as FF for CustomRegexDetector
lirshindalman Nov 24, 2022
5982d77
add enable_secret_scan_all_files as FF for CustomRegexDetector
lirshindalman Nov 24, 2022
4b17566
add enable_secret_scan_all_files as FF for CustomRegexDetector
lirshindalman Nov 24, 2022
9607b52
add enable_secret_scan_all_files as FF for CustomRegexDetector
lirshindalman Nov 24, 2022
beb37e8
add enable_secret_scan_all_files as FF for CustomRegexDetector
lirshindalman Nov 24, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions checkov/secrets/plugins/custom_regex_detector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
from __future__ import annotations

import json
import logging
import os
from typing import Set, Any, Generator, Pattern, Optional, Dict, Tuple, cast, List

import yaml # type: ignore
from detect_secrets.constants import VerifiedResult
from detect_secrets.core.potential_secret import PotentialSecret
from detect_secrets.plugins.base import RegexBasedDetector
import re

from checkov.common.bridgecrew.platform_integration import bc_integration
from detect_secrets.util.code_snippet import CodeSnippet
from detect_secrets.util.inject import call_function_with_arguments


DETECTORS_BY_CUSTOMER_CACHE: dict[str, list[dict[str, Any]]] = {}
lirshindalman marked this conversation as resolved.
Show resolved Hide resolved


def get_customer_cache() -> dict[str, list[dict[str, Any]]]:
return DETECTORS_BY_CUSTOMER_CACHE


def get_detectors_from_cache(customer_name: str | None) -> list[dict[str, Any]]:
if customer_name:
cache = get_customer_cache()
return cache.get(customer_name, [])
return []


def get_detectors_from_local_file() -> list[dict[str, Any]]:
lirshindalman marked this conversation as resolved.
Show resolved Hide resolved
current_dir = os.path.dirname(os.path.realpath(__file__))
with open(f'{current_dir}/detectors.json') as f:
return cast("list[dict[str, Any]]", json.load(f))


def load_detectors() -> list[dict[str, Any]]:
customer_name = os.getenv('CUSTOMER_NAME')
detectors = get_detectors_from_cache(customer_name)
if not detectors:
try:
customer_run_config_response = bc_integration.customer_run_config_response
policies_list: List[dict[str, Any]] | dict[str, Any] = customer_run_config_response['secretsPolicies'] if \
customer_run_config_response['secretsPolicies'] else []
except Exception as e:
logging.error(f'Failed to get detectors from customer_run_config_response, error: {e}')
return []
lirshindalman marked this conversation as resolved.
Show resolved Hide resolved

if policies_list:
if isinstance(policies_list, dict):
policies_list = [policies_list]
detectors = modify_secrets_policy_to_detectors(policies_list)

if customer_name:
DETECTORS_BY_CUSTOMER_CACHE[customer_name] = detectors

logging.info(f'Successfully loaded {len(detectors)} detectors from s3')
return detectors


def modify_secrets_policy_to_detectors(policies_list: List[dict[str, Any]]) -> List[dict[str, Any]]:
secrets_list = transforms_policies_to_detectors_list(policies_list)
logging.info(f'(modify_secrets_policy_to_detectors) secrets_list = {secrets_list}')
Fixed Show fixed Hide fixed
return secrets_list


def transforms_policies_to_detectors_list(custom_secrets: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
custom_detectors: List[Dict[str, Any]] = []
for secret_policy in custom_secrets:
not_parsed = True
code = secret_policy['code']
if code:
code_dict = yaml.safe_load(secret_policy['code'])
if 'definition' in code_dict:
if 'value' in code_dict['definition']:
not_parsed = False
for regex in code_dict['definition']['value']:
check_id = secret_policy['checkovCheckId'] if secret_policy['checkovCheckId'] else \
secret_policy['incidentId']
custom_detectors.append({'Name': secret_policy['title'],
'Check_ID': check_id,
'Regex': regex})
if not_parsed:
logging.info(f'policy : {secret_policy} could not be parsed')
Fixed Show fixed Hide fixed
return custom_detectors


class CustomRegexDetector(RegexBasedDetector):
secret_type = "Regex Detector"

denylist: Set[Pattern[str]] = set()
lirshindalman marked this conversation as resolved.
Show resolved Hide resolved

def __init__(self) -> None:
self.regex_to_metadata: dict[str, dict[str, Any]] = dict()
self.denylist = set()
lirshindalman marked this conversation as resolved.
Show resolved Hide resolved
detectors = load_detectors()

for detector in detectors:
self.denylist.add(re.compile(r'{}'.format(detector["Regex"])))
self.regex_to_metadata[detector["Regex"]] = detector

def analyze_line(
self,
filename: str,
line: str,
line_number: int = 0,
context: Optional[CodeSnippet] = None,
raw_context: Optional[CodeSnippet] = None,
**kwargs: Any
) -> Set[PotentialSecret]:
"""This examines a line and finds all possible secret values in it."""
output: Set[PotentialSecret] = set()
for match, regex in self.analyze_string(line, **kwargs):
try:
verified_result = call_function_with_arguments(self.verify, secret=match, context=context)
is_verified = True if verified_result == VerifiedResult.VERIFIED_TRUE else False
except Exception:
is_verified = False

ps = PotentialSecret(type=self.regex_to_metadata[regex.pattern]["Name"], filename=filename, secret=match,
line_number=line_number, is_verified=is_verified)
ps.check_id = self.regex_to_metadata[regex.pattern]["Check_ID"] # type:ignore[attr-defined]
output.add(ps)

return output

def analyze_string(self, string: str, **kwargs: Optional[Dict[str, Any]]) -> Generator[
Tuple[str, Pattern[str]], None, None]: # type:ignore[override]
for regex in self.denylist:
for match in regex.findall(string):
if isinstance(match, tuple):
for submatch in filter(bool, match):
# It might make sense to paste break after yielding
yield submatch, regex
else:
yield match, regex
23 changes: 11 additions & 12 deletions checkov/secrets/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from detect_secrets.core import scan
from detect_secrets.settings import transient_settings


from checkov.common.bridgecrew.check_type import CheckType
from checkov.common.bridgecrew.integration_features.features.policy_metadata_integration import \
integration as metadata_integration
Expand Down Expand Up @@ -95,18 +96,16 @@ def run(
{'name': 'TwilioKeyDetector'},
{'name': 'EntropyKeywordCombinator', 'path': f'file://{current_dir}/plugins/entropy_keyword_combinator.py'}
]
custom_plugins = os.getenv("CHECKOV_CUSTOM_DETECTOR_PLUGINS_PATH")
logging.info(f"Custom detector flag set to {custom_plugins}")
if custom_plugins:
detector_path = f"{custom_plugins}/custom_regex_detector.py"
if exists(detector_path):
logging.info(f"Custom detector found at {detector_path}. Loading...")
plugins_used.append({
'name': 'CustomRegexDetector',
'path': f'file://{detector_path}'
})
else:
logging.info(f"Custom detector not found at path {detector_path}. Skipping...")

detector_path = f"{current_dir}/plugins/custom_regex_detector.py"
lirshindalman marked this conversation as resolved.
Show resolved Hide resolved
if exists(detector_path):
logging.info(f"Custom detector found at {detector_path}. Loading...")
plugins_used.append({
'name': 'CustomRegexDetector',
'path': f'file://{detector_path}'
})
else:
logging.info(f"Custom detector not found at path {detector_path}. Skipping...")
with transient_settings({
# Only run scans with only these plugins.
'plugins_used': plugins_used
Expand Down