예제 #1
0
파일: pool.py 프로젝트: hyuntae95/octavia
    def _validate_create_pool(self, lock_session, pool_dict, listener_id=None):
        """Validate creating pool on load balancer.

        Update database for load balancer and (optional) listener based on
        provisioning status.
        """
        # Make sure we have a client CA if they specify a CRL
        if (pool_dict.get('crl_container_id')
                and not pool_dict.get('ca_tls_certificate_id')):
            raise exceptions.ValidationException(
                detail=_("A CA certificate reference is required to "
                         "specify a revocation list."))

        tls_certificate_id = pool_dict.get('tls_certificate_id', None)
        tls_refs = [tls_certificate_id] if tls_certificate_id else []
        self._validate_tls_refs(tls_refs)

        # Validate the client CA cert and optional client CRL
        if pool_dict.get('ca_tls_certificate_id'):
            self._validate_client_ca_and_crl_refs(
                pool_dict.get('ca_tls_certificate_id'),
                pool_dict.get('crl_container_id', None))

        # Check TLS cipher blacklist
        if 'tls_ciphers' in pool_dict and pool_dict['tls_ciphers']:
            rejected_ciphers = validate.check_cipher_blacklist(
                pool_dict['tls_ciphers'])
            if rejected_ciphers:
                raise exceptions.ValidationException(detail=_(
                    'The following ciphers have been blacklisted by an '
                    'administrator: ' + ', '.join(rejected_ciphers)))

        if pool_dict['tls_enabled']:
            # Validate TLS version list
            validate.check_tls_version_list(pool_dict['tls_versions'])
            # Validate TLS versions against minimum
            validate.check_tls_version_min(pool_dict['tls_versions'])

        try:
            return self.repositories.create_pool_on_load_balancer(
                lock_session, pool_dict, listener_id=listener_id)
        except odb_exceptions.DBDuplicateEntry:
            raise exceptions.IDAlreadyExists()
        except odb_exceptions.DBError:
            # TODO(blogan): will have to do separate validation protocol
            # before creation or update since the exception messages
            # do not give any information as to what constraint failed
            raise exceptions.InvalidOption(value='', option='')
