cartography 0.99.0rc1__py3-none-any.whl → 0.100.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/_version.py +2 -2
- cartography/intel/aws/apigateway.py +140 -177
- cartography/intel/aws/ec2/images.py +31 -43
- cartography/models/aws/apigateway.py +47 -0
- cartography/models/aws/apigatewaycertificate.py +66 -0
- cartography/models/aws/apigatewayresource.py +62 -0
- cartography/models/aws/apigatewaystage.py +67 -0
- {cartography-0.99.0rc1.dist-info → cartography-0.100.0rc1.dist-info}/METADATA +10 -4
- {cartography-0.99.0rc1.dist-info → cartography-0.100.0rc1.dist-info}/RECORD +13 -11
- cartography/data/jobs/cleanup/aws_apigateway_details.json +0 -10
- cartography/data/jobs/cleanup/aws_import_apigateway_cleanup.json +0 -45
- {cartography-0.99.0rc1.dist-info → cartography-0.100.0rc1.dist-info}/LICENSE +0 -0
- {cartography-0.99.0rc1.dist-info → cartography-0.100.0rc1.dist-info}/WHEEL +0 -0
- {cartography-0.99.0rc1.dist-info → cartography-0.100.0rc1.dist-info}/entry_points.txt +0 -0
- {cartography-0.99.0rc1.dist-info → cartography-0.100.0rc1.dist-info}/top_level.txt +0 -0
cartography/_version.py
CHANGED
|
@@ -12,5 +12,5 @@ __version__: str
|
|
|
12
12
|
__version_tuple__: VERSION_TUPLE
|
|
13
13
|
version_tuple: VERSION_TUPLE
|
|
14
14
|
|
|
15
|
-
__version__ = version = '0.
|
|
16
|
-
__version_tuple__ = version_tuple = (0,
|
|
15
|
+
__version__ = version = '0.100.0rc1'
|
|
16
|
+
__version_tuple__ = version_tuple = (0, 100, 0)
|
|
@@ -12,8 +12,13 @@ import neo4j
|
|
|
12
12
|
from botocore.exceptions import ClientError
|
|
13
13
|
from policyuniverse.policy import Policy
|
|
14
14
|
|
|
15
|
+
from cartography.client.core.tx import load
|
|
16
|
+
from cartography.graph.job import GraphJob
|
|
17
|
+
from cartography.models.aws.apigateway import APIGatewayRestAPISchema
|
|
18
|
+
from cartography.models.aws.apigatewaycertificate import APIGatewayClientCertificateSchema
|
|
19
|
+
from cartography.models.aws.apigatewayresource import APIGatewayResourceSchema
|
|
20
|
+
from cartography.models.aws.apigatewaystage import APIGatewayStageSchema
|
|
15
21
|
from cartography.util import aws_handle_regions
|
|
16
|
-
from cartography.util import run_cleanup_job
|
|
17
22
|
from cartography.util import timeit
|
|
18
23
|
|
|
19
24
|
logger = logging.getLogger(__name__)
|
|
@@ -107,222 +112,146 @@ def get_rest_api_policy(api: Dict, client: botocore.client.BaseClient) -> Any:
|
|
|
107
112
|
return policy
|
|
108
113
|
|
|
109
114
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
aws_update_tag: int,
|
|
114
|
-
) -> None:
|
|
115
|
-
"""
|
|
116
|
-
Ingest the details of API Gateway REST APIs into neo4j.
|
|
115
|
+
def transform_apigateway_rest_apis(
|
|
116
|
+
rest_apis: List[Dict], resource_policies: List[Dict], region: str, current_aws_account_id: str, aws_update_tag: int,
|
|
117
|
+
) -> List[Dict]:
|
|
117
118
|
"""
|
|
118
|
-
|
|
119
|
-
UNWIND $rest_apis_list AS r
|
|
120
|
-
MERGE (rest_api:APIGatewayRestAPI{id:r.id})
|
|
121
|
-
ON CREATE SET rest_api.firstseen = timestamp(),
|
|
122
|
-
rest_api.createddate = r.createdDate
|
|
123
|
-
SET rest_api.version = r.version,
|
|
124
|
-
rest_api.minimumcompressionsize = r.minimumCompressionSize,
|
|
125
|
-
rest_api.disableexecuteapiendpoint = r.disableExecuteApiEndpoint,
|
|
126
|
-
rest_api.lastupdated = $aws_update_tag,
|
|
127
|
-
rest_api.region = $Region
|
|
128
|
-
WITH rest_api
|
|
129
|
-
MATCH (aa:AWSAccount{id: $AWS_ACCOUNT_ID})
|
|
130
|
-
MERGE (aa)-[r:RESOURCE]->(rest_api)
|
|
131
|
-
ON CREATE SET r.firstseen = timestamp()
|
|
132
|
-
SET r.lastupdated = $aws_update_tag
|
|
119
|
+
Transform API Gateway REST API data for ingestion, including policy analysis
|
|
133
120
|
"""
|
|
121
|
+
# Create a mapping of api_id to policy data for easier lookup
|
|
122
|
+
policy_map = {
|
|
123
|
+
policy['api_id']: policy
|
|
124
|
+
for policy in resource_policies
|
|
125
|
+
}
|
|
134
126
|
|
|
135
|
-
|
|
136
|
-
# these values to string.
|
|
127
|
+
transformed_apis = []
|
|
137
128
|
for api in rest_apis:
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
129
|
+
policy_data = policy_map.get(api['id'], {})
|
|
130
|
+
transformed_api = {
|
|
131
|
+
'id': api['id'],
|
|
132
|
+
'createdDate': str(api['createdDate']) if 'createdDate' in api else None,
|
|
133
|
+
'version': api.get('version'),
|
|
134
|
+
'minimumCompressionSize': api.get('minimumCompressionSize'),
|
|
135
|
+
'disableExecuteApiEndpoint': api.get('disableExecuteApiEndpoint'),
|
|
136
|
+
# Set defaults in the transform function
|
|
137
|
+
'anonymous_access': policy_data.get('internet_accessible', False),
|
|
138
|
+
'anonymous_actions': policy_data.get('accessible_actions', []),
|
|
139
|
+
# TODO Issue #1452: clarify internet exposure vs anonymous access
|
|
140
|
+
}
|
|
141
|
+
transformed_apis.append(transformed_api)
|
|
142
|
+
|
|
143
|
+
return transformed_apis
|
|
147
144
|
|
|
148
145
|
|
|
149
146
|
@timeit
|
|
150
|
-
def
|
|
151
|
-
|
|
147
|
+
def load_apigateway_rest_apis(
|
|
148
|
+
neo4j_session: neo4j.Session, data: List[Dict], region: str, current_aws_account_id: str,
|
|
149
|
+
aws_update_tag: int,
|
|
152
150
|
) -> None:
|
|
153
151
|
"""
|
|
154
|
-
Ingest API Gateway REST API
|
|
155
|
-
"""
|
|
156
|
-
ingest_policies = """
|
|
157
|
-
UNWIND $policies as policy
|
|
158
|
-
MATCH (r:APIGatewayRestAPI) where r.name = policy.api_id
|
|
159
|
-
SET r.anonymous_access = (coalesce(r.anonymous_access, false) OR policy.internet_accessible),
|
|
160
|
-
r.anonymous_actions = coalesce(r.anonymous_actions, []) + policy.accessible_actions,
|
|
161
|
-
r.lastupdated = $UpdateTag
|
|
152
|
+
Ingest API Gateway REST API data into neo4j.
|
|
162
153
|
"""
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
def _set_default_values(neo4j_session: neo4j.Session, aws_account_id: str) -> None:
|
|
172
|
-
set_defaults = """
|
|
173
|
-
MATCH (:AWSAccount{id: $AWS_ID})-[:RESOURCE]->(restApi:APIGatewayRestAPI)
|
|
174
|
-
where restApi.anonymous_actions IS NULL
|
|
175
|
-
SET restApi.anonymous_access = false, restApi.anonymous_actions = []
|
|
176
|
-
"""
|
|
177
|
-
|
|
178
|
-
neo4j_session.run(
|
|
179
|
-
set_defaults,
|
|
180
|
-
AWS_ID=aws_account_id,
|
|
154
|
+
load(
|
|
155
|
+
neo4j_session,
|
|
156
|
+
APIGatewayRestAPISchema(),
|
|
157
|
+
data,
|
|
158
|
+
region=region,
|
|
159
|
+
lastupdated=aws_update_tag,
|
|
160
|
+
AWS_ID=current_aws_account_id,
|
|
181
161
|
)
|
|
182
162
|
|
|
183
163
|
|
|
184
|
-
|
|
185
|
-
def _load_apigateway_stages(
|
|
186
|
-
neo4j_session: neo4j.Session, stages: List, update_tag: int,
|
|
187
|
-
) -> None:
|
|
164
|
+
def transform_apigateway_stages(stages: List[Dict], update_tag: int) -> List[Dict]:
|
|
188
165
|
"""
|
|
189
|
-
|
|
166
|
+
Transform API Gateway Stage data for ingestion
|
|
190
167
|
"""
|
|
191
|
-
|
|
192
|
-
UNWIND $stages_list AS stage
|
|
193
|
-
MERGE (s:APIGatewayStage{id: stage.arn})
|
|
194
|
-
ON CREATE SET s.firstseen = timestamp(), s.stagename = stage.stageName,
|
|
195
|
-
s.createddate = stage.createdDate
|
|
196
|
-
SET s.deploymentid = stage.deploymentId,
|
|
197
|
-
s.clientcertificateid = stage.clientCertificateId,
|
|
198
|
-
s.cacheclusterenabled = stage.cacheClusterEnabled,
|
|
199
|
-
s.cacheclusterstatus = stage.cacheClusterStatus,
|
|
200
|
-
s.tracingenabled = stage.tracingEnabled,
|
|
201
|
-
s.webaclarn = stage.webAclArn,
|
|
202
|
-
s.lastupdated = $UpdateTag
|
|
203
|
-
WITH s, stage
|
|
204
|
-
MATCH (rest_api:APIGatewayRestAPI{id: stage.apiId})
|
|
205
|
-
MERGE (rest_api)-[r:ASSOCIATED_WITH]->(s)
|
|
206
|
-
ON CREATE SET r.firstseen = timestamp()
|
|
207
|
-
SET r.lastupdated = $UpdateTag
|
|
208
|
-
"""
|
|
209
|
-
|
|
210
|
-
# neo4j does not accept datetime objects and values. This loop is used to convert
|
|
211
|
-
# these values to string.
|
|
168
|
+
stage_data = []
|
|
212
169
|
for stage in stages:
|
|
213
170
|
stage['createdDate'] = str(stage['createdDate'])
|
|
214
|
-
stage['arn'] = "arn:aws:apigateway:::
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
ingest_stages,
|
|
218
|
-
stages_list=stages,
|
|
219
|
-
UpdateTag=update_tag,
|
|
220
|
-
)
|
|
171
|
+
stage['arn'] = f"arn:aws:apigateway:::{stage['apiId']}/{stage['stageName']}"
|
|
172
|
+
stage_data.append(stage)
|
|
173
|
+
return stage_data
|
|
221
174
|
|
|
222
175
|
|
|
223
|
-
|
|
224
|
-
def _load_apigateway_certificates(
|
|
225
|
-
neo4j_session: neo4j.Session, certificates: List, update_tag: int,
|
|
226
|
-
) -> None:
|
|
227
|
-
"""
|
|
228
|
-
Ingest the API Gateway Client Certificate details into neo4j.
|
|
176
|
+
def transform_apigateway_certificates(certificates: List[Dict], update_tag: int) -> List[Dict]:
|
|
229
177
|
"""
|
|
230
|
-
|
|
231
|
-
UNWIND $certificates_list as certificate
|
|
232
|
-
MERGE (c:APIGatewayClientCertificate{id: certificate.clientCertificateId})
|
|
233
|
-
ON CREATE SET c.firstseen = timestamp(), c.createddate = certificate.createdDate
|
|
234
|
-
SET c.lastupdated = $UpdateTag, c.expirationdate = certificate.expirationDate
|
|
235
|
-
WITH c, certificate
|
|
236
|
-
MATCH (stage:APIGatewayStage{id: certificate.stageArn})
|
|
237
|
-
MERGE (stage)-[r:HAS_CERTIFICATE]->(c)
|
|
238
|
-
ON CREATE SET r.firstseen = timestamp()
|
|
239
|
-
SET r.lastupdated = $UpdateTag
|
|
178
|
+
Transform API Gateway Client Certificate data for ingestion
|
|
240
179
|
"""
|
|
241
|
-
|
|
242
|
-
# neo4j does not accept datetime objects and values. This loop is used to convert
|
|
243
|
-
# these values to string.
|
|
180
|
+
cert_data = []
|
|
244
181
|
for certificate in certificates:
|
|
245
182
|
certificate['createdDate'] = str(certificate['createdDate'])
|
|
246
183
|
certificate['expirationDate'] = str(certificate.get('expirationDate'))
|
|
247
|
-
certificate['stageArn'] = "arn:aws:apigateway:::
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
ingest_certificates,
|
|
251
|
-
certificates_list=certificates,
|
|
252
|
-
UpdateTag=update_tag,
|
|
253
|
-
)
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
@timeit
|
|
257
|
-
def _load_apigateway_resources(
|
|
258
|
-
neo4j_session: neo4j.Session, resources: List, update_tag: int,
|
|
259
|
-
) -> None:
|
|
260
|
-
"""
|
|
261
|
-
Ingest the API Gateway Resource details into neo4j.
|
|
262
|
-
"""
|
|
263
|
-
ingest_resources = """
|
|
264
|
-
UNWIND $resources_list AS res
|
|
265
|
-
MERGE (s:APIGatewayResource{id: res.id})
|
|
266
|
-
ON CREATE SET s.firstseen = timestamp()
|
|
267
|
-
SET s.path = res.path,
|
|
268
|
-
s.pathpart = res.pathPart,
|
|
269
|
-
s.parentid = res.parentId,
|
|
270
|
-
s.lastupdated =$UpdateTag
|
|
271
|
-
WITH s, res
|
|
272
|
-
MATCH (rest_api:APIGatewayRestAPI{id: res.apiId})
|
|
273
|
-
MERGE (rest_api)-[r:RESOURCE]->(s)
|
|
274
|
-
ON CREATE SET r.firstseen = timestamp()
|
|
275
|
-
SET r.lastupdated = $UpdateTag
|
|
276
|
-
"""
|
|
277
|
-
|
|
278
|
-
neo4j_session.run(
|
|
279
|
-
ingest_resources,
|
|
280
|
-
resources_list=resources,
|
|
281
|
-
UpdateTag=update_tag,
|
|
282
|
-
)
|
|
184
|
+
certificate['stageArn'] = f"arn:aws:apigateway:::{certificate['apiId']}/{certificate['stageName']}"
|
|
185
|
+
cert_data.append(certificate)
|
|
186
|
+
return cert_data
|
|
283
187
|
|
|
284
188
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
aws_account_id: str, update_tag: int,
|
|
289
|
-
) -> None:
|
|
189
|
+
def transform_rest_api_details(
|
|
190
|
+
stages_certificate_resources: List[Tuple[Any, Any, Any, Any, Any]],
|
|
191
|
+
) -> Tuple[List[Dict], List[Dict], List[Dict]]:
|
|
290
192
|
"""
|
|
291
|
-
|
|
292
|
-
so we can import them in a single query
|
|
193
|
+
Transform Stage, Client Certificate, and Resource data for ingestion
|
|
293
194
|
"""
|
|
294
195
|
stages: List[Dict] = []
|
|
295
196
|
certificates: List[Dict] = []
|
|
296
197
|
resources: List[Dict] = []
|
|
297
|
-
|
|
298
|
-
for api_id, stage, certificate, resource,
|
|
299
|
-
parsed_policy = parse_policy(api_id, policy)
|
|
300
|
-
if parsed_policy is not None:
|
|
301
|
-
policies.append(parsed_policy)
|
|
198
|
+
|
|
199
|
+
for api_id, stage, certificate, resource, _ in stages_certificate_resources:
|
|
302
200
|
if len(stage) > 0:
|
|
303
201
|
for s in stage:
|
|
304
202
|
s['apiId'] = api_id
|
|
203
|
+
s['createdDate'] = str(s['createdDate'])
|
|
204
|
+
s['arn'] = f"arn:aws:apigateway:::{api_id}/{s['stageName']}"
|
|
305
205
|
stages.extend(stage)
|
|
206
|
+
|
|
207
|
+
if certificate:
|
|
208
|
+
certificate['apiId'] = api_id
|
|
209
|
+
certificate['createdDate'] = str(certificate['createdDate'])
|
|
210
|
+
certificate['expirationDate'] = str(certificate.get('expirationDate'))
|
|
211
|
+
certificate['stageArn'] = f"arn:aws:apigateway:::{api_id}/{certificate['stageName']}"
|
|
212
|
+
certificates.append(certificate)
|
|
213
|
+
|
|
306
214
|
if len(resource) > 0:
|
|
307
215
|
for r in resource:
|
|
308
216
|
r['apiId'] = api_id
|
|
309
217
|
resources.extend(resource)
|
|
310
|
-
if certificate:
|
|
311
|
-
certificate['apiId'] = api_id
|
|
312
|
-
certificates.append(certificate)
|
|
313
218
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
219
|
+
return stages, certificates, resources
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@timeit
|
|
223
|
+
def load_rest_api_details(
|
|
224
|
+
neo4j_session: neo4j.Session, stages_certificate_resources: List[Tuple[Any, Any, Any, Any, Any]],
|
|
225
|
+
aws_account_id: str, update_tag: int,
|
|
226
|
+
) -> None:
|
|
227
|
+
"""
|
|
228
|
+
Transform and load Stage, Client Certificate, and Resource data
|
|
229
|
+
"""
|
|
230
|
+
stages, certificates, resources = transform_rest_api_details(stages_certificate_resources)
|
|
231
|
+
|
|
232
|
+
load(
|
|
317
233
|
neo4j_session,
|
|
318
|
-
|
|
234
|
+
APIGatewayStageSchema(),
|
|
235
|
+
stages,
|
|
236
|
+
lastupdated=update_tag,
|
|
237
|
+
AWS_ID=aws_account_id,
|
|
319
238
|
)
|
|
320
239
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
240
|
+
load(
|
|
241
|
+
neo4j_session,
|
|
242
|
+
APIGatewayClientCertificateSchema(),
|
|
243
|
+
certificates,
|
|
244
|
+
lastupdated=update_tag,
|
|
245
|
+
AWS_ID=aws_account_id,
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
load(
|
|
249
|
+
neo4j_session,
|
|
250
|
+
APIGatewayResourceSchema(),
|
|
251
|
+
resources,
|
|
252
|
+
lastupdated=update_tag,
|
|
253
|
+
AWS_ID=aws_account_id,
|
|
254
|
+
)
|
|
326
255
|
|
|
327
256
|
|
|
328
257
|
@timeit
|
|
@@ -353,7 +282,27 @@ def parse_policy(api_id: str, policy: Policy) -> Optional[Dict[Any, Any]]:
|
|
|
353
282
|
|
|
354
283
|
@timeit
|
|
355
284
|
def cleanup(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
|
|
356
|
-
|
|
285
|
+
"""
|
|
286
|
+
Delete out-of-date API Gateway resources and relationships.
|
|
287
|
+
Order matters - clean up certificates, stages, and resources before cleaning up the REST APIs they connect to.
|
|
288
|
+
"""
|
|
289
|
+
logger.info("Running API Gateway cleanup job.")
|
|
290
|
+
|
|
291
|
+
# Clean up certificates first
|
|
292
|
+
cleanup_job = GraphJob.from_node_schema(APIGatewayClientCertificateSchema(), common_job_parameters)
|
|
293
|
+
cleanup_job.run(neo4j_session)
|
|
294
|
+
|
|
295
|
+
# Then stages
|
|
296
|
+
cleanup_job = GraphJob.from_node_schema(APIGatewayStageSchema(), common_job_parameters)
|
|
297
|
+
cleanup_job.run(neo4j_session)
|
|
298
|
+
|
|
299
|
+
# Then resources
|
|
300
|
+
cleanup_job = GraphJob.from_node_schema(APIGatewayResourceSchema(), common_job_parameters)
|
|
301
|
+
cleanup_job.run(neo4j_session)
|
|
302
|
+
|
|
303
|
+
# Finally REST APIs
|
|
304
|
+
cleanup_job = GraphJob.from_node_schema(APIGatewayRestAPISchema(), common_job_parameters)
|
|
305
|
+
cleanup_job.run(neo4j_session)
|
|
357
306
|
|
|
358
307
|
|
|
359
308
|
@timeit
|
|
@@ -362,9 +311,23 @@ def sync_apigateway_rest_apis(
|
|
|
362
311
|
aws_update_tag: int,
|
|
363
312
|
) -> None:
|
|
364
313
|
rest_apis = get_apigateway_rest_apis(boto3_session, region)
|
|
365
|
-
load_apigateway_rest_apis(neo4j_session, rest_apis, region, current_aws_account_id, aws_update_tag)
|
|
366
|
-
|
|
367
314
|
stages_certificate_resources = get_rest_api_details(boto3_session, rest_apis, region)
|
|
315
|
+
|
|
316
|
+
# Extract policies and transform the data
|
|
317
|
+
policies = []
|
|
318
|
+
for api_id, _, _, _, policy in stages_certificate_resources:
|
|
319
|
+
parsed_policy = parse_policy(api_id, policy)
|
|
320
|
+
if parsed_policy is not None:
|
|
321
|
+
policies.append(parsed_policy)
|
|
322
|
+
|
|
323
|
+
transformed_apis = transform_apigateway_rest_apis(
|
|
324
|
+
rest_apis,
|
|
325
|
+
policies,
|
|
326
|
+
region,
|
|
327
|
+
current_aws_account_id,
|
|
328
|
+
aws_update_tag,
|
|
329
|
+
)
|
|
330
|
+
load_apigateway_rest_apis(neo4j_session, transformed_apis, region, current_aws_account_id, aws_update_tag)
|
|
368
331
|
load_rest_api_details(neo4j_session, stages_certificate_resources, current_aws_account_id, aws_update_tag)
|
|
369
332
|
|
|
370
333
|
|
|
@@ -8,8 +8,8 @@ import neo4j
|
|
|
8
8
|
from botocore.exceptions import ClientError
|
|
9
9
|
|
|
10
10
|
from cartography.client.core.tx import load
|
|
11
|
+
from cartography.client.core.tx import read_list_of_values_tx
|
|
11
12
|
from cartography.graph.job import GraphJob
|
|
12
|
-
from cartography.intel.aws.ec2 import get_ec2_regions
|
|
13
13
|
from cartography.intel.aws.ec2.util import get_botocore_config
|
|
14
14
|
from cartography.models.aws.ec2.images import EC2ImageSchema
|
|
15
15
|
from cartography.util import aws_handle_regions
|
|
@@ -21,22 +21,26 @@ logger = logging.getLogger(__name__)
|
|
|
21
21
|
@timeit
|
|
22
22
|
def get_images_in_use(neo4j_session: neo4j.Session, region: str, current_aws_account_id: str) -> List[str]:
|
|
23
23
|
get_images_query = """
|
|
24
|
+
CALL {
|
|
24
25
|
MATCH (:AWSAccount{id: $AWS_ACCOUNT_ID})-[:RESOURCE]->(i:EC2Instance)
|
|
25
|
-
WHERE i.region = $Region
|
|
26
|
-
RETURN
|
|
27
|
-
UNION
|
|
26
|
+
WHERE i.region = $Region AND i.imageid IS NOT NULL
|
|
27
|
+
RETURN i.imageid AS image
|
|
28
|
+
UNION ALL
|
|
28
29
|
MATCH (:AWSAccount{id: $AWS_ACCOUNT_ID})-[:RESOURCE]->(lc:LaunchConfiguration)
|
|
29
|
-
WHERE lc.region = $Region
|
|
30
|
-
RETURN
|
|
31
|
-
UNION
|
|
30
|
+
WHERE lc.region = $Region AND lc.image_id IS NOT NULL
|
|
31
|
+
RETURN lc.image_id AS image
|
|
32
|
+
UNION ALL
|
|
32
33
|
MATCH (:AWSAccount{id: $AWS_ACCOUNT_ID})-[:RESOURCE]->(ltv:LaunchTemplateVersion)
|
|
33
|
-
WHERE ltv.region = $Region
|
|
34
|
-
RETURN
|
|
34
|
+
WHERE ltv.region = $Region AND ltv.image_id IS NOT NULL
|
|
35
|
+
RETURN ltv.image_id AS image
|
|
36
|
+
}
|
|
37
|
+
RETURN DISTINCT image;
|
|
35
38
|
"""
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
result = read_list_of_values_tx(
|
|
40
|
+
neo4j_session, get_images_query,
|
|
41
|
+
AWS_ACCOUNT_ID=current_aws_account_id, Region=region,
|
|
42
|
+
)
|
|
43
|
+
images = [str(image) for image in result]
|
|
40
44
|
return images
|
|
41
45
|
|
|
42
46
|
|
|
@@ -45,39 +49,23 @@ def get_images_in_use(neo4j_session: neo4j.Session, region: str, current_aws_acc
|
|
|
45
49
|
def get_images(boto3_session: boto3.session.Session, region: str, image_ids: List[str]) -> List[Dict]:
|
|
46
50
|
client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
|
|
47
51
|
images = []
|
|
52
|
+
self_images = []
|
|
48
53
|
try:
|
|
49
54
|
self_images = client.describe_images(Owners=['self'])['Images']
|
|
50
|
-
images.extend(self_images)
|
|
51
|
-
except ClientError as e:
|
|
52
|
-
logger.warning(f"Failed to retrieve private images for region - {region}. Error - {e}")
|
|
53
|
-
try:
|
|
54
|
-
if image_ids:
|
|
55
|
-
image_ids = [image_id for image_id in image_ids if image_id is not None]
|
|
56
|
-
images_in_use = client.describe_images(ImageIds=image_ids)['Images']
|
|
57
|
-
# Ensure we're not adding duplicates
|
|
58
|
-
_ids = [image["ImageId"] for image in images]
|
|
59
|
-
for image in images_in_use:
|
|
60
|
-
if image["ImageId"] not in _ids:
|
|
61
|
-
images.append(image)
|
|
62
|
-
_ids.append(image["ImageId"])
|
|
63
|
-
# Handle cross region image ids
|
|
64
|
-
if len(_ids) != len(image_ids):
|
|
65
|
-
logger.info("Attempting to retrieve images from other regions")
|
|
66
|
-
pending_ids = [image_id for image_id in image_ids if image_id not in _ids]
|
|
67
|
-
all_regions = get_ec2_regions(boto3_session)
|
|
68
|
-
clients = {
|
|
69
|
-
other_region: boto3_session.client('ec2', region_name=other_region, config=get_botocore_config())
|
|
70
|
-
for other_region in all_regions if other_region != region
|
|
71
|
-
}
|
|
72
|
-
for other_region, client in clients.items():
|
|
73
|
-
for _id in pending_ids:
|
|
74
|
-
try:
|
|
75
|
-
pending_image = client.describe_images(ImageIds=[_id])['Images']
|
|
76
|
-
images.extend(pending_image)
|
|
77
|
-
except ClientError as e:
|
|
78
|
-
logger.warning(f"Image {id} could not be found at region - {other_region}. Error - {e}")
|
|
79
55
|
except ClientError as e:
|
|
80
|
-
logger.warning(f"Failed
|
|
56
|
+
logger.warning(f"Failed retrieve self owned images for region - {region}. Error - {e}")
|
|
57
|
+
images.extend(self_images)
|
|
58
|
+
if image_ids:
|
|
59
|
+
self_image_ids = {image['ImageId'] for image in images}
|
|
60
|
+
# Go one by one to avoid losing all images if one fails
|
|
61
|
+
for image in image_ids:
|
|
62
|
+
if image in self_image_ids:
|
|
63
|
+
continue
|
|
64
|
+
try:
|
|
65
|
+
public_images = client.describe_images(ImageIds=[image])['Images']
|
|
66
|
+
images.extend(public_images)
|
|
67
|
+
except ClientError as e:
|
|
68
|
+
logger.warning(f"Failed retrieve image id {image} for region - {region}. Error - {e}")
|
|
81
69
|
return images
|
|
82
70
|
|
|
83
71
|
|
|
@@ -0,0 +1,47 @@
|
|
|
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 TargetNodeMatcher
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class APIGatewayRestAPINodeProperties(CartographyNodeProperties):
|
|
15
|
+
id: PropertyRef = PropertyRef('id', extra_index=True)
|
|
16
|
+
createddate: PropertyRef = PropertyRef('createdDate')
|
|
17
|
+
version: PropertyRef = PropertyRef('version')
|
|
18
|
+
minimumcompressionsize: PropertyRef = PropertyRef('minimumCompressionSize')
|
|
19
|
+
disableexecuteapiendpoint: PropertyRef = PropertyRef('disableExecuteApiEndpoint')
|
|
20
|
+
region: PropertyRef = PropertyRef('region', set_in_kwargs=True)
|
|
21
|
+
lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True)
|
|
22
|
+
anonymous_access: PropertyRef = PropertyRef('anonymous_access')
|
|
23
|
+
anonymous_actions: PropertyRef = PropertyRef('anonymous_actions')
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass(frozen=True)
|
|
27
|
+
class APIGatewayRestAPIToAwsAccountRelProperties(CartographyRelProperties):
|
|
28
|
+
lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(frozen=True)
|
|
32
|
+
# (:APIGatewayRestAPI)<-[:RESOURCE]-(:AWSAccount)
|
|
33
|
+
class APIGatewayRestAPIToAWSAccount(CartographyRelSchema):
|
|
34
|
+
target_node_label: str = 'AWSAccount'
|
|
35
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
36
|
+
{'id': PropertyRef('AWS_ID', set_in_kwargs=True)},
|
|
37
|
+
)
|
|
38
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
39
|
+
rel_label: str = "RESOURCE"
|
|
40
|
+
properties: APIGatewayRestAPIToAwsAccountRelProperties = APIGatewayRestAPIToAwsAccountRelProperties()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass(frozen=True)
|
|
44
|
+
class APIGatewayRestAPISchema(CartographyNodeSchema):
|
|
45
|
+
label: str = 'APIGatewayRestAPI'
|
|
46
|
+
properties: APIGatewayRestAPINodeProperties = APIGatewayRestAPINodeProperties()
|
|
47
|
+
sub_resource_relationship: APIGatewayRestAPIToAWSAccount = APIGatewayRestAPIToAWSAccount()
|
|
@@ -0,0 +1,66 @@
|
|
|
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 APIGatewayClientCertificateNodeProperties(CartographyNodeProperties):
|
|
16
|
+
id: PropertyRef = PropertyRef('clientCertificateId')
|
|
17
|
+
createddate: PropertyRef = PropertyRef('createdDate')
|
|
18
|
+
expirationdate: PropertyRef = PropertyRef('expirationDate')
|
|
19
|
+
lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass(frozen=True)
|
|
23
|
+
class APIGatewayClientCertificateToStageRelProperties(CartographyRelProperties):
|
|
24
|
+
lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class CertToStageRelProps(CartographyRelProperties):
|
|
29
|
+
lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass(frozen=True)
|
|
33
|
+
# (:APIGatewayStage)-[:HAS_CERTIFICATE]->(:APIGatewayClientCertificate)
|
|
34
|
+
class APIGatewayClientCertificateToStage(CartographyRelSchema):
|
|
35
|
+
target_node_label: str = 'APIGatewayStage'
|
|
36
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
37
|
+
{'id': PropertyRef('stageArn')},
|
|
38
|
+
)
|
|
39
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
40
|
+
rel_label: str = "HAS_CERTIFICATE"
|
|
41
|
+
properties: CertToStageRelProps = CertToStageRelProps()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass(frozen=True)
|
|
45
|
+
class CertToAccountRelProps(CartographyRelProperties):
|
|
46
|
+
lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass(frozen=True)
|
|
50
|
+
# (:APIGatewayClientCertificate)<-[:RESOURCE]-(:AWSAccount)
|
|
51
|
+
class APIGatewayClientCertificateToAWSAccount(CartographyRelSchema):
|
|
52
|
+
target_node_label: str = 'AWSAccount'
|
|
53
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
54
|
+
{'id': PropertyRef('AWS_ID', set_in_kwargs=True)},
|
|
55
|
+
)
|
|
56
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
57
|
+
rel_label: str = "RESOURCE"
|
|
58
|
+
properties: CertToAccountRelProps = CertToAccountRelProps()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass(frozen=True)
|
|
62
|
+
class APIGatewayClientCertificateSchema(CartographyNodeSchema):
|
|
63
|
+
label: str = 'APIGatewayClientCertificate'
|
|
64
|
+
properties: APIGatewayClientCertificateNodeProperties = APIGatewayClientCertificateNodeProperties()
|
|
65
|
+
sub_resource_relationship: APIGatewayClientCertificateToAWSAccount = APIGatewayClientCertificateToAWSAccount()
|
|
66
|
+
other_relationships: OtherRelationships = OtherRelationships([APIGatewayClientCertificateToStage()])
|
|
@@ -0,0 +1,62 @@
|
|
|
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 APIGatewayResourceNodeProperties(CartographyNodeProperties):
|
|
16
|
+
id: PropertyRef = PropertyRef('id')
|
|
17
|
+
path: PropertyRef = PropertyRef('path')
|
|
18
|
+
pathpart: PropertyRef = PropertyRef('pathPart')
|
|
19
|
+
parentid: PropertyRef = PropertyRef('parentId')
|
|
20
|
+
lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass(frozen=True)
|
|
24
|
+
class APIGatewayResourceToRestAPIRelProperties(CartographyRelProperties):
|
|
25
|
+
lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
# (:APIGatewayResource)<-[:RESOURCE]-(:APIGatewayRestAPI)
|
|
30
|
+
class APIGatewayResourceToRestAPI(CartographyRelSchema):
|
|
31
|
+
target_node_label: str = 'APIGatewayRestAPI'
|
|
32
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
33
|
+
{'id': PropertyRef('apiId')},
|
|
34
|
+
)
|
|
35
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
36
|
+
rel_label: str = "RESOURCE"
|
|
37
|
+
properties: APIGatewayResourceToRestAPIRelProperties = APIGatewayResourceToRestAPIRelProperties()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass(frozen=True)
|
|
41
|
+
class APIGatewayResourceToAwsAccountRelProperties(CartographyRelProperties):
|
|
42
|
+
lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass(frozen=True)
|
|
46
|
+
# (:APIGatewayResource)<-[:RESOURCE]-(:AWSAccount)
|
|
47
|
+
class APIGatewayResourceToAWSAccount(CartographyRelSchema):
|
|
48
|
+
target_node_label: str = 'AWSAccount'
|
|
49
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
50
|
+
{'id': PropertyRef('AWS_ID', set_in_kwargs=True)},
|
|
51
|
+
)
|
|
52
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
53
|
+
rel_label: str = "RESOURCE"
|
|
54
|
+
properties: APIGatewayResourceToAwsAccountRelProperties = APIGatewayResourceToAwsAccountRelProperties()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass(frozen=True)
|
|
58
|
+
class APIGatewayResourceSchema(CartographyNodeSchema):
|
|
59
|
+
label: str = 'APIGatewayResource'
|
|
60
|
+
properties: APIGatewayResourceNodeProperties = APIGatewayResourceNodeProperties()
|
|
61
|
+
sub_resource_relationship: APIGatewayResourceToAWSAccount = APIGatewayResourceToAWSAccount()
|
|
62
|
+
other_relationships: OtherRelationships = OtherRelationships([APIGatewayResourceToRestAPI()])
|
|
@@ -0,0 +1,67 @@
|
|
|
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 APIGatewayStageNodeProperties(CartographyNodeProperties):
|
|
16
|
+
id: PropertyRef = PropertyRef('arn')
|
|
17
|
+
stagename: PropertyRef = PropertyRef('stageName')
|
|
18
|
+
createddate: PropertyRef = PropertyRef('createdDate')
|
|
19
|
+
deploymentid: PropertyRef = PropertyRef('deploymentId')
|
|
20
|
+
clientcertificateid: PropertyRef = PropertyRef('clientCertificateId')
|
|
21
|
+
cacheclusterenabled: PropertyRef = PropertyRef('cacheClusterEnabled')
|
|
22
|
+
cacheclusterstatus: PropertyRef = PropertyRef('cacheClusterStatus')
|
|
23
|
+
tracingenabled: PropertyRef = PropertyRef('tracingEnabled')
|
|
24
|
+
webaclarn: PropertyRef = PropertyRef('webAclArn')
|
|
25
|
+
lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
class APIGatewayStageToRestAPIRelProperties(CartographyRelProperties):
|
|
30
|
+
lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True)
|
|
34
|
+
# (:APIGatewayStage)<-[:ASSOCIATED_WITH]-(:APIGatewayRestAPI)
|
|
35
|
+
class APIGatewayStageToRestAPI(CartographyRelSchema):
|
|
36
|
+
target_node_label: str = 'APIGatewayRestAPI'
|
|
37
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
38
|
+
{'id': PropertyRef('apiId')},
|
|
39
|
+
)
|
|
40
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
41
|
+
rel_label: str = "ASSOCIATED_WITH"
|
|
42
|
+
properties: APIGatewayStageToRestAPIRelProperties = APIGatewayStageToRestAPIRelProperties()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass(frozen=True)
|
|
46
|
+
class APIGatewayStageToAwsAccountRelProperties(CartographyRelProperties):
|
|
47
|
+
lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass(frozen=True)
|
|
51
|
+
# (:APIGatewayStage)<-[:RESOURCE]-(:AWSAccount)
|
|
52
|
+
class APIGatewayStageToAWSAccount(CartographyRelSchema):
|
|
53
|
+
target_node_label: str = 'AWSAccount'
|
|
54
|
+
target_node_matcher: TargetNodeMatcher = make_target_node_matcher(
|
|
55
|
+
{'id': PropertyRef('AWS_ID', set_in_kwargs=True)},
|
|
56
|
+
)
|
|
57
|
+
direction: LinkDirection = LinkDirection.INWARD
|
|
58
|
+
rel_label: str = "RESOURCE"
|
|
59
|
+
properties: APIGatewayStageToAwsAccountRelProperties = APIGatewayStageToAwsAccountRelProperties()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass(frozen=True)
|
|
63
|
+
class APIGatewayStageSchema(CartographyNodeSchema):
|
|
64
|
+
label: str = 'APIGatewayStage'
|
|
65
|
+
properties: APIGatewayStageNodeProperties = APIGatewayStageNodeProperties()
|
|
66
|
+
sub_resource_relationship: APIGatewayStageToAWSAccount = APIGatewayStageToAWSAccount()
|
|
67
|
+
other_relationships: OtherRelationships = OtherRelationships([APIGatewayStageToRestAPI()])
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: cartography
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.100.0rc1
|
|
4
4
|
Summary: Explore assets and their relationships across your technical infrastructure.
|
|
5
5
|
Maintainer: Cartography Contributors
|
|
6
6
|
License: apache2
|
|
@@ -62,10 +62,16 @@ Requires-Dist: pytest-mock; extra == "dev"
|
|
|
62
62
|
Requires-Dist: pytest-cov==2.10.0; extra == "dev"
|
|
63
63
|
Requires-Dist: pytest-rerunfailures; extra == "dev"
|
|
64
64
|
Requires-Dist: types-PyYAML; extra == "dev"
|
|
65
|
-
Requires-Dist: types-requests<2.
|
|
65
|
+
Requires-Dist: types-requests<2.32.0.20241017; extra == "dev"
|
|
66
66
|
|
|
67
67
|

|
|
68
68
|
|
|
69
|
+
[](https://scorecard.dev/viewer/?uri=github.com/cartography-cncf/cartography)
|
|
70
|
+
[](https://www.bestpractices.dev/projects/9637)
|
|
71
|
+

|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
69
75
|
Cartography is a Python tool that consolidates infrastructure assets and the relationships between them in an intuitive graph view powered by a [Neo4j](https://www.neo4j.com) database.
|
|
70
76
|
|
|
71
77
|

|
|
@@ -147,9 +153,9 @@ Directly querying Neo4j is already very useful as a sort of "swiss army knife" f
|
|
|
147
153
|
## Community
|
|
148
154
|
|
|
149
155
|
- Hang out with us on Slack: Join the CNCF Slack workspace [here](https://communityinviter.com/apps/cloud-native/cncf), and then join the `#cartography` channel.
|
|
150
|
-
- Talk to us and see what we're working on at our [monthly community meeting](https://
|
|
156
|
+
- Talk to us and see what we're working on at our [monthly community meeting](https://zoom-lfx.platform.linuxfoundation.org/meetings/cartography?view=week).
|
|
151
157
|
- Meeting minutes are [here](https://docs.google.com/document/d/1VyRKmB0dpX185I15BmNJZpfAJ_Ooobwz0U1WIhjDxvw).
|
|
152
|
-
- Recorded videos are posted [here](https://www.youtube.com/playlist?list=PLMga2YJvAGzidUWJB_fnG7EHI4wsDDsE1).
|
|
158
|
+
- Recorded videos from before 2025 are posted [here](https://www.youtube.com/playlist?list=PLMga2YJvAGzidUWJB_fnG7EHI4wsDDsE1).
|
|
153
159
|
|
|
154
160
|
## License
|
|
155
161
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
cartography/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
cartography/__main__.py,sha256=JftXT_nUPkqcEh8uxCCT4n-OyHYqbldEgrDS-4ygy0U,101
|
|
3
|
-
cartography/_version.py,sha256=
|
|
3
|
+
cartography/_version.py,sha256=m60nwdmRfNS_e1bH0LUuweYWYEmDYMPRcAZovFm1Lq4,418
|
|
4
4
|
cartography/cli.py,sha256=LPjeOkx-cKhRkuhqMicB-0X3SHOjLXxEeGqsp2FtpC0,33285
|
|
5
5
|
cartography/config.py,sha256=ZcadsKmooAkti9Kv0eDl8Ec1PcZDu3lWobtNaCnwY3k,11872
|
|
6
6
|
cartography/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -31,10 +31,8 @@ cartography/data/jobs/analysis/gcp_gke_basic_auth.json,sha256=qLkrw1eZvV9ETtkIQN
|
|
|
31
31
|
cartography/data/jobs/analysis/gsuite_human_link.json,sha256=ArWA51fNIeeXwYiroJbKnuqN8y-TLrndOq0ZdC9q5os,541
|
|
32
32
|
cartography/data/jobs/cleanup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
cartography/data/jobs/cleanup/aws_account_cleanup.json,sha256=DEB4h6Z4NSpYaLXECPhNk8HHbT0XNlqUA01pXIskBxc,473
|
|
34
|
-
cartography/data/jobs/cleanup/aws_apigateway_details.json,sha256=rh7cMTebjyUoEu_s7nKl3m-GLQ3gXgw0s3kMJfWKjro,323
|
|
35
34
|
cartography/data/jobs/cleanup/aws_dns_cleanup.json,sha256=H5uMZV4tN6HcjTYwh2I1dENzNGqu2D2Rs2q-5CK5e0Y,3498
|
|
36
35
|
cartography/data/jobs/cleanup/aws_import_account_access_key_cleanup.json,sha256=UCrAXf-8yQIoUa843VLLTpqrSpNa753c1cxzg32oqU0,737
|
|
37
|
-
cartography/data/jobs/cleanup/aws_import_apigateway_cleanup.json,sha256=wCV95ydo3dmlhK7VrDrxCqrP6dbhCCMTzcz_qaJQ4Jo,2189
|
|
38
36
|
cartography/data/jobs/cleanup/aws_import_config_cleanup.json,sha256=VCAJjEnFcQUR16VxKdpsOkBJEnhMuLk-7Kgm_p9k1NM,754
|
|
39
37
|
cartography/data/jobs/cleanup/aws_import_ec2_launch_configurations_cleanup.json,sha256=x9IIzb9Sr1353ygkA-qqUUbZS9XO2v3GzUHe-0J4Pw8,281
|
|
40
38
|
cartography/data/jobs/cleanup/aws_import_ec2_security_groupinfo_cleanup.json,sha256=CackEgSs1PN15pTg8oIdS0amB-n-PsKODLAaqC3gf_A,1183
|
|
@@ -143,7 +141,7 @@ cartography/intel/analysis.py,sha256=gHtN42NqqLL1G5MOm2Q6rMyg-V5lU_wqbnKp5hbOOao
|
|
|
143
141
|
cartography/intel/create_indexes.py,sha256=HM2jB2v3NZvGqgVDtNoBQRVpkei_JXcYXqM14w8Rjss,741
|
|
144
142
|
cartography/intel/dns.py,sha256=M-WSiGQoxWZsl0sg-2SDR8OD8e1Rexkt2Tbb2OpeioA,5596
|
|
145
143
|
cartography/intel/aws/__init__.py,sha256=siRhVNypfGxMPNIXHSjfYbLX9qlB6RYyN6aWX64N-t8,11076
|
|
146
|
-
cartography/intel/aws/apigateway.py,sha256=
|
|
144
|
+
cartography/intel/aws/apigateway.py,sha256=w4QdxlwnVegKKsZFfoI36i-FGlIUjzxzaayZyz9oQvM,11654
|
|
147
145
|
cartography/intel/aws/config.py,sha256=wrZbz7bc8vImLmRvTLkPcWnjjPzk3tOG4bB_BFS2lq8,7329
|
|
148
146
|
cartography/intel/aws/dynamodb.py,sha256=LZ6LGNThLi0zC3eLMq2JN3mwiSwZeaH58YQQHvsXMGE,5013
|
|
149
147
|
cartography/intel/aws/ecr.py,sha256=9yK8bXnXBJHW_AOalATjqfC4GTpR9pilpDScla4EFuY,6624
|
|
@@ -172,7 +170,7 @@ cartography/intel/aws/ssm.py,sha256=IDOYa8v2FgziU8nBOZ7wyDG4o_nFYshbB-si9Ut_9Zc,
|
|
|
172
170
|
cartography/intel/aws/ec2/__init__.py,sha256=IDK2Yap7mllK_ab6yVMLXatJ94znIkn-szv5RJP5fbo,346
|
|
173
171
|
cartography/intel/aws/ec2/auto_scaling_groups.py,sha256=ylfks8_oC0-fVMnToFbmRcbKdEN0H17LlN1-ZqW6ULc,8148
|
|
174
172
|
cartography/intel/aws/ec2/elastic_ip_addresses.py,sha256=0k4NwS73VyWbEj5jXvSkaq2RNvmAlBlrN-UKa_Bj0uk,3957
|
|
175
|
-
cartography/intel/aws/ec2/images.py,sha256=
|
|
173
|
+
cartography/intel/aws/ec2/images.py,sha256=SLoxcy_PQgNomVMDMdutm0zXJCOLosiHJlN63YQPA0k,3973
|
|
176
174
|
cartography/intel/aws/ec2/instances.py,sha256=uI8eVJmeEybS8y_T8CVKAkwxJyVDCH7sbuEJYeWGSWY,12468
|
|
177
175
|
cartography/intel/aws/ec2/internet_gateways.py,sha256=dI-4-85_3DGGZZBcY_DN6XqESx9P26S6jKok314lcnQ,2883
|
|
178
176
|
cartography/intel/aws/ec2/key_pairs.py,sha256=g4imIo_5jk8upq9J4--erg-OZXG2i3cJMe6SnNCYj9s,2635
|
|
@@ -280,6 +278,10 @@ cartography/intel/snipeit/user.py,sha256=hm9v_p29bphHtGe9LKVo1FD_rQcbCigrCRf8Ysm
|
|
|
280
278
|
cartography/intel/snipeit/util.py,sha256=fXlzdFQXm01Oaa2REYNN7x3y3k2l3zCVhf_BxcRUELY,1040
|
|
281
279
|
cartography/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
282
280
|
cartography/models/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
281
|
+
cartography/models/aws/apigateway.py,sha256=NTzaHlZVGBWv9GNWoHDOgMUt53HN9xO1E06s9RPj7Ek,2262
|
|
282
|
+
cartography/models/aws/apigatewaycertificate.py,sha256=xNjB2wDtW16jo1S4cPYEjU3BUttjQvW8TysrBVpuNnw,2924
|
|
283
|
+
cartography/models/aws/apigatewayresource.py,sha256=qj9OYoDCoAtw4olRgmhfhdQ1Y6ESq14n-mRr2gzUgfI,2760
|
|
284
|
+
cartography/models/aws/apigatewaystage.py,sha256=C1ntCj52iHyyR4APxeYJootvICMk4FVOovvoluL8lIM,3083
|
|
283
285
|
cartography/models/aws/emr.py,sha256=TkuwoZnw_VHbJ5bwkac7-ZfwSLe_TeK3gxkuwGQOUk4,3037
|
|
284
286
|
cartography/models/aws/dynamodb/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
285
287
|
cartography/models/aws/dynamodb/gsi.py,sha256=KYsHJpSgrTQndZGIdKAi5MjgvUne2iNvqTr29BDzI14,3021
|
|
@@ -354,9 +356,9 @@ cartography/models/snipeit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
|
354
356
|
cartography/models/snipeit/asset.py,sha256=FyRAaeXuZjMy0eUQcSDFcgEAF5lbLMlvqp1Tv9d3Lv4,3238
|
|
355
357
|
cartography/models/snipeit/tenant.py,sha256=p4rFnpNNuF1W5ilGBbexDaETWTwavfb38RcQGoImkQI,679
|
|
356
358
|
cartography/models/snipeit/user.py,sha256=MsB4MiCVNTH6JpESime7cOkB89autZOXQpL6Z0l7L6o,2113
|
|
357
|
-
cartography-0.
|
|
358
|
-
cartography-0.
|
|
359
|
-
cartography-0.
|
|
360
|
-
cartography-0.
|
|
361
|
-
cartography-0.
|
|
362
|
-
cartography-0.
|
|
359
|
+
cartography-0.100.0rc1.dist-info/LICENSE,sha256=kvLEBRYaQ1RvUni6y7Ti9uHeooqnjPoo6n_-0JO1ETc,11351
|
|
360
|
+
cartography-0.100.0rc1.dist-info/METADATA,sha256=go8iGhWQYwh93GnkZX-Ut4_epIBTQL7e1Xrpz7Y8k-o,11860
|
|
361
|
+
cartography-0.100.0rc1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
362
|
+
cartography-0.100.0rc1.dist-info/entry_points.txt,sha256=GVIAWD0o0_K077qMA_k1oZU4v-M0a8GLKGJR8tZ-qH8,112
|
|
363
|
+
cartography-0.100.0rc1.dist-info/top_level.txt,sha256=BHqsNJQiI6Q72DeypC1IINQJE59SLhU4nllbQjgJi9g,12
|
|
364
|
+
cartography-0.100.0rc1.dist-info/RECORD,,
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"statements": [
|
|
3
|
-
{
|
|
4
|
-
"query": "MATCH (:AWSAccount{id: $AWS_ID})-[:RESOURCE]->(s:RestAPI) WHERE s.anonymous_access IS NOT NULL\n WITH s LIMIT $LIMIT_SIZE\nREMOVE s.anonymous_access, s.anonymous_actions",
|
|
5
|
-
"iterative": true,
|
|
6
|
-
"iterationsize": 100
|
|
7
|
-
}
|
|
8
|
-
],
|
|
9
|
-
"name": "AWS APIGateway Exposure Details"
|
|
10
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"statements": [
|
|
3
|
-
{
|
|
4
|
-
"query": "MATCH (n:APIGatewayClientCertificate)<-[:HAS_CERTIFICATE]-(:APIGatewayStage)<-[:ASSOCIATED_WITH]-(:APIGatewayRestAPI)<-[:RESOURCE]-(:AWSAccount{id: $AWS_ID}) WHERE n.lastupdated <> $UPDATE_TAG WITH n LIMIT $LIMIT_SIZE DETACH DELETE (n)",
|
|
5
|
-
"iterative": true,
|
|
6
|
-
"iterationsize": 100
|
|
7
|
-
},
|
|
8
|
-
{
|
|
9
|
-
"query": "MATCH (:APIGatewayClientCertificate)<-[r:HAS_CERTIFICATE]-(:APIGatewayStage)<-[:ASSOCIATED_WITH]-(:APIGatewayRestAPI)<-[:RESOURCE]-(:AWSAccount{id: $AWS_ID}) WHERE r.lastupdated <> $UPDATE_TAG WITH r LIMIT $LIMIT_SIZE DELETE (r)",
|
|
10
|
-
"iterative": true,
|
|
11
|
-
"iterationsize": 100
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"query": "MATCH (n:APIGatewayStage)<-[:ASSOCIATED_WITH]-(:APIGatewayRestAPI)<-[:RESOURCE]-(:AWSAccount{id: $AWS_ID}) WHERE n.lastupdated <> $UPDATE_TAG WITH n LIMIT $LIMIT_SIZE DETACH DELETE (n)",
|
|
15
|
-
"iterative": true,
|
|
16
|
-
"iterationsize": 100
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
"query": "MATCH (:APIGatewayStage)<-[r:ASSOCIATED_WITH]-(:APIGatewayRestAPI)<-[:RESOURCE]-(:AWSAccount{id: $AWS_ID}) WHERE r.lastupdated <> $UPDATE_TAG WITH r LIMIT $LIMIT_SIZE DELETE (r)",
|
|
20
|
-
"iterative": true,
|
|
21
|
-
"iterationsize": 100
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"query": "MATCH (n:APIGatewayResource)<-[:RESOURCE]-(:APIGatewayRestAPI)<-[:RESOURCE]-(:AWSAccount{id: $AWS_ID}) WHERE n.lastupdated <> $UPDATE_TAG WITH n LIMIT $LIMIT_SIZE DETACH DELETE (n)",
|
|
25
|
-
"iterative": true,
|
|
26
|
-
"iterationsize": 100
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
"query": "MATCH (:APIGatewayResource)<-[r:RESOURCE]-(:APIGatewayRestAPI)<-[:RESOURCE]-(:AWSAccount{id: $AWS_ID}) WHERE r.lastupdated <> $UPDATE_TAG WITH r LIMIT $LIMIT_SIZE DELETE (r)",
|
|
30
|
-
"iterative": true,
|
|
31
|
-
"iterationsize": 100
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
"query": "MATCH (n:APIGatewayRestAPI)<-[:RESOURCE]-(:AWSAccount{id: $AWS_ID}) WHERE n.lastupdated <> $UPDATE_TAG WITH n LIMIT $LIMIT_SIZE DETACH DELETE (n)",
|
|
35
|
-
"iterative": true,
|
|
36
|
-
"iterationsize": 100
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"query": "MATCH (:APIGatewayRestAPI)<-[r:RESOURCE]-(:AWSAccount{id: $AWS_ID}) WHERE r.lastupdated <> $UPDATE_TAG WITH r LIMIT $LIMIT_SIZE DELETE (r)",
|
|
40
|
-
"iterative": true,
|
|
41
|
-
"iterationsize": 100
|
|
42
|
-
}
|
|
43
|
-
],
|
|
44
|
-
"name": "cleanup APIGateway"
|
|
45
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|