cartography 0.102.0rc2__py3-none-any.whl → 0.103.0rc1__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/__main__.py +1 -2
- cartography/_version.py +2 -2
- cartography/cli.py +302 -253
- cartography/client/core/tx.py +39 -18
- cartography/config.py +4 -0
- cartography/driftdetect/__main__.py +1 -2
- cartography/driftdetect/add_shortcut.py +10 -2
- cartography/driftdetect/cli.py +71 -75
- cartography/driftdetect/detect_deviations.py +7 -3
- cartography/driftdetect/get_states.py +20 -8
- cartography/driftdetect/model.py +5 -5
- cartography/driftdetect/serializers.py +8 -6
- cartography/driftdetect/storage.py +2 -2
- cartography/graph/cleanupbuilder.py +35 -15
- cartography/graph/job.py +46 -17
- cartography/graph/querybuilder.py +165 -80
- cartography/graph/statement.py +35 -26
- cartography/intel/analysis.py +4 -1
- cartography/intel/aws/__init__.py +114 -55
- cartography/intel/aws/apigateway.py +134 -63
- cartography/intel/aws/cloudtrail.py +127 -0
- cartography/intel/aws/config.py +56 -20
- cartography/intel/aws/dynamodb.py +108 -40
- cartography/intel/aws/ec2/__init__.py +2 -2
- cartography/intel/aws/ec2/auto_scaling_groups.py +181 -78
- cartography/intel/aws/ec2/elastic_ip_addresses.py +41 -13
- cartography/intel/aws/ec2/images.py +49 -20
- cartography/intel/aws/ec2/instances.py +234 -136
- cartography/intel/aws/ec2/internet_gateways.py +40 -11
- cartography/intel/aws/ec2/key_pairs.py +44 -20
- cartography/intel/aws/ec2/launch_templates.py +101 -59
- cartography/intel/aws/ec2/load_balancer_v2s.py +104 -39
- cartography/intel/aws/ec2/load_balancers.py +82 -42
- cartography/intel/aws/ec2/network_acls.py +89 -65
- cartography/intel/aws/ec2/network_interfaces.py +146 -87
- cartography/intel/aws/ec2/reserved_instances.py +45 -16
- cartography/intel/aws/ec2/route_tables.py +138 -98
- cartography/intel/aws/ec2/security_groups.py +71 -21
- cartography/intel/aws/ec2/snapshots.py +61 -22
- cartography/intel/aws/ec2/subnets.py +54 -18
- cartography/intel/aws/ec2/tgw.py +100 -34
- cartography/intel/aws/ec2/util.py +1 -1
- cartography/intel/aws/ec2/volumes.py +69 -41
- cartography/intel/aws/ec2/vpc.py +37 -12
- cartography/intel/aws/ec2/vpc_peerings.py +83 -24
- cartography/intel/aws/ecr.py +88 -32
- cartography/intel/aws/ecs.py +83 -47
- cartography/intel/aws/eks.py +55 -29
- cartography/intel/aws/elasticache.py +42 -18
- cartography/intel/aws/elasticsearch.py +57 -20
- cartography/intel/aws/emr.py +61 -23
- cartography/intel/aws/iam.py +401 -145
- cartography/intel/aws/iam_instance_profiles.py +22 -22
- cartography/intel/aws/identitycenter.py +71 -37
- cartography/intel/aws/inspector.py +159 -89
- cartography/intel/aws/kms.py +92 -38
- cartography/intel/aws/lambda_function.py +103 -34
- cartography/intel/aws/organizations.py +30 -10
- cartography/intel/aws/permission_relationships.py +133 -51
- cartography/intel/aws/rds.py +249 -85
- cartography/intel/aws/redshift.py +107 -46
- cartography/intel/aws/resourcegroupstaggingapi.py +120 -66
- cartography/intel/aws/resources.py +53 -46
- cartography/intel/aws/route53.py +108 -61
- cartography/intel/aws/s3.py +168 -83
- cartography/intel/aws/s3accountpublicaccessblock.py +157 -0
- cartography/intel/aws/secretsmanager.py +24 -12
- cartography/intel/aws/securityhub.py +20 -9
- cartography/intel/aws/sns.py +166 -0
- cartography/intel/aws/sqs.py +60 -28
- cartography/intel/aws/ssm.py +70 -30
- cartography/intel/aws/util/arns.py +7 -7
- cartography/intel/aws/util/common.py +31 -4
- cartography/intel/azure/__init__.py +78 -19
- cartography/intel/azure/compute.py +101 -27
- cartography/intel/azure/cosmosdb.py +496 -170
- cartography/intel/azure/sql.py +296 -105
- cartography/intel/azure/storage.py +322 -113
- cartography/intel/azure/subscription.py +39 -23
- cartography/intel/azure/tenant.py +13 -4
- cartography/intel/azure/util/credentials.py +95 -55
- cartography/intel/bigfix/__init__.py +2 -2
- cartography/intel/bigfix/computers.py +93 -65
- cartography/intel/create_indexes.py +3 -2
- cartography/intel/crowdstrike/__init__.py +11 -9
- cartography/intel/crowdstrike/endpoints.py +5 -1
- cartography/intel/crowdstrike/spotlight.py +8 -3
- cartography/intel/cve/__init__.py +46 -13
- cartography/intel/cve/feed.py +48 -12
- cartography/intel/digitalocean/__init__.py +22 -13
- cartography/intel/digitalocean/compute.py +75 -108
- cartography/intel/digitalocean/management.py +44 -80
- cartography/intel/digitalocean/platform.py +48 -43
- cartography/intel/dns.py +36 -10
- cartography/intel/duo/__init__.py +21 -16
- cartography/intel/duo/api_host.py +14 -9
- cartography/intel/duo/endpoints.py +50 -45
- cartography/intel/duo/groups.py +18 -14
- cartography/intel/duo/phones.py +37 -34
- cartography/intel/duo/tokens.py +26 -23
- cartography/intel/duo/users.py +54 -50
- cartography/intel/duo/web_authn_credentials.py +30 -25
- cartography/intel/entra/__init__.py +25 -7
- cartography/intel/entra/ou.py +112 -0
- cartography/intel/entra/users.py +69 -63
- cartography/intel/gcp/__init__.py +185 -49
- cartography/intel/gcp/compute.py +418 -231
- cartography/intel/gcp/crm.py +96 -43
- cartography/intel/gcp/dns.py +60 -19
- cartography/intel/gcp/gke.py +72 -38
- cartography/intel/gcp/iam.py +61 -41
- cartography/intel/gcp/storage.py +84 -55
- cartography/intel/github/__init__.py +13 -11
- cartography/intel/github/repos.py +270 -137
- cartography/intel/github/teams.py +170 -88
- cartography/intel/github/users.py +70 -39
- cartography/intel/github/util.py +36 -34
- cartography/intel/gsuite/__init__.py +47 -26
- cartography/intel/gsuite/api.py +73 -30
- cartography/intel/jamf/__init__.py +19 -1
- cartography/intel/jamf/computers.py +30 -7
- cartography/intel/jamf/util.py +7 -2
- cartography/intel/kandji/__init__.py +6 -3
- cartography/intel/kandji/devices.py +14 -8
- cartography/intel/kubernetes/namespaces.py +7 -4
- cartography/intel/kubernetes/pods.py +7 -4
- cartography/intel/kubernetes/services.py +8 -4
- cartography/intel/lastpass/__init__.py +2 -2
- cartography/intel/lastpass/users.py +23 -12
- cartography/intel/oci/__init__.py +44 -11
- cartography/intel/oci/iam.py +134 -38
- cartography/intel/oci/organizations.py +13 -6
- cartography/intel/oci/utils.py +43 -20
- cartography/intel/okta/__init__.py +66 -15
- cartography/intel/okta/applications.py +42 -20
- cartography/intel/okta/awssaml.py +93 -33
- cartography/intel/okta/factors.py +16 -4
- cartography/intel/okta/groups.py +56 -29
- cartography/intel/okta/organization.py +5 -1
- cartography/intel/okta/origins.py +6 -2
- cartography/intel/okta/roles.py +15 -5
- cartography/intel/okta/users.py +20 -8
- cartography/intel/okta/utils.py +6 -4
- cartography/intel/pagerduty/__init__.py +8 -7
- cartography/intel/pagerduty/escalation_policies.py +18 -6
- cartography/intel/pagerduty/schedules.py +12 -4
- cartography/intel/pagerduty/services.py +11 -4
- cartography/intel/pagerduty/teams.py +8 -3
- cartography/intel/pagerduty/users.py +3 -1
- cartography/intel/pagerduty/vendors.py +3 -1
- cartography/intel/semgrep/__init__.py +24 -6
- cartography/intel/semgrep/dependencies.py +50 -28
- cartography/intel/semgrep/deployment.py +3 -1
- cartography/intel/semgrep/findings.py +42 -18
- cartography/intel/snipeit/__init__.py +17 -3
- cartography/intel/snipeit/asset.py +12 -6
- cartography/intel/snipeit/user.py +8 -5
- cartography/intel/snipeit/util.py +9 -4
- cartography/models/aws/apigateway.py +21 -17
- cartography/models/aws/apigatewaycertificate.py +28 -22
- cartography/models/aws/apigatewayresource.py +28 -20
- cartography/models/aws/apigatewaystage.py +33 -25
- cartography/models/aws/cloudtrail/__init__.py +0 -0
- cartography/models/aws/cloudtrail/trail.py +61 -0
- cartography/models/aws/dynamodb/gsi.py +30 -22
- cartography/models/aws/dynamodb/tables.py +25 -17
- cartography/models/aws/ec2/auto_scaling_groups.py +102 -82
- cartography/models/aws/ec2/images.py +36 -34
- cartography/models/aws/ec2/instances.py +51 -45
- cartography/models/aws/ec2/keypair.py +21 -16
- cartography/models/aws/ec2/keypair_instance.py +28 -21
- cartography/models/aws/ec2/launch_configurations.py +30 -26
- cartography/models/aws/ec2/launch_template_versions.py +48 -38
- cartography/models/aws/ec2/launch_templates.py +21 -17
- cartography/models/aws/ec2/load_balancer_listeners.py +27 -23
- cartography/models/aws/ec2/load_balancers.py +47 -37
- cartography/models/aws/ec2/network_acl_rules.py +38 -30
- cartography/models/aws/ec2/network_acls.py +38 -29
- cartography/models/aws/ec2/networkinterface_instance.py +52 -39
- cartography/models/aws/ec2/networkinterfaces.py +53 -37
- cartography/models/aws/ec2/privateip_networkinterface.py +32 -22
- cartography/models/aws/ec2/reservations.py +18 -14
- cartography/models/aws/ec2/route_table_associations.py +44 -34
- cartography/models/aws/ec2/route_tables.py +50 -43
- cartography/models/aws/ec2/routes.py +45 -37
- cartography/models/aws/ec2/securitygroup_instance.py +29 -20
- cartography/models/aws/ec2/securitygroup_networkinterface.py +24 -15
- cartography/models/aws/ec2/subnet_instance.py +24 -19
- cartography/models/aws/ec2/subnet_networkinterface.py +40 -31
- cartography/models/aws/ec2/volumes.py +47 -40
- cartography/models/aws/eks/clusters.py +23 -21
- cartography/models/aws/emr.py +32 -30
- cartography/models/aws/iam/instanceprofile.py +33 -24
- cartography/models/aws/identitycenter/awsidentitycenter.py +18 -14
- cartography/models/aws/identitycenter/awspermissionset.py +37 -29
- cartography/models/aws/identitycenter/awsssouser.py +23 -21
- cartography/models/aws/inspector/findings.py +77 -65
- cartography/models/aws/inspector/packages.py +35 -29
- cartography/models/aws/s3/__init__.py +0 -0
- cartography/models/aws/s3/account_public_access_block.py +51 -0
- cartography/models/aws/sns/__init__.py +0 -0
- cartography/models/aws/sns/topic.py +50 -0
- cartography/models/aws/ssm/instance_information.py +51 -39
- cartography/models/aws/ssm/instance_patch.py +32 -26
- cartography/models/bigfix/bigfix_computer.py +42 -38
- cartography/models/bigfix/bigfix_root.py +3 -3
- cartography/models/core/common.py +12 -10
- cartography/models/core/nodes.py +5 -2
- cartography/models/core/relationships.py +14 -6
- cartography/models/crowdstrike/hosts.py +37 -35
- cartography/models/cve/cve.py +34 -32
- cartography/models/cve/cve_feed.py +6 -6
- cartography/models/digitalocean/__init__.py +0 -0
- cartography/models/digitalocean/account.py +21 -0
- cartography/models/digitalocean/droplet.py +56 -0
- cartography/models/digitalocean/project.py +48 -0
- cartography/models/duo/api_host.py +3 -3
- cartography/models/duo/endpoint.py +43 -41
- cartography/models/duo/group.py +14 -14
- cartography/models/duo/phone.py +27 -27
- cartography/models/duo/token.py +16 -16
- cartography/models/duo/user.py +46 -44
- cartography/models/duo/web_authn_credential.py +27 -19
- cartography/models/entra/ou.py +48 -0
- cartography/models/entra/tenant.py +24 -18
- cartography/models/entra/user.py +64 -48
- cartography/models/gcp/iam.py +23 -23
- cartography/models/github/orgs.py +5 -4
- cartography/models/github/teams.py +37 -31
- cartography/models/github/users.py +34 -23
- cartography/models/kandji/device.py +22 -16
- cartography/models/kandji/tenant.py +6 -4
- cartography/models/lastpass/tenant.py +3 -3
- cartography/models/lastpass/user.py +32 -28
- cartography/models/semgrep/dependencies.py +36 -24
- cartography/models/semgrep/deployment.py +5 -5
- cartography/models/semgrep/findings.py +58 -42
- cartography/models/semgrep/locations.py +27 -21
- cartography/models/snipeit/asset.py +30 -21
- cartography/models/snipeit/tenant.py +6 -4
- cartography/models/snipeit/user.py +19 -12
- cartography/stats.py +3 -3
- cartography/sync.py +107 -31
- cartography/util.py +84 -62
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/METADATA +3 -14
- cartography-0.103.0rc1.dist-info/RECORD +396 -0
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/WHEEL +1 -1
- cartography-0.102.0rc2.dist-info/RECORD +0 -381
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/entry_points.txt +0 -0
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/licenses/LICENSE +0 -0
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/top_level.txt +0 -0
cartography/intel/aws/ecs.py
CHANGED
|
@@ -17,12 +17,15 @@ logger = logging.getLogger(__name__)
|
|
|
17
17
|
|
|
18
18
|
@timeit
|
|
19
19
|
@aws_handle_regions
|
|
20
|
-
def get_ecs_cluster_arns(
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
def get_ecs_cluster_arns(
|
|
21
|
+
boto3_session: boto3.session.Session,
|
|
22
|
+
region: str,
|
|
23
|
+
) -> List[str]:
|
|
24
|
+
client = boto3_session.client("ecs", region_name=region)
|
|
25
|
+
paginator = client.get_paginator("list_clusters")
|
|
23
26
|
cluster_arns: List[str] = []
|
|
24
27
|
for page in paginator.paginate():
|
|
25
|
-
cluster_arns.extend(page.get(
|
|
28
|
+
cluster_arns.extend(page.get("clusterArns", []))
|
|
26
29
|
return cluster_arns
|
|
27
30
|
|
|
28
31
|
|
|
@@ -33,15 +36,18 @@ def get_ecs_clusters(
|
|
|
33
36
|
region: str,
|
|
34
37
|
cluster_arns: List[str],
|
|
35
38
|
) -> List[Dict[str, Any]]:
|
|
36
|
-
client = boto3_session.client(
|
|
39
|
+
client = boto3_session.client("ecs", region_name=region)
|
|
37
40
|
# TODO: also include attachment info, and make relationships between the attachements
|
|
38
41
|
# and the cluster.
|
|
39
|
-
includes = [
|
|
42
|
+
includes = ["SETTINGS", "CONFIGURATIONS"]
|
|
40
43
|
clusters: List[Dict[str, Any]] = []
|
|
41
44
|
for i in range(0, len(cluster_arns), 100):
|
|
42
|
-
cluster_arn_chunk = cluster_arns[i:i + 100]
|
|
43
|
-
cluster_chunk = client.describe_clusters(
|
|
44
|
-
|
|
45
|
+
cluster_arn_chunk = cluster_arns[i : i + 100]
|
|
46
|
+
cluster_chunk = client.describe_clusters(
|
|
47
|
+
clusters=cluster_arn_chunk,
|
|
48
|
+
include=includes,
|
|
49
|
+
)
|
|
50
|
+
clusters.extend(cluster_chunk.get("clusters", []))
|
|
45
51
|
return clusters
|
|
46
52
|
|
|
47
53
|
|
|
@@ -52,40 +58,46 @@ def get_ecs_container_instances(
|
|
|
52
58
|
boto3_session: boto3.session.Session,
|
|
53
59
|
region: str,
|
|
54
60
|
) -> List[Dict[str, Any]]:
|
|
55
|
-
client = boto3_session.client(
|
|
56
|
-
paginator = client.get_paginator(
|
|
61
|
+
client = boto3_session.client("ecs", region_name=region)
|
|
62
|
+
paginator = client.get_paginator("list_container_instances")
|
|
57
63
|
container_instances: List[Dict[str, Any]] = []
|
|
58
64
|
container_instance_arns: List[str] = []
|
|
59
65
|
for page in paginator.paginate(cluster=cluster_arn):
|
|
60
|
-
container_instance_arns.extend(page.get(
|
|
61
|
-
includes = [
|
|
66
|
+
container_instance_arns.extend(page.get("containerInstanceArns", []))
|
|
67
|
+
includes = ["CONTAINER_INSTANCE_HEALTH"]
|
|
62
68
|
for i in range(0, len(container_instance_arns), 100):
|
|
63
|
-
container_instance_arn_chunk = container_instance_arns[i:i + 100]
|
|
69
|
+
container_instance_arn_chunk = container_instance_arns[i : i + 100]
|
|
64
70
|
container_instance_chunk = client.describe_container_instances(
|
|
65
71
|
cluster=cluster_arn,
|
|
66
72
|
containerInstances=container_instance_arn_chunk,
|
|
67
73
|
include=includes,
|
|
68
74
|
)
|
|
69
|
-
container_instances.extend(
|
|
75
|
+
container_instances.extend(
|
|
76
|
+
container_instance_chunk.get("containerInstances", []),
|
|
77
|
+
)
|
|
70
78
|
return container_instances
|
|
71
79
|
|
|
72
80
|
|
|
73
81
|
@timeit
|
|
74
82
|
@aws_handle_regions
|
|
75
|
-
def get_ecs_services(
|
|
76
|
-
|
|
77
|
-
|
|
83
|
+
def get_ecs_services(
|
|
84
|
+
cluster_arn: str,
|
|
85
|
+
boto3_session: boto3.session.Session,
|
|
86
|
+
region: str,
|
|
87
|
+
) -> List[Dict[str, Any]]:
|
|
88
|
+
client = boto3_session.client("ecs", region_name=region)
|
|
89
|
+
paginator = client.get_paginator("list_services")
|
|
78
90
|
services: List[Dict[str, Any]] = []
|
|
79
91
|
service_arns: List[str] = []
|
|
80
92
|
for page in paginator.paginate(cluster=cluster_arn):
|
|
81
|
-
service_arns.extend(page.get(
|
|
93
|
+
service_arns.extend(page.get("serviceArns", []))
|
|
82
94
|
for i in range(0, len(service_arns), 10):
|
|
83
|
-
service_arn_chunk = service_arns[i:i + 10]
|
|
95
|
+
service_arn_chunk = service_arns[i : i + 10]
|
|
84
96
|
service_chunk = client.describe_services(
|
|
85
97
|
cluster=cluster_arn,
|
|
86
98
|
services=service_arn_chunk,
|
|
87
99
|
)
|
|
88
|
-
services.extend(service_chunk.get(
|
|
100
|
+
services.extend(service_chunk.get("services", []))
|
|
89
101
|
return services
|
|
90
102
|
|
|
91
103
|
|
|
@@ -96,32 +108,36 @@ def get_ecs_task_definitions(
|
|
|
96
108
|
region: str,
|
|
97
109
|
tasks: List[Dict[str, Any]],
|
|
98
110
|
) -> List[Dict[str, Any]]:
|
|
99
|
-
client = boto3_session.client(
|
|
111
|
+
client = boto3_session.client("ecs", region_name=region)
|
|
100
112
|
task_definitions: List[Dict[str, Any]] = []
|
|
101
113
|
for task in tasks:
|
|
102
114
|
task_definition = client.describe_task_definition(
|
|
103
|
-
taskDefinition=task[
|
|
115
|
+
taskDefinition=task["taskDefinitionArn"],
|
|
104
116
|
)
|
|
105
|
-
task_definitions.append(task_definition[
|
|
117
|
+
task_definitions.append(task_definition["taskDefinition"])
|
|
106
118
|
return task_definitions
|
|
107
119
|
|
|
108
120
|
|
|
109
121
|
@timeit
|
|
110
122
|
@aws_handle_regions
|
|
111
|
-
def get_ecs_tasks(
|
|
112
|
-
|
|
113
|
-
|
|
123
|
+
def get_ecs_tasks(
|
|
124
|
+
cluster_arn: str,
|
|
125
|
+
boto3_session: boto3.session.Session,
|
|
126
|
+
region: str,
|
|
127
|
+
) -> List[Dict[str, Any]]:
|
|
128
|
+
client = boto3_session.client("ecs", region_name=region)
|
|
129
|
+
paginator = client.get_paginator("list_tasks")
|
|
114
130
|
tasks: List[Dict[str, Any]] = []
|
|
115
131
|
task_arns: List[str] = []
|
|
116
132
|
for page in paginator.paginate(cluster=cluster_arn):
|
|
117
|
-
task_arns.extend(page.get(
|
|
133
|
+
task_arns.extend(page.get("taskArns", []))
|
|
118
134
|
for i in range(0, len(task_arns), 100):
|
|
119
|
-
task_arn_chunk = task_arns[i:i + 100]
|
|
135
|
+
task_arn_chunk = task_arns[i : i + 100]
|
|
120
136
|
task_chunk = client.describe_tasks(
|
|
121
137
|
cluster=cluster_arn,
|
|
122
138
|
tasks=task_arn_chunk,
|
|
123
139
|
)
|
|
124
|
-
tasks.extend(task_chunk.get(
|
|
140
|
+
tasks.extend(task_chunk.get("tasks", []))
|
|
125
141
|
return tasks
|
|
126
142
|
|
|
127
143
|
|
|
@@ -207,7 +223,7 @@ def load_ecs_container_instances(
|
|
|
207
223
|
"""
|
|
208
224
|
instances: List[Dict[str, Any]] = []
|
|
209
225
|
for instance in data:
|
|
210
|
-
instance[
|
|
226
|
+
instance["registeredAt"] = dict_date_to_epoch(instance, "registeredAt")
|
|
211
227
|
instances.append(instance)
|
|
212
228
|
|
|
213
229
|
neo4j_session.run(
|
|
@@ -269,7 +285,7 @@ def load_ecs_services(
|
|
|
269
285
|
""" # noqa:E501
|
|
270
286
|
services: List[Dict[str, Any]] = []
|
|
271
287
|
for service in data:
|
|
272
|
-
service[
|
|
288
|
+
service["createdAt"] = dict_date_to_epoch(service, "createdAt")
|
|
273
289
|
services.append(service)
|
|
274
290
|
|
|
275
291
|
neo4j_session.run(
|
|
@@ -331,8 +347,14 @@ def load_ecs_task_definitions(
|
|
|
331
347
|
container_definitions: List[Dict[str, Any]] = []
|
|
332
348
|
task_definitions: List[Dict[str, Any]] = []
|
|
333
349
|
for task_definition in data:
|
|
334
|
-
task_definition[
|
|
335
|
-
|
|
350
|
+
task_definition["registeredAt"] = dict_date_to_epoch(
|
|
351
|
+
task_definition,
|
|
352
|
+
"registeredAt",
|
|
353
|
+
)
|
|
354
|
+
task_definition["deregisteredAt"] = dict_date_to_epoch(
|
|
355
|
+
task_definition,
|
|
356
|
+
"deregisteredAt",
|
|
357
|
+
)
|
|
336
358
|
for container in task_definition.get("containerDefinitions", []):
|
|
337
359
|
container["_taskDefinitionArn"] = task_definition["taskDefinitionArn"]
|
|
338
360
|
container_definitions.append(container)
|
|
@@ -418,14 +440,14 @@ def load_ecs_tasks(
|
|
|
418
440
|
containers: List[Dict[str, Any]] = []
|
|
419
441
|
tasks: List[Dict[str, Any]] = []
|
|
420
442
|
for task in data:
|
|
421
|
-
task[
|
|
422
|
-
task[
|
|
423
|
-
task[
|
|
424
|
-
task[
|
|
425
|
-
task[
|
|
426
|
-
task[
|
|
427
|
-
task[
|
|
428
|
-
task[
|
|
443
|
+
task["connectivityAt"] = dict_date_to_epoch(task, "connectivityAt")
|
|
444
|
+
task["createdAt"] = dict_date_to_epoch(task, "createdAt")
|
|
445
|
+
task["executionStoppedAt"] = dict_date_to_epoch(task, "executionStoppedAt")
|
|
446
|
+
task["pullStartedAt"] = dict_date_to_epoch(task, "pullStartedAt")
|
|
447
|
+
task["pullStoppedAt"] = dict_date_to_epoch(task, "pullStoppedAt")
|
|
448
|
+
task["startedAt"] = dict_date_to_epoch(task, "startedAt")
|
|
449
|
+
task["stoppedAt"] = dict_date_to_epoch(task, "stoppedAt")
|
|
450
|
+
task["stoppingAt"] = dict_date_to_epoch(task, "stoppingAt")
|
|
429
451
|
containers.extend(task["containers"])
|
|
430
452
|
tasks.append(task)
|
|
431
453
|
|
|
@@ -542,21 +564,35 @@ def load_ecs_containers(
|
|
|
542
564
|
|
|
543
565
|
@timeit
|
|
544
566
|
def cleanup_ecs(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
|
|
545
|
-
run_cleanup_job(
|
|
567
|
+
run_cleanup_job("aws_import_ecs_cleanup.json", neo4j_session, common_job_parameters)
|
|
546
568
|
|
|
547
569
|
|
|
548
570
|
@timeit
|
|
549
571
|
def sync(
|
|
550
|
-
neo4j_session: neo4j.Session,
|
|
551
|
-
|
|
572
|
+
neo4j_session: neo4j.Session,
|
|
573
|
+
boto3_session: boto3.session.Session,
|
|
574
|
+
regions: List[str],
|
|
575
|
+
current_aws_account_id: str,
|
|
576
|
+
update_tag: int,
|
|
577
|
+
common_job_parameters: Dict,
|
|
552
578
|
) -> None:
|
|
553
579
|
for region in regions:
|
|
554
|
-
logger.info(
|
|
580
|
+
logger.info(
|
|
581
|
+
"Syncing ECS for region '%s' in account '%s'.",
|
|
582
|
+
region,
|
|
583
|
+
current_aws_account_id,
|
|
584
|
+
)
|
|
555
585
|
cluster_arns = get_ecs_cluster_arns(boto3_session, region)
|
|
556
586
|
clusters = get_ecs_clusters(boto3_session, region, cluster_arns)
|
|
557
587
|
if len(clusters) == 0:
|
|
558
588
|
continue
|
|
559
|
-
load_ecs_clusters(
|
|
589
|
+
load_ecs_clusters(
|
|
590
|
+
neo4j_session,
|
|
591
|
+
clusters,
|
|
592
|
+
region,
|
|
593
|
+
current_aws_account_id,
|
|
594
|
+
update_tag,
|
|
595
|
+
)
|
|
560
596
|
for cluster_arn in cluster_arns:
|
|
561
597
|
cluster_instances = get_ecs_container_instances(
|
|
562
598
|
cluster_arn,
|
cartography/intel/aws/eks.py
CHANGED
|
@@ -18,28 +18,32 @@ logger = logging.getLogger(__name__)
|
|
|
18
18
|
@timeit
|
|
19
19
|
@aws_handle_regions
|
|
20
20
|
def get_eks_clusters(boto3_session: boto3.session.Session, region: str) -> List[str]:
|
|
21
|
-
client = boto3_session.client(
|
|
21
|
+
client = boto3_session.client("eks", region_name=region)
|
|
22
22
|
clusters: List[str] = []
|
|
23
|
-
paginator = client.get_paginator(
|
|
23
|
+
paginator = client.get_paginator("list_clusters")
|
|
24
24
|
for page in paginator.paginate():
|
|
25
|
-
clusters.extend(page[
|
|
25
|
+
clusters.extend(page["clusters"])
|
|
26
26
|
return clusters
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
@timeit
|
|
30
|
-
def get_eks_describe_cluster(
|
|
31
|
-
|
|
30
|
+
def get_eks_describe_cluster(
|
|
31
|
+
boto3_session: boto3.session.Session,
|
|
32
|
+
region: str,
|
|
33
|
+
cluster_name: str,
|
|
34
|
+
) -> Dict:
|
|
35
|
+
client = boto3_session.client("eks", region_name=region)
|
|
32
36
|
response = client.describe_cluster(name=cluster_name)
|
|
33
|
-
return response[
|
|
37
|
+
return response["cluster"]
|
|
34
38
|
|
|
35
39
|
|
|
36
40
|
@timeit
|
|
37
41
|
def load_eks_clusters(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
neo4j_session: neo4j.Session,
|
|
43
|
+
cluster_data: List[Dict[str, Any]],
|
|
44
|
+
region: str,
|
|
45
|
+
current_aws_account_id: str,
|
|
46
|
+
aws_update_tag: int,
|
|
43
47
|
) -> None:
|
|
44
48
|
load(
|
|
45
49
|
neo4j_session,
|
|
@@ -57,50 +61,72 @@ def _process_logging(cluster: Dict) -> bool:
|
|
|
57
61
|
at least one entry has audit logging set to Enabled.
|
|
58
62
|
"""
|
|
59
63
|
logging: bool = False
|
|
60
|
-
cluster_logging: Any = cluster.get(
|
|
64
|
+
cluster_logging: Any = cluster.get("logging", {}).get("clusterLogging")
|
|
61
65
|
if cluster_logging:
|
|
62
|
-
logging = any(filter(lambda x:
|
|
66
|
+
logging = any(filter(lambda x: "audit" in x["types"] and x["enabled"], cluster_logging)) # type: ignore
|
|
63
67
|
return logging
|
|
64
68
|
|
|
65
69
|
|
|
66
70
|
@timeit
|
|
67
|
-
def cleanup(
|
|
71
|
+
def cleanup(
|
|
72
|
+
neo4j_session: neo4j.Session,
|
|
73
|
+
common_job_parameters: Dict[str, Any],
|
|
74
|
+
) -> None:
|
|
68
75
|
logger.info("Running EKS cluster cleanup")
|
|
69
|
-
GraphJob.from_node_schema(EKSClusterSchema(), common_job_parameters).run(
|
|
76
|
+
GraphJob.from_node_schema(EKSClusterSchema(), common_job_parameters).run(
|
|
77
|
+
neo4j_session,
|
|
78
|
+
)
|
|
70
79
|
|
|
71
80
|
|
|
72
81
|
def transform(cluster_data: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
73
82
|
transformed_list = []
|
|
74
83
|
for cluster_name, cluster_dict in cluster_data.items():
|
|
75
84
|
transformed_dict = cluster_dict.copy()
|
|
76
|
-
transformed_dict[
|
|
77
|
-
transformed_dict[
|
|
78
|
-
|
|
85
|
+
transformed_dict["ClusterLogging"] = _process_logging(transformed_dict)
|
|
86
|
+
transformed_dict["ClusterEndpointPublic"] = transformed_dict.get(
|
|
87
|
+
"resourcesVpcConfig",
|
|
88
|
+
{},
|
|
89
|
+
).get(
|
|
90
|
+
"endpointPublicAccess",
|
|
79
91
|
)
|
|
80
|
-
if
|
|
81
|
-
transformed_dict[
|
|
92
|
+
if "createdAt" in transformed_dict:
|
|
93
|
+
transformed_dict["created_at"] = str(transformed_dict["createdAt"])
|
|
82
94
|
transformed_list.append(transformed_dict)
|
|
83
95
|
return transformed_list
|
|
84
96
|
|
|
85
97
|
|
|
86
98
|
@timeit
|
|
87
99
|
def sync(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
100
|
+
neo4j_session: neo4j.Session,
|
|
101
|
+
boto3_session: boto3.session.Session,
|
|
102
|
+
regions: List[str],
|
|
103
|
+
current_aws_account_id: str,
|
|
104
|
+
update_tag: int,
|
|
105
|
+
common_job_parameters: Dict[str, Any],
|
|
94
106
|
) -> None:
|
|
95
107
|
for region in regions:
|
|
96
|
-
logger.info(
|
|
108
|
+
logger.info(
|
|
109
|
+
"Syncing EKS for region '%s' in account '%s'.",
|
|
110
|
+
region,
|
|
111
|
+
current_aws_account_id,
|
|
112
|
+
)
|
|
97
113
|
|
|
98
114
|
clusters: List[str] = get_eks_clusters(boto3_session, region)
|
|
99
115
|
cluster_data = {}
|
|
100
116
|
for cluster_name in clusters:
|
|
101
|
-
cluster_data[cluster_name] = get_eks_describe_cluster(
|
|
117
|
+
cluster_data[cluster_name] = get_eks_describe_cluster(
|
|
118
|
+
boto3_session,
|
|
119
|
+
region,
|
|
120
|
+
cluster_name,
|
|
121
|
+
)
|
|
102
122
|
transformed_list = transform(cluster_data)
|
|
103
123
|
|
|
104
|
-
load_eks_clusters(
|
|
124
|
+
load_eks_clusters(
|
|
125
|
+
neo4j_session,
|
|
126
|
+
transformed_list,
|
|
127
|
+
region,
|
|
128
|
+
current_aws_account_id,
|
|
129
|
+
update_tag,
|
|
130
|
+
)
|
|
105
131
|
|
|
106
132
|
cleanup(neo4j_session, common_job_parameters)
|
|
@@ -17,7 +17,7 @@ stat_handler = get_stats_client(__name__)
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def _get_topic(cluster: Dict) -> Dict:
|
|
20
|
-
return cluster[
|
|
20
|
+
return cluster["NotificationConfiguration"]
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def transform_elasticache_topics(cluster_data: List[Dict]) -> List[Dict]:
|
|
@@ -28,7 +28,7 @@ def transform_elasticache_topics(cluster_data: List[Dict]) -> List[Dict]:
|
|
|
28
28
|
topics: List[Dict] = []
|
|
29
29
|
for cluster in cluster_data:
|
|
30
30
|
topic = _get_topic(cluster)
|
|
31
|
-
topic_arn = topic[
|
|
31
|
+
topic_arn = topic["TopicArn"]
|
|
32
32
|
if topic_arn not in seen:
|
|
33
33
|
seen.add(topic_arn)
|
|
34
34
|
topics.append(topic)
|
|
@@ -37,20 +37,26 @@ def transform_elasticache_topics(cluster_data: List[Dict]) -> List[Dict]:
|
|
|
37
37
|
|
|
38
38
|
@timeit
|
|
39
39
|
@aws_handle_regions
|
|
40
|
-
def get_elasticache_clusters(
|
|
40
|
+
def get_elasticache_clusters(
|
|
41
|
+
boto3_session: boto3.session.Session,
|
|
42
|
+
region: str,
|
|
43
|
+
) -> List[Dict]:
|
|
41
44
|
logger.debug(f"Getting ElastiCache Clusters in region '{region}'.")
|
|
42
|
-
client = boto3_session.client(
|
|
43
|
-
paginator = client.get_paginator(
|
|
45
|
+
client = boto3_session.client("elasticache", region_name=region)
|
|
46
|
+
paginator = client.get_paginator("describe_cache_clusters")
|
|
44
47
|
clusters: List[Dict] = []
|
|
45
48
|
for page in paginator.paginate():
|
|
46
|
-
clusters.extend(page[
|
|
49
|
+
clusters.extend(page["CacheClusters"])
|
|
47
50
|
return clusters
|
|
48
51
|
|
|
49
52
|
|
|
50
53
|
@timeit
|
|
51
54
|
def load_elasticache_clusters(
|
|
52
|
-
neo4j_session: neo4j.Session,
|
|
53
|
-
|
|
55
|
+
neo4j_session: neo4j.Session,
|
|
56
|
+
clusters: List[Dict],
|
|
57
|
+
region: str,
|
|
58
|
+
aws_account_id: str,
|
|
59
|
+
update_tag: int,
|
|
54
60
|
) -> None:
|
|
55
61
|
query = """
|
|
56
62
|
UNWIND $clusters as elasticache_cluster
|
|
@@ -85,7 +91,9 @@ def load_elasticache_clusters(
|
|
|
85
91
|
ON CREATE SET r2.firstseen = timestamp()
|
|
86
92
|
SET r2.lastupdated = $aws_update_tag
|
|
87
93
|
"""
|
|
88
|
-
logger.info(
|
|
94
|
+
logger.info(
|
|
95
|
+
f"Loading f{len(clusters)} ElastiCache clusters for region '{region}' into graph.",
|
|
96
|
+
)
|
|
89
97
|
neo4j_session.run(
|
|
90
98
|
query,
|
|
91
99
|
clusters=clusters,
|
|
@@ -96,29 +104,45 @@ def load_elasticache_clusters(
|
|
|
96
104
|
|
|
97
105
|
|
|
98
106
|
@timeit
|
|
99
|
-
def cleanup(
|
|
107
|
+
def cleanup(
|
|
108
|
+
neo4j_session: neo4j.Session,
|
|
109
|
+
current_aws_account_id: str,
|
|
110
|
+
update_tag: int,
|
|
111
|
+
) -> None:
|
|
100
112
|
run_cleanup_job(
|
|
101
|
-
|
|
113
|
+
"aws_import_elasticache_cleanup.json",
|
|
102
114
|
neo4j_session,
|
|
103
|
-
{
|
|
115
|
+
{"UPDATE_TAG": update_tag, "AWS_ID": current_aws_account_id},
|
|
104
116
|
)
|
|
105
117
|
|
|
106
118
|
|
|
107
119
|
@timeit
|
|
108
120
|
def sync(
|
|
109
|
-
neo4j_session: neo4j.Session,
|
|
110
|
-
|
|
121
|
+
neo4j_session: neo4j.Session,
|
|
122
|
+
boto3_session: boto3.session.Session,
|
|
123
|
+
regions: List[str],
|
|
124
|
+
current_aws_account_id: str,
|
|
125
|
+
update_tag: int,
|
|
126
|
+
common_job_parameters: Dict,
|
|
111
127
|
) -> None:
|
|
112
128
|
for region in regions:
|
|
113
|
-
logger.info(
|
|
129
|
+
logger.info(
|
|
130
|
+
f"Syncing ElastiCache clusters for region '{region}' in account {current_aws_account_id}",
|
|
131
|
+
)
|
|
114
132
|
clusters = get_elasticache_clusters(boto3_session, region)
|
|
115
|
-
load_elasticache_clusters(
|
|
133
|
+
load_elasticache_clusters(
|
|
134
|
+
neo4j_session,
|
|
135
|
+
clusters,
|
|
136
|
+
region,
|
|
137
|
+
current_aws_account_id,
|
|
138
|
+
update_tag,
|
|
139
|
+
)
|
|
116
140
|
cleanup(neo4j_session, current_aws_account_id, update_tag)
|
|
117
141
|
merge_module_sync_metadata(
|
|
118
142
|
neo4j_session,
|
|
119
|
-
group_type=
|
|
143
|
+
group_type="AWSAccount",
|
|
120
144
|
group_id=current_aws_account_id,
|
|
121
|
-
synced_type=
|
|
145
|
+
synced_type="ElasticacheCluster",
|
|
122
146
|
update_tag=update_tag,
|
|
123
147
|
stat_handler=stat_handler,
|
|
124
148
|
)
|
|
@@ -20,7 +20,7 @@ logger = logging.getLogger(__name__)
|
|
|
20
20
|
def _get_botocore_config() -> botocore.config.Config:
|
|
21
21
|
return botocore.config.Config(
|
|
22
22
|
retries={
|
|
23
|
-
|
|
23
|
+
"max_attempts": 8,
|
|
24
24
|
},
|
|
25
25
|
)
|
|
26
26
|
|
|
@@ -35,19 +35,26 @@ def _get_es_domains(client: botocore.client.BaseClient) -> List[Dict]:
|
|
|
35
35
|
:return: list of ES domains
|
|
36
36
|
"""
|
|
37
37
|
data = client.list_domain_names()
|
|
38
|
-
domain_names = [d[
|
|
38
|
+
domain_names = [d["DomainName"] for d in data.get("DomainNames", [])]
|
|
39
39
|
# NOTE describe_elasticsearch_domains takes at most 5 domain names
|
|
40
|
-
domain_name_chunks = [
|
|
40
|
+
domain_name_chunks = [
|
|
41
|
+
domain_names[i : i + 5] for i in range(0, len(domain_names), 5)
|
|
42
|
+
]
|
|
41
43
|
domains: List[Dict] = []
|
|
42
44
|
for domain_name_chunk in domain_name_chunks:
|
|
43
|
-
chunk_data = client.describe_elasticsearch_domains(
|
|
44
|
-
|
|
45
|
+
chunk_data = client.describe_elasticsearch_domains(
|
|
46
|
+
DomainNames=domain_name_chunk,
|
|
47
|
+
)
|
|
48
|
+
domains.extend(chunk_data["DomainStatusList"])
|
|
45
49
|
return domains
|
|
46
50
|
|
|
47
51
|
|
|
48
52
|
@timeit
|
|
49
53
|
def _load_es_domains(
|
|
50
|
-
neo4j_session: neo4j.Session,
|
|
54
|
+
neo4j_session: neo4j.Session,
|
|
55
|
+
domain_list: List[Dict],
|
|
56
|
+
aws_account_id: str,
|
|
57
|
+
aws_update_tag: int,
|
|
51
58
|
) -> None:
|
|
52
59
|
"""
|
|
53
60
|
Ingest Elastic Search domains
|
|
@@ -86,7 +93,7 @@ def _load_es_domains(
|
|
|
86
93
|
# TODO this is a hacky workaround -- neo4j doesn't accept datetime objects and this section of the object
|
|
87
94
|
# TODO contains one. we really shouldn't be sending the entire object to neo4j
|
|
88
95
|
for d in domain_list:
|
|
89
|
-
del d[
|
|
96
|
+
del d["ServiceSoftwareOptions"]
|
|
90
97
|
|
|
91
98
|
neo4j_session.run(
|
|
92
99
|
ingest_records,
|
|
@@ -104,7 +111,10 @@ def _load_es_domains(
|
|
|
104
111
|
|
|
105
112
|
@timeit
|
|
106
113
|
def _link_es_domains_to_dns(
|
|
107
|
-
neo4j_session: neo4j.Session,
|
|
114
|
+
neo4j_session: neo4j.Session,
|
|
115
|
+
domain_id: str,
|
|
116
|
+
domain_data: Dict,
|
|
117
|
+
aws_update_tag: int,
|
|
108
118
|
) -> None:
|
|
109
119
|
"""
|
|
110
120
|
Link the ES domain to its DNS FQDN endpoint and create associated nodes in the graph
|
|
@@ -117,15 +127,24 @@ def _link_es_domains_to_dns(
|
|
|
117
127
|
# TODO add support for endpoints to this method
|
|
118
128
|
if domain_data.get("Endpoint"):
|
|
119
129
|
ingest_dns_record_by_fqdn(
|
|
120
|
-
neo4j_session,
|
|
121
|
-
|
|
130
|
+
neo4j_session,
|
|
131
|
+
aws_update_tag,
|
|
132
|
+
domain_data["Endpoint"],
|
|
133
|
+
domain_id,
|
|
134
|
+
record_label="ESDomain",
|
|
135
|
+
dns_node_additional_label="AWSDNSRecord",
|
|
122
136
|
)
|
|
123
137
|
else:
|
|
124
138
|
logger.debug(f"No es endpoint data for domain id {domain_id}")
|
|
125
139
|
|
|
126
140
|
|
|
127
141
|
@timeit
|
|
128
|
-
def _link_es_domain_vpc(
|
|
142
|
+
def _link_es_domain_vpc(
|
|
143
|
+
neo4j_session: neo4j.Session,
|
|
144
|
+
domain_id: str,
|
|
145
|
+
domain_data: Dict,
|
|
146
|
+
aws_update_tag: int,
|
|
147
|
+
) -> None:
|
|
129
148
|
"""
|
|
130
149
|
Link the ES domain to its DNS FQDN endpoint and create associated nodes in the graph
|
|
131
150
|
if needed
|
|
@@ -177,7 +196,11 @@ def _link_es_domain_vpc(neo4j_session: neo4j.Session, domain_id: str, domain_dat
|
|
|
177
196
|
|
|
178
197
|
|
|
179
198
|
@timeit
|
|
180
|
-
def _process_access_policy(
|
|
199
|
+
def _process_access_policy(
|
|
200
|
+
neo4j_session: neo4j.Session,
|
|
201
|
+
domain_id: str,
|
|
202
|
+
domain_data: Dict,
|
|
203
|
+
) -> None:
|
|
181
204
|
"""
|
|
182
205
|
Link the ES domain to its DNS FQDN endpoint and create associated nodes in the graph
|
|
183
206
|
if needed
|
|
@@ -186,12 +209,14 @@ def _process_access_policy(neo4j_session: neo4j.Session, domain_id: str, domain_
|
|
|
186
209
|
:param domain_id: ES domain id
|
|
187
210
|
:param domain_data: domain data
|
|
188
211
|
"""
|
|
189
|
-
tag_es =
|
|
212
|
+
tag_es = (
|
|
213
|
+
"MATCH (es:ESDomain{id: $DomainId}) SET es.exposed_internet = $InternetExposed"
|
|
214
|
+
)
|
|
190
215
|
|
|
191
216
|
exposed_internet = False
|
|
192
217
|
|
|
193
218
|
if domain_data.get("Endpoint") and domain_data.get("AccessPolicies"):
|
|
194
|
-
policy = Policy(json.loads(domain_data[
|
|
219
|
+
policy = Policy(json.loads(domain_data["AccessPolicies"]))
|
|
195
220
|
if policy.is_internet_accessible():
|
|
196
221
|
exposed_internet = True
|
|
197
222
|
|
|
@@ -201,20 +226,32 @@ def _process_access_policy(neo4j_session: neo4j.Session, domain_id: str, domain_
|
|
|
201
226
|
@timeit
|
|
202
227
|
def cleanup(neo4j_session: neo4j.Session, update_tag: int, aws_account_id: int) -> None:
|
|
203
228
|
run_cleanup_job(
|
|
204
|
-
|
|
229
|
+
"aws_import_es_cleanup.json",
|
|
205
230
|
neo4j_session,
|
|
206
|
-
{
|
|
231
|
+
{"UPDATE_TAG": update_tag, "AWS_ID": aws_account_id},
|
|
207
232
|
)
|
|
208
233
|
|
|
209
234
|
|
|
210
235
|
@timeit
|
|
211
236
|
def sync(
|
|
212
|
-
neo4j_session: neo4j.Session,
|
|
213
|
-
|
|
237
|
+
neo4j_session: neo4j.Session,
|
|
238
|
+
boto3_session: boto3.session.Session,
|
|
239
|
+
regions: List[str],
|
|
240
|
+
current_aws_account_id: str,
|
|
241
|
+
update_tag: int,
|
|
242
|
+
common_job_parameters: Dict,
|
|
214
243
|
) -> None:
|
|
215
244
|
for region in regions:
|
|
216
|
-
logger.info(
|
|
217
|
-
|
|
245
|
+
logger.info(
|
|
246
|
+
"Syncing Elasticsearch Service for region '%s' in account '%s'.",
|
|
247
|
+
region,
|
|
248
|
+
current_aws_account_id,
|
|
249
|
+
)
|
|
250
|
+
client = boto3_session.client(
|
|
251
|
+
"es",
|
|
252
|
+
region_name=region,
|
|
253
|
+
config=_get_botocore_config(),
|
|
254
|
+
)
|
|
218
255
|
data = _get_es_domains(client)
|
|
219
256
|
_load_es_domains(neo4j_session, data, current_aws_account_id, update_tag)
|
|
220
257
|
|