def _verify_subnet_ips(region, ip_addresses): """Perform additional checks on the IPAddresses. NOTE: This does not include IPv6 addresses. """ if len(ip_addresses) < 2: raise InvalidRequestException( "Resolver endpoint needs to have at least 2 IP addresses") subnets = defaultdict(set) for subnet_id, ip_addr in [(x["SubnetId"], x["Ip"]) for x in ip_addresses]: try: subnet_info = ec2_backends[region].get_all_subnets( subnet_ids=[subnet_id])[0] except InvalidSubnetIdError as exc: raise InvalidParameterException( f"The subnet ID '{subnet_id}' does not exist") from exc # IP in IPv4 CIDR range and not reserved? if ip_address(ip_addr) in subnet_info.reserved_ips or ip_address( ip_addr) not in ip_network(subnet_info.cidr_block): raise InvalidRequestException( f"IP address '{ip_addr}' is either not in subnet " f"'{subnet_id}' CIDR range or is reserved") if ip_addr in subnets[subnet_id]: raise ResourceExistsException( f"The IP address '{ip_addr}' in subnet '{subnet_id}' is already in use" ) subnets[subnet_id].add(ip_addr)
def delete_resolver_endpoint(self, resolver_endpoint_id): """Delete a resolver endpoint.""" self._validate_resolver_endpoint_id(resolver_endpoint_id) # Can't delete an endpoint if there are rules associated with it. rules = [ x.id for x in self.resolver_rules.values() if x.resolver_endpoint_id == resolver_endpoint_id ] if rules: raise InvalidRequestException( f"Cannot delete resolver endpoint unless its related resolver " f"rules are deleted. The following rules still exist for " f"this resolver endpoint: {','.join(rules)}" ) self.tagger.delete_all_tags_for_resource(resolver_endpoint_id) resolver_endpoint = self.resolver_endpoints.pop(resolver_endpoint_id) resolver_endpoint.delete_eni() resolver_endpoint.status = "DELETING" resolver_endpoint.status_message = resolver_endpoint.status_message.replace( "Successfully created", "Deleting" ) return resolver_endpoint
def disassociate_resolver_endpoint_ip_address( self, resolver_endpoint_id, ip_address ): self._validate_resolver_endpoint_id(resolver_endpoint_id) resolver_endpoint = self.resolver_endpoints[resolver_endpoint_id] if not (ip_address.get("Ip") or ip_address.get("IpId")): raise InvalidRequestException( "[RSLVR-00503] Need to specify either the IP ID or both subnet and IP address in order to remove IP address." ) resolver_endpoint.disassociate_ip_address(ip_address) return resolver_endpoint
def associate_resolver_rule(self, region, resolver_rule_id, name, vpc_id): """Return description for a newly created resolver rule association.""" validate_args( [("resolverRuleId", resolver_rule_id), ("name", name), ("vPCId", vpc_id)] ) associations = [ x for x in self.resolver_rule_associations.values() if x.region == region ] if len(associations) > ResolverRuleAssociation.MAX_RULE_ASSOCIATIONS_PER_REGION: # This error message was not verified to be the same for AWS. raise LimitExceededException( f"Account '{ACCOUNT_ID}' has exceeded 'max-rule-association'" ) if resolver_rule_id not in self.resolver_rules: raise ResourceNotFoundException( f"Resolver rule with ID '{resolver_rule_id}' does not exist." ) vpcs = ec2_backends[region].describe_vpcs() if vpc_id not in [x.id for x in vpcs]: raise InvalidParameterException(f"The vpc ID '{vpc_id}' does not exist") # Can't duplicate resolver rule, vpc id associations. for association in self.resolver_rule_associations.values(): if ( resolver_rule_id == association.resolver_rule_id and vpc_id == association.vpc_id ): raise InvalidRequestException( f"Cannot associate rules with same domain name with same " f"VPC. Conflict with resolver rule '{resolver_rule_id}'" ) rule_association_id = f"rslvr-rrassoc-{get_random_hex(17)}" rule_association = ResolverRuleAssociation( region, rule_association_id, resolver_rule_id, vpc_id, name ) self.resolver_rule_associations[rule_association_id] = rule_association return rule_association
def create_resolver_rule( self, region, creator_request_id, name, rule_type, domain_name, target_ips, resolver_endpoint_id, tags, ): # pylint: disable=too-many-arguments """Return description for a newly created resolver rule.""" validate_args( [ ("creatorRequestId", creator_request_id), ("ruleType", rule_type), ("domainName", domain_name), ("name", name), *[("targetIps.port", x) for x in target_ips], ("resolverEndpointId", resolver_endpoint_id), ] ) errmsg = self.tagger.validate_tags( tags or [], limit=ResolverRule.MAX_TAGS_PER_RESOLVER_RULE ) if errmsg: raise TagValidationException(errmsg) rules = [x for x in self.resolver_rules.values() if x.region == region] if len(rules) > ResolverRule.MAX_RULES_PER_REGION: # Did not verify that this is the actual error message. raise LimitExceededException( f"Account '{get_account_id()}' has exceeded 'max-rules'" ) # Per the AWS documentation and as seen with the AWS console, target # ips are only relevant when the value of Rule is FORWARD. However, # boto3 ignores this condition and so shall we. for ip_addr in [x["Ip"] for x in target_ips]: try: # boto3 fails with an InternalServiceException if IPv6 # addresses are used, which isn't helpful. if not isinstance(ip_address(ip_addr), IPv4Address): raise InvalidParameterException( f"Only IPv4 addresses may be used: '{ip_addr}'" ) except ValueError as exc: raise InvalidParameterException( f"Invalid IP address: '{ip_addr}'" ) from exc # The boto3 documentation indicates that ResolverEndpoint is # optional, as does the AWS documention. But if resolver_endpoint_id # is set to None or an empty string, it results in boto3 raising # a ParamValidationError either regarding the type or len of string. if resolver_endpoint_id: if resolver_endpoint_id not in [ x.id for x in self.resolver_endpoints.values() ]: raise ResourceNotFoundException( f"Resolver endpoint with ID '{resolver_endpoint_id}' does not exist." ) if rule_type == "SYSTEM": raise InvalidRequestException( "Cannot specify resolver endpoint ID and target IP " "for SYSTEM type resolver rule" ) if creator_request_id in [ x.creator_request_id for x in self.resolver_rules.values() ]: raise ResourceExistsException( f"Resolver rule with creator request ID " f"'{creator_request_id}' already exists" ) rule_id = f"rslvr-rr-{get_random_hex(17)}" resolver_rule = ResolverRule( region, rule_id, creator_request_id, rule_type, domain_name, target_ips, resolver_endpoint_id, name, ) self.resolver_rules[rule_id] = resolver_rule self.tagger.tag_resource(resolver_rule.arn, tags or []) return resolver_rule