From 11a37c357bf5e63ee2f57e19474d00d4718651f6 Mon Sep 17 00:00:00 2001 From: Mohit Alonja Date: Fri, 27 Aug 2021 00:27:07 +0530 Subject: [PATCH] SecurityGroup Improvements (#4183) --- moto/ec2/models.py | 122 +++++++++++-- moto/ec2/responses/security_groups.py | 228 +++++++++++++++++++++---- moto/ec2/utils.py | 11 ++ tests/terraform-tests.success.txt | 34 ++++ tests/test_ec2/test_security_groups.py | 16 ++ 5 files changed, 363 insertions(+), 48 deletions(-) diff --git a/moto/ec2/models.py b/moto/ec2/models.py index bab9a65e8..a0331bd1f 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -145,6 +145,7 @@ from .utils import ( create_dns_entries, split_route_id, random_security_group_id, + random_security_group_rule_id, random_snapshot_id, random_spot_fleet_request_id, random_spot_request_id, @@ -161,6 +162,7 @@ from .utils import ( get_prefix, simple_aws_filter_to_re, is_valid_cidr, + is_valid_ipv6_cidr, filter_internet_gateways, filter_reservations, filter_iam_instance_profile_associations, @@ -1999,16 +2001,47 @@ class RegionsAndZonesBackend(object): class SecurityRule(object): - def __init__(self, ip_protocol, from_port, to_port, ip_ranges, source_groups): + def __init__( + self, + ip_protocol, + from_port, + to_port, + ip_ranges, + source_groups, + prefix_list_ids=None, + ): + self.id = random_security_group_rule_id() self.ip_protocol = str(ip_protocol) self.ip_ranges = ip_ranges or [] self.source_groups = source_groups + self.prefix_list_ids = prefix_list_ids or [] self.from_port = self.to_port = None if self.ip_protocol != "-1": self.from_port = int(from_port) self.to_port = int(to_port) + ip_protocol_keywords = { + "tcp": "tcp", + "6": "tcp", + "udp": "udp", + "17": "udp", + "all": "-1", + "-1": "-1", + "tCp": "tcp", + "6": "tcp", + "UDp": "udp", + "17": "udp", + "ALL": "-1", + "icMp": "icmp", + "1": "icmp", + } + self.ip_protocol = ip_protocol_keywords.get(self.ip_protocol) + + @property + def owner_id(self): + return ACCOUNT_ID + def __eq__(self, other): if self.ip_protocol != other.ip_protocol: return False @@ -2016,6 +2049,8 @@ class SecurityRule(object): return False if self.source_groups != other.source_groups: return False + if self.prefix_list_ids != other.prefix_list_ids: + return False if self.ip_protocol != "-1": if self.from_port != other.from_port: return False @@ -2035,18 +2070,20 @@ class SecurityGroup(TaggedEC2Resource, CloudFormationModel): self.description = description self.ingress_rules = [] self.egress_rules = [ - SecurityRule("-1", None, None, [{"CidrIp": "0.0.0.0/0"}], []) + SecurityRule("-1", None, None, [{"CidrIp": "0.0.0.0/0"}], []), ] self.enis = {} self.vpc_id = vpc_id - self.owner_id = OWNER_ID + self.owner_id = ACCOUNT_ID self.add_tags(tags or {}) # Append default IPv6 egress rule for VPCs with IPv6 support if vpc_id: vpc = self.ec2_backend.vpcs.get(vpc_id) if vpc and len(vpc.get_cidr_block_association_set(ipv6=True)) > 0: - self.egress_rules.append(SecurityRule("-1", None, None, [], [])) + self.egress_rules.append( + SecurityRule("-1", None, None, [{"CidrIpv6": "::/0"}], []) + ) @staticmethod def cloudformation_name_type(): @@ -2077,7 +2114,7 @@ class SecurityGroup(TaggedEC2Resource, CloudFormationModel): security_group.add_tag(tag_key, tag_value) for ingress_rule in properties.get("SecurityGroupIngress", []): - source_group_id = ingress_rule.get("SourceSecurityGroupId") + source_group_id = ingress_rule.get("SourceSecurityGroupId",) ec2_backend.authorize_security_group_ingress( group_name_or_id=security_group.id, @@ -2085,7 +2122,7 @@ class SecurityGroup(TaggedEC2Resource, CloudFormationModel): from_port=ingress_rule["FromPort"], to_port=ingress_rule["ToPort"], ip_ranges=ingress_rule.get("CidrIp"), - source_group_ids=[source_group_id], + source_group_ids=[source_group_id] if source_group_id else [], vpc_id=vpc_id, ) @@ -2196,6 +2233,9 @@ class SecurityGroupBackend(object): def __init__(self): # the key in the dict group is the vpc_id or None (non-vpc) self.groups = defaultdict(dict) + # This will help us in RuleLimitExceed errors. + self.sg_old_ingress_ruls = {} + self.sg_old_egress_ruls = {} # Create the default security group self.create_security_group("default", "default group") @@ -2289,6 +2329,7 @@ class SecurityGroupBackend(object): ip_ranges, source_group_names=None, source_group_ids=None, + prefix_list_ids=None, vpc_id=None, ): group = self.get_security_group_by_name_or_id(group_name_or_id, vpc_id) @@ -2301,8 +2342,17 @@ class SecurityGroupBackend(object): ip_ranges = [json.loads(ip_ranges)] if ip_ranges: for cidr in ip_ranges: - if (type(cidr) is dict and not is_valid_cidr(cidr["CidrIp"])) or ( - type(cidr) is str and not is_valid_cidr(cidr) + if ( + type(cidr) is dict + and not any( + [ + is_valid_cidr(cidr.get("CidrIp", "")), + is_valid_ipv6_cidr(cidr.get("CidrIpv6", "")), + ] + ) + ) or ( + type(cidr) is str + and not any([is_valid_cidr(cidr), is_valid_ipv6_cidr(cidr)]) ): raise InvalidCIDRSubnetError(cidr=cidr) @@ -2320,21 +2370,24 @@ class SecurityGroupBackend(object): source_groups = [] for source_group_name in source_group_names: source_group = self.get_security_group_from_name(source_group_name, vpc_id) - # TODO raise exception if source_group is None? if source_group: source_groups.append(source_group) + else: + raise InvalidSecurityGroupNotFoundError(source_group_name) # for VPCs for source_group_id in source_group_ids: source_group = self.get_security_group_from_id(source_group_id) - # TODO raise exception if source_group is None? if source_group: source_groups.append(source_group) + else: + raise InvalidSecurityGroupNotFoundError(source_group_id) security_rule = SecurityRule( - ip_protocol, from_port, to_port, ip_ranges, source_groups + ip_protocol, from_port, to_port, ip_ranges, source_groups, prefix_list_ids ) group.add_ingress_rule(security_rule) + return security_rule, group def revoke_security_group_ingress( self, @@ -2345,6 +2398,7 @@ class SecurityGroupBackend(object): ip_ranges, source_group_names=None, source_group_ids=None, + prefix_list_ids=None, vpc_id=None, ): @@ -2362,10 +2416,11 @@ class SecurityGroupBackend(object): source_groups.append(source_group) security_rule = SecurityRule( - ip_protocol, from_port, to_port, ip_ranges, source_groups + ip_protocol, from_port, to_port, ip_ranges, source_groups, prefix_list_ids ) if security_rule in group.ingress_rules: group.ingress_rules.remove(security_rule) + self.sg_old_ingress_ruls[group.id] = group.ingress_rules.copy() return security_rule raise InvalidPermissionNotFoundError() @@ -2378,9 +2433,9 @@ class SecurityGroupBackend(object): ip_ranges, source_group_names=None, source_group_ids=None, + prefix_list_ids=None, vpc_id=None, ): - group = self.get_security_group_by_name_or_id(group_name_or_id, vpc_id) if group is None: raise InvalidSecurityGroupNotFoundError(group_name_or_id) @@ -2392,15 +2447,26 @@ class SecurityGroupBackend(object): ip_ranges = [json.loads(ip_ranges)] if ip_ranges: for cidr in ip_ranges: - if not is_valid_cidr(cidr["CidrIp"]): + if ( + type(cidr) is dict + and not any( + [ + is_valid_cidr(cidr.get("CidrIp", "")), + is_valid_ipv6_cidr(cidr.get("CidrIpv6", "")), + ] + ) + ) or ( + type(cidr) is str + and not any([is_valid_cidr(cidr), is_valid_ipv6_cidr(cidr)]) + ): raise InvalidCIDRSubnetError(cidr=cidr) - self._verify_group_will_respect_rule_count_limit( group, group.get_number_of_egress_rules(), ip_ranges, source_group_names, source_group_ids, + egress=True, ) source_group_names = source_group_names if source_group_names else [] @@ -2418,10 +2484,18 @@ class SecurityGroupBackend(object): if source_group: source_groups.append(source_group) + if group.vpc_id: + vpc = self.vpcs.get(group.vpc_id) + if vpc and not len(vpc.get_cidr_block_association_set(ipv6=True)) > 0: + for item in ip_ranges.copy(): + if "CidrIpv6" in item: + ip_ranges.remove(item) + security_rule = SecurityRule( - ip_protocol, from_port, to_port, ip_ranges, source_groups + ip_protocol, from_port, to_port, ip_ranges, source_groups, prefix_list_ids ) group.add_egress_rule(security_rule) + return security_rule, group def revoke_security_group_egress( self, @@ -2432,6 +2506,7 @@ class SecurityGroupBackend(object): ip_ranges, source_group_names=None, source_group_ids=None, + prefix_list_ids=None, vpc_id=None, ): @@ -2455,11 +2530,19 @@ class SecurityGroupBackend(object): # for ip in ip_ranges: # ip_ranges = [ip.get("CidrIp") if ip.get("CidrIp") == "0.0.0.0/0" else ip] + if group.vpc_id: + vpc = self.vpcs.get(group.vpc_id) + if vpc and not len(vpc.get_cidr_block_association_set(ipv6=True)) > 0: + for item in ip_ranges.copy(): + if "CidrIpv6" in item: + ip_ranges.remove(item) + security_rule = SecurityRule( - ip_protocol, from_port, to_port, ip_ranges, source_groups + ip_protocol, from_port, to_port, ip_ranges, source_groups, prefix_list_ids ) if security_rule in group.egress_rules: group.egress_rules.remove(security_rule) + self.sg_old_egress_ruls[group.id] = group.egress_rules.copy() return security_rule raise InvalidPermissionNotFoundError() @@ -2470,6 +2553,7 @@ class SecurityGroupBackend(object): ip_ranges, source_group_names=None, source_group_ids=None, + egress=False, ): max_nb_rules = 50 if group.vpc_id else 100 future_group_nb_rules = current_rule_nb @@ -2480,6 +2564,10 @@ class SecurityGroupBackend(object): if source_group_names: future_group_nb_rules += len(source_group_names) if future_group_nb_rules > max_nb_rules: + if group and not egress: + group.ingress_rules = self.sg_old_ingress_ruls[group.id] + if group and egress: + group.egress_rules = self.sg_old_egress_ruls[group.id] raise RulesPerSecurityGroupLimitExceededError diff --git a/moto/ec2/responses/security_groups.py b/moto/ec2/responses/security_groups.py index 8d71d1ce2..cc60201cd 100644 --- a/moto/ec2/responses/security_groups.py +++ b/moto/ec2/responses/security_groups.py @@ -2,7 +2,6 @@ from __future__ import unicode_literals from moto.core.responses import BaseResponse from moto.ec2.utils import filters_from_querystring -from moto.core import ACCOUNT_ID def try_parse_int(value, default=None): @@ -26,6 +25,22 @@ def parse_sg_attributes_from_dict(sg_attributes): ip_ranges.append(ip_range) + ip_ranges_tree = sg_attributes.get("Ipv6Ranges") or {} + for ip_range_idx in sorted(ip_ranges_tree.keys()): + ip_range = {"CidrIpv6": ip_ranges_tree[ip_range_idx]["CidrIpv6"][0]} + if ip_ranges_tree[ip_range_idx].get("Description"): + ip_range["Description"] = ip_ranges_tree[ip_range_idx].get("Description")[0] + + ip_ranges.append(ip_range) + + if "CidrIp" in sg_attributes: + cidr_ip = sg_attributes.get("CidrIp")[0] + ip_ranges.append({"CidrIp": cidr_ip}) + + if "CidrIpv6" in sg_attributes: + cidr_ipv6 = sg_attributes.get("CidrIpv6")[0] + ip_ranges.append({"CidrIpv6": cidr_ipv6}) + source_groups = [] source_group_ids = [] groups_tree = sg_attributes.get("Groups") or {} @@ -36,7 +51,26 @@ def parse_sg_attributes_from_dict(sg_attributes): elif "GroupName" in group_dict: source_groups.append(group_dict["GroupName"][0]) - return ip_protocol, from_port, to_port, ip_ranges, source_groups, source_group_ids + prefix_list_ids = [] + pl_tree = sg_attributes.get("PrefixListIds") or {} + for pl_index in sorted(pl_tree): + pl_dict = pl_tree.get(pl_index, {}) + pl_item = {} + if "PrefixListId" in pl_dict: + pl_item["PrefixListId"] = pl_dict.get("PrefixListId")[0] + if "Description" in pl_dict: + pl_item["Description"] = pl_dict.get("Description")[0] + if pl_item: + prefix_list_ids.append(pl_item) + return ( + ip_protocol, + from_port, + to_port, + ip_ranges, + source_groups, + source_group_ids, + prefix_list_ids, + ) class SecurityGroups(BaseResponse): @@ -64,6 +98,7 @@ class SecurityGroups(BaseResponse): ip_ranges, source_groups, source_group_ids, + prefix_list_ids, ) = parse_sg_attributes_from_dict(querytree) yield ( @@ -74,6 +109,7 @@ class SecurityGroups(BaseResponse): ip_ranges, source_groups, source_group_ids, + prefix_list_ids, ) ip_permissions = querytree.get("IpPermissions") or {} @@ -87,6 +123,7 @@ class SecurityGroups(BaseResponse): ip_ranges, source_groups, source_group_ids, + prefix_list_ids, ) = parse_sg_attributes_from_dict(ip_permission) yield ( @@ -97,19 +134,24 @@ class SecurityGroups(BaseResponse): ip_ranges, source_groups, source_group_ids, + prefix_list_ids, ) def authorize_security_group_egress(self): if self.is_not_dryrun("GrantSecurityGroupEgress"): for args in self._process_rules_from_querystring(): - self.ec2_backend.authorize_security_group_egress(*args) - return AUTHORIZE_SECURITY_GROUP_EGRESS_RESPONSE + rule, group = self.ec2_backend.authorize_security_group_egress(*args) + self.ec2_backend.sg_old_egress_ruls[group.id] = group.egress_rules.copy() + template = self.response_template(AUTHORIZE_SECURITY_GROUP_EGRESS_RESPONSE) + return template.render(rule=rule, group=group) def authorize_security_group_ingress(self): if self.is_not_dryrun("GrantSecurityGroupIngress"): for args in self._process_rules_from_querystring(): - self.ec2_backend.authorize_security_group_ingress(*args) - return AUTHORIZE_SECURITY_GROUP_INGRESS_RESPONSE + rule, group = self.ec2_backend.authorize_security_group_ingress(*args) + self.ec2_backend.sg_old_ingress_ruls[group.id] = group.ingress_rules.copy() + template = self.response_template(AUTHORIZE_SECURITY_GROUP_INGRESS_RESPONSE) + return template.render(rule=rule, group=group) def create_security_group(self): name = self._get_param("GroupName") @@ -124,6 +166,13 @@ class SecurityGroups(BaseResponse): group = self.ec2_backend.create_security_group( name, description, vpc_id=vpc_id, tags=tags ) + if group: + self.ec2_backend.sg_old_ingress_ruls[ + group.id + ] = group.ingress_rules.copy() + self.ec2_backend.sg_old_egress_ruls[ + group.id + ] = group.egress_rules.copy() template = self.response_template(CREATE_SECURITY_GROUP_RESPONSE) return template.render(group=group) @@ -181,15 +230,12 @@ DELETE_GROUP_RESPONSE = """ +DESCRIBE_SECURITY_GROUPS_RESPONSE = """ 59dbff89-35bd-4eac-99ed-be587EXAMPLE {% for group in groups %} - """ - + ACCOUNT_ID - + """ + {{ group.owner_id }} {{ group.id }} {{ group.name }} {{ group.description }} @@ -209,9 +255,7 @@ DESCRIBE_SECURITY_GROUPS_RESPONSE = ( {% for source_group in rule.source_groups %} - """ - + ACCOUNT_ID - + """ + {{ source_group.owner_id }} {{ source_group.id }} {{ source_group.name }} @@ -219,14 +263,36 @@ DESCRIBE_SECURITY_GROUPS_RESPONSE = ( {% for ip_range in rule.ip_ranges %} + {% if ip_range['CidrIp'] %} - {{ ip_range['CidrIp'] }} + {{ ip_range['CidrIp'] }} {% if ip_range['Description'] %} - {{ ip_range['Description'] }} + {{ ip_range['Description'] }} {% endif %} + {% endif %} {% endfor %} + + {% for ip_range in rule.ip_ranges %} + {% if ip_range['CidrIpv6'] %} + + {{ ip_range['CidrIpv6'] }} + {% if ip_range['Description'] %} + {{ ip_range['Description'] }} + {% endif %} + + {% endif %} + {% endfor %} + + + {% for prefix_list in rule.prefix_list_ids %} + + {{ prefix_list.PrefixListId }} + {{ prefix_list.Description }} + + {% endfor %} + {% endfor %} @@ -243,9 +309,7 @@ DESCRIBE_SECURITY_GROUPS_RESPONSE = ( {% for source_group in rule.source_groups %} - """ - + ACCOUNT_ID - + """ + {{ source_group.owner_id }} {{ source_group.id }} {{ source_group.name }} @@ -253,22 +317,44 @@ DESCRIBE_SECURITY_GROUPS_RESPONSE = ( {% for ip_range in rule.ip_ranges %} + {% if ip_range['CidrIp'] %} - {{ ip_range['CidrIp'] }} + {{ ip_range['CidrIp'] }} {% if ip_range['Description'] %} - {{ ip_range['Description'] }} + {{ ip_range['Description'] }} {% endif %} + {% endif %} {% endfor %} + + {% for ip_range in rule.ip_ranges %} + {% if ip_range['CidrIpv6'] %} + + {{ ip_range['CidrIpv6'] }} + {% if ip_range['Description'] %} + {{ ip_range['Description'] }} + {% endif %} + + {% endif %} + {% endfor %} + + + {% if rule.prefix_list_ids %} + {% for prefix_list in rule.prefix_list_ids %} + + {{ prefix_list.PrefixListId }} + {{ prefix_list.Description }} + + {% endfor %} + {% endif %} + {% endfor %} {% for tag in group.get_tags() %} - {{ tag.resource_id }} - {{ tag.resource_type }} {{ tag.key }} {{ tag.value }} @@ -278,11 +364,51 @@ DESCRIBE_SECURITY_GROUPS_RESPONSE = ( {% endfor %} """ -) -AUTHORIZE_SECURITY_GROUP_INGRESS_RESPONSE = """ - 59dbff89-35bd-4eac-99ed-be587EXAMPLE - true +AUTHORIZE_SECURITY_GROUP_INGRESS_RESPONSE = """ + b1f67202-c2c2-4ba4-8464-c8b1d8f5af7a + true + + {% for item in rule.ip_ranges %} + + {% if item.CidrIp %} + {{ item.CidrIp }} + {% endif %} + {% if item.CidrIpv6 %} + {{ item.CidrIpv6 }} + {% endif %} + {{ item.Description or '' }} + {% if rule.from_port is not none %} + {{ rule.from_port }} + {% endif %} + {{ group.id }} + {{ rule.owner_id }} + {{ rule.ip_protocol }} + false + {{ rule.id }} + {% if rule.to_port is not none %} + {{ rule.to_port }} + {% endif %} + + {% endfor %} + {% for item in rule.prefix_list_ids %} + + {{ item.PrefixListId }} + {{ item.Description or '' }} + {% if rule.from_port is not none %} + {{ rule.from_port }} + {% endif %} + {{ group.id }} + {{ rule.owner_id }} + {{ rule.ip_protocol }} + false + {{ rule.id }} + {% if rule.to_port is not none %} + {{ rule.to_port }} + {% endif %} + + {% endfor %} + """ REVOKE_SECURITY_GROUP_INGRESS_RESPONSE = """ @@ -290,10 +416,50 @@ REVOKE_SECURITY_GROUP_INGRESS_RESPONSE = """true """ -AUTHORIZE_SECURITY_GROUP_EGRESS_RESPONSE = """ - - 59dbff89-35bd-4eac-99ed-be587EXAMPLE - true +AUTHORIZE_SECURITY_GROUP_EGRESS_RESPONSE = """ + b1f67202-c2c2-4ba4-8464-c8b1d8f5af7a + true + + {% for item in rule.ip_ranges %} + + {% if item.CidrIp %} + {{ item.CidrIp }} + {% endif %} + {% if item.CidrIpv6 %} + {{ item.CidrIpv6 }} + {% endif %} + {{ item.Description or '' }} + {% if rule.from_port is not none %} + {{ rule.from_port }} + {% endif %} + {{ group.id }} + {{ rule.owner_id }} + {{ rule.ip_protocol }} + true + {{ rule.id }} + {% if rule.to_port is not none %} + {{ rule.to_port }} + {% endif %} + + {% endfor %} + {% for item in rule.prefix_list_ids %} + + {{ item.PrefixListId }} + {{ item.Description or '' }} + {% if rule.from_port is not none %} + {{ rule.from_port }} + {% endif %} + {{ group.id }} + {{ rule.owner_id }} + {{ rule.ip_protocol }} + true + {{ rule.id }} + {% if rule.to_port is not none %} + {{ rule.to_port }} + {% endif %} + + {% endfor %} + """ REVOKE_SECURITY_GROUP_EGRESS_RESPONSE = """ diff --git a/moto/ec2/utils.py b/moto/ec2/utils.py index 328b77029..5c0835bd5 100644 --- a/moto/ec2/utils.py +++ b/moto/ec2/utils.py @@ -34,6 +34,7 @@ EC2_RESOURCE_TO_PREFIX = { "route-table": "rtb", "route-table-association": "rtbassoc", "security-group": "sg", + "security-group-rule": "sgr", "snapshot": "snap", "spot-instance-request": "sir", "spot-fleet-request": "sfr", @@ -82,6 +83,10 @@ def random_security_group_id(): return random_id(prefix=EC2_RESOURCE_TO_PREFIX["security-group"]) +def random_security_group_rule_id(): + return random_id(prefix=EC2_RESOURCE_TO_PREFIX["security-group-rule"], size=17) + + def random_flow_log_id(): return random_id(prefix=EC2_RESOURCE_TO_PREFIX["flow-logs"]) @@ -590,6 +595,12 @@ def is_valid_cidr(cird): return cidr_pattern_re.match(cird) is not None +def is_valid_ipv6_cidr(cird): + cidr_pattern = r"^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$" + cidr_pattern_re = re.compile(cidr_pattern) + return cidr_pattern_re.match(cird) is not None + + def generate_instance_identity_document(instance): """ http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html diff --git a/tests/terraform-tests.success.txt b/tests/terraform-tests.success.txt index 44e0bd056..82172fd3c 100644 --- a/tests/terraform-tests.success.txt +++ b/tests/terraform-tests.success.txt @@ -93,3 +93,37 @@ TestAccAWSRouteTable_basic TestAccAWSSsmDocumentDataSource TestAccAwsEc2ManagedPrefixList TestAccAWSEgressOnlyInternetGateway +TestAccAWSSecurityGroup_allowAll +TestAccAWSSecurityGroup_sourceSecurityGroup +TestAccAWSSecurityGroup_IPRangeAndSecurityGroupWithSameRules +TestAccAWSSecurityGroup_IPRangesWithSameRules +TestAccAWSSecurityGroup_basic +TestAccAWSSecurityGroup_egressConfigMode +TestAccAWSSecurityGroup_ingressConfigMode +TestAccAWSSecurityGroup_ipv6 +TestAccAWSSecurityGroup_Name_Generated +TestAccAWSSecurityGroup_Name_TerraformPrefix +TestAccAWSSecurityGroup_NamePrefix +TestAccAWSSecurityGroup_NamePrefix_TerraformPrefix +TestAccAWSSecurityGroup_self +TestAccAWSSecurityGroup_vpc +TestAccAWSSecurityGroup_vpcNegOneIngress +TestAccAWSSecurityGroup_vpcProtoNumIngress +TestAccAWSSecurityGroup_multiIngress +TestAccAWSSecurityGroup_ruleDescription +TestAccAWSSecurityGroup_defaultEgressVPC +TestAccAWSSecurityGroup_defaultEgressClassic +TestAccAWSSecurityGroup_driftComplex +TestAccAWSSecurityGroup_invalidCIDRBlock +TestAccAWSSecurityGroup_tags +TestAccAWSSecurityGroup_CIDRandGroups +TestAccAWSSecurityGroup_ingressWithCidrAndSGsVPC +TestAccAWSSecurityGroup_ipv4andipv6Egress +TestAccAWSSecurityGroup_failWithDiffMismatch +TestAccAWSSecurityGroup_ruleLimitExceededAppend +TestAccAWSSecurityGroupRule_Ingress_VPC +TestAccAWSSecurityGroupRule_MultipleRuleSearching_AllProtocolCrash +TestAccAWSSecurityGroup_rulesDropOnError +TestAccAWSSecurityGroup_ruleLimitExceededAllNew +TestAccAWSSecurityGroup_ruleLimitExceededPrepend +TestAccAWSSecurityGroup_ruleLimitCidrBlockExceededAppend diff --git a/tests/test_ec2/test_security_groups.py b/tests/test_ec2/test_security_groups.py index 4d3349c08..65e959b08 100644 --- a/tests/test_ec2/test_security_groups.py +++ b/tests/test_ec2/test_security_groups.py @@ -378,6 +378,8 @@ def test_authorize_other_group_egress_and_revoke(): {"GroupId": sg02.id, "GroupName": "sg02", "UserId": sg02.owner_id} ], "IpRanges": [], + "Ipv6Ranges": [], + "PrefixListIds": [], } sg01.authorize_egress(IpPermissions=[ip_permission]) @@ -858,6 +860,8 @@ def test_authorize_and_revoke_in_bulk(): {"GroupId": sg02.id, "GroupName": "sg02", "UserId": sg02.owner_id} ], "IpRanges": [], + "Ipv6Ranges": [], + "PrefixListIds": [], }, { "IpProtocol": "tcp", @@ -865,6 +869,8 @@ def test_authorize_and_revoke_in_bulk(): "ToPort": 27018, "UserIdGroupPairs": [{"GroupId": sg02.id, "UserId": sg02.owner_id}], "IpRanges": [], + "Ipv6Ranges": [], + "PrefixListIds": [], }, { "IpProtocol": "tcp", @@ -872,6 +878,8 @@ def test_authorize_and_revoke_in_bulk(): "ToPort": 27017, "UserIdGroupPairs": [{"GroupName": "sg03", "UserId": sg03.owner_id}], "IpRanges": [], + "Ipv6Ranges": [], + "PrefixListIds": [], }, { "IpProtocol": "tcp", @@ -881,6 +889,8 @@ def test_authorize_and_revoke_in_bulk(): "IpRanges": [ {"CidrIp": "10.10.10.0/24", "Description": "Some Description"} ], + "Ipv6Ranges": [], + "PrefixListIds": [], }, { "IpProtocol": "tcp", @@ -888,6 +898,8 @@ def test_authorize_and_revoke_in_bulk(): "ToPort": 27016, "UserIdGroupPairs": [{"GroupId": sg04.id, "UserId": sg04.owner_id}], "IpRanges": [{"CidrIp": "10.10.10.0/24"}], + "Ipv6Ranges": [], + "PrefixListIds": [], }, ] expected_ip_permissions = copy.deepcopy(ip_permissions) @@ -979,6 +991,8 @@ def test_revoke_security_group_egress(): "IpProtocol": "-1", "IpRanges": [{"CidrIp": "0.0.0.0/0"}], "UserIdGroupPairs": [], + "Ipv6Ranges": [], + "PrefixListIds": [], } ] ) @@ -989,6 +1003,8 @@ def test_revoke_security_group_egress(): "IpProtocol": "-1", "IpRanges": [{"CidrIp": "0.0.0.0/0"}], "UserIdGroupPairs": [], + "Ipv6Ranges": [], + "PrefixListIds": [], } ] )