cartography 0.117.0__py3-none-any.whl → 0.118.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 cartography might be problematic. Click here for more details.
- cartography/_version.py +2 -2
- cartography/cli.py +11 -0
- cartography/config.py +5 -0
- cartography/graph/job.py +6 -2
- cartography/graph/statement.py +4 -0
- cartography/intel/aws/__init__.py +1 -0
- cartography/intel/aws/apigateway.py +18 -5
- cartography/intel/aws/ec2/elastic_ip_addresses.py +3 -1
- cartography/intel/aws/ec2/internet_gateways.py +4 -2
- cartography/intel/aws/ec2/load_balancer_v2s.py +11 -5
- cartography/intel/aws/ec2/network_interfaces.py +4 -0
- cartography/intel/aws/ec2/reserved_instances.py +3 -1
- cartography/intel/aws/ec2/tgw.py +11 -5
- cartography/intel/aws/ec2/volumes.py +1 -1
- cartography/intel/aws/ecr.py +202 -26
- cartography/intel/aws/elasticsearch.py +13 -4
- cartography/intel/aws/identitycenter.py +93 -54
- cartography/intel/aws/inspector.py +26 -14
- cartography/intel/aws/permission_relationships.py +3 -3
- cartography/intel/aws/s3.py +26 -13
- cartography/intel/aws/ssm.py +3 -5
- cartography/intel/azure/compute.py +9 -4
- cartography/intel/azure/cosmosdb.py +31 -15
- cartography/intel/azure/sql.py +25 -12
- cartography/intel/azure/storage.py +19 -9
- cartography/intel/azure/subscription.py +3 -1
- cartography/intel/crowdstrike/spotlight.py +5 -2
- cartography/intel/entra/app_role_assignments.py +9 -2
- cartography/intel/gcp/__init__.py +26 -9
- cartography/intel/gcp/clients.py +8 -4
- cartography/intel/gcp/compute.py +39 -18
- cartography/intel/gcp/crm/folders.py +9 -3
- cartography/intel/gcp/crm/orgs.py +8 -3
- cartography/intel/gcp/crm/projects.py +14 -3
- cartography/intel/jamf/computers.py +7 -1
- cartography/intel/oci/iam.py +23 -9
- cartography/intel/oci/organizations.py +3 -1
- cartography/intel/oci/utils.py +28 -5
- cartography/intel/okta/awssaml.py +8 -7
- cartography/intel/pagerduty/escalation_policies.py +13 -6
- cartography/intel/pagerduty/schedules.py +9 -4
- cartography/intel/pagerduty/services.py +7 -3
- cartography/intel/pagerduty/teams.py +5 -2
- cartography/intel/pagerduty/users.py +3 -1
- cartography/intel/pagerduty/vendors.py +3 -1
- cartography/intel/trivy/__init__.py +109 -58
- cartography/models/aws/ec2/networkinterfaces.py +2 -0
- cartography/models/aws/ecr/image.py +8 -0
- cartography/models/aws/ecr/repository_image.py +1 -1
- cartography/sync.py +1 -1
- cartography/util.py +5 -1
- {cartography-0.117.0.dist-info → cartography-0.118.0.dist-info}/METADATA +3 -3
- {cartography-0.117.0.dist-info → cartography-0.118.0.dist-info}/RECORD +57 -57
- {cartography-0.117.0.dist-info → cartography-0.118.0.dist-info}/WHEEL +0 -0
- {cartography-0.117.0.dist-info → cartography-0.118.0.dist-info}/entry_points.txt +0 -0
- {cartography-0.117.0.dist-info → cartography-0.118.0.dist-info}/licenses/LICENSE +0 -0
- {cartography-0.117.0.dist-info → cartography-0.118.0.dist-info}/top_level.txt +0 -0
|
@@ -8,6 +8,7 @@ import botocore.config
|
|
|
8
8
|
import neo4j
|
|
9
9
|
from policyuniverse.policy import Policy
|
|
10
10
|
|
|
11
|
+
from cartography.client.core.tx import run_write_query
|
|
11
12
|
from cartography.intel.dns import ingest_dns_record_by_fqdn
|
|
12
13
|
from cartography.util import aws_handle_regions
|
|
13
14
|
from cartography.util import run_cleanup_job
|
|
@@ -95,7 +96,8 @@ def _load_es_domains(
|
|
|
95
96
|
for d in domain_list:
|
|
96
97
|
del d["ServiceSoftwareOptions"]
|
|
97
98
|
|
|
98
|
-
|
|
99
|
+
run_write_query(
|
|
100
|
+
neo4j_session,
|
|
99
101
|
ingest_records,
|
|
100
102
|
Records=domain_list,
|
|
101
103
|
AWS_ACCOUNT_ID=aws_account_id,
|
|
@@ -179,7 +181,8 @@ def _link_es_domain_vpc(
|
|
|
179
181
|
groupList = vpc_data.get("SecurityGroupIds", [])
|
|
180
182
|
|
|
181
183
|
if len(subnetList) > 0:
|
|
182
|
-
|
|
184
|
+
run_write_query(
|
|
185
|
+
neo4j_session,
|
|
183
186
|
ingest_subnet,
|
|
184
187
|
DomainId=domain_id,
|
|
185
188
|
SubnetList=subnetList,
|
|
@@ -187,7 +190,8 @@ def _link_es_domain_vpc(
|
|
|
187
190
|
)
|
|
188
191
|
|
|
189
192
|
if len(groupList) > 0:
|
|
190
|
-
|
|
193
|
+
run_write_query(
|
|
194
|
+
neo4j_session,
|
|
191
195
|
ingest_sec_groups,
|
|
192
196
|
DomainId=domain_id,
|
|
193
197
|
SecGroupList=groupList,
|
|
@@ -220,7 +224,12 @@ def _process_access_policy(
|
|
|
220
224
|
if policy.is_internet_accessible():
|
|
221
225
|
exposed_internet = True
|
|
222
226
|
|
|
223
|
-
|
|
227
|
+
run_write_query(
|
|
228
|
+
neo4j_session,
|
|
229
|
+
tag_es,
|
|
230
|
+
DomainId=domain_id,
|
|
231
|
+
InternetExposed=exposed_internet,
|
|
232
|
+
)
|
|
224
233
|
|
|
225
234
|
|
|
226
235
|
@timeit
|
|
@@ -6,10 +6,12 @@ from typing import Optional
|
|
|
6
6
|
from typing import Union
|
|
7
7
|
|
|
8
8
|
import boto3
|
|
9
|
+
import botocore.exceptions
|
|
9
10
|
import neo4j
|
|
10
11
|
|
|
11
12
|
from cartography.client.core.tx import load
|
|
12
13
|
from cartography.client.core.tx import load_matchlinks
|
|
14
|
+
from cartography.client.core.tx import read_list_of_dicts_tx
|
|
13
15
|
from cartography.graph.job import GraphJob
|
|
14
16
|
from cartography.models.aws.identitycenter.awsidentitycenter import (
|
|
15
17
|
AWSIdentityCenterInstanceSchema,
|
|
@@ -31,6 +33,18 @@ from cartography.util import timeit
|
|
|
31
33
|
logger = logging.getLogger(__name__)
|
|
32
34
|
|
|
33
35
|
|
|
36
|
+
def _is_permission_set_sync_unsupported_error(
|
|
37
|
+
error: botocore.exceptions.ClientError,
|
|
38
|
+
) -> bool:
|
|
39
|
+
"""Return True when the Identity Center instance does not support permission sets."""
|
|
40
|
+
error_info = error.response.get("Error", {})
|
|
41
|
+
if error_info.get("Code") != "ValidationException":
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
message = error_info.get("Message", "").lower()
|
|
45
|
+
return "not supported for this identity center instance" in message
|
|
46
|
+
|
|
47
|
+
|
|
34
48
|
@timeit
|
|
35
49
|
@aws_handle_regions
|
|
36
50
|
def get_identity_center_instances(
|
|
@@ -394,8 +408,11 @@ def get_permset_roles(
|
|
|
394
408
|
WHERE permset.arn IN $PermSetIds
|
|
395
409
|
RETURN permset.arn AS PermissionSetArn, role.arn AS RoleArn
|
|
396
410
|
"""
|
|
397
|
-
|
|
398
|
-
|
|
411
|
+
permset_to_role = neo4j_session.execute_read(
|
|
412
|
+
read_list_of_dicts_tx,
|
|
413
|
+
query,
|
|
414
|
+
PermSetIds=permset_ids,
|
|
415
|
+
)
|
|
399
416
|
|
|
400
417
|
# Create mapping from permission set ARN to role ARN
|
|
401
418
|
permset_to_role_map = {
|
|
@@ -504,32 +521,51 @@ def sync_identity_center_instances(
|
|
|
504
521
|
instance_arn = instance["InstanceArn"]
|
|
505
522
|
identity_store_id = instance["IdentityStoreId"]
|
|
506
523
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
524
|
+
permission_set_sync_supported = True
|
|
525
|
+
try:
|
|
526
|
+
permission_sets = get_permission_sets(
|
|
527
|
+
boto3_session, instance_arn, region
|
|
528
|
+
)
|
|
529
|
+
except botocore.exceptions.ClientError as error:
|
|
530
|
+
if _is_permission_set_sync_unsupported_error(error):
|
|
531
|
+
permission_set_sync_supported = False
|
|
532
|
+
permission_sets = []
|
|
533
|
+
logger.warning(
|
|
534
|
+
"Skipping permission set sync for Identity Center instance %s in region %s "
|
|
535
|
+
"because the instance does not support permission sets.",
|
|
536
|
+
instance_arn,
|
|
537
|
+
region,
|
|
538
|
+
)
|
|
539
|
+
else:
|
|
540
|
+
raise
|
|
541
|
+
|
|
542
|
+
if permission_set_sync_supported:
|
|
543
|
+
load_permission_sets(
|
|
544
|
+
neo4j_session,
|
|
545
|
+
permission_sets,
|
|
546
|
+
instance_arn,
|
|
547
|
+
region,
|
|
548
|
+
current_aws_account_id,
|
|
549
|
+
update_tag,
|
|
550
|
+
)
|
|
517
551
|
|
|
518
552
|
# Fetch groups first to avoid interleaving between groups and users
|
|
519
553
|
groups = get_sso_groups(boto3_session, identity_store_id, region)
|
|
520
554
|
|
|
521
555
|
# Get permission set assignments for groups
|
|
522
556
|
group_permission_sets: Dict[str, List[str]] = {}
|
|
523
|
-
group_role_assignments_raw =
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
557
|
+
group_role_assignments_raw: List[Dict[str, Any]] = []
|
|
558
|
+
if permission_set_sync_supported:
|
|
559
|
+
group_role_assignments_raw = get_group_role_assignments(
|
|
560
|
+
boto3_session,
|
|
561
|
+
groups,
|
|
562
|
+
instance_arn,
|
|
563
|
+
region,
|
|
564
|
+
)
|
|
565
|
+
for assignment in group_role_assignments_raw:
|
|
566
|
+
group_id = assignment["GroupId"]
|
|
567
|
+
perm_set = assignment["PermissionSetArn"]
|
|
568
|
+
group_permission_sets.setdefault(group_id, []).append(perm_set)
|
|
533
569
|
|
|
534
570
|
# Transform and load groups with their permission set assignments FIRST
|
|
535
571
|
# so that user->group membership edges can attach in the same run.
|
|
@@ -554,16 +590,18 @@ def sync_identity_center_instances(
|
|
|
554
590
|
|
|
555
591
|
# Get direct permission set assignments for users
|
|
556
592
|
user_permission_sets: Dict[str, List[str]] = {}
|
|
557
|
-
user_role_assignments_raw =
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
593
|
+
user_role_assignments_raw: List[Dict[str, Any]] = []
|
|
594
|
+
if permission_set_sync_supported:
|
|
595
|
+
user_role_assignments_raw = get_role_assignments(
|
|
596
|
+
boto3_session,
|
|
597
|
+
users,
|
|
598
|
+
instance_arn,
|
|
599
|
+
region,
|
|
600
|
+
)
|
|
601
|
+
for assignment in user_role_assignments_raw:
|
|
602
|
+
uid = assignment["UserId"]
|
|
603
|
+
perm_set = assignment["PermissionSetArn"]
|
|
604
|
+
user_permission_sets.setdefault(uid, []).append(perm_set)
|
|
567
605
|
|
|
568
606
|
# Transform and load users with their group memberships AFTER groups exist
|
|
569
607
|
transformed_users = transform_sso_users(
|
|
@@ -584,28 +622,29 @@ def sync_identity_center_instances(
|
|
|
584
622
|
# Note: we do this after groups and users are loaded so that
|
|
585
623
|
# load_role_assignments calls can MATCH existing AWSSSOUser/AWSSSOGroup
|
|
586
624
|
# nodes when drawing the ALLOWED_BY edges.
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
625
|
+
if permission_set_sync_supported:
|
|
626
|
+
enriched_role_assignments = get_permset_roles(
|
|
627
|
+
neo4j_session,
|
|
628
|
+
user_role_assignments_raw,
|
|
629
|
+
)
|
|
630
|
+
load_role_assignments(
|
|
631
|
+
neo4j_session,
|
|
632
|
+
enriched_role_assignments,
|
|
633
|
+
current_aws_account_id,
|
|
634
|
+
update_tag,
|
|
635
|
+
RoleAssignmentAllowedByMatchLink(),
|
|
636
|
+
)
|
|
598
637
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
638
|
+
enriched_group_role_assignments = get_permset_roles(
|
|
639
|
+
neo4j_session,
|
|
640
|
+
group_role_assignments_raw,
|
|
641
|
+
)
|
|
642
|
+
load_role_assignments(
|
|
643
|
+
neo4j_session,
|
|
644
|
+
enriched_group_role_assignments,
|
|
645
|
+
current_aws_account_id,
|
|
646
|
+
update_tag,
|
|
647
|
+
RoleAssignmentAllowedByGroupMatchLink(),
|
|
648
|
+
)
|
|
610
649
|
|
|
611
650
|
cleanup(neo4j_session, common_job_parameters)
|
|
@@ -75,16 +75,17 @@ def get_inspector_findings(
|
|
|
75
75
|
session: boto3.session.Session,
|
|
76
76
|
region: str,
|
|
77
77
|
account_id: str,
|
|
78
|
+
batch_size: int,
|
|
78
79
|
) -> Iterator[List[Dict[str, Any]]]:
|
|
79
80
|
"""
|
|
80
81
|
Query inspector2.list_findings by filtering the request, otherwise the request could timeout.
|
|
81
82
|
First, we filter by account_id. And since there may be millions of CLOSED findings that may never go away,
|
|
82
83
|
only fetch those in ACTIVE or SUPPRESSED statuses.
|
|
83
|
-
Run the query in batches
|
|
84
|
+
Run the query in batches and return an iterator to fetch the results.
|
|
84
85
|
"""
|
|
85
86
|
client = session.client("inspector2", region_name=region)
|
|
86
87
|
logger.info(
|
|
87
|
-
f"Getting findings in batches of {
|
|
88
|
+
f"Getting findings in batches of {batch_size} for account {account_id} in region {region}"
|
|
88
89
|
)
|
|
89
90
|
aws_args: Dict[str, Any] = {
|
|
90
91
|
"filterCriteria": {
|
|
@@ -103,7 +104,7 @@ def get_inspector_findings(
|
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
findings_batches = batch(
|
|
106
|
-
aws_paginate(client, "list_findings", "findings", None, **aws_args),
|
|
107
|
+
aws_paginate(client, "list_findings", "findings", None, **aws_args), batch_size
|
|
107
108
|
)
|
|
108
109
|
yield from findings_batches
|
|
109
110
|
|
|
@@ -271,19 +272,25 @@ def load_inspector_finding_to_package_match_links(
|
|
|
271
272
|
def cleanup(
|
|
272
273
|
neo4j_session: neo4j.Session,
|
|
273
274
|
common_job_parameters: Dict[str, Any],
|
|
275
|
+
batch_size: int = BATCH_SIZE,
|
|
274
276
|
) -> None:
|
|
275
277
|
logger.info("Running AWS Inspector cleanup")
|
|
276
|
-
GraphJob.from_node_schema(AWSInspectorFindingSchema(), common_job_parameters).run(
|
|
277
|
-
neo4j_session,
|
|
278
|
-
)
|
|
279
|
-
GraphJob.from_node_schema(AWSInspectorPackageSchema(), common_job_parameters).run(
|
|
280
|
-
neo4j_session,
|
|
281
|
-
)
|
|
282
278
|
GraphJob.from_matchlink(
|
|
283
279
|
InspectorFindingToPackageMatchLink(),
|
|
284
280
|
"AWSAccount",
|
|
285
281
|
common_job_parameters["ACCOUNT_ID"],
|
|
286
282
|
common_job_parameters["UPDATE_TAG"],
|
|
283
|
+
iterationsize=batch_size,
|
|
284
|
+
).run(
|
|
285
|
+
neo4j_session,
|
|
286
|
+
)
|
|
287
|
+
GraphJob.from_node_schema(
|
|
288
|
+
AWSInspectorPackageSchema(), common_job_parameters, iterationsize=batch_size
|
|
289
|
+
).run(
|
|
290
|
+
neo4j_session,
|
|
291
|
+
)
|
|
292
|
+
GraphJob.from_node_schema(
|
|
293
|
+
AWSInspectorFindingSchema(), common_job_parameters, iterationsize=batch_size
|
|
287
294
|
).run(
|
|
288
295
|
neo4j_session,
|
|
289
296
|
)
|
|
@@ -296,11 +303,12 @@ def _sync_findings_for_account(
|
|
|
296
303
|
account_id: str,
|
|
297
304
|
update_tag: int,
|
|
298
305
|
current_aws_account_id: str,
|
|
306
|
+
batch_size: int = BATCH_SIZE,
|
|
299
307
|
) -> None:
|
|
300
308
|
"""
|
|
301
309
|
Syncs the findings for a given account in a given region.
|
|
302
310
|
"""
|
|
303
|
-
findings = get_inspector_findings(boto3_session, region, account_id)
|
|
311
|
+
findings = get_inspector_findings(boto3_session, region, account_id, batch_size)
|
|
304
312
|
if not findings:
|
|
305
313
|
logger.info(f"No findings to sync for account {account_id} in region {region}")
|
|
306
314
|
return
|
|
@@ -343,6 +351,10 @@ def sync(
|
|
|
343
351
|
update_tag: int,
|
|
344
352
|
common_job_parameters: Dict[str, Any],
|
|
345
353
|
) -> None:
|
|
354
|
+
batch_size = common_job_parameters.get(
|
|
355
|
+
"experimental_aws_inspector_batch", BATCH_SIZE
|
|
356
|
+
)
|
|
357
|
+
|
|
346
358
|
inspector_regions = [
|
|
347
359
|
region for region in regions if region in AWS_INSPECTOR_REGIONS
|
|
348
360
|
]
|
|
@@ -363,8 +375,8 @@ def sync(
|
|
|
363
375
|
account_id,
|
|
364
376
|
update_tag,
|
|
365
377
|
current_aws_account_id,
|
|
378
|
+
batch_size,
|
|
366
379
|
)
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
cleanup(neo4j_session, common_job_parameters)
|
|
380
|
+
common_job_parameters["ACCOUNT_ID"] = current_aws_account_id
|
|
381
|
+
common_job_parameters["UPDATE_TAG"] = update_tag
|
|
382
|
+
cleanup(neo4j_session, common_job_parameters, batch_size)
|
|
@@ -13,6 +13,7 @@ import neo4j
|
|
|
13
13
|
import yaml
|
|
14
14
|
|
|
15
15
|
from cartography.client.core.tx import read_list_of_dicts_tx
|
|
16
|
+
from cartography.client.core.tx import read_list_of_values_tx
|
|
16
17
|
from cartography.client.core.tx import run_write_query
|
|
17
18
|
from cartography.graph.statement import GraphStatement
|
|
18
19
|
from cartography.util import timeit
|
|
@@ -300,12 +301,11 @@ def get_resource_arns(
|
|
|
300
301
|
get_resource_query_template = get_resource_query.safe_substitute(
|
|
301
302
|
node_label=node_label,
|
|
302
303
|
)
|
|
303
|
-
|
|
304
|
+
return neo4j_session.execute_read(
|
|
305
|
+
read_list_of_values_tx,
|
|
304
306
|
get_resource_query_template,
|
|
305
307
|
AccountId=account_id,
|
|
306
308
|
)
|
|
307
|
-
arns = [r["arn"] for r in results]
|
|
308
|
-
return arns
|
|
309
309
|
|
|
310
310
|
|
|
311
311
|
def load_principal_mappings(
|
cartography/intel/aws/s3.py
CHANGED
|
@@ -16,6 +16,7 @@ from botocore.exceptions import ClientError
|
|
|
16
16
|
from botocore.exceptions import EndpointConnectionError
|
|
17
17
|
from policyuniverse.policy import Policy
|
|
18
18
|
|
|
19
|
+
from cartography.client.core.tx import run_write_query
|
|
19
20
|
from cartography.stats import get_stats_client
|
|
20
21
|
from cartography.util import aws_handle_regions
|
|
21
22
|
from cartography.util import merge_module_sync_metadata
|
|
@@ -334,7 +335,8 @@ def _load_s3_acls(
|
|
|
334
335
|
SET r.lastupdated = $UpdateTag
|
|
335
336
|
"""
|
|
336
337
|
|
|
337
|
-
|
|
338
|
+
run_write_query(
|
|
339
|
+
neo4j_session,
|
|
338
340
|
ingest_acls,
|
|
339
341
|
acls=acls,
|
|
340
342
|
UpdateTag=update_tag,
|
|
@@ -368,7 +370,8 @@ def _load_s3_policies(
|
|
|
368
370
|
s.lastupdated = $UpdateTag
|
|
369
371
|
"""
|
|
370
372
|
|
|
371
|
-
|
|
373
|
+
run_write_query(
|
|
374
|
+
neo4j_session,
|
|
372
375
|
ingest_policies,
|
|
373
376
|
policies=policies,
|
|
374
377
|
UpdateTag=update_tag,
|
|
@@ -401,11 +404,12 @@ def _load_s3_policy_statements(
|
|
|
401
404
|
MERGE (bucket)-[r:POLICY_STATEMENT]->(statement)
|
|
402
405
|
SET r.lastupdated = $UpdateTag
|
|
403
406
|
"""
|
|
404
|
-
|
|
407
|
+
run_write_query(
|
|
408
|
+
neo4j_session,
|
|
405
409
|
ingest_policy_statement,
|
|
406
410
|
Statements=statements,
|
|
407
411
|
UpdateTag=update_tag,
|
|
408
|
-
)
|
|
412
|
+
)
|
|
409
413
|
|
|
410
414
|
|
|
411
415
|
@timeit
|
|
@@ -427,7 +431,8 @@ def _load_s3_encryption(
|
|
|
427
431
|
s.lastupdated = $UpdateTag
|
|
428
432
|
"""
|
|
429
433
|
|
|
430
|
-
|
|
434
|
+
run_write_query(
|
|
435
|
+
neo4j_session,
|
|
431
436
|
ingest_encryption,
|
|
432
437
|
encryption_configs=encryption_configs,
|
|
433
438
|
UpdateTag=update_tag,
|
|
@@ -451,7 +456,8 @@ def _load_s3_versioning(
|
|
|
451
456
|
s.lastupdated = $UpdateTag
|
|
452
457
|
"""
|
|
453
458
|
|
|
454
|
-
|
|
459
|
+
run_write_query(
|
|
460
|
+
neo4j_session,
|
|
455
461
|
ingest_versioning,
|
|
456
462
|
versioning_configs=versioning_configs,
|
|
457
463
|
UpdateTag=update_tag,
|
|
@@ -477,7 +483,8 @@ def _load_s3_public_access_block(
|
|
|
477
483
|
s.lastupdated = $UpdateTag
|
|
478
484
|
"""
|
|
479
485
|
|
|
480
|
-
|
|
486
|
+
run_write_query(
|
|
487
|
+
neo4j_session,
|
|
481
488
|
ingest_public_access_block,
|
|
482
489
|
public_access_block_configs=public_access_block_configs,
|
|
483
490
|
UpdateTag=update_tag,
|
|
@@ -500,7 +507,8 @@ def _load_bucket_ownership_controls(
|
|
|
500
507
|
s.lastupdated = $UpdateTag
|
|
501
508
|
"""
|
|
502
509
|
|
|
503
|
-
|
|
510
|
+
run_write_query(
|
|
511
|
+
neo4j_session,
|
|
504
512
|
ingest_bucket_ownership_controls,
|
|
505
513
|
bucket_ownership_controls_configs=bucket_ownership_controls_configs,
|
|
506
514
|
UpdateTag=update_tag,
|
|
@@ -524,7 +532,8 @@ def _load_bucket_logging(
|
|
|
524
532
|
bucket.logging_target_bucket = bucket_logging.target_bucket,
|
|
525
533
|
bucket.lastupdated = $update_tag
|
|
526
534
|
"""
|
|
527
|
-
|
|
535
|
+
run_write_query(
|
|
536
|
+
neo4j_session,
|
|
528
537
|
ingest_bucket_logging,
|
|
529
538
|
bucket_logging_configs=bucket_logging_configs,
|
|
530
539
|
update_tag=update_tag,
|
|
@@ -536,7 +545,8 @@ def _set_default_values(neo4j_session: neo4j.Session, aws_account_id: str) -> No
|
|
|
536
545
|
MATCH (:AWSAccount{id: $AWS_ID})-[:RESOURCE]->(s:S3Bucket) where s.anonymous_actions IS NULL
|
|
537
546
|
SET s.anonymous_access = false, s.anonymous_actions = []
|
|
538
547
|
"""
|
|
539
|
-
|
|
548
|
+
run_write_query(
|
|
549
|
+
neo4j_session,
|
|
540
550
|
set_defaults,
|
|
541
551
|
AWS_ID=aws_account_id,
|
|
542
552
|
)
|
|
@@ -545,7 +555,8 @@ def _set_default_values(neo4j_session: neo4j.Session, aws_account_id: str) -> No
|
|
|
545
555
|
MATCH (:AWSAccount{id: $AWS_ID})-[:RESOURCE]->(s:S3Bucket) where s.default_encryption IS NULL
|
|
546
556
|
SET s.default_encryption = false
|
|
547
557
|
"""
|
|
548
|
-
|
|
558
|
+
run_write_query(
|
|
559
|
+
neo4j_session,
|
|
549
560
|
set_encryption_defaults,
|
|
550
561
|
AWS_ID=aws_account_id,
|
|
551
562
|
)
|
|
@@ -993,7 +1004,8 @@ def _load_s3_notifications(
|
|
|
993
1004
|
ON CREATE SET r.firstseen = timestamp()
|
|
994
1005
|
SET r.lastupdated = $UpdateTag
|
|
995
1006
|
"""
|
|
996
|
-
|
|
1007
|
+
run_write_query(
|
|
1008
|
+
neo4j_session,
|
|
997
1009
|
ingest_notifications,
|
|
998
1010
|
notifications=notifications,
|
|
999
1011
|
UpdateTag=update_tag,
|
|
@@ -1025,7 +1037,8 @@ def load_s3_buckets(
|
|
|
1025
1037
|
|
|
1026
1038
|
for bucket in data["Buckets"]:
|
|
1027
1039
|
arn = "arn:aws:s3:::" + bucket["Name"]
|
|
1028
|
-
|
|
1040
|
+
run_write_query(
|
|
1041
|
+
neo4j_session,
|
|
1029
1042
|
ingest_bucket,
|
|
1030
1043
|
BucketName=bucket["Name"],
|
|
1031
1044
|
BucketRegion=bucket["Region"],
|
cartography/intel/aws/ssm.py
CHANGED
|
@@ -9,6 +9,7 @@ import boto3
|
|
|
9
9
|
import neo4j
|
|
10
10
|
|
|
11
11
|
from cartography.client.core.tx import load
|
|
12
|
+
from cartography.client.core.tx import read_list_of_values_tx
|
|
12
13
|
from cartography.graph.job import GraphJob
|
|
13
14
|
from cartography.models.aws.ssm.instance_information import SSMInstanceInformationSchema
|
|
14
15
|
from cartography.models.aws.ssm.instance_patch import SSMInstancePatchSchema
|
|
@@ -31,15 +32,12 @@ def get_instance_ids(
|
|
|
31
32
|
WHERE i.region = $Region
|
|
32
33
|
RETURN i.id
|
|
33
34
|
"""
|
|
34
|
-
|
|
35
|
+
return neo4j_session.execute_read(
|
|
36
|
+
read_list_of_values_tx,
|
|
35
37
|
get_instances_query,
|
|
36
38
|
AWS_ACCOUNT_ID=current_aws_account_id,
|
|
37
39
|
Region=region,
|
|
38
40
|
)
|
|
39
|
-
instance_ids = []
|
|
40
|
-
for r in results:
|
|
41
|
-
instance_ids.append(r["i.id"])
|
|
42
|
-
return instance_ids
|
|
43
41
|
|
|
44
42
|
|
|
45
43
|
@timeit
|
|
@@ -6,6 +6,7 @@ import neo4j
|
|
|
6
6
|
from azure.core.exceptions import HttpResponseError
|
|
7
7
|
from azure.mgmt.compute import ComputeManagementClient
|
|
8
8
|
|
|
9
|
+
from cartography.client.core.tx import run_write_query
|
|
9
10
|
from cartography.util import run_cleanup_job
|
|
10
11
|
from cartography.util import timeit
|
|
11
12
|
|
|
@@ -63,7 +64,8 @@ def load_vms(
|
|
|
63
64
|
SET r.lastupdated = $update_tag
|
|
64
65
|
"""
|
|
65
66
|
|
|
66
|
-
|
|
67
|
+
run_write_query(
|
|
68
|
+
neo4j_session,
|
|
67
69
|
ingest_vm,
|
|
68
70
|
vms=vm_list,
|
|
69
71
|
SUBSCRIPTION_ID=subscription_id,
|
|
@@ -103,7 +105,8 @@ def load_vm_data_disks(
|
|
|
103
105
|
"""
|
|
104
106
|
|
|
105
107
|
# for disk in data_disks:
|
|
106
|
-
|
|
108
|
+
run_write_query(
|
|
109
|
+
neo4j_session,
|
|
107
110
|
ingest_data_disk,
|
|
108
111
|
disks=data_disks,
|
|
109
112
|
VM_ID=vm_id,
|
|
@@ -162,7 +165,8 @@ def load_disks(
|
|
|
162
165
|
ON CREATE SET r.firstseen = timestamp()
|
|
163
166
|
SET r.lastupdated = $update_tag"""
|
|
164
167
|
|
|
165
|
-
|
|
168
|
+
run_write_query(
|
|
169
|
+
neo4j_session,
|
|
166
170
|
ingest_disks,
|
|
167
171
|
disks=disk_list,
|
|
168
172
|
SUBSCRIPTION_ID=subscription_id,
|
|
@@ -217,7 +221,8 @@ def load_snapshots(
|
|
|
217
221
|
ON CREATE SET r.firstseen = timestamp()
|
|
218
222
|
SET r.lastupdated = $update_tag"""
|
|
219
223
|
|
|
220
|
-
|
|
224
|
+
run_write_query(
|
|
225
|
+
neo4j_session,
|
|
221
226
|
ingest_snapshots,
|
|
222
227
|
snapshots=snapshots,
|
|
223
228
|
SUBSCRIPTION_ID=subscription_id,
|