cartography 0.108.0rc2__py3-none-any.whl → 0.109.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 +14 -0
- cartography/config.py +4 -0
- cartography/data/indexes.cypher +0 -17
- cartography/data/jobs/cleanup/gcp_compute_vpc_cleanup.json +0 -12
- cartography/intel/aws/cloudtrail_management_events.py +57 -3
- cartography/intel/aws/ecr.py +55 -80
- cartography/intel/aws/eventbridge.py +91 -0
- cartography/intel/aws/glue.py +117 -0
- cartography/intel/aws/identitycenter.py +71 -23
- cartography/intel/aws/kms.py +160 -200
- cartography/intel/aws/lambda_function.py +206 -190
- cartography/intel/aws/rds.py +243 -458
- cartography/intel/aws/resourcegroupstaggingapi.py +77 -18
- cartography/intel/aws/resources.py +4 -0
- cartography/intel/aws/route53.py +334 -332
- cartography/intel/aws/secretsmanager.py +62 -44
- cartography/intel/entra/groups.py +29 -1
- cartography/intel/gcp/__init__.py +10 -0
- cartography/intel/gcp/compute.py +19 -42
- cartography/intel/trivy/__init__.py +73 -13
- cartography/intel/trivy/scanner.py +115 -92
- cartography/models/aws/ecr/__init__.py +0 -0
- cartography/models/aws/ecr/image.py +41 -0
- cartography/models/aws/ecr/repository.py +72 -0
- cartography/models/aws/ecr/repository_image.py +95 -0
- cartography/models/aws/eventbridge/__init__.py +0 -0
- cartography/models/aws/eventbridge/rule.py +77 -0
- cartography/models/aws/glue/__init__.py +0 -0
- cartography/models/aws/glue/connection.py +51 -0
- cartography/models/aws/identitycenter/awspermissionset.py +44 -0
- cartography/models/aws/kms/__init__.py +0 -0
- cartography/models/aws/kms/aliases.py +86 -0
- cartography/models/aws/kms/grants.py +65 -0
- cartography/models/aws/kms/keys.py +88 -0
- cartography/models/aws/lambda_function/__init__.py +0 -0
- cartography/models/aws/lambda_function/alias.py +74 -0
- cartography/models/aws/lambda_function/event_source_mapping.py +88 -0
- cartography/models/aws/lambda_function/lambda_function.py +89 -0
- cartography/models/aws/lambda_function/layer.py +72 -0
- cartography/models/aws/rds/__init__.py +0 -0
- cartography/models/aws/rds/cluster.py +89 -0
- cartography/models/aws/rds/instance.py +154 -0
- cartography/models/aws/rds/snapshot.py +108 -0
- cartography/models/aws/rds/subnet_group.py +101 -0
- cartography/models/aws/route53/__init__.py +0 -0
- cartography/models/aws/route53/dnsrecord.py +214 -0
- cartography/models/aws/route53/nameserver.py +63 -0
- cartography/models/aws/route53/subzone.py +40 -0
- cartography/models/aws/route53/zone.py +47 -0
- cartography/models/aws/secretsmanager/secret.py +106 -0
- cartography/models/entra/group.py +26 -0
- cartography/models/entra/user.py +6 -0
- cartography/models/gcp/compute/__init__.py +0 -0
- cartography/models/gcp/compute/vpc.py +50 -0
- cartography/util.py +8 -1
- {cartography-0.108.0rc2.dist-info → cartography-0.109.0.dist-info}/METADATA +2 -2
- {cartography-0.108.0rc2.dist-info → cartography-0.109.0.dist-info}/RECORD +62 -38
- cartography/data/jobs/cleanup/aws_dns_cleanup.json +0 -65
- cartography/data/jobs/cleanup/aws_import_identity_center_cleanup.json +0 -16
- cartography/data/jobs/cleanup/aws_import_lambda_cleanup.json +0 -50
- cartography/data/jobs/cleanup/aws_import_rds_clusters_cleanup.json +0 -23
- cartography/data/jobs/cleanup/aws_import_rds_instances_cleanup.json +0 -47
- cartography/data/jobs/cleanup/aws_import_rds_snapshots_cleanup.json +0 -23
- cartography/data/jobs/cleanup/aws_import_secrets_cleanup.json +0 -8
- cartography/data/jobs/cleanup/aws_kms_details.json +0 -10
- {cartography-0.108.0rc2.dist-info → cartography-0.109.0.dist-info}/WHEEL +0 -0
- {cartography-0.108.0rc2.dist-info → cartography-0.109.0.dist-info}/entry_points.txt +0 -0
- {cartography-0.108.0rc2.dist-info → cartography-0.109.0.dist-info}/licenses/LICENSE +0 -0
- {cartography-0.108.0rc2.dist-info → cartography-0.109.0.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from string import Template
|
|
3
|
+
from typing import Any
|
|
3
4
|
from typing import Dict
|
|
4
5
|
from typing import List
|
|
5
6
|
|
|
@@ -56,6 +57,35 @@ def get_short_id_from_lb2_arn(alb_arn: str) -> str:
|
|
|
56
57
|
return alb_arn.split("/")[-2]
|
|
57
58
|
|
|
58
59
|
|
|
60
|
+
def get_resource_type_from_arn(arn: str) -> str:
|
|
61
|
+
"""Return the resource type format expected by the Tagging API.
|
|
62
|
+
|
|
63
|
+
The Resource Groups Tagging API requires resource types in the form
|
|
64
|
+
``service:resource``. Most ARNs embed the resource type in the fifth segment
|
|
65
|
+
after the service name. Load balancer ARNs add an extra ``app`` or ``net``
|
|
66
|
+
component that must be preserved. S3 and SQS ARNs only contain the service
|
|
67
|
+
name. This helper extracts the appropriate string so that ARNs can be
|
|
68
|
+
grouped correctly for API calls.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
parts = arn.split(":", 5)
|
|
72
|
+
service = parts[2]
|
|
73
|
+
if service in {"s3", "sqs"}:
|
|
74
|
+
return service
|
|
75
|
+
|
|
76
|
+
resource = parts[5]
|
|
77
|
+
if service == "elasticloadbalancing" and resource.startswith("loadbalancer/"):
|
|
78
|
+
segments = resource.split("/")
|
|
79
|
+
if len(segments) > 2 and segments[1] in {"app", "net"}:
|
|
80
|
+
resource_type = f"{segments[0]}/{segments[1]}"
|
|
81
|
+
else:
|
|
82
|
+
resource_type = segments[0]
|
|
83
|
+
else:
|
|
84
|
+
resource_type = resource.split("/")[0].split(":")[0]
|
|
85
|
+
|
|
86
|
+
return f"{service}:{resource_type}" if resource_type else service
|
|
87
|
+
|
|
88
|
+
|
|
59
89
|
# We maintain a mapping from AWS resource types to their associated labels and unique identifiers.
|
|
60
90
|
# label: the node label used in cartography for this resource type
|
|
61
91
|
# property: the field of this node that uniquely identified this resource type
|
|
@@ -158,27 +188,27 @@ TAG_RESOURCE_TYPE_MAPPINGS: Dict = {
|
|
|
158
188
|
@aws_handle_regions
|
|
159
189
|
def get_tags(
|
|
160
190
|
boto3_session: boto3.session.Session,
|
|
161
|
-
|
|
191
|
+
resource_types: list[str],
|
|
162
192
|
region: str,
|
|
163
|
-
) ->
|
|
164
|
-
"""
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
193
|
+
) -> list[dict[str, Any]]:
|
|
194
|
+
"""Retrieve tag data for the provided resource types."""
|
|
195
|
+
resources: list[dict[str, Any]] = []
|
|
196
|
+
|
|
197
|
+
if "iam:role" in resource_types:
|
|
198
|
+
resources.extend(get_role_tags(boto3_session))
|
|
199
|
+
resource_types = [rt for rt in resource_types if rt != "iam:role"]
|
|
200
|
+
|
|
201
|
+
if not resource_types:
|
|
202
|
+
return resources
|
|
172
203
|
|
|
173
204
|
client = boto3_session.client("resourcegroupstaggingapi", region_name=region)
|
|
174
205
|
paginator = client.get_paginator("get_resources")
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
ResourceTypeFilters=
|
|
180
|
-
|
|
181
|
-
resources.extend(page["ResourceTagMappingList"])
|
|
206
|
+
|
|
207
|
+
# Batch resource types into groups of 100
|
|
208
|
+
# (https://docs.aws.amazon.com/resourcegroupstagging/latest/APIReference/API_GetResources.html)
|
|
209
|
+
for resource_types_batch in batch(resource_types, size=100):
|
|
210
|
+
for page in paginator.paginate(ResourceTypeFilters=resource_types_batch):
|
|
211
|
+
resources.extend(page["ResourceTagMappingList"])
|
|
182
212
|
return resources
|
|
183
213
|
|
|
184
214
|
|
|
@@ -210,6 +240,9 @@ def _load_tags_tx(
|
|
|
210
240
|
r.firstseen = timestamp()
|
|
211
241
|
""",
|
|
212
242
|
)
|
|
243
|
+
if not tag_data:
|
|
244
|
+
return
|
|
245
|
+
|
|
213
246
|
query = INGEST_TAG_TEMPLATE.safe_substitute(
|
|
214
247
|
resource_label=TAG_RESOURCE_TYPE_MAPPINGS[resource_type]["label"],
|
|
215
248
|
property=TAG_RESOURCE_TYPE_MAPPINGS[resource_type]["property"],
|
|
@@ -262,6 +295,26 @@ def compute_resource_id(tag_mapping: Dict, resource_type: str) -> str:
|
|
|
262
295
|
return resource_id
|
|
263
296
|
|
|
264
297
|
|
|
298
|
+
def _group_tag_data_by_resource_type(
|
|
299
|
+
tag_data: List[Dict],
|
|
300
|
+
tag_resource_type_mappings: Dict,
|
|
301
|
+
) -> Dict[str, List[Dict]]:
|
|
302
|
+
"""Group raw tag data by the resource types Cartography supports."""
|
|
303
|
+
|
|
304
|
+
grouped: Dict[str, List[Dict]] = {rtype: [] for rtype in tag_resource_type_mappings}
|
|
305
|
+
for mapping in tag_data:
|
|
306
|
+
rtype = get_resource_type_from_arn(mapping["ResourceARN"])
|
|
307
|
+
if rtype in grouped:
|
|
308
|
+
grouped[rtype].append(mapping)
|
|
309
|
+
else:
|
|
310
|
+
logger.debug(
|
|
311
|
+
"Unknown tag resource type %s from ARN %s",
|
|
312
|
+
rtype,
|
|
313
|
+
mapping["ResourceARN"],
|
|
314
|
+
)
|
|
315
|
+
return grouped
|
|
316
|
+
|
|
317
|
+
|
|
265
318
|
@timeit
|
|
266
319
|
def cleanup(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
|
|
267
320
|
run_cleanup_job(
|
|
@@ -285,8 +338,14 @@ def sync(
|
|
|
285
338
|
logger.info(
|
|
286
339
|
f"Syncing AWS tags for account {current_aws_account_id} and region {region}",
|
|
287
340
|
)
|
|
341
|
+
all_tag_data = get_tags(
|
|
342
|
+
boto3_session, list(tag_resource_type_mappings.keys()), region
|
|
343
|
+
)
|
|
344
|
+
grouped = _group_tag_data_by_resource_type(
|
|
345
|
+
all_tag_data, tag_resource_type_mappings
|
|
346
|
+
)
|
|
288
347
|
for resource_type in tag_resource_type_mappings.keys():
|
|
289
|
-
tag_data =
|
|
348
|
+
tag_data = grouped.get(resource_type, [])
|
|
290
349
|
transform_tags(tag_data, resource_type) # type: ignore
|
|
291
350
|
logger.info(
|
|
292
351
|
f"Loading {len(tag_data)} tags for resource type {resource_type}",
|
|
@@ -18,6 +18,8 @@ from . import eks
|
|
|
18
18
|
from . import elasticache
|
|
19
19
|
from . import elasticsearch
|
|
20
20
|
from . import emr
|
|
21
|
+
from . import eventbridge
|
|
22
|
+
from . import glue
|
|
21
23
|
from . import guardduty
|
|
22
24
|
from . import iam
|
|
23
25
|
from . import identitycenter
|
|
@@ -114,4 +116,6 @@ RESOURCE_FUNCTIONS: Dict[str, Callable[..., None]] = {
|
|
|
114
116
|
"efs": efs.sync,
|
|
115
117
|
"guardduty": guardduty.sync,
|
|
116
118
|
"codebuild": codebuild.sync,
|
|
119
|
+
"eventbridge": eventbridge.sync,
|
|
120
|
+
"glue": glue.sync,
|
|
117
121
|
}
|