def _validate_policy_lifetime(self, policy_info, policy_type): """NSX supports only units=seconds""" lifetime = policy_info.get('lifetime') if not lifetime: return if lifetime.get('units') != 'seconds': msg = _("Unsupported policy lifetime %(val)s in %(pol)s policy. " "Only seconds lifetime is supported.") % { 'val': lifetime, 'pol': policy_type } raise nsx_exc.NsxVpnValidationError(details=msg) value = lifetime.get('value') if policy_type == 'IKE': limits = vpn_ipsec.IkeSALifetimeLimits else: limits = vpn_ipsec.IPsecSALifetimeLimits if (value and (value < limits.SA_LIFETIME_MIN or value > limits.SA_LIFETIME_MAX)): msg = _("Unsupported policy lifetime %(value)s in %(pol)s policy. " "Value range is [%(min)s-%(max)s].") % { 'value': value, 'pol': policy_type, 'min': limits.SA_LIFETIME_MIN, 'max': limits.SA_LIFETIME_MAX } raise nsx_exc.NsxVpnValidationError(details=msg)
def _check_advertisment_overlap(self, context, ipsec_site_conn): """Validate there is no overlapping advertisement of networks The plugin advertise all no-snat routers networks + vpn local networks. The NSX does not allow different Tier1 router to advertise the same subnets """ admin_con = context.elevated() srv_id = ipsec_site_conn.get('vpnservice_id') srv = self.vpn_plugin._get_vpnservice(admin_con, srv_id) this_router = srv['router_id'] this_cidr = srv['subnet']['cidr'] # get all subnets of no-snat routers all_routers = self._core_plugin.get_routers(admin_con) nosnat_routers = [ rtr for rtr in all_routers if (rtr['id'] != this_router and rtr.get('external_gateway_info') and not rtr['external_gateway_info'].get( 'enable_snat', cfg.CONF.enable_snat_by_default)) ] for rtr in nosnat_routers: if rtr['id'] == this_router: continue # go over the subnets of this router subnets = self._core_plugin._find_router_subnets_cidrs( admin_con, rtr['id']) if subnets and netaddr.IPSet(subnets) & netaddr.IPSet([this_cidr]): msg = (_("Cannot create connection with overlapping local " "cidrs %(local)s which was already advertised by " "no-snat router %(rtr)s") % { 'local': subnets, 'rtr': rtr['id'] }) raise nsx_exc.NsxVpnValidationError(details=msg) # add all vpn local subnets connections = self.vpn_plugin.get_ipsec_site_connections(admin_con) for conn in connections: # skip this connection and connections in non active state if (conn['id'] == ipsec_site_conn.get('id') or conn['status'] != constants.ACTIVE): continue # check the service local address conn_srv_id = conn.get('vpnservice_id') conn_srv = self.vpn_plugin._get_vpnservice(admin_con, conn_srv_id) if conn_srv['router_id'] == this_router: continue conn_cidr = conn_srv['subnet']['cidr'] if netaddr.IPSet([conn_cidr]) & netaddr.IPSet([this_cidr]): msg = (_("Cannot create connection with overlapping local " "cidr %(local)s which was already advertised by " "router %(rtr)s and connection %(conn)s") % { 'local': conn_cidr, 'rtr': conn_srv['router_id'], 'conn': conn['id'] }) raise nsx_exc.NsxVpnValidationError(details=msg)
def _check_unique_addresses(self, context, ipsec_site_conn): """Validate no repeating local & peer addresses (of all tenants) The nsx does not support it cross all tenants, and tier0 routers """ vpnservice_id = ipsec_site_conn.get('vpnservice_id') local_addr = self._get_service_local_address(context, vpnservice_id) peer_address = ipsec_site_conn.get('peer_address') filters = {'peer_address': [peer_address]} connections = self.vpn_plugin.get_ipsec_site_connections( context.elevated(), filters=filters) for conn in connections: # skip this connection and connections in non active state if (conn['id'] == ipsec_site_conn.get('id') or conn['status'] != constants.ACTIVE): continue # this connection has the same peer addr as ours. # check the service local address srv_id = conn.get('vpnservice_id') srv_local = self._get_service_local_address( context.elevated(), srv_id) if srv_local == local_addr: msg = (_("Cannot create another connection with the same " "local address %(local)s and peer address %(peer)s " "as connection %(id)s") % { 'local': local_addr, 'peer': peer_address, 'id': conn['id'] }) raise nsx_exc.NsxVpnValidationError(details=msg)
def _validate_router(self, context, router_id): # Only support distributed and exclusive router type router = self.core_plugin.get_router(context, router_id) if self._is_shared_router(router): msg = _("Router type is not supported for VPN service, only " "support distributed and exclusive router") raise nsxv_exc.NsxVpnValidationError(details=msg)
def validate_ipsec_policy(self, context, policy_info): """Ensure IPSec policy encap mode is tunnel for current REST API.""" mode = policy_info['encapsulation_mode'] if mode not in nsxv_constants.ENCAPSULATION_MODE_ALLOWED: msg = _("Unsupported encapsulation mode: %s! currently only" "'tunnel' mode is supported.") % mode raise nsxv_exc.NsxVpnValidationError(details=msg)
def validate_ikepolicy_version(self, policy_info): """NSX Edge provides IKEv1""" version = policy_info.get('ike_version') if version != 'v1': msg = _("Unsupported ike policy %s! only v1 " "is supported right now.") % version raise nsxv_exc.NsxVpnValidationError(details=msg)
def validate_ikepolicy_pfs(self, policy_info): # Check whether pfs is allowed. if not nsxv_constants.PFS_MAP.get(policy_info['pfs']): msg = _("Unsupported pfs: %(pfs)s! currently only " "the following pfs are supported on VSE: %s") % { 'pfs': policy_info['pfs'], 'supported': nsxv_constants.PFS_MAP } raise nsxv_exc.NsxVpnValidationError(details=msg)
def _validate_router(self, context, router_id): # Verify that the router gw network is connected to an active-standby # Tier0 router router_db = self._core_plugin._get_router(context, router_id) tier0_uuid = self._core_plugin._get_tier0_uuid_by_router( context, router_db) # TODO(asarfaty): cache this result tier0_router = self.nsxlib.logical_router.get(tier0_uuid) if (not tier0_router or tier0_router.get('high_availability_mode') != 'ACTIVE_STANDBY'): msg = _("The router GW should be connected to a TIER-0 router " "with ACTIVE_STANDBY HA mode") raise nsx_exc.NsxVpnValidationError(details=msg) # Verify that this is a no-snat router if router_db.enable_snat: msg = _("VPN is supported only for routers with disabled SNAT") raise nsx_exc.NsxVpnValidationError(details=msg)
def validate_encryption_algorithm(self, policy_info): encryption = policy_info['encryption_algorithm'] if encryption not in nsxv_constants.ENCRYPTION_ALGORITHM_MAP: msg = _("Unsupported encryption_algorithm: %(algo)s! please " "select one of the following supported algorithms: " "%(supported_algos)s") % { 'algo': encryption, 'supported_algos': nsxv_constants.ENCRYPTION_ALGORITHM_MAP } raise nsxv_exc.NsxVpnValidationError(details=msg)
def _validate_policy_pfs(self, policy_info, policy_type): pfs = policy_info.get('pfs') if pfs and pfs not in ipsec_utils.PFS_MAP: msg = _("Unsupported pfs: %(pfs)s in %(pol)s policy. Please " "select one of the following pfs: " "%(supported_pfs)s") % { 'pfs': pfs, 'pol': policy_type, 'supported_pfs': ipsec_utils.PFS_MAP.keys() } raise nsx_exc.NsxVpnValidationError(details=msg)
def _validate_policy_auth_algorithm(self, policy_info, policy_type): """NSX supports only SHA1 and SHA256""" auth = policy_info.get('auth_algorithm') if auth and auth not in ipsec_utils.AUTH_ALGORITHM_MAP: msg = _("Unsupported auth_algorithm: %(algo)s in %(pol)s policy. " "Please select one of the following supported algorithms: " "%(supported_algos)s") % { 'pol': policy_type, 'algo': auth, 'supported_algos': ipsec_utils.AUTH_ALGORITHM_MAP.keys() } raise nsx_exc.NsxVpnValidationError(details=msg)
def _validate_policy_encryption_algorithm(self, policy_info, policy_type): encryption = policy_info.get('encryption_algorithm') if (encryption and encryption not in ipsec_utils.ENCRYPTION_ALGORITHM_MAP): msg = _("Unsupported encryption_algorithm: %(algo)s in %(pol)s " "policy. Please select one of the following supported " "algorithms: %(supported_algos)s") % { 'algo': encryption, 'pol': policy_type, 'supported_algos': ipsec_utils.ENCRYPTION_ALGORITHM_MAP.keys() } raise nsx_exc.NsxVpnValidationError(details=msg)
def _validate_dpd(self, connection): dpd_info = connection.get('dpd') if not dpd_info: return action = dpd_info.get('action') if action not in ipsec_utils.DPD_ACTION_MAP.keys(): msg = _("Unsupported DPD action: %(action)s! Currently only " "%(supported)s is supported.") % { 'action': action, 'supported': ipsec_utils.DPD_ACTION_MAP.keys() } raise nsx_exc.NsxVpnValidationError(details=msg) timeout = dpd_info.get('timeout') if (timeout < vpn_ipsec.DpdProfileTimeoutLimits.DPD_TIMEOUT_MIN or timeout > vpn_ipsec.DpdProfileTimeoutLimits.DPD_TIMEOUT_MAX): msg = _( "Unsupported DPD timeout: %(timeout)s. Value range is " "[%(min)s-%(max)s].") % { 'timeout': timeout, 'min': vpn_ipsec.DpdProfileTimeoutLimits.DPD_TIMEOUT_MIN, 'max': vpn_ipsec.DpdProfileTimeoutLimits.DPD_TIMEOUT_MAX } raise nsx_exc.NsxVpnValidationError(details=msg)
def validate_vpnservice(self, context, vpnservice): """Called upon create/update of a service""" # Call general validations super(IPsecValidator, self).validate_vpnservice(context, vpnservice) # Call specific NSX validations self._validate_router(context, vpnservice['router_id']) if not vpnservice['subnet_id']: # we currently do not support multiple subnets so a subnet must # be defined msg = _("Subnet must be defined in a service") raise nsxv_exc.NsxVpnValidationError(details=msg)
def validate_ike_policy(self, context, ike_policy): # Call general validations super(IPsecV3Validator, self).validate_ike_policy(context, ike_policy) # Call specific NSX validations self._validate_policy_lifetime(ike_policy, "IKE") self._validate_policy_auth_algorithm(ike_policy, "IKE") self._validate_policy_encryption_algorithm(ike_policy, "IKE") self._validate_policy_pfs(ike_policy, "IKE") # 'aggressive' phase1-negotiation-mode is not supported if ike_policy.get('phase1-negotiation-mode', 'main') != 'main': msg = _("Unsupported phase1-negotiation-mode: %s! Only 'main' is " "supported.") % ike_policy['phase1-negotiation-mode'] raise nsx_exc.NsxVpnValidationError(details=msg)
def validate_ipsec_policy(self, context, ipsec_policy): # Call general validations super(IPsecV3Validator, self).validate_ipsec_policy(context, ipsec_policy) # Call specific NSX validations self._validate_policy_lifetime(ipsec_policy, "IPSec") self._validate_policy_auth_algorithm(ipsec_policy, "IPSec") self._validate_policy_encryption_algorithm(ipsec_policy, "IPSec") self._validate_policy_pfs(ipsec_policy, "IPSec") # Ensure IPSec policy encap mode is tunnel mode = ipsec_policy.get('encapsulation_mode') if mode and mode not in ipsec_utils.ENCAPSULATION_MODE_MAP.keys(): msg = _("Unsupported encapsulation mode: %s. Only 'tunnel' mode " "is supported.") % mode raise nsx_exc.NsxVpnValidationError(details=msg) # Ensure IPSec policy transform protocol is esp prot = ipsec_policy.get('transform_protocol') if prot and prot not in ipsec_utils.TRANSFORM_PROTOCOL_MAP.keys(): msg = _("Unsupported transform protocol: %s. Only 'esp' protocol " "is supported.") % prot raise nsx_exc.NsxVpnValidationError(details=msg)
def validate_ipsec_site_connection(self, context, ipsec_site_conn): if not ipsec_site_conn.get('tenant_id'): # nothing we can do here. return v = self._get_validator_for_project(ipsec_site_conn['tenant_id']) # first make sure the plugin is the same as the one of the vpnservice srv_id = ipsec_site_conn.get('vpnservice_id') srv = self.vpn_plugin._get_vpnservice(context, srv_id) srv_validator = self._get_validator_for_project(srv['tenant_id']) if v != srv_validator: err_msg = _('VPN service should belong to the same plugin ' 'as the connection') raise nsx_exc.NsxVpnValidationError(details=err_msg) return v.validate_ipsec_site_connection(context, ipsec_site_conn)
def validate_vpnservice(self, context, vpnservice): if not vpnservice.get('tenant_id'): # This will happen during update. # nothing significant like router or subnet can be changes # so we can skip it. return v = self._get_validator_for_project(vpnservice['tenant_id']) # first make sure the router&subnet plugin matches the vpnservice router_id = vpnservice['router_id'] p = self.core_plugin._get_plugin_from_router_id(context, router_id) if self.validators.get(p.plugin_type()) != v: err_msg = _('Router & subnet should belong to the same plugin ' 'as the VPN service') raise nsx_exc.NsxVpnValidationError(details=err_msg) return v.validate_vpnservice(context, vpnservice)
def _check_policy_rules_overlap(self, context, ipsec_site_conn): """validate no overlapping policy rules The nsx does not support overlapping policy rules cross all tenants, and tier0 routers """ connections = self.vpn_plugin.get_ipsec_site_connections( context.elevated()) if not connections: return vpnservice_id = ipsec_site_conn.get('vpnservice_id') vpnservice = self.vpn_plugin._get_vpnservice(context, vpnservice_id) local_cidrs = [vpnservice['subnet']['cidr']] peer_cidrs = ipsec_site_conn['peer_cidrs'] for conn in connections: # skip this connection and connections in non active state if (conn['id'] == ipsec_site_conn.get('id') or conn['status'] != constants.ACTIVE): continue # TODO(asarfaty): support peer groups too # check if it overlaps with the peer cidrs conn_peer_cidrs = conn['peer_cidrs'] if netaddr.IPSet(conn_peer_cidrs) & netaddr.IPSet(peer_cidrs): # check if the local cidr also overlaps con_service_id = conn.get('vpnservice_id') con_service = self.vpn_plugin._get_vpnservice( context.elevated(), con_service_id) conn_local_cidr = [con_service['subnet']['cidr']] if netaddr.IPSet(conn_local_cidr) & netaddr.IPSet(local_cidrs): msg = (_("Cannot create a connection with overlapping " "local and peer cidrs (%(local)s and %(peer)s) " "as connection %(id)s") % { 'local': local_cidrs, 'peer': peer_cidrs, 'id': conn['id'] }) raise nsx_exc.NsxVpnValidationError(details=msg)
def _validate_psk(self, connection): if 'psk' in connection and not connection['psk']: msg = _("'psk' cannot be empty or null when authentication " "mode is psk") raise nsx_exc.NsxVpnValidationError(details=msg)
def _validate_backend_version(self): if not self.backend_support: msg = (_("VPNaaS is not supported by the NSX backend " "(version %s)") % self.nsxlib.get_version()) raise nsx_exc.NsxVpnValidationError(details=msg)