From 08821741267680c3c2686281c5e6c6aaf7c82095 Mon Sep 17 00:00:00 2001 From: Yann Lambret Date: Tue, 19 Apr 2016 23:50:12 +0200 Subject: [PATCH 1/5] Replace exception message by the one sent by boto, because it is used for bot ingress and egress rules --- moto/ec2/exceptions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moto/ec2/exceptions.py b/moto/ec2/exceptions.py index 9e8f9300..1bba89fd 100644 --- a/moto/ec2/exceptions.py +++ b/moto/ec2/exceptions.py @@ -136,7 +136,7 @@ class InvalidPermissionNotFoundError(EC2ClientError): def __init__(self): super(InvalidPermissionNotFoundError, self).__init__( "InvalidPermission.NotFound", - "Could not find a matching ingress rule") + "The specified rule does not exist in this security group") class InvalidRouteTableIdError(EC2ClientError): From de68c94a0afe99b8603d30542ac6ceec2fa8f6ee Mon Sep 17 00:00:00 2001 From: Yann Lambret Date: Tue, 19 Apr 2016 23:50:46 +0200 Subject: [PATCH 2/5] Add the default outboud rule for security groups --- moto/ec2/models.py | 1 + tests/test_ec2/test_security_groups.py | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/moto/ec2/models.py b/moto/ec2/models.py index 4c523bc3..6d35e528 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -1102,6 +1102,7 @@ class SecurityGroup(TaggedEC2Resource): self.enis = {} self.vpc_id = vpc_id self.owner_id = "123456789012" + self.egress_rules.append(SecurityRule(-1, -1, -1, ['0.0.0.0/0'], [])) @classmethod def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name): diff --git a/tests/test_ec2/test_security_groups.py b/tests/test_ec2/test_security_groups.py index a36713d6..0d4e1f11 100644 --- a/tests/test_ec2/test_security_groups.py +++ b/tests/test_ec2/test_security_groups.py @@ -157,8 +157,8 @@ def test_authorize_ip_range_and_revoke(): success = conn.authorize_security_group_egress(egress_security_group.id, "tcp", from_port="22", to_port="2222", cidr_ip="123.123.123.123/32") assert success.should.be.true egress_security_group = conn.get_all_security_groups(groupnames='testegress')[0] - int(egress_security_group.rules_egress[0].to_port).should.equal(2222) - egress_security_group.rules_egress[0].grants[0].cidr_ip.should.equal("123.123.123.123/32") + int(egress_security_group.rules_egress[1].to_port).should.equal(2222) + egress_security_group.rules_egress[1].grants[0].cidr_ip.should.equal("123.123.123.123/32") # Wrong Cidr should throw error egress_security_group.revoke.when.called_with(ip_protocol="tcp", from_port="22", to_port="2222", cidr_ip="123.123.123.122/32").should.throw(EC2ResponseError) @@ -167,7 +167,7 @@ def test_authorize_ip_range_and_revoke(): conn.revoke_security_group_egress(egress_security_group.id, "tcp", from_port="22", to_port="2222", cidr_ip="123.123.123.123/32") egress_security_group = conn.get_all_security_groups()[0] - egress_security_group.rules_egress.should.have.length_of(0) + egress_security_group.rules_egress.should.have.length_of(1) @mock_ec2 From f9267cff6c323833e54d72dabe27c08e4af7da39 Mon Sep 17 00:00:00 2001 From: Yann Lambret Date: Wed, 20 Apr 2016 23:01:09 +0200 Subject: [PATCH 3/5] Fix egress rules management to autorize or revoke a security group --- moto/ec2/models.py | 31 +++++++++++++++++++------- tests/test_ec2/test_security_groups.py | 30 ++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/moto/ec2/models.py b/moto/ec2/models.py index 6d35e528..fc1321b1 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -1324,7 +1324,6 @@ class SecurityGroupBackend(object): if security_rule in group.ingress_rules: group.ingress_rules.remove(security_rule) return security_rule - raise InvalidPermissionNotFoundError() def authorize_security_group_egress(self, @@ -1333,22 +1332,33 @@ class SecurityGroupBackend(object): from_port, to_port, ip_ranges, - src_group_id=None, - cidr_ip=None, + source_group_names=None, + source_group_ids=None, vpc_id=None): group = self.get_security_group_by_name_or_id(group_name_or_id, vpc_id) - + if ip_ranges and not isinstance(ip_ranges, list): + ip_ranges = [ip_ranges] if ip_ranges: for cidr in ip_ranges: if not is_valid_cidr(cidr): raise InvalidCIDRSubnetError(cidr=cidr) - # for VPCs + source_group_names = source_group_names if source_group_names else [] + source_group_ids = source_group_ids if source_group_ids else [] + source_groups = [] - source_group = self.get_security_group_from_id(src_group_id) - if source_group: - source_groups.append(source_group) + for source_group_name in source_group_names: + source_group = self.get_security_group_from_name(source_group_name, vpc_id) + if source_group: + source_groups.append(source_group) + + # for VPCs + for source_group_id in source_group_ids: + source_group = self.get_security_group_from_id(source_group_id) + if source_group: + source_groups.append(source_group) + security_rule = SecurityRule(ip_protocol, from_port, to_port, ip_ranges, source_groups) group.egress_rules.append(security_rule) @@ -1370,6 +1380,11 @@ class SecurityGroupBackend(object): if source_group: source_groups.append(source_group) + for source_group_id in source_group_ids: + source_group = self.get_security_group_from_id(source_group_id) + if source_group: + source_groups.append(source_group) + security_rule = SecurityRule(ip_protocol, from_port, to_port, ip_ranges, source_groups) if security_rule in group.egress_rules: group.egress_rules.remove(security_rule) diff --git a/tests/test_ec2/test_security_groups.py b/tests/test_ec2/test_security_groups.py index 0d4e1f11..2588f7ae 100644 --- a/tests/test_ec2/test_security_groups.py +++ b/tests/test_ec2/test_security_groups.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import tests.backport_assert_raises # noqa from nose.tools import assert_raises +import boto3 import boto from boto.exception import EC2ResponseError import sure # noqa @@ -157,6 +158,8 @@ def test_authorize_ip_range_and_revoke(): success = conn.authorize_security_group_egress(egress_security_group.id, "tcp", from_port="22", to_port="2222", cidr_ip="123.123.123.123/32") assert success.should.be.true egress_security_group = conn.get_all_security_groups(groupnames='testegress')[0] + # There are two egress rules associated with the security group: + # the default outbound rule and the new one int(egress_security_group.rules_egress[1].to_port).should.equal(2222) egress_security_group.rules_egress[1].grants[0].cidr_ip.should.equal("123.123.123.123/32") @@ -167,6 +170,7 @@ def test_authorize_ip_range_and_revoke(): conn.revoke_security_group_egress(egress_security_group.id, "tcp", from_port="22", to_port="2222", cidr_ip="123.123.123.123/32") egress_security_group = conn.get_all_security_groups()[0] + # There is still the default outbound rule egress_security_group.rules_egress.should.have.length_of(1) @@ -198,6 +202,30 @@ def test_authorize_other_group_and_revoke(): security_group.rules.should.have.length_of(0) +@mock_ec2 +def test_authorize_other_group_egress_and_revoke(): + ec2 = boto3.resource('ec2', region_name='us-west-1') + + vpc = ec2.create_vpc(CidrBlock='10.0.0.0/16') + + sg01 = ec2.create_security_group(GroupName='sg01', Description='Test security group sg01', VpcId=vpc.id) + sg02 = ec2.create_security_group(GroupName='sg02', Description='Test security group sg02', VpcId=vpc.id) + + ip_permission = { + 'IpProtocol': u'tcp', + 'FromPort': 27017, + 'ToPort': 27017, + 'UserIdGroupPairs': [{'GroupId': sg02.id, 'GroupName': 'sg02', 'UserId': sg02.owner_id}], + 'IpRanges': [] + } + + sg01.authorize_egress(IpPermissions=[ip_permission]) + sg01.ip_permissions_egress.should.have.length_of(2) + sg01.ip_permissions_egress.should.contain(ip_permission) + + sg01.revoke_egress(IpPermissions=[ip_permission]) + sg01.ip_permissions_egress.should.have.length_of(1) + @mock_ec2 def test_authorize_group_in_vpc(): conn = boto.connect_ec2('the_key', 'the_secret') @@ -215,7 +243,7 @@ def test_authorize_group_in_vpc(): int(security_group.rules[0].to_port).should.equal(2222) security_group.rules[0].grants[0].group_id.should.equal(other_security_group.id) - # Now revome the rule + # Now remove the rule success = security_group.revoke(ip_protocol="tcp", from_port="22", to_port="2222", src_group=other_security_group) success.should.be.true From 232b83256338bb0b59ebae266c4044ef1ab14bd3 Mon Sep 17 00:00:00 2001 From: Yann Lambret Date: Wed, 20 Apr 2016 23:21:39 +0200 Subject: [PATCH 4/5] Change type for IpProtocol key --- tests/test_ec2/test_security_groups.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_ec2/test_security_groups.py b/tests/test_ec2/test_security_groups.py index 2588f7ae..6e09925b 100644 --- a/tests/test_ec2/test_security_groups.py +++ b/tests/test_ec2/test_security_groups.py @@ -212,7 +212,7 @@ def test_authorize_other_group_egress_and_revoke(): sg02 = ec2.create_security_group(GroupName='sg02', Description='Test security group sg02', VpcId=vpc.id) ip_permission = { - 'IpProtocol': u'tcp', + 'IpProtocol': 'tcp', 'FromPort': 27017, 'ToPort': 27017, 'UserIdGroupPairs': [{'GroupId': sg02.id, 'GroupName': 'sg02', 'UserId': sg02.owner_id}], From 5a5f2f12c7c9f7c1c02e903f178b13872daf813a Mon Sep 17 00:00:00 2001 From: Yann Lambret Date: Fri, 22 Apr 2016 19:12:26 +0200 Subject: [PATCH 5/5] Remove useless statement --- moto/ec2/models.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/moto/ec2/models.py b/moto/ec2/models.py index fc1321b1..05865e35 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -1098,11 +1098,10 @@ class SecurityGroup(TaggedEC2Resource): self.name = name self.description = description self.ingress_rules = [] - self.egress_rules = [] + self.egress_rules = [SecurityRule(-1, -1, -1, ['0.0.0.0/0'], [])] self.enis = {} self.vpc_id = vpc_id self.owner_id = "123456789012" - self.egress_rules.append(SecurityRule(-1, -1, -1, ['0.0.0.0/0'], [])) @classmethod def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):