예제 #2
0
    def _validate_listener_PUT(self, listener, db_listener):
        # TODO(rm_work): Do we need something like this? What do we do on an
        # empty body for a PUT?
        if not listener:
            raise exceptions.ValidationException(
                detail='No listener object supplied.')

        # Check for UDP compatibility
        if (db_listener.protocol == constants.PROTOCOL_UDP
                and self._is_tls_or_insert_header(listener.to_dict())):
            raise exceptions.ValidationException(
                detail=_("%s protocol listener does not support TLS or header "
                         "insertion.") % constants.PROTOCOL_UDP)

        # Check for certs when not TERMINATED_HTTPS
        if (db_listener.protocol != constants.PROTOCOL_TERMINATED_HTTPS
                and self._has_tls_container_refs(listener.to_dict())):
            raise exceptions.ValidationException(
                detail=_(
                    "Certificate container references are only allowed on "
                    "%s protocol listeners.") %
                constants.PROTOCOL_TERMINATED_HTTPS)

        # Make sure we have a client CA cert if they enable client auth
        if ((listener.client_authentication != wtypes.Unset
             and listener.client_authentication != constants.CLIENT_AUTH_NONE)
                and not (db_listener.client_ca_tls_certificate_id
                         or listener.client_ca_tls_container_ref)):
            raise exceptions.ValidationException(detail=_(
                "Client authentication setting %s requires a client CA "
                "container reference.") % listener.client_authentication)

        if listener.insert_headers:
            self._validate_insert_headers(list(listener.insert_headers.keys()),
                                          db_listener.protocol)

        sni_containers = listener.sni_container_refs or []
        tls_refs = list(sni_containers)
        if listener.default_tls_container_ref:
            tls_refs.append(listener.default_tls_container_ref)
        self._validate_tls_refs(tls_refs)

        ca_ref = None
        if (listener.client_ca_tls_container_ref
                and listener.client_ca_tls_container_ref != wtypes.Unset):
            ca_ref = listener.client_ca_tls_container_ref
        elif db_listener.client_ca_tls_certificate_id:
            ca_ref = db_listener.client_ca_tls_certificate_id

        crl_ref = None
        if (listener.client_crl_container_ref
                and listener.client_crl_container_ref != wtypes.Unset):
            crl_ref = listener.client_crl_container_ref
        elif db_listener.client_crl_container_id:
            crl_ref = db_listener.client_crl_container_id

        if crl_ref and not ca_ref:
            raise exceptions.ValidationException(
                detail=_("A client authentication CA reference is required to "
                         "specify a client authentication revocation list."))

        if ca_ref or crl_ref:
            self._validate_client_ca_and_crl_refs(ca_ref, crl_ref)

        # Validate allowed CIDRs
        if (listener.allowed_cidrs and listener.allowed_cidrs != wtypes.Unset):
            vip_address = db_listener.load_balancer.vip.ip_address
            self._validate_cidr_compatible_with_vip(vip_address,
                                                    listener.allowed_cidrs)

        # Check TLS cipher blacklist
        if listener.tls_ciphers:
            rejected_ciphers = validate.check_cipher_blacklist(
                listener.tls_ciphers)
            if rejected_ciphers:
                raise exceptions.ValidationException(detail=_(
                    'The following ciphers have been blacklisted by an '
                    'administrator: ' + ', '.join(rejected_ciphers)))

        if listener.tls_versions is not wtypes.Unset:
            # Validate TLS version list
            validate.check_tls_version_list(listener.tls_versions)
            # Validate TLS versions against minimum
            validate.check_tls_version_min(listener.tls_versions)
