Source code for smc.vpn.route

"""
.. versionadded:: 0.5.6
    Route based VPNs with multi-domain support, requires SMC >=6.3

Module for configuring Route Based VPN.
Creating a route based VPN consists of creating a local and remote tunnel
endpoint. Once you have the required endpoints, use TunnelEndpoint
classmethods to create the VPN by type (i.e. GRE, IPSEC).

List all existing route based VPNs::

    print(list(RouteVPN.objects.all()))
    
Example of fully provisioning an IPSEC wrapped RBVPN using a third
party remote GW::

    engine = Layer3Firewall.create(name='myfw', mgmt_ip='1.1.1.1', mgmt_network='1.1.1.0/24')
    
    # Add a second layer 3 interface for VPN
    engine.physical_interface.add_layer3_interface(
        interface_id=1, address='10.10.10.10', network_value='10.10.10.0/24', zone_ref='vpn')
    
    engine.tunnel_interface.add_layer3_interface(
        interface_id=1000, 
        address='2.2.2.2', 
        network_value='2.2.2.0/24')
    
    # Enable VPN on the 'Internal Endpoint' interface
    vpn_endpoint = engine.vpn_endpoint.get_contains('10.10.10.10')
    vpn_endpoint.update(enabled=True)
    
    # A Tunnel Endpoint pairs the interface of the NGFW with it's local VPN gateway.
    # You must create a tunnel endpoint for both sides of the Route VPN.
    
    # Create the local Tunnel Endpoint using the engine internal gateway
    # and previously created tunnel interface
    tunnel_if = engine.tunnel_interface.get(1000)
    local_gateway = TunnelEndpoint.create_ipsec_endpoint(engine.vpn.internal_gateway, tunnel_if)
    
    # Define the remote side details
    
    # Create the remote side network elements
    Network.create(name='remotenet', ipv4_network='172.18.10.0/24')
    
    # An ExternalGateway defines the remote side as a 3rd party gateway
    # Add the address of the remote gateway and the network element created
    # that defines the remote network/s.
    gw = ExternalGateway.create(name='remotegw')
    gw.external_endpoint.create(name='endpoint1', address='10.10.10.10')
    gw.vpn_site.create(name='remotesite', site_element=[Network('remotenet')])
    
    # Create the remote Tunnel Endpoint using the external gateway
    remote_gateway = TunnelEndpoint.create_ipsec_endpoint(gw)
    
    RouteVPN.create_ipsec_tunnel(
        name='myvpn',
        preshared_key='abcdefgh123456789',
        local_endpoint=local_gateway, 
        remote_endpoint=remote_gateway)
        

Create a GRE Tunnel Mode RBVPN with a remote gateway (non-SMC managed)::

    engine = Engine('fw') 
    
    # Enable VPN endpoint on interface 0 
    # Note: An interface can have multiple IP addresses in which case you 
    # may want to get the VPN endpoint match by address 
    vpn_endpoint = None 
    for endpoint in engine.vpn_endpoint: 
        if endpoint.physical_interface.interface_id == '0': 
            endpoint.update(enabled=True) 
            vpn_endpoint = endpoint
            break
     
    # Create a new Tunnel Interface for the engine 
    engine.tunnel_interface.add_layer3_interface( 
        interface_id=3000, address='30.30.30.30', network_value='30.30.30.0/24') 
    
    tunnel_interface =  engine.tunnel_interface.get(3000)
    local_endpoint = TunnelEndpoint.create_gre_tunnel_endpoint( 
        endpoint=vpn_endpoint, tunnel_interface=tunnel_interface) 
 
    # Create GRE tunnel endpoint for remote gateway 
    remote_endpoint = TunnelEndpoint.create_gre_tunnel_endpoint( 
        remote_address='10.1.1.2') 
    
    # Create the top level IPSEC tunnel to encapsulate RBVPN 
    policy_vpn = PolicyVPN.create(name='myIPSEC') 
     
    RouteVPN.create_gre_tunnel_mode( 
        name='mytunnelvpn',  
        local_endpoint=local_endpoint,  
        remote_endpoint=remote_endpoint,  
        policy_vpn=policy_vpn) 

Create a no-encryption GRE route based VPN between two managed NGFWs::

    engine1 = Layer3Firewall.create(name='engine1', mgmt_ip='1.1.1.1', mgmt_network='1.1.1.0/24')
    engine1.tunnel_interface.add_layer3_interface( 
        interface_id=1000, 
        address='2.2.2.2', 
        network_value='2.2.2.0/24')
    
    # Obtain the 'internal endpoint' from the NGFW and enable VPN
    for vpn in engine1.vpn_endpoint:
        internal_endpoint = vpn
        vpn.update(enabled=True)
        
    tunnel_if = engine1.tunnel_interface.get(1000) 
    local_gateway = TunnelEndpoint.create_gre_tunnel_endpoint(
        internal_endpoint, tunnel_if)
    
    engine2 = Layer3Firewall.create(name='engine2', mgmt_ip='1.1.1.1', mgmt_network='1.1.1.0/24')
    engine2.tunnel_interface.add_layer3_interface( 
        interface_id=1000, 
        address='2.2.2.2', 
        network_value='2.2.2.0/24')
    
    # Obtain the 'internal endpoint' from the NGFW and enable VPN
    for vpn in engine2.vpn_endpoint:
        internal_endpoint = vpn
        vpn.update(enabled=True)
    
    tunnel_if = engine2.tunnel_interface.get(1000) 
    remote_gateway = TunnelEndpoint.create_gre_tunnel_endpoint(
        internal_endpoint, tunnel_if)
    
    RouteVPN.create_gre_tunnel_no_encryption(
        name='openvpn', 
        local_endpoint=local_gateway,
        remote_endpoint=remote_gateway)

"""
from smc.base.model import Element, ElementCreator, ElementRef
from smc.vpn.elements import VPNProfile
from smc.api.exceptions import CreateElementFailed, CreateVPNFailed
from smc.core.engine import InternalEndpoint
from smc.core.interfaces import TunnelInterface


