1313"""API for Simple File Manager for Amazon EFS"""
1414import os
1515import logging
16+ import ipaddress
1617import json
1718import botocore
1819from botocore .config import Config
4142EFS = boto3 .client ('efs' , config = CONFIG )
4243SERVERLESS = boto3 .client ('lambda' , config = CONFIG )
4344CFN = boto3 .client ('cloudformation' , config = CONFIG )
45+ EC2 = boto3 .client ('ec2' , config = CONFIG )
4446
4547
4648# Helper functions
@@ -246,6 +248,52 @@ def format_operation_response(result, error_message):
246248 return response
247249
248250
251+ def test_nfs_access (group , mount_target_ip ):
252+ rules = EC2 .describe_security_group_rules (
253+ Filters = [
254+ {
255+ 'Name' : 'group-id' ,
256+ 'Values' : [group ]
257+ }
258+ ]
259+ )
260+
261+ contains_valid_rule = False
262+
263+ for rule in rules ['SecurityGroupRules' ]:
264+ # check if rule is inbound
265+ if rule ['IsEgress' ] is False :
266+ if 'ReferencedGroupInfo' in rule :
267+ # references a sg in the rule
268+ ref_group_id = rule ['ReferencedGroupInfo' ]['GroupId' ]
269+ if ref_group_id == rule ['GroupId' ]:
270+ if rule ['IpProtocol' ] == '-1' or rule ['IpProtocol' ] == 'tcp' :
271+ if rule ['FromPort' ] and rule ['ToPort' ] == 2049 or rule ['FromPort' ] and rule ['ToPort' ] == - 1 :
272+ contains_valid_rule = True
273+ elif rule ['FromPort' ] <= 2049 <= rule ['ToPort' ]:
274+ contains_valid_rule = True
275+ else :
276+ pass
277+ elif 'CidrIpv4' in rule :
278+ # references an ipv4 subnet
279+ subnet = rule ['CidrIpv4' ]
280+ if ipaddress .ip_address (mount_target_ip ) in ipaddress .ip_network (subnet ):
281+ if rule ['IpProtocol' ] == '-1' or rule ['IpProtocol' ] == 'tcp' :
282+ if rule ['FromPort' ] and rule ['ToPort' ] == 2049 or rule ['FromPort' ] and rule ['ToPort' ] == - 1 :
283+ contains_valid_rule = True
284+ elif rule ['FromPort' ] <= 2049 <= rule ['ToPort' ]:
285+ contains_valid_rule = True
286+ else :
287+ pass
288+ else :
289+ # bad request
290+ pass
291+ else :
292+ # outbound rule
293+ pass
294+
295+ return contains_valid_rule
296+
249297# Routes
250298
251299@app .route ('/filesystems' , methods = ["GET" ], cors = True , authorizer = AUTHORIZER )
@@ -324,13 +372,13 @@ def describe_filesystem(filesystem_id):
324372 authorizer = AUTHORIZER )
325373def get_netinfo_for_filesystem (filesystem_id ):
326374 """
327- Retrieves network info for a specified filesystem
375+ Retrieves mount target network info for a specified filesystem
328376
329377 :param filesystem_id: The filesystem to get net info for
330- :returns: Filesystem network info
378+ :returns: Filesystem mount target network info
331379 :raises ChaliceViewError
332380 """
333- netinfo = []
381+ mount_target_info = []
334382 try :
335383 response = EFS .describe_mount_targets (
336384 FileSystemId = filesystem_id
@@ -343,6 +391,8 @@ def get_netinfo_for_filesystem(filesystem_id):
343391 app .log .debug (mount_targets )
344392 for target in mount_targets :
345393 mount_target_id = target ['MountTargetId' ]
394+ mount_target_ip = target ['IpAddress' ]
395+
346396 try :
347397 response = EFS .describe_mount_target_security_groups (
348398 MountTargetId = mount_target_id
@@ -352,11 +402,25 @@ def get_netinfo_for_filesystem(filesystem_id):
352402 raise ChaliceViewError
353403 else :
354404 security_groups = response ['SecurityGroups' ]
355- vpc_item = {'{id}' .format (id = mount_target_id ): {'security_groups' : \
356- security_groups , 'subnet_id' : target ['SubnetId' ]}}
357- netinfo .append (vpc_item )
358-
359- return netinfo
405+
406+ # test security groups to see if the mount target can be used
407+ valid_security_groups = []
408+ for group in security_groups :
409+ is_valid_group = test_nfs_access (group , mount_target_ip )
410+ if is_valid_group :
411+ valid_security_groups .append (group )
412+ else :
413+ pass
414+
415+ mount_target_item = {'{id}' .format (id = mount_target_id ): {'security_groups' : \
416+ valid_security_groups , 'subnet_id' : target ['SubnetId' ]}}
417+
418+ mount_target_info .append (mount_target_item )
419+
420+ if len (mount_target_info ) == 0 :
421+ raise BadRequestError ('No mount target available with required network configuration. See the deployment guide for configuration details.' )
422+ else :
423+ return mount_target_info
360424
361425
362426@app .route ('/filesystems/{filesystem_id}/lambda' , methods = ['POST' ], cors = True , \
0 commit comments