예제 #3
0
    def _validate_create_listener(self, lock_session, listener_dict):
        """Validate listener for wrong protocol or duplicate listeners

        Update the load balancer db when provisioning status changes.
        """
        listener_protocol = listener_dict.get('protocol')

        if listener_dict and listener_dict.get('insert_headers'):
            self._validate_insert_headers(
                listener_dict['insert_headers'].keys(), listener_protocol)

        # Check for UDP compatibility
        if (listener_protocol == constants.PROTOCOL_UDP
                and self._is_tls_or_insert_header(listener_dict)):
            raise exceptions.ValidationException(
                detail=_("%s protocol listener does not support TLS or header "
                         "insertion.") % constants.PROTOCOL_UDP)

        # Check for TLS disabled
        if (not CONF.api_settings.allow_tls_terminated_listeners
                and listener_protocol == constants.PROTOCOL_TERMINATED_HTTPS):
            raise exceptions.DisabledOption(
                value=constants.PROTOCOL_TERMINATED_HTTPS, option='protocol')

        # Check for certs when not TERMINATED_HTTPS
        if (listener_protocol != constants.PROTOCOL_TERMINATED_HTTPS
                and self._has_tls_container_refs(listener_dict)):
            raise exceptions.ValidationException(
                detail=_(
                    "Certificate container references are only allowed on "
                    "%s protocol listeners.") %
                constants.PROTOCOL_TERMINATED_HTTPS)

        # Make sure a base certificate exists if specifying a client ca
        if (listener_dict.get('client_ca_tls_certificate_id')
                and not (listener_dict.get('tls_certificate_id')
                         or listener_dict.get('sni_containers'))):
            raise exceptions.ValidationException(detail=_(
                "An SNI or default certificate container reference must "
                "be provided with a client CA container reference."))

        # Make sure a certificate container is specified for TERMINATED_HTTPS
        if (listener_protocol == constants.PROTOCOL_TERMINATED_HTTPS
                and not (listener_dict.get('tls_certificate_id')
                         or listener_dict.get('sni_containers'))):
            raise exceptions.ValidationException(
                detail=_(
                    "An SNI or default certificate container reference must "
                    "be provided for %s protocol listeners.") %
                constants.PROTOCOL_TERMINATED_HTTPS)

        # Make sure we have a client CA cert if they enable client auth
        if (listener_dict.get('client_authentication') !=
                constants.CLIENT_AUTH_NONE
                and not listener_dict.get('client_ca_tls_certificate_id')):
            raise exceptions.ValidationException(
                detail=_(
                    "Client authentication setting %s requires a client CA "
                    "container reference.") %
                listener_dict.get('client_authentication'))

        # Make sure we have a client CA if they specify a CRL
        if (listener_dict.get('client_crl_container_id')
                and not listener_dict.get('client_ca_tls_certificate_id')):
            raise exceptions.ValidationException(
                detail=_("A client authentication CA reference is required to "
                         "specify a client authentication revocation list."))

        # Check TLS cipher blacklist
        if 'tls_ciphers' in listener_dict and listener_dict['tls_ciphers']:
            rejected_ciphers = validate.check_cipher_blacklist(
                listener_dict['tls_ciphers'])
            if rejected_ciphers:
                raise exceptions.ValidationException(detail=_(
                    'The following ciphers have been blacklisted by an '
                    'administrator: ' + ', '.join(rejected_ciphers)))

        # Validate the TLS containers
        sni_containers = listener_dict.pop('sni_containers', [])
        tls_refs = [sni['tls_container_id'] for sni in sni_containers]
        if listener_dict.get('tls_certificate_id'):
            tls_refs.append(listener_dict.get('tls_certificate_id'))
        self._validate_tls_refs(tls_refs)

        # Validate the client CA cert and optional client CRL
        if listener_dict.get('client_ca_tls_certificate_id'):
            self._validate_client_ca_and_crl_refs(
                listener_dict.get('client_ca_tls_certificate_id'),
                listener_dict.get('client_crl_container_id', None))

        # Validate that the L4 protocol (UDP or TCP) is not already used for
        # the specified protocol_port in this load balancer
        pcontext = pecan_request.context
        query_filter = {
            'project_id': listener_dict['project_id'],
            'load_balancer_id': listener_dict['load_balancer_id'],
            'protocol_port': listener_dict['protocol_port']
        }

        # Get listeners on the same load balancer that use the same
        # protocol port
        db_listeners = self.repositories.listener.get_all_API_list(
            lock_session,
            show_deleted=False,
            pagination_helper=pcontext.get(constants.PAGINATION_HELPER),
            **query_filter)[0]

        if db_listeners:
            l4_protocol = constants.L4_PROTOCOL_MAP[listener_protocol]

            # List supported protocols that share the same L4 protocol as our
            # new listener
            disallowed_protocols = [
                p for p in constants.L4_PROTOCOL_MAP
                if constants.L4_PROTOCOL_MAP[p] == l4_protocol
            ]

            for db_l in db_listeners:
                # Check if l4 protocol ports conflict
                if db_l.protocol in disallowed_protocols:
                    raise exceptions.DuplicateListenerEntry(
                        protocol=db_l.protocol,
                        port=listener_dict.get('protocol_port'))

        # Validate allowed CIDRs
        allowed_cidrs = listener_dict.get('allowed_cidrs', []) or []
        lb_id = listener_dict.get('load_balancer_id')
        vip_db = self.repositories.vip.get(lock_session,
                                           load_balancer_id=lb_id)
        vip_address = vip_db.ip_address
        self._validate_cidr_compatible_with_vip(vip_address, allowed_cidrs)

        if listener_protocol == constants.PROTOCOL_TERMINATED_HTTPS:
            # Validate TLS version list
            validate.check_tls_version_list(listener_dict['tls_versions'])
            # Validate TLS versions against minimum
            validate.check_tls_version_min(listener_dict['tls_versions'])

        try:
            db_listener = self.repositories.listener.create(
                lock_session, **listener_dict)
            if sni_containers:
                for container in sni_containers:
                    sni_dict = {
                        'listener_id': db_listener.id,
                        'tls_container_id': container.get('tls_container_id')
                    }
                    self.repositories.sni.create(lock_session, **sni_dict)
                # DB listener needs to be refreshed
                db_listener = self.repositories.listener.get(lock_session,
                                                             id=db_listener.id)

            return db_listener
        except odb_exceptions.DBDuplicateEntry as de:
            column_list = ['load_balancer_id', 'protocol', 'protocol_port']
            constraint_list = ['uq_listener_load_balancer_id_protocol_port']
            if ['id'] == de.columns:
                raise exceptions.IDAlreadyExists()
            if (set(column_list) == set(de.columns)
                    or set(constraint_list) == set(de.columns)):
                raise exceptions.DuplicateListenerEntry(
                    protocol=listener_dict.get('protocol'),
                    port=listener_dict.get('protocol_port'))
        except odb_exceptions.DBError:
            raise exceptions.InvalidOption(value=listener_dict.get('protocol'),
                                           option='protocol')
