cartography 0.111.0__py3-none-any.whl → 0.112.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.

Files changed (40) hide show
  1. cartography/_version.py +2 -2
  2. cartography/cli.py +11 -0
  3. cartography/config.py +8 -0
  4. cartography/data/indexes.cypher +0 -2
  5. cartography/intel/aws/apigateway.py +126 -17
  6. cartography/intel/aws/ec2/instances.py +3 -1
  7. cartography/intel/aws/ec2/network_interfaces.py +1 -1
  8. cartography/intel/aws/ec2/vpc_peerings.py +262 -125
  9. cartography/intel/azure/__init__.py +35 -32
  10. cartography/intel/azure/subscription.py +2 -2
  11. cartography/intel/azure/tenant.py +39 -30
  12. cartography/intel/azure/util/credentials.py +49 -174
  13. cartography/intel/entra/__init__.py +47 -1
  14. cartography/intel/entra/applications.py +220 -170
  15. cartography/intel/entra/groups.py +41 -22
  16. cartography/intel/entra/ou.py +28 -20
  17. cartography/intel/entra/users.py +24 -18
  18. cartography/intel/gcp/__init__.py +25 -8
  19. cartography/intel/gcp/compute.py +47 -12
  20. cartography/intel/kubernetes/__init__.py +26 -0
  21. cartography/intel/kubernetes/eks.py +402 -0
  22. cartography/intel/kubernetes/rbac.py +133 -0
  23. cartography/models/aws/apigateway/apigatewayintegration.py +79 -0
  24. cartography/models/aws/apigateway/apigatewaymethod.py +74 -0
  25. cartography/models/aws/ec2/vpc_peering.py +157 -0
  26. cartography/models/azure/principal.py +44 -0
  27. cartography/models/azure/tenant.py +20 -0
  28. cartography/models/kubernetes/clusterrolebindings.py +40 -0
  29. cartography/models/kubernetes/groups.py +107 -0
  30. cartography/models/kubernetes/oidc.py +51 -0
  31. cartography/models/kubernetes/rolebindings.py +40 -0
  32. cartography/models/kubernetes/users.py +105 -0
  33. cartography/util.py +2 -0
  34. {cartography-0.111.0.dist-info → cartography-0.112.0.dist-info}/METADATA +8 -5
  35. {cartography-0.111.0.dist-info → cartography-0.112.0.dist-info}/RECORD +39 -31
  36. cartography/data/jobs/cleanup/aws_import_vpc_peering_cleanup.json +0 -45
  37. {cartography-0.111.0.dist-info → cartography-0.112.0.dist-info}/WHEEL +0 -0
  38. {cartography-0.111.0.dist-info → cartography-0.112.0.dist-info}/entry_points.txt +0 -0
  39. {cartography-0.111.0.dist-info → cartography-0.112.0.dist-info}/licenses/LICENSE +0 -0
  40. {cartography-0.111.0.dist-info → cartography-0.112.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,402 @@
1
+ import logging
2
+ from typing import Any
3
+ from typing import Dict
4
+ from typing import List
5
+
6
+ import boto3
7
+ import neo4j
8
+ import yaml
9
+ from kubernetes.client.models import V1ConfigMap
10
+
11
+ from cartography.client.core.tx import load
12
+ from cartography.graph.job import GraphJob
13
+ from cartography.intel.kubernetes.util import K8sClient
14
+ from cartography.models.kubernetes.groups import KubernetesGroupSchema
15
+ from cartography.models.kubernetes.oidc import KubernetesOIDCProviderSchema
16
+ from cartography.models.kubernetes.users import KubernetesUserSchema
17
+ from cartography.util import aws_handle_regions
18
+ from cartography.util import timeit
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ @timeit
24
+ def get_aws_auth_configmap(client: K8sClient) -> V1ConfigMap:
25
+ """
26
+ Get aws-auth ConfigMap from kube-system namespace.
27
+ """
28
+ logger.info(f"Retrieving aws-auth ConfigMap from cluster {client.name}")
29
+ return client.core.read_namespaced_config_map(
30
+ name="aws-auth", namespace="kube-system"
31
+ )
32
+
33
+
34
+ def parse_aws_auth_map(configmap: V1ConfigMap) -> Dict[str, List[Dict[str, Any]]]:
35
+ """
36
+ Parse mapRoles and mapUsers from aws-auth ConfigMap.
37
+
38
+ :param configmap: V1ConfigMap containing aws-auth data
39
+ :return: Dictionary with 'roles' and 'users' keys containing their respective mappings
40
+ """
41
+ result: Dict[str, List[Dict[str, Any]]] = {"roles": [], "users": []}
42
+
43
+ # Parse mapRoles
44
+ if "mapRoles" in configmap.data:
45
+ map_roles_yaml = configmap.data["mapRoles"]
46
+ role_mappings = yaml.safe_load(map_roles_yaml) or []
47
+
48
+ # Filter out templated entries for now (https://github.com/cartography-cncf/cartography/issues/1854)
49
+ filtered_role_mappings = []
50
+ for mapping in role_mappings:
51
+ username = mapping.get("username", "")
52
+ if "{{" in username:
53
+ logger.debug(f"Skipping templated username in mapRoles: {username}")
54
+ continue
55
+ filtered_role_mappings.append(mapping)
56
+
57
+ result["roles"] = filtered_role_mappings
58
+ logger.info(
59
+ f"Parsed {len(filtered_role_mappings)} role mappings from aws-auth ConfigMap"
60
+ )
61
+ else:
62
+ logger.info("No mapRoles found in aws-auth ConfigMap")
63
+
64
+ # Parse mapUsers
65
+ if "mapUsers" in configmap.data:
66
+ map_users_yaml = configmap.data["mapUsers"]
67
+ user_mappings = yaml.safe_load(map_users_yaml) or []
68
+
69
+ filtered_user_mappings = []
70
+ for mapping in user_mappings:
71
+ username = mapping.get("username", "")
72
+ if "{{" in username:
73
+ logger.debug(f"Skipping templated username in mapUsers: {username}")
74
+ continue
75
+ filtered_user_mappings.append(mapping)
76
+
77
+ result["users"] = filtered_user_mappings
78
+ logger.info(
79
+ f"Parsed {len(filtered_user_mappings)} user mappings from aws-auth ConfigMap"
80
+ )
81
+ else:
82
+ logger.info("No mapUsers found in aws-auth ConfigMap")
83
+
84
+ return result
85
+
86
+
87
+ def transform_aws_auth_mappings(
88
+ auth_mappings: Dict[str, List[Dict[str, Any]]], cluster_name: str
89
+ ) -> Dict[str, List[Dict[str, Any]]]:
90
+ """
91
+ Transform both role and user mappings from aws-auth ConfigMap into combined user/group data.
92
+ """
93
+ all_users = []
94
+ all_groups = []
95
+
96
+ # Process role mappings if they exist
97
+ if auth_mappings.get("roles"):
98
+ for mapping in auth_mappings.get("roles", []):
99
+ role_arn = mapping.get("rolearn")
100
+ username = mapping.get("username")
101
+ group_names = mapping.get("groups", [])
102
+
103
+ if not role_arn:
104
+ continue
105
+
106
+ # Create user data with AWS role relationship (only if username is provided)
107
+ if username:
108
+ all_users.append(
109
+ {
110
+ "id": f"{cluster_name}/{username}",
111
+ "name": username,
112
+ "cluster_name": cluster_name,
113
+ "aws_role_arn": role_arn,
114
+ }
115
+ )
116
+
117
+ # Create group data with AWS role relationship for each group
118
+ for group_name in group_names:
119
+ all_groups.append(
120
+ {
121
+ "id": f"{cluster_name}/{group_name}",
122
+ "name": group_name,
123
+ "cluster_name": cluster_name,
124
+ "aws_role_arn": role_arn,
125
+ }
126
+ )
127
+
128
+ # Process user mappings if they exist
129
+ if auth_mappings.get("users"):
130
+ for mapping in auth_mappings.get("users", []):
131
+ user_arn = mapping.get("userarn")
132
+ username = mapping.get("username")
133
+ group_names = mapping.get("groups", [])
134
+
135
+ if not user_arn:
136
+ continue
137
+
138
+ # Create user data with AWS user relationship (only if username is provided)
139
+ if username:
140
+ all_users.append(
141
+ {
142
+ "id": f"{cluster_name}/{username}",
143
+ "name": username,
144
+ "cluster_name": cluster_name,
145
+ "aws_user_arn": user_arn,
146
+ }
147
+ )
148
+
149
+ # Create group data with AWS user relationship for each group
150
+ for group_name in group_names:
151
+ all_groups.append(
152
+ {
153
+ "id": f"{cluster_name}/{group_name}",
154
+ "name": group_name,
155
+ "cluster_name": cluster_name,
156
+ "aws_user_arn": user_arn,
157
+ }
158
+ )
159
+
160
+ # Count entries with vs without usernames for visibility
161
+ role_entries_with_username = sum(
162
+ 1 for mapping in auth_mappings.get("roles", []) if mapping.get("username")
163
+ )
164
+ user_entries_with_username = sum(
165
+ 1 for mapping in auth_mappings.get("users", []) if mapping.get("username")
166
+ )
167
+ total_entries_with_username = (
168
+ role_entries_with_username + user_entries_with_username
169
+ )
170
+ total_entries = len(auth_mappings.get("roles", [])) + len(
171
+ auth_mappings.get("users", [])
172
+ )
173
+ entries_without_username = total_entries - total_entries_with_username
174
+
175
+ logger.info(
176
+ f"Transformed {len(all_users)} users (from {total_entries_with_username} entries with usernames) "
177
+ f"and {len(all_groups)} groups from {len(auth_mappings.get('roles', []))} role mappings "
178
+ f"and {len(auth_mappings.get('users', []))} user mappings "
179
+ f"({entries_without_username} entries without usernames created groups only)"
180
+ )
181
+
182
+ return {"users": all_users, "groups": all_groups}
183
+
184
+
185
+ @timeit
186
+ @aws_handle_regions
187
+ def get_oidc_provider(
188
+ boto3_session: boto3.session.Session,
189
+ region: str,
190
+ cluster_name: str,
191
+ ) -> List[Dict[str, Any]]:
192
+ """
193
+ Get external OIDC identity provider configurations for an EKS cluster.
194
+
195
+ Returns raw AWS API responses for configured external identity providers.
196
+ """
197
+ client = boto3_session.client("eks", region_name=region)
198
+ oidc_providers = []
199
+
200
+ # Extract just the cluster name from ARN if needed
201
+ # ARN format: arn:aws:eks:region:account:cluster/cluster-name
202
+ if cluster_name.startswith("arn:aws:eks:"):
203
+ cluster_name = cluster_name.split("/")[-1]
204
+
205
+ # Get configured external identity provider configs
206
+ configs_response = client.list_identity_provider_configs(clusterName=cluster_name)
207
+
208
+ for config in configs_response["identityProviderConfigs"]:
209
+ if config["type"] == "oidc":
210
+ # Get detailed config for this OIDC provider
211
+ detail_response = client.describe_identity_provider_config(
212
+ clusterName=cluster_name,
213
+ identityProviderConfig={"type": "oidc", "name": config["name"]},
214
+ )
215
+
216
+ oidc_providers.append(detail_response["identityProviderConfig"]["oidc"])
217
+
218
+ return oidc_providers
219
+
220
+
221
+ def transform_oidc_provider(
222
+ oidc_providers: List[Dict[str, Any]],
223
+ cluster_name: str,
224
+ ) -> List[Dict[str, Any]]:
225
+ """
226
+ Transform raw AWS OIDC provider data into standardized format.
227
+
228
+ Takes raw AWS API responses and creates OIDC provider nodes that match
229
+ the KubernetesOIDCProvider data model for infrastructure metadata.
230
+ """
231
+ transformed_providers = []
232
+
233
+ for provider in oidc_providers:
234
+ # Extract fields from raw AWS API response
235
+ provider_name = provider["identityProviderConfigName"]
236
+ issuer_url = provider["issuerUrl"]
237
+
238
+ # Create a unique ID for the external OIDC provider
239
+ # Format: cluster_name/oidc/provider_name
240
+ provider_id = f"{cluster_name}/oidc/{provider_name}"
241
+
242
+ transformed_provider = {
243
+ "id": provider_id,
244
+ "issuer_url": issuer_url,
245
+ "cluster_name": cluster_name,
246
+ "k8s_platform": "eks",
247
+ "client_id": provider.get("clientId", ""),
248
+ "status": provider.get("status", "UNKNOWN"),
249
+ "name": provider_name,
250
+ }
251
+
252
+ transformed_providers.append(transformed_provider)
253
+
254
+ return transformed_providers
255
+
256
+
257
+ def load_oidc_provider(
258
+ neo4j_session: neo4j.Session,
259
+ oidc_providers: List[Dict[str, Any]],
260
+ update_tag: int,
261
+ cluster_id: str,
262
+ cluster_name: str,
263
+ ) -> None:
264
+ """
265
+ Load OIDC providers and their relationships to users and groups into Neo4j.
266
+ """
267
+ logger.info(f"Loading {len(oidc_providers)} EKS OIDC providers")
268
+ load(
269
+ neo4j_session,
270
+ KubernetesOIDCProviderSchema(),
271
+ oidc_providers,
272
+ lastupdated=update_tag,
273
+ CLUSTER_ID=cluster_id,
274
+ CLUSTER_NAME=cluster_name,
275
+ )
276
+
277
+
278
+ def load_aws_auth_mappings(
279
+ neo4j_session: neo4j.Session,
280
+ users: List[Dict[str, Any]],
281
+ groups: List[Dict[str, Any]],
282
+ update_tag: int,
283
+ cluster_id: str,
284
+ cluster_name: str,
285
+ ) -> None:
286
+ """
287
+ Load Kubernetes Users/Groups with AWS Role and User relationships into Neo4j using schema-based loading.
288
+ """
289
+ logger.info(f"Loading {len(users)} Kubernetes Users with AWS mappings")
290
+
291
+ # Load Kubernetes Users with AWS relationships
292
+ if users:
293
+ load(
294
+ neo4j_session,
295
+ KubernetesUserSchema(),
296
+ users,
297
+ lastupdated=update_tag,
298
+ CLUSTER_ID=cluster_id,
299
+ CLUSTER_NAME=cluster_name,
300
+ )
301
+
302
+ logger.info(f"Loading {len(groups)} Kubernetes Groups with AWS mappings")
303
+
304
+ # Load Kubernetes Groups with AWS relationships
305
+ if groups:
306
+ load(
307
+ neo4j_session,
308
+ KubernetesGroupSchema(),
309
+ groups,
310
+ lastupdated=update_tag,
311
+ CLUSTER_ID=cluster_id,
312
+ CLUSTER_NAME=cluster_name,
313
+ )
314
+
315
+
316
+ def cleanup(
317
+ neo4j_session: neo4j.Session, common_job_parameters: Dict[str, Any]
318
+ ) -> None:
319
+ logger.debug("Running cleanup job for EKS AWS Role and User relationships")
320
+
321
+ cleanup_job = GraphJob.from_node_schema(
322
+ KubernetesUserSchema(), common_job_parameters
323
+ )
324
+ cleanup_job.run(neo4j_session)
325
+
326
+ cleanup_job = GraphJob.from_node_schema(
327
+ KubernetesGroupSchema(), common_job_parameters
328
+ )
329
+ cleanup_job.run(neo4j_session)
330
+
331
+
332
+ def sync(
333
+ neo4j_session: neo4j.Session,
334
+ k8s_client: K8sClient,
335
+ boto3_session: boto3.session.Session,
336
+ region: str,
337
+ update_tag: int,
338
+ cluster_id: str,
339
+ cluster_name: str,
340
+ ) -> None:
341
+ """
342
+ Sync EKS identity providers:
343
+ 1. AWS IAM role and user mappings (aws-auth ConfigMap)
344
+ 2. External OIDC providers (EKS API)
345
+ """
346
+ logger.info(f"Starting EKS identity provider sync for cluster {cluster_name}")
347
+
348
+ # 1. Sync AWS IAM mappings (aws-auth ConfigMap)
349
+ logger.info("Syncing AWS IAM mappings from aws-auth ConfigMap")
350
+ configmap = get_aws_auth_configmap(k8s_client)
351
+ auth_mappings = parse_aws_auth_map(configmap)
352
+
353
+ # Transform and load both role and user mappings
354
+ if auth_mappings.get("roles") or auth_mappings.get("users"):
355
+ transformed_data = transform_aws_auth_mappings(auth_mappings, cluster_name)
356
+ load_aws_auth_mappings(
357
+ neo4j_session,
358
+ transformed_data["users"],
359
+ transformed_data["groups"],
360
+ update_tag,
361
+ cluster_id,
362
+ cluster_name,
363
+ )
364
+ logger.info(
365
+ f"Successfully synced {len(auth_mappings.get('roles', []))} AWS IAM role mappings "
366
+ f"and {len(auth_mappings.get('users', []))} AWS IAM user mappings"
367
+ )
368
+ else:
369
+ logger.info("No role or user mappings found in aws-auth ConfigMap")
370
+
371
+ # 2. Sync External OIDC providers (EKS API)
372
+ logger.info("Syncing external OIDC providers from EKS API")
373
+
374
+ # Get OIDC providers from EKS API
375
+ oidc_provider = get_oidc_provider(boto3_session, region, cluster_name)
376
+
377
+ if oidc_provider:
378
+ # Transform OIDC providers (infrastructure metadata only)
379
+ transformed_oidc_provider = transform_oidc_provider(oidc_provider, cluster_name)
380
+
381
+ # Load OIDC providers
382
+ load_oidc_provider(
383
+ neo4j_session,
384
+ transformed_oidc_provider,
385
+ update_tag,
386
+ cluster_id,
387
+ cluster_name,
388
+ )
389
+ logger.info(f"Successfully synced {len(oidc_provider)} external OIDC provider")
390
+ else:
391
+ logger.info("No external OIDC provider found for cluster")
392
+
393
+ # Cleanup
394
+ common_job_parameters = {
395
+ "UPDATE_TAG": update_tag,
396
+ "CLUSTER_ID": cluster_id,
397
+ }
398
+ cleanup(neo4j_session, common_job_parameters)
399
+
400
+ logger.info(
401
+ f"Successfully completed EKS identity provider sync for cluster {cluster_name}"
402
+ )
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ from itertools import chain
2
3
  from typing import Any
3
4
  from typing import Dict
4
5
  from typing import List
@@ -19,9 +20,11 @@ from cartography.models.kubernetes.clusterrolebindings import (
19
20
  KubernetesClusterRoleBindingSchema,
20
21
  )
21
22
  from cartography.models.kubernetes.clusterroles import KubernetesClusterRoleSchema
23
+ from cartography.models.kubernetes.groups import KubernetesGroupSchema
22
24
  from cartography.models.kubernetes.rolebindings import KubernetesRoleBindingSchema
23
25
  from cartography.models.kubernetes.roles import KubernetesRoleSchema
24
26
  from cartography.models.kubernetes.serviceaccounts import KubernetesServiceAccountSchema
27
+ from cartography.models.kubernetes.users import KubernetesUserSchema
25
28
  from cartography.util import timeit
26
29
 
27
30
  logger = logging.getLogger(__name__)
@@ -263,6 +266,62 @@ def transform_cluster_role_bindings(
263
266
  return result
264
267
 
265
268
 
269
+ def transform_users(
270
+ role_bindings: List[V1RoleBinding],
271
+ cluster_role_bindings: List[V1ClusterRoleBinding],
272
+ cluster_name: str,
273
+ ) -> List[Dict[str, Any]]:
274
+ """
275
+ Transform Kubernetes Users from RoleBindings and ClusterRoleBindings into a list of dicts.
276
+ """
277
+ # Extract all users from rolebindings and clusterrolebindings
278
+ all_users = {
279
+ subject.name
280
+ for binding in chain(
281
+ role_bindings, cluster_role_bindings
282
+ ) # iterate through combined bindings and role bindings
283
+ for subject in (
284
+ binding.subjects or []
285
+ ) # iterates through each binding's subjects to get unique users
286
+ if subject.kind == "User"
287
+ }
288
+
289
+ return [
290
+ {
291
+ "id": f"{cluster_name}/{user_name}",
292
+ "name": user_name,
293
+ "cluster_name": cluster_name,
294
+ }
295
+ for user_name in sorted(all_users)
296
+ ]
297
+
298
+
299
+ def transform_groups(
300
+ role_bindings: List[V1RoleBinding],
301
+ cluster_role_bindings: List[V1ClusterRoleBinding],
302
+ cluster_name: str,
303
+ ) -> List[Dict[str, Any]]:
304
+ """
305
+ Transform Kubernetes Groups from RoleBindings and ClusterRoleBindings into a list of dicts.
306
+ """
307
+ # Extract all groups from rolebindings and clusterrolebindings
308
+ all_groups = {
309
+ subject.name
310
+ for binding in chain(role_bindings, cluster_role_bindings)
311
+ for subject in (binding.subjects or [])
312
+ if subject.kind == "Group"
313
+ }
314
+
315
+ return [
316
+ {
317
+ "id": f"{cluster_name}/{group_name}",
318
+ "name": group_name,
319
+ "cluster_name": cluster_name,
320
+ }
321
+ for group_name in sorted(all_groups)
322
+ ]
323
+
324
+
266
325
  @timeit
267
326
  def load_service_accounts(
268
327
  session: neo4j.Session,
@@ -358,6 +417,44 @@ def load_cluster_role_bindings(
358
417
  )
359
418
 
360
419
 
420
+ @timeit
421
+ def load_users(
422
+ session: neo4j.Session,
423
+ users: List[Dict[str, Any]],
424
+ update_tag: int,
425
+ cluster_id: str,
426
+ cluster_name: str,
427
+ ) -> None:
428
+ logger.info(f"Loading {len(users)} KubernetesUsers")
429
+ load(
430
+ session,
431
+ KubernetesUserSchema(),
432
+ users,
433
+ lastupdated=update_tag,
434
+ CLUSTER_ID=cluster_id,
435
+ CLUSTER_NAME=cluster_name,
436
+ )
437
+
438
+
439
+ @timeit
440
+ def load_groups(
441
+ session: neo4j.Session,
442
+ groups: List[Dict[str, Any]],
443
+ update_tag: int,
444
+ cluster_id: str,
445
+ cluster_name: str,
446
+ ) -> None:
447
+ logger.info(f"Loading {len(groups)} KubernetesGroups")
448
+ load(
449
+ session,
450
+ KubernetesGroupSchema(),
451
+ groups,
452
+ lastupdated=update_tag,
453
+ CLUSTER_ID=cluster_id,
454
+ CLUSTER_NAME=cluster_name,
455
+ )
456
+
457
+
361
458
  @timeit
362
459
  def cleanup(session: neo4j.Session, common_job_parameters: Dict[str, Any]) -> None:
363
460
  logger.debug("Running cleanup job for Kubernetes RBAC resources")
@@ -386,6 +483,16 @@ def cleanup(session: neo4j.Session, common_job_parameters: Dict[str, Any]) -> No
386
483
  )
387
484
  cleanup_job.run(session)
388
485
 
486
+ cleanup_job = GraphJob.from_node_schema(
487
+ KubernetesUserSchema(), common_job_parameters
488
+ )
489
+ cleanup_job.run(session)
490
+
491
+ cleanup_job = GraphJob.from_node_schema(
492
+ KubernetesGroupSchema(), common_job_parameters
493
+ )
494
+ cleanup_job.run(session)
495
+
389
496
 
390
497
  @timeit
391
498
  def sync_kubernetes_rbac(
@@ -418,9 +525,35 @@ def sync_kubernetes_rbac(
418
525
  cluster_role_bindings, client.name
419
526
  )
420
527
 
528
+ # Transform users from all bindings
529
+ transformed_users = transform_users(
530
+ role_bindings, cluster_role_bindings, client.name
531
+ )
532
+
533
+ # Transform groups from all bindings
534
+ transformed_groups = transform_groups(
535
+ role_bindings, cluster_role_bindings, client.name
536
+ )
537
+
421
538
  cluster_id = common_job_parameters["CLUSTER_ID"]
422
539
  cluster_name = client.name
423
540
 
541
+ load_users(
542
+ session=session,
543
+ users=transformed_users,
544
+ update_tag=update_tag,
545
+ cluster_id=cluster_id,
546
+ cluster_name=cluster_name,
547
+ )
548
+
549
+ load_groups(
550
+ session=session,
551
+ groups=transformed_groups,
552
+ update_tag=update_tag,
553
+ cluster_id=cluster_id,
554
+ cluster_name=cluster_name,
555
+ )
556
+
424
557
  load_service_accounts(
425
558
  session=session,
426
559
  service_accounts=transformed_service_accounts,
@@ -0,0 +1,79 @@
1
+ from dataclasses import dataclass
2
+
3
+ from cartography.models.core.common import PropertyRef
4
+ from cartography.models.core.nodes import CartographyNodeProperties
5
+ from cartography.models.core.nodes import CartographyNodeSchema
6
+ from cartography.models.core.relationships import CartographyRelProperties
7
+ from cartography.models.core.relationships import CartographyRelSchema
8
+ from cartography.models.core.relationships import LinkDirection
9
+ from cartography.models.core.relationships import make_target_node_matcher
10
+ from cartography.models.core.relationships import OtherRelationships
11
+ from cartography.models.core.relationships import TargetNodeMatcher
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class APIGatewayIntegrationNodeProperties(CartographyNodeProperties):
16
+ id: PropertyRef = PropertyRef("id")
17
+ httpmethod: PropertyRef = PropertyRef("httpMethod")
18
+ integration_http_method: PropertyRef = PropertyRef("integrationHttpMethod")
19
+ resource_id: PropertyRef = PropertyRef("resourceId")
20
+ api_id: PropertyRef = PropertyRef("apiId")
21
+ type: PropertyRef = PropertyRef("type")
22
+ uri: PropertyRef = PropertyRef("uri")
23
+ connection_type: PropertyRef = PropertyRef("connectionType")
24
+ connection_id: PropertyRef = PropertyRef("connectionId")
25
+ credentials: PropertyRef = PropertyRef("credentials")
26
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
27
+
28
+
29
+ @dataclass(frozen=True)
30
+ class APIGatewayIntegrationToAPIGatewayResourceRelRelProperties(
31
+ CartographyRelProperties
32
+ ):
33
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
34
+
35
+
36
+ @dataclass(frozen=True)
37
+ class APIGatewayIntegrationToAPIGatewayResourceRel(CartographyRelSchema):
38
+ target_node_label: str = "APIGatewayResource"
39
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
40
+ {"id": PropertyRef("resourceId")},
41
+ )
42
+ direction: LinkDirection = LinkDirection.INWARD
43
+ rel_label: str = "HAS_INTEGRATION"
44
+ properties: APIGatewayIntegrationToAPIGatewayResourceRelRelProperties = (
45
+ APIGatewayIntegrationToAPIGatewayResourceRelRelProperties()
46
+ )
47
+
48
+
49
+ @dataclass(frozen=True)
50
+ class APIGatewayIntegrationToAWSAccountRelRelProperties(CartographyRelProperties):
51
+ lastupdated: PropertyRef = PropertyRef("lastupdated", set_in_kwargs=True)
52
+
53
+
54
+ @dataclass(frozen=True)
55
+ # (:APIGatewayIntegration)<-[:RESOURCE]-(:AWSAccount)
56
+ class APIGatewayIntegrationToAWSAccountRel(CartographyRelSchema):
57
+ target_node_label: str = "AWSAccount"
58
+ target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
59
+ {"id": PropertyRef("AWS_ID", set_in_kwargs=True)},
60
+ )
61
+ direction: LinkDirection = LinkDirection.INWARD
62
+ rel_label: str = "RESOURCE"
63
+ properties: APIGatewayIntegrationToAWSAccountRelRelProperties = (
64
+ APIGatewayIntegrationToAWSAccountRelRelProperties()
65
+ )
66
+
67
+
68
+ @dataclass(frozen=True)
69
+ class APIGatewayIntegrationSchema(CartographyNodeSchema):
70
+ label: str = "APIGatewayIntegration"
71
+ properties: APIGatewayIntegrationNodeProperties = (
72
+ APIGatewayIntegrationNodeProperties()
73
+ )
74
+ sub_resource_relationship: APIGatewayIntegrationToAWSAccountRel = (
75
+ APIGatewayIntegrationToAWSAccountRel()
76
+ )
77
+ other_relationships: OtherRelationships = OtherRelationships(
78
+ [APIGatewayIntegrationToAPIGatewayResourceRel()],
79
+ )