regscale-cli 6.21.0.0__py3-none-any.whl → 6.21.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of regscale-cli might be problematic. Click here for more details.
- regscale/_version.py +1 -1
- regscale/integrations/commercial/__init__.py +1 -2
- regscale/integrations/commercial/amazon/common.py +79 -2
- regscale/integrations/commercial/aws/cli.py +183 -9
- regscale/integrations/commercial/aws/scanner.py +544 -9
- regscale/integrations/commercial/cpe.py +18 -1
- regscale/integrations/commercial/tenablev2/jsonl_scanner.py +2 -1
- regscale/integrations/commercial/wizv2/async_client.py +10 -3
- regscale/integrations/commercial/wizv2/click.py +102 -26
- regscale/integrations/commercial/wizv2/constants.py +249 -1
- regscale/integrations/commercial/wizv2/issue.py +2 -2
- regscale/integrations/commercial/wizv2/parsers.py +3 -2
- regscale/integrations/commercial/wizv2/policy_compliance.py +1858 -0
- regscale/integrations/commercial/wizv2/scanner.py +15 -21
- regscale/integrations/commercial/wizv2/utils.py +258 -85
- regscale/integrations/commercial/wizv2/variables.py +4 -3
- regscale/integrations/compliance_integration.py +1455 -0
- regscale/integrations/public/fedramp/fedramp_five.py +1 -1
- regscale/integrations/public/fedramp/markdown_parser.py +7 -1
- regscale/integrations/scanner_integration.py +30 -2
- regscale/models/app_models/__init__.py +1 -0
- regscale/models/integration_models/cisa_kev_data.json +73 -4
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/{integrations/commercial/wizv2/models.py → models/integration_models/wizv2.py} +4 -12
- regscale/models/regscale_models/file.py +4 -0
- regscale/models/regscale_models/issue.py +123 -0
- regscale/models/regscale_models/regscale_model.py +4 -2
- regscale/models/regscale_models/security_plan.py +1 -1
- regscale/utils/graphql_client.py +3 -1
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/METADATA +9 -9
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/RECORD +37 -34
- tests/regscale/core/test_version_regscale.py +5 -3
- tests/regscale/integrations/test_wiz_policy_compliance_affected_controls.py +154 -0
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.21.0.0.dist-info → regscale_cli-6.21.1.0.dist-info}/top_level.txt +0 -0
|
@@ -109,6 +109,23 @@ def extract_product_name_and_version(cpe_string: str) -> Dict:
|
|
|
109
109
|
:rtype: Dict
|
|
110
110
|
"""
|
|
111
111
|
# convert to version 2.3 if 2.2
|
|
112
|
+
# TODO: Note this is an incomplete conversion as the additional properties
|
|
113
|
+
# in the URI format (which is still supported in 2.3) are separated by
|
|
114
|
+
# tildes (~) after the final colon. We should extend this to support them
|
|
115
|
+
# at some point to be safe. Example from NISTIR7697 the 2.3 dictionary
|
|
116
|
+
# specification:
|
|
117
|
+
#
|
|
118
|
+
# WFN:
|
|
119
|
+
# wfn:[part="o",vendor="microsoft",product="windows_vista",version="6\.0",
|
|
120
|
+
# update="sp1",edition=NA,language=NA,sw_edition="home_premium",
|
|
121
|
+
# target_sw=NA,target_hw="x64",other=NA]
|
|
122
|
+
#
|
|
123
|
+
# WFN bound to a URI:
|
|
124
|
+
# cpe:/o:microsoft:windows_vista:6.0:sp1:~-~home_premium~-~x64~-
|
|
125
|
+
#
|
|
126
|
+
# WFN bound to a formatted string:
|
|
127
|
+
# cpe:2.3:o:microsoft:windows_vista:6.0:sp1:-:-:home_premium:-:x64:-
|
|
128
|
+
#
|
|
112
129
|
if cpe_string.startswith("cpe:/"):
|
|
113
130
|
cpe_string = cpe_string.replace("cpe:/", "cpe:2.3:")
|
|
114
131
|
|
|
@@ -117,7 +134,7 @@ def extract_product_name_and_version(cpe_string: str) -> Dict:
|
|
|
117
134
|
|
|
118
135
|
# Extract the product name and version
|
|
119
136
|
# parts[3] is the product name, parts[4] is the version
|
|
120
|
-
part = parts[2]
|
|
137
|
+
part = parts[2] if len(parts) > 2 else None
|
|
121
138
|
logger.debug(f"part: {part}")
|
|
122
139
|
vendor_name = parts[3] if len(parts) > 3 else None
|
|
123
140
|
product_name = parts[4] if len(parts) > 4 else None
|
|
@@ -446,7 +446,7 @@ class TenableSCJsonlScanner(JSONLScannerIntegration):
|
|
|
446
446
|
# If no findings were created, return a basic finding
|
|
447
447
|
# Get the IP from the vulnerability directly rather than using passed asset_identifier
|
|
448
448
|
finding_asset_id = vuln.ip or asset_identifier
|
|
449
|
-
|
|
449
|
+
logger.debug(item)
|
|
450
450
|
return IntegrationFinding(
|
|
451
451
|
title=item.get("pluginName", "Unknown Finding"),
|
|
452
452
|
description=item.get("description", "No description available"),
|
|
@@ -456,6 +456,7 @@ class TenableSCJsonlScanner(JSONLScannerIntegration):
|
|
|
456
456
|
category="Vulnerability",
|
|
457
457
|
scan_date=self.scan_date,
|
|
458
458
|
plugin_name=item.get("pluginName", UNKNOWN_PLUGIN),
|
|
459
|
+
control_labels=item.get("controlLabels", []),
|
|
459
460
|
)
|
|
460
461
|
|
|
461
462
|
except Exception as e:
|
|
@@ -10,6 +10,7 @@ import anyio
|
|
|
10
10
|
import httpx
|
|
11
11
|
|
|
12
12
|
from regscale.core.app.utils.app_utils import error_and_exit
|
|
13
|
+
from regscale.integrations.variables import ScannerVariables
|
|
13
14
|
|
|
14
15
|
logger = logging.getLogger("regscale")
|
|
15
16
|
|
|
@@ -72,7 +73,9 @@ class AsyncWizGraphQLClient:
|
|
|
72
73
|
logger.debug(f"Variables: {variables}")
|
|
73
74
|
|
|
74
75
|
try:
|
|
75
|
-
|
|
76
|
+
# Get SSL verify setting from scanner variables config
|
|
77
|
+
ssl_verify = getattr(ScannerVariables, "sslVerify", True)
|
|
78
|
+
async with httpx.AsyncClient(timeout=self.timeout, verify=ssl_verify) as client:
|
|
76
79
|
if progress_callback:
|
|
77
80
|
progress_callback(task_name, "requesting")
|
|
78
81
|
|
|
@@ -81,7 +84,7 @@ class AsyncWizGraphQLClient:
|
|
|
81
84
|
if progress_callback:
|
|
82
85
|
progress_callback(task_name, "processing")
|
|
83
86
|
|
|
84
|
-
if response.
|
|
87
|
+
if not response.is_success:
|
|
85
88
|
error_and_exit(
|
|
86
89
|
f"Received non-200 response from GraphQL API: {response.status_code}: {response.text}"
|
|
87
90
|
)
|
|
@@ -304,6 +307,7 @@ def run_async_queries(
|
|
|
304
307
|
query_configs: List[Dict[str, Any]],
|
|
305
308
|
progress_tracker: Optional[Any] = None,
|
|
306
309
|
max_concurrent: int = 5,
|
|
310
|
+
timeout: int = 60,
|
|
307
311
|
) -> List[Tuple[str, List[Dict[str, Any]], Optional[Exception]]]:
|
|
308
312
|
"""
|
|
309
313
|
Convenience function to run async queries from synchronous code.
|
|
@@ -313,12 +317,15 @@ def run_async_queries(
|
|
|
313
317
|
:param List[Dict[str, Any]] query_configs: Query configurations
|
|
314
318
|
:param Optional[Any] progress_tracker: Progress tracker
|
|
315
319
|
:param int max_concurrent: Maximum concurrent requests
|
|
320
|
+
:param int timeout: Request timeout in seconds
|
|
316
321
|
:return: Query results
|
|
317
322
|
:rtype: List[Tuple[str, List[Dict[str, Any]], Optional[Exception]]]
|
|
318
323
|
"""
|
|
319
324
|
|
|
320
325
|
async def _run():
|
|
321
|
-
client = AsyncWizGraphQLClient(
|
|
326
|
+
client = AsyncWizGraphQLClient(
|
|
327
|
+
endpoint=endpoint, headers=headers, max_concurrent=max_concurrent, timeout=timeout
|
|
328
|
+
)
|
|
322
329
|
return await client.execute_concurrent_queries(query_configs, progress_tracker)
|
|
323
330
|
|
|
324
331
|
# Use anyio.run for better compatibility
|
|
@@ -9,7 +9,7 @@ from typing import Optional
|
|
|
9
9
|
import click
|
|
10
10
|
|
|
11
11
|
from regscale.integrations.commercial.wizv2.variables import WizVariables
|
|
12
|
-
from regscale.models import regscale_id
|
|
12
|
+
from regscale.models import regscale_id
|
|
13
13
|
from regscale.models.app_models.click import regscale_ssp_id
|
|
14
14
|
|
|
15
15
|
logger = logging.getLogger("regscale")
|
|
@@ -333,12 +333,10 @@ def add_report_evidence(
|
|
|
333
333
|
"--wiz_project_id",
|
|
334
334
|
"-p",
|
|
335
335
|
prompt="Enter the Wiz project ID",
|
|
336
|
-
help="Enter the Wiz Project ID
|
|
337
|
-
policies, supplychain, securityplans, components.",
|
|
336
|
+
help="Enter the Wiz Project ID for policy compliance sync.",
|
|
338
337
|
required=True,
|
|
339
338
|
)
|
|
340
|
-
@regscale_id(help="RegScale will create and update
|
|
341
|
-
@regscale_module()
|
|
339
|
+
@regscale_id(help="RegScale will create and update control assessments as children of this record.")
|
|
342
340
|
@click.option( # type: ignore
|
|
343
341
|
"--client_id",
|
|
344
342
|
"-i",
|
|
@@ -356,44 +354,122 @@ def add_report_evidence(
|
|
|
356
354
|
required=False,
|
|
357
355
|
)
|
|
358
356
|
@click.option( # type: ignore
|
|
359
|
-
"--
|
|
360
|
-
"-
|
|
361
|
-
help="
|
|
362
|
-
|
|
357
|
+
"--framework_id",
|
|
358
|
+
"-f",
|
|
359
|
+
help="Wiz framework ID or shorthand (e.g., 'nist', 'aws', 'wf-id-4'). Use --list-frameworks to see options. Default: wf-id-4 (NIST SP 800-53 Rev 5)",
|
|
360
|
+
default="wf-id-4",
|
|
363
361
|
required=False,
|
|
364
|
-
default=None,
|
|
365
362
|
)
|
|
366
363
|
@click.option( # type: ignore
|
|
367
|
-
"--
|
|
368
|
-
"-
|
|
369
|
-
|
|
370
|
-
help="
|
|
371
|
-
default=
|
|
372
|
-
|
|
364
|
+
"--list-frameworks",
|
|
365
|
+
"-lf",
|
|
366
|
+
is_flag=True,
|
|
367
|
+
help="List all available framework options and shortcuts",
|
|
368
|
+
default=False,
|
|
369
|
+
)
|
|
370
|
+
@click.option( # type: ignore
|
|
371
|
+
"--create-issues/--no-create-issues",
|
|
372
|
+
"-ci/-ni",
|
|
373
|
+
default=True,
|
|
374
|
+
help="Create issues for failed policy assessments (default: enabled)",
|
|
375
|
+
)
|
|
376
|
+
@click.option( # type: ignore
|
|
377
|
+
"--update-control-status/--no-update-control-status",
|
|
378
|
+
"-ucs/-nucs",
|
|
379
|
+
default=True,
|
|
380
|
+
help="Update control implementation status based on assessment results (default: enabled)",
|
|
381
|
+
)
|
|
382
|
+
@click.option( # type: ignore
|
|
383
|
+
"--create-poams/--no-create-poams",
|
|
384
|
+
"-cp/-ncp",
|
|
385
|
+
default=False,
|
|
386
|
+
help="Mark created issues as POAMs (default: disabled)",
|
|
387
|
+
)
|
|
388
|
+
@click.option( # type: ignore
|
|
389
|
+
"--refresh/--no-refresh",
|
|
390
|
+
"-r/-nr",
|
|
391
|
+
default=False,
|
|
392
|
+
help="Force refresh and ignore cached data (default: use cache if available)",
|
|
393
|
+
)
|
|
394
|
+
@click.option( # type: ignore
|
|
395
|
+
"--cache-duration",
|
|
396
|
+
"-cd",
|
|
397
|
+
type=click.INT,
|
|
398
|
+
default=1440,
|
|
399
|
+
help="Cache duration in minutes - reuse cached data if newer than this (default: 1440 minutes / 1 day)",
|
|
373
400
|
)
|
|
374
401
|
def sync_compliance(
|
|
375
402
|
wiz_project_id,
|
|
376
403
|
regscale_id,
|
|
377
|
-
regscale_module,
|
|
378
404
|
client_id,
|
|
379
405
|
client_secret,
|
|
380
|
-
|
|
381
|
-
|
|
406
|
+
framework_id,
|
|
407
|
+
list_frameworks,
|
|
408
|
+
create_issues,
|
|
409
|
+
update_control_status,
|
|
410
|
+
create_poams,
|
|
411
|
+
refresh,
|
|
412
|
+
cache_duration,
|
|
382
413
|
):
|
|
383
|
-
"""
|
|
384
|
-
from
|
|
414
|
+
"""
|
|
415
|
+
Sync policy compliance assessments from Wiz to RegScale.
|
|
416
|
+
|
|
417
|
+
This command fetches policy assessment data from Wiz and creates:
|
|
418
|
+
- Control assessments based on policy compliance results
|
|
419
|
+
- Issues for failed policy assessments (if --create-issues enabled)
|
|
420
|
+
- Updates to control implementation status (if --update-control-status enabled)
|
|
421
|
+
- JSON output file with policy compliance data in artifacts/wiz/ directory
|
|
422
|
+
- Cached framework mapping for improved performance
|
|
423
|
+
|
|
424
|
+
CACHING:
|
|
425
|
+
By default, the command will reuse cached policy data if it's newer than the cache
|
|
426
|
+
duration (default: 60 minutes). Use --refresh to force fresh data from Wiz.
|
|
427
|
+
Use --cache-duration to adjust how long cached data is considered valid.
|
|
428
|
+
"""
|
|
429
|
+
from regscale.integrations.commercial.wizv2.policy_compliance import (
|
|
430
|
+
WizPolicyComplianceIntegration,
|
|
431
|
+
list_available_frameworks,
|
|
432
|
+
resolve_framework_id,
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
# Handle --list-frameworks flag
|
|
436
|
+
if list_frameworks:
|
|
437
|
+
click.echo(list_available_frameworks())
|
|
438
|
+
return
|
|
385
439
|
|
|
440
|
+
# Use environment variables if not provided
|
|
386
441
|
if not client_secret:
|
|
387
442
|
client_secret = WizVariables.wizClientSecret
|
|
388
443
|
if not client_id:
|
|
389
444
|
client_id = WizVariables.wizClientId
|
|
390
445
|
|
|
391
|
-
|
|
446
|
+
# Resolve framework ID using the enhanced framework resolution
|
|
447
|
+
try:
|
|
448
|
+
resolved_framework_id = resolve_framework_id(framework_id.lower())
|
|
449
|
+
if resolved_framework_id != framework_id:
|
|
450
|
+
from regscale.integrations.commercial.wizv2.policy_compliance import FRAMEWORK_MAPPINGS
|
|
451
|
+
|
|
452
|
+
framework_name = FRAMEWORK_MAPPINGS.get(resolved_framework_id, resolved_framework_id)
|
|
453
|
+
click.echo(f"🔍 Resolved '{framework_id}' to '{framework_name}' ({resolved_framework_id})")
|
|
454
|
+
except ValueError as e:
|
|
455
|
+
click.echo(f"❌ {str(e)}")
|
|
456
|
+
click.echo("\nUse --list-frameworks to see all available options.")
|
|
457
|
+
return
|
|
458
|
+
|
|
459
|
+
# Create and run the policy compliance integration
|
|
460
|
+
policy_integration = WizPolicyComplianceIntegration(
|
|
461
|
+
plan_id=regscale_id,
|
|
392
462
|
wiz_project_id=wiz_project_id,
|
|
393
|
-
regscale_id=regscale_id,
|
|
394
|
-
regscale_module=regscale_module,
|
|
395
463
|
client_id=client_id,
|
|
396
464
|
client_secret=client_secret,
|
|
397
|
-
|
|
398
|
-
|
|
465
|
+
framework_id=resolved_framework_id,
|
|
466
|
+
create_poams=create_poams,
|
|
467
|
+
cache_duration_minutes=cache_duration,
|
|
468
|
+
force_refresh=refresh,
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
# Run the policy compliance sync
|
|
472
|
+
policy_integration.sync_policy_compliance(
|
|
473
|
+
create_issues=create_issues,
|
|
474
|
+
update_control_status=update_control_status,
|
|
399
475
|
)
|
|
@@ -3,7 +3,225 @@
|
|
|
3
3
|
from enum import Enum
|
|
4
4
|
from typing import List, Optional
|
|
5
5
|
|
|
6
|
-
from regscale.models import IssueSeverity
|
|
6
|
+
from regscale.models import IssueSeverity, regscale_models
|
|
7
|
+
|
|
8
|
+
WIZ_POLICY_QUERY = """
|
|
9
|
+
query PolicyAssessmentsTable($filterBy: PolicyAssessmentFilters, $first: Int, $after: String) {
|
|
10
|
+
policyAssessments(filterBy: $filterBy, first: $first, after: $after) {
|
|
11
|
+
nodes {
|
|
12
|
+
id
|
|
13
|
+
policy {
|
|
14
|
+
... on CloudConfigurationRule {
|
|
15
|
+
id
|
|
16
|
+
shortId
|
|
17
|
+
name
|
|
18
|
+
ruleDescription: description
|
|
19
|
+
severity
|
|
20
|
+
graphId
|
|
21
|
+
remediationInstructions
|
|
22
|
+
risks
|
|
23
|
+
threats
|
|
24
|
+
securitySubCategories {
|
|
25
|
+
...SecuritySubCategoriesDetails
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
... on Control {
|
|
29
|
+
id
|
|
30
|
+
name
|
|
31
|
+
description
|
|
32
|
+
lastRunAt
|
|
33
|
+
lastRunError
|
|
34
|
+
lastSuccessfulRunAt
|
|
35
|
+
severity
|
|
36
|
+
risks
|
|
37
|
+
threats
|
|
38
|
+
securitySubCategories {
|
|
39
|
+
...SecuritySubCategoriesDetails
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
... on HostConfigurationRule {
|
|
43
|
+
id
|
|
44
|
+
name
|
|
45
|
+
shortName
|
|
46
|
+
remediationInstructions
|
|
47
|
+
risks
|
|
48
|
+
threats
|
|
49
|
+
securitySubCategories {
|
|
50
|
+
...SecuritySubCategoriesDetails
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
result
|
|
55
|
+
resource {
|
|
56
|
+
id
|
|
57
|
+
name
|
|
58
|
+
type
|
|
59
|
+
region
|
|
60
|
+
tags { key value }
|
|
61
|
+
subscription { id name externalId cloudProvider }
|
|
62
|
+
}
|
|
63
|
+
output {
|
|
64
|
+
... on Issue { id issueStatus: status }
|
|
65
|
+
... on ConfigurationFinding { id name cloudConfigurationFindingStatus: status remediation }
|
|
66
|
+
... on HostConfigurationRuleAssessment { id hostConfigurationRule: rule { id name shortName description remediationInstructions } }
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
pageInfo { hasNextPage endCursor }
|
|
70
|
+
totalCount
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fragment SecuritySubCategoriesDetails on SecuritySubCategory {
|
|
75
|
+
description
|
|
76
|
+
id
|
|
77
|
+
resolutionRecommendation
|
|
78
|
+
title
|
|
79
|
+
externalId
|
|
80
|
+
category { id name framework { id name enabled } }
|
|
81
|
+
}
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
WIZ_FRAMEWORK_QUERY = """
|
|
85
|
+
query SecurityFrameworksTable($first: Int, $after: String, $filterBy: SecurityFrameworkFilters) {
|
|
86
|
+
securityFrameworks(first: $first, after: $after, filterBy: $filterBy) {
|
|
87
|
+
nodes { policyTypes ...SecurityFrameworkFragment }
|
|
88
|
+
pageInfo { hasNextPage endCursor }
|
|
89
|
+
totalCount
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
fragment SecurityFrameworkFragment on SecurityFramework {
|
|
94
|
+
id
|
|
95
|
+
name
|
|
96
|
+
description
|
|
97
|
+
builtin
|
|
98
|
+
enabled
|
|
99
|
+
parentFramework { id name }
|
|
100
|
+
}
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
# Comprehensive framework mappings with shorthand names for easy CLI usage
|
|
104
|
+
FRAMEWORK_MAPPINGS = {
|
|
105
|
+
"wf-id-4": "NIST SP 800-53 Revision 5",
|
|
106
|
+
"wf-id-48": "NIST SP 800-53 Revision 4",
|
|
107
|
+
"wf-id-5": "FedRAMP (Moderate and Low levels)",
|
|
108
|
+
"wf-id-17": "CIS Controls v7.1",
|
|
109
|
+
"wf-id-24": "CIS Controls v8",
|
|
110
|
+
"wf-id-6": "CIS AWS v1.2.0",
|
|
111
|
+
"wf-id-7": "CIS AWS v1.3.0",
|
|
112
|
+
"wf-id-32": "CIS AWS v1.4.0",
|
|
113
|
+
"wf-id-45": "CIS AWS v1.5.0",
|
|
114
|
+
"wf-id-84": "CIS AWS v2.0.0",
|
|
115
|
+
"wf-id-98": "CIS AWS v3.0.0",
|
|
116
|
+
"wf-id-197": "CIS AWS v4.0.0",
|
|
117
|
+
"wf-id-50": "AWS Foundational Security Best Practices v1.0.0",
|
|
118
|
+
"wf-id-124": "AWS Well-Architected Framework (Section 2 - Security)",
|
|
119
|
+
"wf-id-8": "CIS Azure v1.3.0",
|
|
120
|
+
"wf-id-35": "CIS Azure v1.4.0",
|
|
121
|
+
"wf-id-52": "CIS Azure v1.5.0",
|
|
122
|
+
"wf-id-74": "CIS Azure v2.0.0",
|
|
123
|
+
"wf-id-100": "CIS Azure v2.1.0",
|
|
124
|
+
"wf-id-196": "CIS Azure v2.1.0 (Latest)",
|
|
125
|
+
"wf-id-40": "Azure Security Benchmark v3",
|
|
126
|
+
"wf-id-9": "CIS GCP v1.1.0",
|
|
127
|
+
"wf-id-36": "CIS GCP v1.2.0",
|
|
128
|
+
"wf-id-53": "CIS GCP v1.3.0",
|
|
129
|
+
"wf-id-85": "CIS GCP v2.0.0",
|
|
130
|
+
"wf-id-25": "CIS AKS v1.0.0",
|
|
131
|
+
"wf-id-68": "CIS AKS v1.2.0",
|
|
132
|
+
"wf-id-75": "CIS AKS v1.3.0",
|
|
133
|
+
"wf-id-93": "CIS AKS v1.4.0",
|
|
134
|
+
"wf-id-162": "CIS AKS v1.5.0",
|
|
135
|
+
"wf-id-218": "CIS AKS v1.6.0",
|
|
136
|
+
"wf-id-23": "CIS EKS v1.0.1",
|
|
137
|
+
"wf-id-67": "CIS EKS v1.1.0",
|
|
138
|
+
"wf-id-86": "CIS EKS v1.2.0",
|
|
139
|
+
"wf-id-18": "CIS Kubernetes v1.5.1",
|
|
140
|
+
"wf-id-66": "CIS Kubernetes v1.6.1",
|
|
141
|
+
"wf-id-87": "CIS Kubernetes v1.7.0",
|
|
142
|
+
"wf-id-76": "SOC 2 Type I",
|
|
143
|
+
"wf-id-16": "ISO/IEC 27001:2013",
|
|
144
|
+
"wf-id-19": "PCI DSS v3.2.1",
|
|
145
|
+
"wf-id-78": "PCI DSS v4.0",
|
|
146
|
+
"wf-id-79": "GDPR",
|
|
147
|
+
"wf-id-64": "CCPA/CPRA",
|
|
148
|
+
"wf-id-77": "CCF (The Adobe Common Controls Framework)",
|
|
149
|
+
"wf-id-70": "Canadian PBMM (ITSG-33)",
|
|
150
|
+
"wf-id-111": "C5 - Cloud Computing Compliance Criteria Catalogue",
|
|
151
|
+
"wf-id-161": "CAF (Cyber Assessment Framework by NCSC)",
|
|
152
|
+
"wf-id-90": "APRA CPG 234",
|
|
153
|
+
"wf-id-207": "CISA Security Requirements for EO 14117",
|
|
154
|
+
"wf-id-214": "5Rs - Wiz for Data Security",
|
|
155
|
+
"wf-id-225": "Wiz for Risk Assessment",
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
FRAMEWORK_SHORTCUTS = {
|
|
159
|
+
"nist": "wf-id-4",
|
|
160
|
+
"nist53r5": "wf-id-4",
|
|
161
|
+
"nist53r4": "wf-id-48",
|
|
162
|
+
"fedramp": "wf-id-5",
|
|
163
|
+
"cis": "wf-id-24",
|
|
164
|
+
"cisv8": "wf-id-24",
|
|
165
|
+
"cisv7": "wf-id-17",
|
|
166
|
+
"aws": "wf-id-197",
|
|
167
|
+
"azure": "wf-id-196",
|
|
168
|
+
"gcp": "wf-id-85",
|
|
169
|
+
"k8s": "wf-id-87",
|
|
170
|
+
"kubernetes": "wf-id-87",
|
|
171
|
+
"eks": "wf-id-86",
|
|
172
|
+
"aks": "wf-id-218",
|
|
173
|
+
"soc2": "wf-id-76",
|
|
174
|
+
"iso27001": "wf-id-16",
|
|
175
|
+
"pci": "wf-id-78",
|
|
176
|
+
"gdpr": "wf-id-79",
|
|
177
|
+
"ccpa": "wf-id-64",
|
|
178
|
+
"aws-foundational": "wf-id-50",
|
|
179
|
+
"aws-wellarchitected": "wf-id-124",
|
|
180
|
+
"azure-benchmark": "wf-id-40",
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
FRAMEWORK_CATEGORIES = {
|
|
184
|
+
"NIST Frameworks": ["wf-id-4", "wf-id-48", "wf-id-5"],
|
|
185
|
+
"CIS Controls": ["wf-id-17", "wf-id-24"],
|
|
186
|
+
"AWS Security": [
|
|
187
|
+
"wf-id-197",
|
|
188
|
+
"wf-id-50",
|
|
189
|
+
"wf-id-124",
|
|
190
|
+
"wf-id-6",
|
|
191
|
+
"wf-id-7",
|
|
192
|
+
"wf-id-32",
|
|
193
|
+
"wf-id-45",
|
|
194
|
+
"wf-id-84",
|
|
195
|
+
"wf-id-98",
|
|
196
|
+
],
|
|
197
|
+
"Azure Security": [
|
|
198
|
+
"wf-id-196",
|
|
199
|
+
"wf-id-40",
|
|
200
|
+
"wf-id-8",
|
|
201
|
+
"wf-id-35",
|
|
202
|
+
"wf-id-52",
|
|
203
|
+
"wf-id-74",
|
|
204
|
+
"wf-id-100",
|
|
205
|
+
],
|
|
206
|
+
"Google Cloud Security": ["wf-id-85", "wf-id-9", "wf-id-36", "wf-id-53"],
|
|
207
|
+
"Kubernetes Security": [
|
|
208
|
+
"wf-id-87",
|
|
209
|
+
"wf-id-86",
|
|
210
|
+
"wf-id-218",
|
|
211
|
+
"wf-id-18",
|
|
212
|
+
"wf-id-23",
|
|
213
|
+
"wf-id-25",
|
|
214
|
+
"wf-id-66",
|
|
215
|
+
"wf-id-67",
|
|
216
|
+
"wf-id-68",
|
|
217
|
+
"wf-id-75",
|
|
218
|
+
"wf-id-93",
|
|
219
|
+
"wf-id-162",
|
|
220
|
+
],
|
|
221
|
+
"Industry Standards": ["wf-id-76", "wf-id-16", "wf-id-78", "wf-id-19"],
|
|
222
|
+
"Privacy & Data Protection": ["wf-id-79", "wf-id-64", "wf-id-214"],
|
|
223
|
+
"Government/Regulatory": ["wf-id-70", "wf-id-111", "wf-id-161", "wf-id-90", "wf-id-207"],
|
|
224
|
+
}
|
|
7
225
|
|
|
8
226
|
SBOM_FILE_PATH = "artifacts/wiz_sbom.json"
|
|
9
227
|
INVENTORY_FILE_PATH = "artifacts/wiz_inventory.json"
|
|
@@ -181,6 +399,36 @@ RECOMMENDED_WIZ_INVENTORY_TYPES = [
|
|
|
181
399
|
"VIRTUAL_NETWORK",
|
|
182
400
|
]
|
|
183
401
|
|
|
402
|
+
# This is the set of technology deploymentModels and CloudResource types which we
|
|
403
|
+
# map to the asset category Hardware (instead of Software) when the useWizHardwareTypes
|
|
404
|
+
# feature is enabled.
|
|
405
|
+
# So either things which are hardware-like, or which use technologies that, in turn,
|
|
406
|
+
# imply they are hardware-like.
|
|
407
|
+
# Note that using technology deploymentModels can grab things such as virutal machine
|
|
408
|
+
# image files in addition to actual virtual machines. While this doesn't fit with
|
|
409
|
+
# general concepts of "hardware", for the purposes of attestation, it is the correct
|
|
410
|
+
# choice, as we may be certifying a source image that dynamic resources are created from,
|
|
411
|
+
# rather than attempt to document a variable pool of auto-scaled resources.
|
|
412
|
+
DEFAULT_WIZ_HARDWARE_TYPES = [
|
|
413
|
+
# CloudResource types
|
|
414
|
+
"VIRTUAL_MACHINE",
|
|
415
|
+
"VIRTUAL_MACHINE_IMAGE",
|
|
416
|
+
"CONTAINER",
|
|
417
|
+
"CONTAINER_IMAGE",
|
|
418
|
+
"DB_SERVER",
|
|
419
|
+
# technology deploymentModels
|
|
420
|
+
"SERVER_APPLICATION",
|
|
421
|
+
"CLIENT_APPLICATION",
|
|
422
|
+
"VIRTUAL_APPLIANCE",
|
|
423
|
+
]
|
|
424
|
+
|
|
425
|
+
# This maps CPE part values to Asset categories.
|
|
426
|
+
CPE_PART_TO_CATEGORY_MAPPING = {
|
|
427
|
+
"h": regscale_models.AssetCategory.Hardware, # Hardware
|
|
428
|
+
"a": regscale_models.AssetCategory.Software, # Application
|
|
429
|
+
"o": regscale_models.AssetCategory.Software, # Other? Operating system? (includes OSs and firmware)
|
|
430
|
+
}
|
|
431
|
+
|
|
184
432
|
INVENTORY_QUERY = """
|
|
185
433
|
query CloudResourceSearch(
|
|
186
434
|
$filterBy: CloudResourceFilters
|
|
@@ -262,12 +262,12 @@ class WizIssue(WizVulnerabilityIntegration):
|
|
|
262
262
|
return "Wiz-Event"
|
|
263
263
|
if not name:
|
|
264
264
|
return f"Wiz-{service_type}-Event"
|
|
265
|
-
event_match = re.match(r"^([A-Za-z\s]+?)\s+(
|
|
265
|
+
event_match = re.match(r"^([A-Za-z\s]+?)\s+(detection|event|alert|activity)", name)
|
|
266
266
|
if not event_match:
|
|
267
267
|
return f"Wiz-{service_type}-Event"
|
|
268
268
|
|
|
269
269
|
event_type = event_match.group(1).strip()
|
|
270
|
-
if event_type == "Suspicious activity":
|
|
270
|
+
if event_type == "Suspicious" and event_match.group(2).strip().lower() == "activity":
|
|
271
271
|
return f"Wiz-{service_type}-SuspiciousActivity"
|
|
272
272
|
|
|
273
273
|
event_type = "".join(word.capitalize() for word in event_type.split())
|
|
@@ -76,11 +76,12 @@ def get_software_name_from_cpe(wiz_entity_properties: Dict, name: str) -> Dict:
|
|
|
76
76
|
"""
|
|
77
77
|
cpe_info_dict = {
|
|
78
78
|
"name": name,
|
|
79
|
+
"part": None,
|
|
79
80
|
"software_name": None,
|
|
80
81
|
"software_version": None,
|
|
81
82
|
"software_vendor": None,
|
|
82
83
|
}
|
|
83
|
-
if "cpe" in wiz_entity_properties
|
|
84
|
+
if "cpe" in wiz_entity_properties and wiz_entity_properties.get("cpe"):
|
|
84
85
|
cpe_info_dict = extract_product_name_and_version(wiz_entity_properties.get("cpe", ""))
|
|
85
86
|
cpe_info_dict["name"] = name
|
|
86
87
|
return cpe_info_dict
|
|
@@ -349,7 +350,7 @@ def get_ip_address(
|
|
|
349
350
|
ip6_address = None
|
|
350
351
|
dns = None
|
|
351
352
|
url = None
|
|
352
|
-
if "address" in wiz_entity_properties
|
|
353
|
+
if "address" in wiz_entity_properties:
|
|
353
354
|
if wiz_entity_properties.get("addressType") == "IPV4":
|
|
354
355
|
ip4_address = wiz_entity_properties.get("address")
|
|
355
356
|
elif wiz_entity_properties.get("addressType") == "IPV6":
|