Skip to content

Commit

Permalink
Closes #9816: VPN tunnel support (#14276)
Browse files Browse the repository at this point in the history
- Introduces a new `vpn` app with the following models:
    - Tunnel
    - TunnelTermination
    - IKEProposal
    - IKEPolicy
    - IPSecProposal
    - IPSecPolicy
    - IPSecProfile
  • Loading branch information
jeremystretch authored Nov 27, 2023
1 parent 975a647 commit 6678880
Show file tree
Hide file tree
Showing 58 changed files with 5,656 additions and 10 deletions.
49 changes: 49 additions & 0 deletions docs/features/vpn-tunnels.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Tunnels

NetBox can model private tunnels formed among virtual termination points across your network. Typical tunnel implementations include GRE, IP-in-IP, and IPSec. A tunnel may be terminated to two or more device or virtual machine interfaces.

```mermaid
flowchart TD
Termination1[TunnelTermination]
Termination2[TunnelTermination]
Interface1[Interface]
Interface2[Interface]
Tunnel --> Termination1 & Termination2
Termination1 --> Interface1
Termination2 --> Interface2
Interface1 --> Device
Interface2 --> VirtualMachine
click Tunnel "../../models/vpn/tunnel/"
click TunnelTermination1 "../../models/vpn/tunneltermination/"
click TunnelTermination2 "../../models/vpn/tunneltermination/"
```

# IPSec & IKE

NetBox includes robust support for modeling IPSec & IKE policies. These are used to define encryption and authentication parameters for IPSec tunnels.

```mermaid
flowchart TD
subgraph IKEProposals[Proposals]
IKEProposal1[IKEProposal]
IKEProposal2[IKEProposal]
end
subgraph IPSecProposals[Proposals]
IPSecProposal1[IPSecProposal]
IPSecProposal2[IPSecProposal]
end
IKEProposals --> IKEPolicy
IPSecProposals --> IPSecPolicy
IKEPolicy & IPSecPolicy--> IPSecProfile
IPSecProfile --> Tunnel
click IKEProposal1 "../../models/vpn/ikeproposal/"
click IKEProposal2 "../../models/vpn/ikeproposal/"
click IKEPolicy "../../models/vpn/ikepolicy/"
click IPSecProposal1 "../../models/vpn/ipsecproposal/"
click IPSecProposal2 "../../models/vpn/ipsecproposal/"
click IPSecPolicy "../../models/vpn/ipsecpolicy/"
click IPSecProfile "../../models/vpn/ipsecprofile/"
click Tunnel "../../models/vpn/tunnel/"
```
25 changes: 25 additions & 0 deletions docs/models/vpn/ikepolicy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# IKE Policies

