Skip to content

Commit 57f3920

Browse files
authored
refactor(api): migrate Attack Paths network exposure queries from APOC to openCypher (#10266)
1 parent 3288a4a commit 57f3920

File tree

3 files changed

+144
-102
lines changed

3 files changed

+144
-102
lines changed

api/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ All notable changes to the **Prowler API** are documented in this file.
66

77
### 🔄 Changed
88

9+
- Attack Paths: Migrate network exposure queries from APOC to standard openCypher for Neo4j and Neptune compatibility [(#10266)](https://github.com/prowler-cloud/prowler/pull/10266)
910
- `POST /api/v1/providers` returns `409 Conflict` if already exists [(#10293)](https://github.com/prowler-cloud/prowler/pull/10293)
1011

1112
---

api/src/backend/api/attack_paths/queries/aws.py

Lines changed: 17 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616
description="Detect EC2 instances with SSH exposed to the internet that can assume higher-privileged roles to read tagged sensitive S3 buckets despite bucket-level public access blocks.",
1717
provider="aws",
1818
cypher=f"""
19-
CALL apoc.create.vNode(['Internet'], {{id: 'Internet', name: 'Internet', provider_id: $provider_id}})
20-
YIELD node AS internet
19+
OPTIONAL MATCH (internet:Internet {{_provider_id: $provider_id}})
2120
2221
MATCH path_s3 = (aws:AWSAccount {{id: $provider_uid}})--(s3:S3Bucket)--(t:AWSTag)
2322
WHERE toLower(t.key) = toLower($tag_key) AND toLower(t.value) = toLower($tag_value)
@@ -32,8 +31,7 @@
3231
3332
MATCH path_assume_role = (ec2)-[p:STS_ASSUMEROLE_ALLOW*1..9]-(r:AWSRole)
3433
35-
CALL apoc.create.vRelationship(internet, 'CAN_ACCESS', {{provider_id: $provider_id}}, ec2)
36-
YIELD rel AS can_access
34+
OPTIONAL MATCH (internet)-[can_access:CAN_ACCESS]->(ec2)
3735
3836
UNWIND nodes(path_s3) + nodes(path_ec2) + nodes(path_role) + nodes(path_assume_role) as n
3937
OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}})
@@ -181,14 +179,12 @@
181179
description="Find EC2 instances flagged as exposed to the internet within the selected account.",
182180
provider="aws",
183181
cypher=f"""
184-
CALL apoc.create.vNode(['Internet'], {{id: 'Internet', name: 'Internet', provider_id: $provider_id}})
185-
YIELD node AS internet
182+
OPTIONAL MATCH (internet:Internet {{_provider_id: $provider_id}})
186183
187184
MATCH path = (aws:AWSAccount {{id: $provider_uid}})--(ec2:EC2Instance)
188185
WHERE ec2.exposed_internet = true
189186
190-
CALL apoc.create.vRelationship(internet, 'CAN_ACCESS', {{provider_id: $provider_id}}, ec2)
191-
YIELD rel AS can_access
187+
OPTIONAL MATCH (internet)-[can_access:CAN_ACCESS]->(ec2)
192188
193189
UNWIND nodes(path) as n
194190
OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}})
@@ -205,16 +201,14 @@
205201
description="Find internet-facing resources associated with security groups that allow inbound access from '0.0.0.0/0'.",
206202
provider="aws",
207203
cypher=f"""
208-
CALL apoc.create.vNode(['Internet'], {{id: 'Internet', name: 'Internet', provider_id: $provider_id}})
209-
YIELD node AS internet
204+
OPTIONAL MATCH (internet:Internet {{_provider_id: $provider_id}})
210205
211206
// Match EC2 instances that are internet-exposed with open security groups (0.0.0.0/0)
212207
MATCH path_ec2 = (aws:AWSAccount {{id: $provider_uid}})--(ec2:EC2Instance)--(sg:EC2SecurityGroup)--(ipi:IpPermissionInbound)--(ir:IpRange)
213208
WHERE ec2.exposed_internet = true
214209
AND ir.range = "0.0.0.0/0"
215210
216-
CALL apoc.create.vRelationship(internet, 'CAN_ACCESS', {{provider_id: $provider_id}}, ec2)
217-
YIELD rel AS can_access
211+
OPTIONAL MATCH (internet)-[can_access:CAN_ACCESS]->(ec2)
218212
219213
UNWIND nodes(path_ec2) as n
220214
OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}})
@@ -231,14 +225,12 @@
231225
description="Find Classic Load Balancers exposed to the internet along with their listeners.",
232226
provider="aws",
233227
cypher=f"""
234-
CALL apoc.create.vNode(['Internet'], {{id: 'Internet', name: 'Internet', provider_id: $provider_id}})
235-
YIELD node AS internet
228+
OPTIONAL MATCH (internet:Internet {{_provider_id: $provider_id}})
236229
237230
MATCH path = (aws:AWSAccount {{id: $provider_uid}})--(elb:LoadBalancer)--(listener:ELBListener)
238231
WHERE elb.exposed_internet = true
239232
240-
CALL apoc.create.vRelationship(internet, 'CAN_ACCESS', {{provider_id: $provider_id}}, elb)
241-
YIELD rel AS can_access
233+
OPTIONAL MATCH (internet)-[can_access:CAN_ACCESS]->(elb)
242234
243235
UNWIND nodes(path) as n
244236
OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}})
@@ -255,14 +247,12 @@
255247
description="Find ELBv2 load balancers exposed to the internet along with their listeners.",
256248
provider="aws",
257249
cypher=f"""
258-
CALL apoc.create.vNode(['Internet'], {{id: 'Internet', name: 'Internet', provider_id: $provider_id}})
259-
YIELD node AS internet
250+
OPTIONAL MATCH (internet:Internet {{_provider_id: $provider_id}})
260251
261252
MATCH path = (aws:AWSAccount {{id: $provider_uid}})--(elbv2:LoadBalancerV2)--(listener:ELBV2Listener)
262253
WHERE elbv2.exposed_internet = true
263254
264-
CALL apoc.create.vRelationship(internet, 'CAN_ACCESS', {{provider_id: $provider_id}}, elbv2)
265-
YIELD rel AS can_access
255+
OPTIONAL MATCH (internet)-[can_access:CAN_ACCESS]->(elbv2)
266256
267257
UNWIND nodes(path) as n
268258
OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}})
@@ -279,31 +269,15 @@
279269
description="Given a public IP address, find the related AWS resource and its adjacent node within the selected account.",
280270
provider="aws",
281271
cypher=f"""
282-
CALL apoc.create.vNode(['Internet'], {{id: 'Internet', name: 'Internet', provider_id: $provider_id}})
283-
YIELD node AS internet
272+
OPTIONAL MATCH (internet:Internet {{_provider_id: $provider_id}})
284273
285-
CALL () {{
286-
MATCH path = (aws:AWSAccount {{id: $provider_uid}})-[r]-(x:EC2PrivateIp)-[q]-(y)
287-
WHERE x.public_ip = $ip
288-
RETURN path, x
274+
MATCH path = (aws:AWSAccount {{id: $provider_uid}})-[r]-(x)-[q]-(y)
275+
WHERE (x:EC2PrivateIp AND x.public_ip = $ip)
276+
OR (x:EC2Instance AND x.publicipaddress = $ip)
277+
OR (x:NetworkInterface AND x.public_ip = $ip)
278+
OR (x:ElasticIPAddress AND x.public_ip = $ip)
289279
290-
UNION MATCH path = (aws:AWSAccount {{id: $provider_uid}})-[r]-(x:EC2Instance)-[q]-(y)
291-
WHERE x.publicipaddress = $ip
292-
RETURN path, x
293-
294-
UNION MATCH path = (aws:AWSAccount {{id: $provider_uid}})-[r]-(x:NetworkInterface)-[q]-(y)
295-
WHERE x.public_ip = $ip
296-
RETURN path, x
297-
298-
UNION MATCH path = (aws:AWSAccount {{id: $provider_uid}})-[r]-(x:ElasticIPAddress)-[q]-(y)
299-
WHERE x.public_ip = $ip
300-
RETURN path, x
301-
}}
302-
303-
WITH path, x, internet
304-
305-
CALL apoc.create.vRelationship(internet, 'CAN_ACCESS', {{provider_id: $provider_id}}, x)
306-
YIELD rel AS can_access
280+
OPTIONAL MATCH (internet)-[can_access:CAN_ACCESS]->(x)
307281
308282
UNWIND nodes(path) as n
309283
OPTIONAL MATCH (n)-[pfr]-(pf:{PROWLER_FINDING_LABEL} {{status: 'FAIL', provider_uid: $provider_uid}})

0 commit comments

Comments
 (0)