[docs]class RouteVPN(Element): """ Route based VPN in NGFW. :ivar VPNProfile vpn_profile: VPNProfile reference for this RouteVPN :ivar TunnelMonitoringGroup monitoring_group: tunnel monitoring group reference """ typeof = 'rbvpn_tunnel' vpn_profile = ElementRef('vpn_profile_ref') monitoring_group = ElementRef('monitoring_group_ref')
[docs] @classmethod def create_ipsec_tunnel(cls, name, local_endpoint, remote_endpoint, preshared_key=None, monitoring_group=None, vpn_profile=None, mtu=0, pmtu_discovery=True, ttl=0, enabled=True, comment=None): """ The VPN tunnel type negotiates IPsec tunnels in the same way as policy-based VPNs, but traffic is selected to be sent into the tunnel based on routing. :param str name: name of VPN :param TunnelEndpoint local_endpoint: the local side endpoint for this VPN. :param TunnelEndpoint remote_endpoint: the remote side endpoint for this VPN. :param str preshared_key: required if remote endpoint is an ExternalGateway :param TunnelMonitoringGroup monitoring_group: the group to place this VPN in for monitoring. Default: 'Uncategorized'. :param VPNProfile vpn_profile: VPN profile for this VPN. (default: VPN-A Suite) :param int mtu: Set MTU for this VPN tunnel (default: 0) :param boolean pmtu_discovery: enable pmtu discovery (default: True) :param int ttl: ttl for connections on the VPN (default: 0) :param bool enabled: enable the RBVPN or leave it disabled :param str comment: optional comment :raises CreateVPNFailed: failed to create the VPN with reason :rtype: RouteVPN """ group = monitoring_group or TunnelMonitoringGroup('Uncategorized') profile = vpn_profile or VPNProfile('VPN-A Suite') json = { 'name': name, 'mtu': mtu, 'ttl': ttl, 'enabled': enabled, 'monitoring_group_ref': group.href, 'pmtu_discovery': pmtu_discovery, 'preshared_key': preshared_key, 'rbvpn_tunnel_side_a': local_endpoint.data, 'rbvpn_tunnel_side_b': remote_endpoint.data, 'tunnel_mode': 'vpn', 'comment': comment, 'vpn_profile_ref': profile.href } try: return ElementCreator(cls, json) except CreateElementFailed as err: raise CreateVPNFailed(err)
[docs] @classmethod def create_gre_tunnel_mode(cls, name, local_endpoint, remote_endpoint, policy_vpn, mtu=0, pmtu_discovery=True, ttl=0, enabled=True, comment=None): """ Create a GRE based tunnel mode route VPN. Tunnel mode GRE wraps the GRE tunnel in an IPSEC tunnel to provide encrypted end-to-end security. Therefore a policy based VPN is required to 'wrap' the GRE into IPSEC. :param str name: name of VPN :param TunnelEndpoint local_endpoint: the local side endpoint for this VPN. :param TunnelEndpoint remote_endpoint: the remote side endpoint for this VPN. :param PolicyVPN policy_vpn: reference to a policy VPN :param TunnelMonitoringGroup monitoring_group: the group to place this VPN in for monitoring. (default: 'Uncategorized') :param int mtu: Set MTU for this VPN tunnel (default: 0) :param boolean pmtu_discovery: enable pmtu discovery (default: True) :param int ttl: ttl for connections on the VPN (default: 0) :param str comment: optional comment :raises CreateVPNFailed: failed to create the VPN with reason :rtype: RouteVPN """ json = { 'name': name, 'ttl': ttl, 'mtu': mtu, 'pmtu_discovery': pmtu_discovery, 'tunnel_encryption': 'tunnel_mode', 'tunnel_mode': 'gre', 'enabled': enabled, 'comment': comment, 'rbvpn_tunnel_side_a': local_endpoint.data, 'rbvpn_tunnel_side_b': remote_endpoint.data } if policy_vpn is None: json['tunnel_encryption'] = 'no_encryption' else: json['tunnel_mode_vpn_ref'] = policy_vpn.href try: return ElementCreator(cls, json) except CreateElementFailed as err: raise CreateVPNFailed(err)
[docs] @classmethod def create_gre_tunnel_no_encryption(cls, name, local_endpoint, remote_endpoint, mtu=0, pmtu_discovery=True, ttl=0, enabled=True, comment=None): """ Create a GRE Tunnel with no encryption. See `create_gre_tunnel_mode` for constructor descriptions. """ return cls.create_gre_tunnel_mode( name, local_endpoint, remote_endpoint, policy_vpn=None, mtu=mtu, pmtu_discovery=pmtu_discovery, ttl=ttl, enabled=enabled, comment=comment)
[docs] @classmethod def create_gre_transport_mode(cls, name, local_endpoint, remote_endpoint, preshared_key, monitoring_group=None, vpn_profile=None, mtu=0, ttl=0, pmtu_discovery=True, enabled=True, comment=None): """ Create a transport based route VPN. This VPN type uses IPSEC for protecting the payload, therefore a VPN Profile is specified. :param str name: name of VPN :param TunnelEndpoint local_endpoint: the local side endpoint for this VPN. :param TunnelEndpoint remote_endpoint: the remote side endpoint for this VPN. :param str preshared_key: preshared key for RBVPN :param TunnelMonitoringGroup monitoring_group: the group to place this VPN in for monitoring. (default: 'Uncategorized') :param VPNProfile vpn_profile: VPN profile for this VPN. (default: VPN-A Suite) :param int mtu: Set MTU for this VPN tunnel (default: 0) :param boolean pmtu_discovery: enable pmtu discovery (default: True) :param int ttl: ttl for connections on the VPN (default: 0) :param str comment: optional comment :raises CreateVPNFailed: failed to create the VPN with reason :rtype: RouteVPN """ group = monitoring_group or TunnelMonitoringGroup('Uncategorized') profile = vpn_profile or VPNProfile('VPN-A Suite') json = { 'name': name, 'mtu': mtu, 'ttl': ttl, 'preshared_key': preshared_key, 'pmtu_discovery': pmtu_discovery, 'monitoring_group_ref': group.href, 'rbvpn_tunnel_side_a': local_endpoint.data, 'rbvpn_tunnel_side_b': remote_endpoint.data, 'tunnel_encryption': 'transport_mode', 'vpn_profile_ref': profile.href, 'tunnel_mode': 'gre', 'enabled': enabled, 'comment': comment } try: return ElementCreator(cls, json) except CreateElementFailed as err: raise CreateVPNFailed(err)
[docs] def enable(self): """ Enable this route based VPN :return: None """ if not self.enabled: self.update(enabled=True)
[docs] def disable(self): """ Disable this route based VPN :return: None """ if self.enabled: self.update(enabled=False)
[docs] def set_preshared_key(self, new_key): """ Set the preshared key for this VPN. A pre-shared key is only present when the tunnel type is 'VPN' or the encryption mode is 'transport'. :return: None """ if self.data.get('preshared_key'): self.update(preshared_key=new_key)
@property def local_endpoint(self): """ The local endpoint for this RBVPN :rtype: TunnelEndpoint """ return TunnelEndpoint(**self.rbvpn_tunnel_side_a) @property def remote_endpoint(self): """ The remote endpoint for this RBVPN :rtype: TunnelEndpoint """ return TunnelEndpoint(**self.rbvpn_tunnel_side_b) @property def tunnel_mode(self): """ The tunnel mode for this RBVPN :rtype: str """ return self.data.get('tunnel_mode')
[docs]class TunnelMonitoringGroup(Element): """ A tunnel monitoring group is used to group route based VPNs for monitoring on the Home->VPN dashboard. """ typeof = 'rbvpn_tunnel_monitoring_group'
[docs]class TunnelEndpoint(object): """ A Tunnel Endpoint represents one side of a route based VPN. Based on the RBVPN type required, you must create the local and remote endpoints and pass them into the RouteVPN create classmethods. :ivar InternalGateway,ExternalGateway gateway: reference to the element that is used by this tunnel endpoint :ivar TunnelInterface tunnel_interface: Tunnel interface used by this tunnel endpoint """ gateway = ElementRef('gateway_ref') def __init__(self, gateway_ref=None, tunnel_interface_ref=None, endpoint_ref=None, ip_address=None): self.gateway_ref = gateway_ref self.tunnel_interface_ref= tunnel_interface_ref self.endpoint_ref = endpoint_ref self.ip_address = ip_address @property def endpoint(self): """ Endpoint is used to specify which interface is enabled for VPN. This is the InternalEndpoint property of the InternalGateway. :return: internal endpoint where VPN is enabled :rtype: InternalEndpoint,ExternalGateway """ if self.endpoint_ref and self.tunnel_interface_ref: return InternalEndpoint(href=self.endpoint_ref) return Element.from_href(self.endpoint_ref) @property def tunnel_interface(self): """ Show the tunnel interface for this TunnelEndpoint. :return: interface for this endpoint :rtype: TunnelInterface """ if self.tunnel_interface_ref: return TunnelInterface(href=self.tunnel_interface_ref)
[docs] @classmethod def create_gre_tunnel_endpoint(cls, endpoint=None, tunnel_interface=None, remote_address=None): """ Create the GRE tunnel mode or no encryption mode endpoint. If the GRE tunnel mode endpoint is an SMC managed device, both an endpoint and a tunnel interface is required. If the endpoint is externally managed, only an IP address is required. :param InternalEndpoint,ExternalEndpoint endpoint: the endpoint element for this tunnel endpoint. :param TunnelInterface tunnel_interface: the tunnel interface for this tunnel endpoint. Required for SMC managed devices. :param str remote_address: IP address, only required if the tunnel endpoint is a remote gateway. :rtype: TunnelEndpoint """ tunnel_interface = tunnel_interface.href if tunnel_interface else None endpoint = endpoint.href if endpoint else None return TunnelEndpoint( tunnel_interface_ref=tunnel_interface, endpoint_ref=endpoint, ip_address=remote_address)
[docs] @classmethod def create_gre_transport_endpoint(cls, endpoint, tunnel_interface=None): """ Create the GRE transport mode endpoint. If the GRE transport mode endpoint is an SMC managed device, both an endpoint and a tunnel interface is required. If the GRE endpoint is an externally managed device, only an endpoint is required. :param InternalEndpoint,ExternalEndpoint endpoint: the endpoint element for this tunnel endpoint. :param TunnelInterface tunnel_interface: the tunnel interface for this tunnel endpoint. Required for SMC managed devices. :rtype: TunnelEndpoint """ tunnel_interface = tunnel_interface.href if tunnel_interface else None return TunnelEndpoint( endpoint_ref=endpoint.href, tunnel_interface_ref=tunnel_interface)
[docs] @classmethod def create_ipsec_endpoint(cls, gateway, tunnel_interface=None): """ Create the VPN tunnel endpoint. If the VPN tunnel endpoint is an SMC managed device, both a gateway and a tunnel interface is required. If the VPN endpoint is an externally managed device, only a gateway is required. :param InternalGateway,ExternalGateway gateway: the gateway for this tunnel endpoint :param TunnelInterface tunnel_interface: Tunnel interface for this RBVPN. This can be None if the gateway is a non-SMC managed gateway. :rtype: TunnelEndpoint """ tunnel_interface = tunnel_interface.href if tunnel_interface else None return TunnelEndpoint( gateway_ref=gateway.href, tunnel_interface_ref=tunnel_interface)
@property def data(self): return {k: v for k, v in vars(self).items() if v} @property def remote_address(self): """ Show the remote IP address configured for a GRE RBVPN using Tunnel or No Encryption Mode configurations. """ return self.ip_address