SecurityGroup Improvements (#4183)

This commit is contained in:
Mohit Alonja 2021-08-27 00:27:07 +05:30 committed by GitHub
parent 6a644850f6
commit 11a37c357b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 363 additions and 48 deletions

View File

@ -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

View File

@ -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 = """<DeleteSecurityGroupResponse xmlns="http://ec2.amazon
<return>true</return>
</DeleteSecurityGroupResponse>"""
DESCRIBE_SECURITY_GROUPS_RESPONSE = (
"""<DescribeSecurityGroupsResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
DESCRIBE_SECURITY_GROUPS_RESPONSE = """<DescribeSecurityGroupsResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
<requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
<securityGroupInfo>
{% for group in groups %}
<item>
<ownerId>"""
+ ACCOUNT_ID
+ """</ownerId>
<ownerId>{{ group.owner_id }}</ownerId>
<groupId>{{ group.id }}</groupId>
<groupName>{{ group.name }}</groupName>
<groupDescription>{{ group.description }}</groupDescription>
@ -209,9 +255,7 @@ DESCRIBE_SECURITY_GROUPS_RESPONSE = (
<groups>
{% for source_group in rule.source_groups %}
<item>
<userId>"""
+ ACCOUNT_ID
+ """</userId>
<userId>{{ source_group.owner_id }}</userId>
<groupId>{{ source_group.id }}</groupId>
<groupName>{{ source_group.name }}</groupName>
</item>
@ -219,14 +263,36 @@ DESCRIBE_SECURITY_GROUPS_RESPONSE = (
</groups>
<ipRanges>
{% for ip_range in rule.ip_ranges %}
{% if ip_range['CidrIp'] %}
<item>
<cidrIp>{{ ip_range['CidrIp'] }}</cidrIp>
<cidrIp>{{ ip_range['CidrIp'] }}</cidrIp>
{% if ip_range['Description'] %}
<description>{{ ip_range['Description'] }}</description>
<description>{{ ip_range['Description'] }}</description>
{% endif %}
</item>
{% endif %}
{% endfor %}
</ipRanges>
<ipv6Ranges>
{% for ip_range in rule.ip_ranges %}
{% if ip_range['CidrIpv6'] %}
<item>
<cidrIpv6>{{ ip_range['CidrIpv6'] }}</cidrIpv6>
{% if ip_range['Description'] %}
<description>{{ ip_range['Description'] }}</description>
{% endif %}
</item>
{% endif %}
{% endfor %}
</ipv6Ranges>
<prefixListIds>
{% for prefix_list in rule.prefix_list_ids %}
<item>
<prefixListId>{{ prefix_list.PrefixListId }}</prefixListId>
<description>{{ prefix_list.Description }}</description>
</item>
{% endfor %}
</prefixListIds>
</item>
{% endfor %}
</ipPermissions>
@ -243,9 +309,7 @@ DESCRIBE_SECURITY_GROUPS_RESPONSE = (
<groups>
{% for source_group in rule.source_groups %}
<item>
<userId>"""
+ ACCOUNT_ID
+ """</userId>
<userId>{{ source_group.owner_id }}</userId>
<groupId>{{ source_group.id }}</groupId>
<groupName>{{ source_group.name }}</groupName>
</item>
@ -253,22 +317,44 @@ DESCRIBE_SECURITY_GROUPS_RESPONSE = (
</groups>
<ipRanges>
{% for ip_range in rule.ip_ranges %}
{% if ip_range['CidrIp'] %}
<item>
<cidrIp>{{ ip_range['CidrIp'] }}</cidrIp>
<cidrIp>{{ ip_range['CidrIp'] }}</cidrIp>
{% if ip_range['Description'] %}
<description>{{ ip_range['Description'] }}</description>
<description>{{ ip_range['Description'] }}</description>
{% endif %}
</item>
{% endif %}
{% endfor %}
</ipRanges>
<ipv6Ranges>
{% for ip_range in rule.ip_ranges %}
{% if ip_range['CidrIpv6'] %}
<item>
<cidrIpv6>{{ ip_range['CidrIpv6'] }}</cidrIpv6>
{% if ip_range['Description'] %}
<description>{{ ip_range['Description'] }}</description>
{% endif %}
</item>
{% endif %}
{% endfor %}
</ipv6Ranges>
<prefixListIds>
{% if rule.prefix_list_ids %}
{% for prefix_list in rule.prefix_list_ids %}
<item>
<prefixListId>{{ prefix_list.PrefixListId }}</prefixListId>
<description>{{ prefix_list.Description }}</description>
</item>
{% endfor %}
{% endif %}
</prefixListIds>
</item>
{% endfor %}
</ipPermissionsEgress>
<tagSet>
{% for tag in group.get_tags() %}
<item>
<resourceId>{{ tag.resource_id }}</resourceId>
<resourceType>{{ tag.resource_type }}</resourceType>
<key>{{ tag.key }}</key>
<value>{{ tag.value }}</value>
</item>
@ -278,11 +364,51 @@ DESCRIBE_SECURITY_GROUPS_RESPONSE = (
{% endfor %}
</securityGroupInfo>
</DescribeSecurityGroupsResponse>"""
)
AUTHORIZE_SECURITY_GROUP_INGRESS_RESPONSE = """<AuthorizeSecurityGroupIngressResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
<requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
<return>true</return>
AUTHORIZE_SECURITY_GROUP_INGRESS_RESPONSE = """<AuthorizeSecurityGroupIngressResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>b1f67202-c2c2-4ba4-8464-c8b1d8f5af7a</requestId>
<return>true</return>
<securityGroupRuleSet>
{% for item in rule.ip_ranges %}
<item>
{% if item.CidrIp %}
<cidrIpv4>{{ item.CidrIp }}</cidrIpv4>
{% endif %}
{% if item.CidrIpv6 %}
<cidrIpv6>{{ item.CidrIpv6 }}</cidrIpv6>
{% endif %}
<description>{{ item.Description or '' }}</description>
{% if rule.from_port is not none %}
<fromPort>{{ rule.from_port }}</fromPort>
{% endif %}
<groupId>{{ group.id }}</groupId>
<groupOwnerId>{{ rule.owner_id }}</groupOwnerId>
<ipProtocol>{{ rule.ip_protocol }}</ipProtocol>
<isEgress>false</isEgress>
<securityGroupRuleId>{{ rule.id }}</securityGroupRuleId>
{% if rule.to_port is not none %}
<toPort>{{ rule.to_port }}</toPort>
{% endif %}
</item>
{% endfor %}
{% for item in rule.prefix_list_ids %}
<item>
<prefixListId>{{ item.PrefixListId }}</prefixListId>
<description>{{ item.Description or '' }}</description>
{% if rule.from_port is not none %}
<fromPort>{{ rule.from_port }}</fromPort>
{% endif %}
<groupId>{{ group.id }}</groupId>
<groupOwnerId>{{ rule.owner_id }}</groupOwnerId>
<ipProtocol>{{ rule.ip_protocol }}</ipProtocol>
<isEgress>false</isEgress>
<securityGroupRuleId>{{ rule.id }}</securityGroupRuleId>
{% if rule.to_port is not none %}
<toPort>{{ rule.to_port }}</toPort>
{% endif %}
</item>
{% endfor %}
</securityGroupRuleSet>
</AuthorizeSecurityGroupIngressResponse>"""
REVOKE_SECURITY_GROUP_INGRESS_RESPONSE = """<RevokeSecurityGroupIngressResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
@ -290,10 +416,50 @@ REVOKE_SECURITY_GROUP_INGRESS_RESPONSE = """<RevokeSecurityGroupIngressResponse
<return>true</return>
</RevokeSecurityGroupIngressResponse>"""
AUTHORIZE_SECURITY_GROUP_EGRESS_RESPONSE = """
<AuthorizeSecurityGroupEgressResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
<requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
<return>true</return>
AUTHORIZE_SECURITY_GROUP_EGRESS_RESPONSE = """<AuthorizeSecurityGroupEgressResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>b1f67202-c2c2-4ba4-8464-c8b1d8f5af7a</requestId>
<return>true</return>
<securityGroupRuleSet>
{% for item in rule.ip_ranges %}
<item>
{% if item.CidrIp %}
<cidrIpv4>{{ item.CidrIp }}</cidrIpv4>
{% endif %}
{% if item.CidrIpv6 %}
<cidrIpv6>{{ item.CidrIpv6 }}</cidrIpv6>
{% endif %}
<description>{{ item.Description or '' }}</description>
{% if rule.from_port is not none %}
<fromPort>{{ rule.from_port }}</fromPort>
{% endif %}
<groupId>{{ group.id }}</groupId>
<groupOwnerId>{{ rule.owner_id }}</groupOwnerId>
<ipProtocol>{{ rule.ip_protocol }}</ipProtocol>
<isEgress>true</isEgress>
<securityGroupRuleId>{{ rule.id }}</securityGroupRuleId>
{% if rule.to_port is not none %}
<toPort>{{ rule.to_port }}</toPort>
{% endif %}
</item>
{% endfor %}
{% for item in rule.prefix_list_ids %}
<item>
<prefixListId>{{ item.PrefixListId }}</prefixListId>
<description>{{ item.Description or '' }}</description>
{% if rule.from_port is not none %}
<fromPort>{{ rule.from_port }}</fromPort>
{% endif %}
<groupId>{{ group.id }}</groupId>
<groupOwnerId>{{ rule.owner_id }}</groupOwnerId>
<ipProtocol>{{ rule.ip_protocol }}</ipProtocol>
<isEgress>true</isEgress>
<securityGroupRuleId>{{ rule.id }}</securityGroupRuleId>
{% if rule.to_port is not none %}
<toPort>{{ rule.to_port }}</toPort>
{% endif %}
</item>
{% endfor %}
</securityGroupRuleSet>
</AuthorizeSecurityGroupEgressResponse>"""
REVOKE_SECURITY_GROUP_EGRESS_RESPONSE = """<RevokeSecurityGroupEgressResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">

View File

@ -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

View File

@ -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

View File

@ -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": [],
}
]
)