예제 #4
0
파일: pool.py 프로젝트: johnsom/octavia
    def _validate_pool_PUT(self, pool, db_pool):

        if db_pool.protocol == constants.PROTOCOL_UDP:
            self._validate_pool_request_for_udp(pool)
        else:
            if (pool.session_persistence and (
                    pool.session_persistence.persistence_timeout or
                    pool.session_persistence.persistence_granularity)):
                raise exceptions.ValidationException(detail=_(
                    "persistence_timeout and persistence_granularity "
                    "is only for UDP protocol pools."))

        if pool.session_persistence:
            sp_dict = pool.session_persistence.to_dict(render_unsets=False)
            validate.check_session_persistence(sp_dict)

        crl_ref = None
        # If we got a crl_ref and it's not unset, use it
        if (pool.crl_container_ref and
                pool.crl_container_ref != wtypes.Unset):
            crl_ref = pool.crl_container_ref
        # If we got Unset and a CRL exists in the DB, use the DB crl_ref
        elif (db_pool.crl_container_id and
              pool.crl_container_ref == wtypes.Unset):
            crl_ref = db_pool.crl_container_id

        ca_ref = None
        db_ca_ref = db_pool.ca_tls_certificate_id
        if pool.ca_tls_container_ref != wtypes.Unset:
            if not pool.ca_tls_container_ref and db_ca_ref and crl_ref:
                raise exceptions.ValidationException(detail=_(
                    "A CA reference cannot be removed when a "
                    "certificate revocation list is present."))

            if not pool.ca_tls_container_ref and not db_ca_ref and crl_ref:
                raise exceptions.ValidationException(detail=_(
                    "A CA reference is required to "
                    "specify a certificate revocation list."))
            if pool.ca_tls_container_ref:
                ca_ref = pool.ca_tls_container_ref
        elif db_ca_ref and pool.ca_tls_container_ref == wtypes.Unset:
            ca_ref = db_ca_ref
        elif crl_ref and not db_ca_ref:
            raise exceptions.ValidationException(detail=_(
                "A CA reference is required to "
                "specify a certificate revocation list."))

        if pool.tls_container_ref:
            self._validate_tls_refs([pool.tls_container_ref])

        # Validate the client CA cert and optional client CRL
        if ca_ref:
            self._validate_client_ca_and_crl_refs(ca_ref, crl_ref)

        # Check TLS cipher blacklist
        if pool.tls_ciphers:
            rejected_ciphers = validate.check_cipher_blacklist(
                pool.tls_ciphers)
            if rejected_ciphers:
                raise exceptions.ValidationException(detail=_(
                    "The following ciphers have been blacklisted by an "
                    "administrator: " + ', '.join(rejected_ciphers)))

        # Validate TLS version list
        if pool.tls_versions is not wtypes.Unset:
            validate.check_tls_version_list(pool.tls_versions)