An [Internet Key Exhcnage (IKE)](https://en.wikipedia.org/wiki/Internet_Key_Exchange) policy defines an IKE version, mode, and set of [proposals](./ikeproposal.md) to be used in IKE negotiation. These policies are referenced by [IPSec profiles](./ipsecprofile.md).

## Fields

### Name

The unique user-assigned name for the policy.

### Version

The IKE version employed (v1 or v2).

### Mode

The IKE mode employed (main or aggressive).

### Proposals

One or more [IKE proposals](./ikeproposal.md) supported for use by this policy.

### Pre-shared Key

A pre-shared secret key associated with this policy (optional).
39 changes: 39 additions & 0 deletions docs/models/vpn/ikeproposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# IKE Proposals

An [Internet Key Exhcnage (IKE)](https://en.wikipedia.org/wiki/Internet_Key_Exchange) proposal defines a set of parameters used to establish a secure bidirectional connection across an untrusted medium, such as the Internet. IKE proposals defined in NetBox can be referenced by [IKE policies](./ikepolicy.md), which are in turn employed by [IPSec profiles](./ipsecprofile.md).

!!! note
Some platforms refer to IKE proposals as [ISAKMP](https://en.wikipedia.org/wiki/Internet_Security_Association_and_Key_Management_Protocol), which is a framework for authentication and key exchange which employs IKE.

## Fields

### Name

The unique user-assigned name for the proposal.

### Authentication Method

The strategy employed for authenticating the IKE peer. Available options are listed below.

| Name |
|----------------|
| Pre-shared key |
| Certificate |
| RSA signature |
| DSA signature |

### Encryption Algorithm

The protocol employed for data encryption. Options include DES, 3DES, and various flavors of AES.

### Authentication Algorithm

The mechanism employed to ensure data integrity. Options include MD5 and SHA HMAC implementations.

### Group

The [Diffie-Hellman group](https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange) supported by the proposal. Group IDs are [managed by IANA](https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml#ikev2-parameters-8).

### SA Lifetime

The maximum lifetime for the IKE security association (SA), in seconds.
17 changes: 17 additions & 0 deletions docs/models/vpn/ipsecpolicy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# IPSec Policy

An [IPSec](https://en.wikipedia.org/wiki/IPsec) policy defines a set of [proposals](./ikeproposal.md) to be used in the formation of IPSec tunnels. A perfect forward secrecy (PFS) group may optionally also be defined. These policies are referenced by [IPSec profiles](./ipsecprofile.md).

## Fields

### Name

The unique user-assigned name for the policy.

### Proposals

One or more [IPSec proposals](./ipsecproposal.md) supported for use by this policy.

### PFS Group

The [perfect forward secrecy (PFS)](https://en.wikipedia.org/wiki/Forward_secrecy) group supported by this policy (optional).
21 changes: 21 additions & 0 deletions docs/models/vpn/ipsecprofile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# IPSec Profile

An [IPSec](https://en.wikipedia.org/wiki/IPsec) profile defines an [IKE policy](./ikepolicy.md), [IPSec policy](./ipsecpolicy.md), and IPSec mode used for establishing an IPSec tunnel.

## Fields

### Name

The unique user-assigned name for the profile.

### Mode

The IPSec mode employed by the profile: Encapsulating Security Payload (ESP) or Authentication Header (AH).

### IKE Policy

The [IKE policy](./ikepolicy.md) associated with the profile.

### IPSec Policy

The [IPSec policy](./ipsecpolicy.md) associated with the profile.
25 changes: 25 additions & 0 deletions docs/models/vpn/ipsecproposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# IPSec Proposal

An [IPSec](https://en.wikipedia.org/wiki/IPsec) proposal defines a set of parameters used in negotiating security associations for IPSec tunnels. IPSec proposals defined in NetBox can be referenced by [IPSec policies](./ipsecpolicy.md), which are in turn employed by [IPSec profiles](./ipsecprofile.md).

## Fields

### Name

The unique user-assigned name for the proposal.

### Encryption Algorithm

The protocol employed for data encryption. Options include DES, 3DES, and various flavors of AES.

### Authentication Algorithm

The mechanism employed to ensure data integrity. Options include MD5 and SHA HMAC implementations.

### SA Lifetime (Seconds)

The maximum amount of time for which the security association (SA) may be active, in seconds.

### SA Lifetime (Data)

The maximum amount of data which can be transferred within the security association (SA) before it must be rebuilt, in kilobytes.
36 changes: 36 additions & 0 deletions docs/models/vpn/tunnel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Tunnels

A tunnel represents a private virtual connection established among two or more endpoints across a shared infrastructure by employing protocol encapsulation. Common encapsulation techniques include [Generic Routing Encapsulation (GRE)](https://en.wikipedia.org/wiki/Generic_Routing_Encapsulation), [IP-in-IP](https://en.wikipedia.org/wiki/IP_in_IP), and [IPSec](https://en.wikipedia.org/wiki/IPsec). NetBox supports modeling both peer-to-peer and hub-and-spoke tunnel topologies.

Device and virtual machine interfaces are associated to tunnels by creating [tunnel terminations](./tunneltermination.md).

## Fields

### Name

A unique name assigned to the tunnel for identification.

### Status

The operational status of the tunnel. By default, the following statuses are available:

| Name |
|----------------|
| Planned |
| Active |
| Disabled |

!!! tip "Custom tunnel statuses"
Additional tunnel statuses may be defined by setting `Tunnel.status` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter.

### Encapsulation

The encapsulation protocol or technique employed to effect the tunnel. NetBox supports GRE, IP-in-IP, and IPSec encapsulations.

### Tunnel ID

An optional numeric identifier for the tunnel.

### IPSec Profile

For IPSec tunnels, this is the [IPSec Profile](./ipsecprofile.md) employed to negotiate security associations.
30 changes: 30 additions & 0 deletions docs/models/vpn/tunneltermination.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Tunnel Terminations

A tunnel termination connects a device or virtual machine interface to a [tunnel](./tunnel.md). The tunnel must be created before any terminations may be added.

## Fields

### Tunnel

The [tunnel](./tunnel.md) to which this termination is made.

### Role

The functional role of the attached interface. The following options are available:

| Name | Description |
|-------|--------------------------------------------------|
| Peer | An endpoint in a point-to-point or mesh topology |
| Hub | A central point in a hub-and-spoke topology |
| Spoke | An edge point in a hub-and-spoke topology |

!!! note
Multiple hub terminations may be attached to a tunnel.

### Termination

The device or virtual machine interface terminated to the tunnel.

### Outside IP

The public or underlay IP address with which this termination is associated. This is the IP to which peers will route tunneled traffic.
9 changes: 9 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ nav:
- Circuits: 'features/circuits.md'
- Wireless: 'features/wireless.md'
- Virtualization: 'features/virtualization.md'
- VPN Tunnels: 'features/vpn-tunnels.md'
- Tenancy: 'features/tenancy.md'
- Contacts: 'features/contacts.md'
- Search: 'features/search.md'
Expand Down Expand Up @@ -252,6 +253,14 @@ nav:
- ClusterType: 'models/virtualization/clustertype.md'
- VMInterface: 'models/virtualization/vminterface.md'
- VirtualMachine: 'models/virtualization/virtualmachine.md'
- VPN:
- IKEPolicy: 'models/vpn/ikepolicy.md'
- IKEProposal: 'models/vpn/ikeproposal.md'
- IPSecPolicy: 'models/vpn/ipsecpolicy.md'
- IPSecProfile: 'models/vpn/ipsecprofile.md'
- IPSecProposal: 'models/vpn/ipsecproposal.md'
- Tunnel: 'models/vpn/tunnel.md'
- TunnelTermination: 'models/vpn/tunneltermination.md'
- Wireless:
- WirelessLAN: 'models/wireless/wirelesslan.md'
- WirelessLANGroup: 'models/wireless/wirelesslangroup.md'
Expand Down
2 changes: 1 addition & 1 deletion netbox/core/management/commands/nbshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from django.contrib.contenttypes.models import ContentType
from django.core.management.base import BaseCommand

APPS = ('circuits', 'core', 'dcim', 'extras', 'ipam', 'tenancy', 'users', 'virtualization', 'wireless')
APPS = ('circuits', 'core', 'dcim', 'extras', 'ipam', 'tenancy', 'users', 'virtualization', 'vpn', 'wireless')

BANNER_TEXT = """### NetBox interactive shell ({node})
### Python {python} | Django {django} | NetBox {netbox}
Expand Down
10 changes: 10 additions & 0 deletions netbox/dcim/models/device_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,10 @@ def save(self, *args, **kwargs):

return super().save(*args, **kwargs)

@property
def tunnel_termination(self):
return self.tunnel_terminations.first()

@property
def count_ipaddresses(self):
return self.ip_addresses.count()
Expand Down Expand Up @@ -719,6 +723,12 @@ class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEnd
object_id_field='interface_id',
related_query_name='+'
)
tunnel_terminations = GenericRelation(
to='vpn.TunnelTermination',
content_type_field='termination_type',
object_id_field='termination_id',
related_query_name='interface'
)
l2vpn_terminations = GenericRelation(
to='ipam.L2VPNTermination',
content_type_field='assigned_object_type',
Expand Down
13 changes: 10 additions & 3 deletions netbox/dcim/tables/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,12 @@ class BaseInterfaceTable(NetBoxTable):
orderable=False,
verbose_name=_('L2VPN')
)
tunnel = tables.Column(
accessor=tables.A('tunnel_termination__tunnel'),
linkify=True,
orderable=False,
verbose_name=_('Tunnel')
)
untagged_vlan = tables.Column(
verbose_name=_('Untagged VLAN'),
linkify=True
Expand Down Expand Up @@ -646,7 +652,8 @@ class Meta(DeviceComponentTable.Meta):
'speed', 'speed_formatted', 'duplex', 'mode', 'mac_address', 'wwn', 'poe_mode', 'poe_type', 'rf_role', 'rf_channel',
'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'description', 'mark_connected', 'cable',
'cable_color', 'wireless_link', 'wireless_lans', 'link_peer', 'connection', 'tags', 'vdcs', 'vrf', 'l2vpn',
'ip_addresses', 'fhrp_groups', 'untagged_vlan', 'tagged_vlans', 'inventory_items', 'created', 'last_updated',
'tunnel', 'ip_addresses', 'fhrp_groups', 'untagged_vlan', 'tagged_vlans', 'inventory_items', 'created',
'last_updated',
)
default_columns = ('pk', 'name', 'device', 'label', 'enabled', 'type', 'description')

Expand Down Expand Up @@ -682,8 +689,8 @@ class Meta(DeviceComponentTable.Meta):
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'enabled', 'type', 'parent', 'bridge', 'lag',
'mgmt_only', 'mtu', 'mode', 'mac_address', 'wwn', 'rf_role', 'rf_channel', 'rf_channel_frequency',
'rf_channel_width', 'tx_power', 'description', 'mark_connected', 'cable', 'cable_color', 'wireless_link',
'wireless_lans', 'link_peer', 'connection', 'tags', 'vdcs', 'vrf', 'l2vpn', 'ip_addresses', 'fhrp_groups',
'untagged_vlan', 'tagged_vlans', 'actions',
'wireless_lans', 'link_peer', 'connection', 'tags', 'vdcs', 'vrf', 'l2vpn', 'tunnel', 'ip_addresses',
'fhrp_groups', 'untagged_vlan', 'tagged_vlans', 'actions',
)
default_columns = (
'pk', 'name', 'label', 'enabled', 'type', 'parent', 'lag', 'mtu', 'mode', 'description', 'ip_addresses',
Expand Down
10 changes: 10 additions & 0 deletions netbox/dcim/tables/template_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,16 @@
<i class="mdi mdi-wifi-off" aria-hidden="true"></i>
</a>
{% endif %}
{% elif record.type == 'virtual' %}
{% if perms.vpn.add_tunnel and not record.tunnel_termination %}
<a href="{% url 'vpn:tunnel_add' %}?termination1_type=dcim.device&termination1_parent={{ record.device.pk }}&termination1_interface={{ record.pk }}&return_url={% url 'dcim:device_interfaces' pk=object.pk %}" title="Create a tunnel" class="btn btn-success btn-sm">
<i class="mdi mdi-tunnel-outline" aria-hidden="true"></i>
</a>
{% elif perms.vpn.delete_tunneltermination and record.tunnel_termination %}
<a href="{% url 'vpn:tunneltermination_delete' pk=record.tunnel_termination.pk %}?return_url={% url 'dcim:device_interfaces' pk=object.pk %}" title="Remove tunnel" class="btn btn-danger btn-sm">
<i class="mdi mdi-tunnel-outline" aria-hidden="true"></i>
</a>
{% endif %}
{% elif record.is_wired and perms.dcim.add_cable %}
<a href="#" class="btn btn-outline-dark btn-sm disabled"><i class="mdi mdi-transit-connection-variant" aria-hidden="true"></i></a>
<a href="#" class="btn btn-outline-dark btn-sm disabled"><i class="mdi mdi-lan-connect" aria-hidden="true"></i></a>
Expand Down
1 change: 1 addition & 0 deletions netbox/netbox/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def get(self, request, format=None):
'tenancy': reverse('tenancy-api:api-root', request=request, format=format),
'users': reverse('users-api:api-root', request=request, format=format),
'virtualization': reverse('virtualization-api:api-root', request=request, format=format),
'vpn': reverse('vpn-api:api-root', request=request, format=format),
'wireless': reverse('wireless-api:api-root', request=request, format=format),
})

Expand Down
2 changes: 2 additions & 0 deletions netbox/netbox/graphql/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from tenancy.graphql.schema import TenancyQuery
from users.graphql.schema import UsersQuery
from virtualization.graphql.schema import VirtualizationQuery
from vpn.graphql.schema import VPNQuery
from wireless.graphql.schema import WirelessQuery


Expand All @@ -21,6 +22,7 @@ class Query(
IPAMQuery,
TenancyQuery,
VirtualizationQuery,
VPNQuery,
WirelessQuery,
*registry['plugins']['graphql_schemas'], # Append plugin schemas
graphene.ObjectType
Expand Down
Loading

0 comments on commit 6678880

Please sign in to comment.