diff --git a/netbox/netbox/navigation/menu.py b/netbox/netbox/navigation/menu.py
index 904106ecf..6a9f2fa08 100644
--- a/netbox/netbox/navigation/menu.py
+++ b/netbox/netbox/navigation/menu.py
@@ -216,6 +216,10 @@ VPN_MENU = Menu(
MenuGroup(
label=_('Security'),
items=(
+ get_model_item('vpn', 'ikeproposal', _('IKE Proposals')),
+ get_model_item('vpn', 'ikepolicy', _('IKE Policies')),
+ get_model_item('vpn', 'ipsecproposal', _('IPSec Proposals')),
+ get_model_item('vpn', 'ipsecpolicy', _('IPSec Policies')),
get_model_item('vpn', 'ipsecprofile', _('IPSec Profiles')),
),
),
diff --git a/netbox/templates/vpn/ikepolicy.html b/netbox/templates/vpn/ikepolicy.html
new file mode 100644
index 000000000..1bf49818b
--- /dev/null
+++ b/netbox/templates/vpn/ikepolicy.html
@@ -0,0 +1,45 @@
+{% extends 'generic/object.html' %}
+{% load helpers %}
+{% load plugins %}
+{% load i18n %}
+
+{% block content %}
+
+
+
+
+
+
+
+ {% trans "Name" %} |
+ {{ object.name }} |
+
+
+ {% trans "IKE Version" %} |
+ {{ object.get_version_display }} |
+
+
+ {% trans "Mode" %} |
+ {{ object.get_mode_display }} |
+
+
+ {% trans "Description" %} |
+ {{ object.description|placeholder }} |
+
+
+
+
+ {% plugin_left_page object %}
+
+
+ {% include 'inc/panels/custom_fields.html' %}
+ {% include 'inc/panels/tags.html' %}
+ {% plugin_right_page object %}
+
+
+
+
+ {% plugin_full_width_page object %}
+
+
+{% endblock %}
diff --git a/netbox/templates/vpn/ikeproposal.html b/netbox/templates/vpn/ikeproposal.html
new file mode 100644
index 000000000..6079f0771
--- /dev/null
+++ b/netbox/templates/vpn/ikeproposal.html
@@ -0,0 +1,57 @@
+{% extends 'generic/object.html' %}
+{% load helpers %}
+{% load plugins %}
+{% load i18n %}
+
+{% block content %}
+
+
+
+
+
+
+
+ {% trans "Name" %} |
+ {{ object.name }} |
+
+
+ {% trans "Authentication method" %} |
+ {{ object.get_authentication_method_display }} |
+
+
+ {% trans "Encryption algorithm" %} |
+ {{ object.get_encryption_algorithm_display }} |
+
+
+ {% trans "Authentication algorithm" %} |
+ {{ object.get_authentication_algorithm_display }} |
+
+
+ {% trans "DH group" %} |
+ {{ object.get_group_display }} |
+
+
+ {% trans "SA lifetime (seconds)" %} |
+ {{ object.sa_lifetime|placeholder }} |
+
+
+ {% trans "Description" %} |
+ {{ object.description|placeholder }} |
+
+
+
+
+ {% plugin_left_page object %}
+
+
+ {% include 'inc/panels/custom_fields.html' %}
+ {% include 'inc/panels/tags.html' %}
+ {% plugin_right_page object %}
+
+
+
+
+ {% plugin_full_width_page object %}
+
+
+{% endblock %}
diff --git a/netbox/templates/vpn/ipsecpolicy.html b/netbox/templates/vpn/ipsecpolicy.html
new file mode 100644
index 000000000..8b8343876
--- /dev/null
+++ b/netbox/templates/vpn/ipsecpolicy.html
@@ -0,0 +1,41 @@
+{% extends 'generic/object.html' %}
+{% load helpers %}
+{% load plugins %}
+{% load i18n %}
+
+{% block content %}
+
+
+
+
+
+
+
+ {% trans "Name" %} |
+ {{ object.name }} |
+
+
+ {% trans "PFS group" %} |
+ {{ object.get_pfs_group_display|placeholder }} |
+
+
+ {% trans "Description" %} |
+ {{ object.description|placeholder }} |
+
+
+
+
+ {% plugin_left_page object %}
+
+
+ {% include 'inc/panels/custom_fields.html' %}
+ {% include 'inc/panels/tags.html' %}
+ {% plugin_right_page object %}
+
+
+
+
+ {% plugin_full_width_page object %}
+
+
+{% endblock %}
diff --git a/netbox/templates/vpn/ipsecproposal.html b/netbox/templates/vpn/ipsecproposal.html
new file mode 100644
index 000000000..ad375f4e3
--- /dev/null
+++ b/netbox/templates/vpn/ipsecproposal.html
@@ -0,0 +1,53 @@
+{% extends 'generic/object.html' %}
+{% load helpers %}
+{% load plugins %}
+{% load i18n %}
+
+{% block content %}
+
+
+
+
+
+
+
+ {% trans "Name" %} |
+ {{ object.name }} |
+
+
+ {% trans "Encryption algorithm" %} |
+ {{ object.get_encryption_algorithm_display }} |
+
+
+ {% trans "Authentication algorithm" %} |
+ {{ object.get_authentication_algorithm_display }} |
+
+
+ {% trans "SA lifetime (seconds)" %} |
+ {{ object.sa_lifetime_seconds|placeholder }} |
+
+
+ {% trans "SA lifetime (KB)" %} |
+ {{ object.sa_lifetime_data|placeholder }} |
+
+
+ {% trans "Description" %} |
+ {{ object.description|placeholder }} |
+
+
+
+
+ {% plugin_left_page object %}
+
+
+ {% include 'inc/panels/custom_fields.html' %}
+ {% include 'inc/panels/tags.html' %}
+ {% plugin_right_page object %}
+
+
+
+
+ {% plugin_full_width_page object %}
+
+
+{% endblock %}
diff --git a/netbox/vpn/api/nested_serializers.py b/netbox/vpn/api/nested_serializers.py
index 7ab1654b9..9e2dee8ba 100644
--- a/netbox/vpn/api/nested_serializers.py
+++ b/netbox/vpn/api/nested_serializers.py
@@ -4,7 +4,11 @@ from netbox.api.serializers import WritableNestedSerializer
from vpn import models
__all__ = (
+ 'NestedIKEPolicySerializer',
+ 'NestedIKEProposalSerializer',
+ 'NestedIPSecPolicySerializer',
'NestedIPSecProfileSerializer',
+ 'NestedIPSecProposalSerializer',
'NestedTunnelSerializer',
'NestedTunnelTerminationSerializer',
)
@@ -30,6 +34,46 @@ class NestedTunnelTerminationSerializer(WritableNestedSerializer):
fields = ('id', 'url', 'display')
+class NestedIKEProposalSerializer(WritableNestedSerializer):
+ url = serializers.HyperlinkedIdentityField(
+ view_name='vpn-api:ikeproposal-detail'
+ )
+
+ class Meta:
+ model = models.IKEProposal
+ fields = ('id', 'url', 'display', 'name')
+
+
+class NestedIKEPolicySerializer(WritableNestedSerializer):
+ url = serializers.HyperlinkedIdentityField(
+ view_name='vpn-api:ikepolicy-detail'
+ )
+
+ class Meta:
+ model = models.IKEProposal
+ fields = ('id', 'url', 'display', 'name')
+
+
+class NestedIPSecProposalSerializer(WritableNestedSerializer):
+ url = serializers.HyperlinkedIdentityField(
+ view_name='vpn-api:ipsecproposal-detail'
+ )
+
+ class Meta:
+ model = models.IPSecProposal
+ fields = ('id', 'url', 'display', 'name')
+
+
+class NestedIPSecPolicySerializer(WritableNestedSerializer):
+ url = serializers.HyperlinkedIdentityField(
+ view_name='vpn-api:ipsecpolicy-detail'
+ )
+
+ class Meta:
+ model = models.IPSecProposal
+ fields = ('id', 'url', 'display', 'name')
+
+
class NestedIPSecProfileSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='vpn-api:ipsecprofile-detail'
diff --git a/netbox/vpn/api/serializers.py b/netbox/vpn/api/serializers.py
index a65305dfe..0ebe28dba 100644
--- a/netbox/vpn/api/serializers.py
+++ b/netbox/vpn/api/serializers.py
@@ -3,7 +3,7 @@ from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers
from ipam.api.nested_serializers import NestedIPAddressSerializer
-from netbox.api.fields import ChoiceField, ContentTypeField
+from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField
from netbox.api.serializers import NetBoxModelSerializer
from netbox.constants import NESTED_SERIALIZER_PREFIX
from tenancy.api.nested_serializers import NestedTenantSerializer
@@ -13,7 +13,11 @@ from vpn.models import *
from .nested_serializers import *
__all__ = (
+ 'IKEPolicySerializer',
+ 'IKEProposalSerializer',
+ 'IPSecPolicySerializer',
'IPSecProfileSerializer',
+ 'IPSecProposalSerializer',
'TunnelSerializer',
'TunnelTerminationSerializer',
)
@@ -41,8 +45,8 @@ class TunnelSerializer(NetBoxModelSerializer):
class Meta:
model = Tunnel
fields = (
- 'id', 'url', 'display', 'name', 'status', 'encapsulation', 'ipsec_profile', 'tenant', 'preshared_key',
- 'tunnel_id', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
+ 'id', 'url', 'display', 'name', 'status', 'encapsulation', 'ipsec_profile', 'tenant', 'tunnel_id',
+ 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
)
@@ -79,30 +83,130 @@ class TunnelTerminationSerializer(NetBoxModelSerializer):
return serializer(obj.interface, context=context).data
+class IKEProposalSerializer(NetBoxModelSerializer):
+ url = serializers.HyperlinkedIdentityField(
+ view_name='vpn-api:ikeproposal-detail'
+ )
+ authentication_method = ChoiceField(
+ choices=AuthenticationMethodChoices
+ )
+ encryption_algorithm = ChoiceField(
+ choices=EncryptionAlgorithmChoices
+ )
+ authentication_algorithm = ChoiceField(
+ choices=AuthenticationAlgorithmChoices
+ )
+ group = ChoiceField(
+ choices=DHGroupChoices
+ )
+
+ class Meta:
+ model = IKEProposal
+ fields = (
+ 'id', 'url', 'display', 'name', 'description', 'authentication_method', 'encryption_algorithm',
+ 'authentication_algorithm', 'group', 'sa_lifetime', 'tags', 'custom_fields', 'created', 'last_updated',
+ )
+
+
+class IKEPolicySerializer(NetBoxModelSerializer):
+ url = serializers.HyperlinkedIdentityField(
+ view_name='vpn-api:ikepolicy-detail'
+ )
+ version = ChoiceField(
+ choices=IKEVersionChoices
+ )
+ mode = ChoiceField(
+ choices=IKEModeChoices
+ )
+ authentication_algorithm = ChoiceField(
+ choices=AuthenticationAlgorithmChoices
+ )
+ group = ChoiceField(
+ choices=DHGroupChoices
+ )
+ proposals = SerializedPKRelatedField(
+ queryset=IKEProposal.objects.all(),
+ serializer=NestedIKEProposalSerializer,
+ required=False,
+ many=True
+ )
+
+ class Meta:
+ model = IKEPolicy
+ fields = (
+ 'id', 'url', 'display', 'name', 'description', 'version', 'mode', 'proposals', 'preshared_key',
+ 'certificate', 'tags', 'custom_fields', 'created', 'last_updated',
+ )
+
+
+class IPSecProposalSerializer(NetBoxModelSerializer):
+ url = serializers.HyperlinkedIdentityField(
+ view_name='vpn-api:ipsecproposal-detail'
+ )
+ encryption_algorithm = ChoiceField(
+ choices=EncryptionAlgorithmChoices
+ )
+ authentication_algorithm = ChoiceField(
+ choices=AuthenticationAlgorithmChoices
+ )
+ group = ChoiceField(
+ choices=DHGroupChoices
+ )
+
+ class Meta:
+ model = IPSecProposal
+ fields = (
+ 'id', 'url', 'display', 'name', 'description', 'encryption_algorithm', 'authentication_algorithm',
+ 'sa_lifetime_data', 'sa_lifetime_seconds', 'tags', 'custom_fields', 'created', 'last_updated',
+ )
+
+
+class IPSecPolicySerializer(NetBoxModelSerializer):
+ url = serializers.HyperlinkedIdentityField(
+ view_name='vpn-api:ipsecpolicy-detail'
+ )
+ proposals = SerializedPKRelatedField(
+ queryset=IPSecProposal.objects.all(),
+ serializer=NestedIPSecProposalSerializer,
+ required=False,
+ many=True
+ )
+ pfs_group = ChoiceField(
+ choices=DHGroupChoices
+ )
+
+ class Meta:
+ model = IPSecPolicy
+ fields = (
+ 'id', 'url', 'display', 'name', 'description', 'proposals', 'pfs_group', 'tags', 'custom_fields', 'created',
+ 'last_updated',
+ )
+
+
class IPSecProfileSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='vpn-api:ipsecprofile-detail'
)
protocol = ChoiceField(
- choices=IPSecProtocolChoices
+ choices=IPSecModeChoices
)
ike_version = ChoiceField(
choices=IKEVersionChoices
)
phase1_encryption = ChoiceField(
- choices=EncryptionChoices
+ choices=EncryptionAlgorithmChoices
)
phase1_authentication = ChoiceField(
- choices=AuthenticationChoices
+ choices=AuthenticationAlgorithmChoices
)
phase1_group = ChoiceField(
choices=DHGroupChoices
)
phase2_encryption = ChoiceField(
- choices=EncryptionChoices
+ choices=EncryptionAlgorithmChoices
)
phase2_authentication = ChoiceField(
- choices=AuthenticationChoices
+ choices=AuthenticationAlgorithmChoices
)
phase2_group = ChoiceField(
choices=DHGroupChoices
diff --git a/netbox/vpn/api/urls.py b/netbox/vpn/api/urls.py
index 084514e35..f646174d5 100644
--- a/netbox/vpn/api/urls.py
+++ b/netbox/vpn/api/urls.py
@@ -3,6 +3,10 @@ from . import views
router = NetBoxRouter()
router.APIRootView = views.VPNRootView
+router.register('ike-policies', views.IKEPolicyViewSet)
+router.register('ike-proposals', views.IKEProposalViewSet)
+router.register('ipsec-policies', views.IPSecPolicyViewSet)
+router.register('ipsec-proposals', views.IPSecProposalViewSet)
router.register('ipsec-profiles', views.IPSecProfileViewSet)
router.register('tunnels', views.TunnelViewSet)
router.register('tunnel-terminations', views.TunnelTerminationViewSet)
diff --git a/netbox/vpn/api/views.py b/netbox/vpn/api/views.py
index 7d01c48cf..960bcb1b4 100644
--- a/netbox/vpn/api/views.py
+++ b/netbox/vpn/api/views.py
@@ -7,7 +7,11 @@ from vpn.models import *
from . import serializers
__all__ = (
+ 'IKEPolicyViewSet',
+ 'IKEProposalViewSet',
+ 'IPSecPolicyViewSet',
'IPSecProfileViewSet',
+ 'IPSecProposalViewSet',
'TunnelTerminationViewSet',
'TunnelViewSet',
'VPNRootView',
@@ -40,6 +44,30 @@ class TunnelTerminationViewSet(NetBoxModelViewSet):
filterset_class = filtersets.TunnelTerminationFilterSet
+class IKEProposalViewSet(NetBoxModelViewSet):
+ queryset = IKEProposal.objects.all()
+ serializer_class = serializers.IKEProposalSerializer
+ filterset_class = filtersets.IKEProposalFilterSet
+
+
+class IKEPolicyViewSet(NetBoxModelViewSet):
+ queryset = IKEPolicy.objects.all()
+ serializer_class = serializers.IKEPolicySerializer
+ filterset_class = filtersets.IKEPolicyFilterSet
+
+
+class IPSecProposalViewSet(NetBoxModelViewSet):
+ queryset = IPSecProposal.objects.all()
+ serializer_class = serializers.IPSecProposalSerializer
+ filterset_class = filtersets.IPSecProposalFilterSet
+
+
+class IPSecPolicyViewSet(NetBoxModelViewSet):
+ queryset = IKEPolicy.objects.all()
+ serializer_class = serializers.IPSecPolicySerializer
+ filterset_class = filtersets.IPSecPolicyFilterSet
+
+
class IPSecProfileViewSet(NetBoxModelViewSet):
queryset = IPSecProfile.objects.all()
serializer_class = serializers.IPSecProfileSerializer
diff --git a/netbox/vpn/choices.py b/netbox/vpn/choices.py
index 211dcb372..a932c5055 100644
--- a/netbox/vpn/choices.py
+++ b/netbox/vpn/choices.py
@@ -59,19 +59,9 @@ class TunnelTerminationRoleChoices(ChoiceSet):
#
-# IKE
+# Crypto
#
-class IPSecProtocolChoices(ChoiceSet):
- PROTOCOL_ESP = 'esp'
- PROTOCOL_AH = 'ah'
-
- CHOICES = (
- (PROTOCOL_ESP, 'ESP'),
- (PROTOCOL_AH, 'AH'),
- )
-
-
class IKEVersionChoices(ChoiceSet):
VERSION_1 = 1
VERSION_2 = 2
@@ -82,7 +72,41 @@ class IKEVersionChoices(ChoiceSet):
)
-class EncryptionChoices(ChoiceSet):
+class IKEModeChoices(ChoiceSet):
+ AGGRESSIVE = 'aggressive'
+ MAIN = 'main'
+
+ CHOICES = (
+ (AGGRESSIVE, _('Aggressive')),
+ (MAIN, _('Main')),
+ )
+
+
+class AuthenticationMethodChoices(ChoiceSet):
+ PRESHARED_KEYS = 'preshared-keys'
+ CERTIFICATES = 'certificates'
+ RSA_SIGNATURES = 'rsa-signatures'
+ DSA_SIGNATURES = 'dsa-signatures'
+
+ CHOICES = (
+ (PRESHARED_KEYS, _('Pre-shared keys')),
+ (CERTIFICATES, _('Certificates')),
+ (RSA_SIGNATURES, _('RSA signatures')),
+ (DSA_SIGNATURES, _('DSA signatures')),
+ )
+
+
+class IPSecModeChoices(ChoiceSet):
+ ESP = 'esp'
+ AH = 'ah'
+
+ CHOICES = (
+ (ESP, 'ESP'),
+ (AH, 'AH'),
+ )
+
+
+class EncryptionAlgorithmChoices(ChoiceSet):
ENCRYPTION_AES128_CBC = 'aes-128-cbc'
ENCRYPTION_AES128_GCM = 'aes-128-gcm'
ENCRYPTION_AES192_CBC = 'aes-192-cbc'
@@ -104,7 +128,7 @@ class EncryptionChoices(ChoiceSet):
)
-class AuthenticationChoices(ChoiceSet):
+class AuthenticationAlgorithmChoices(ChoiceSet):
AUTH_HMAC_SHA1 = 'hmac-sha1'
AUTH_HMAC_SHA256 = 'hmac-sha256'
AUTH_HMAC_SHA384 = 'hmac-sha384'
diff --git a/netbox/vpn/filtersets.py b/netbox/vpn/filtersets.py
index 99dcde379..a417f4e32 100644
--- a/netbox/vpn/filtersets.py
+++ b/netbox/vpn/filtersets.py
@@ -6,12 +6,17 @@ from dcim.models import Interface
from ipam.models import IPAddress
from netbox.filtersets import NetBoxModelFilterSet
from tenancy.filtersets import TenancyFilterSet
+from utilities.filters import ContentTypeFilter, MultiValueNumberFilter
from virtualization.models import VMInterface
from .choices import *
from .models import *
__all__ = (
+ 'IKEPolicyFilterSet',
+ 'IKEProposalFilterSet',
+ 'IPSecPolicyFilterSet',
'IPSecProfileFilterSet',
+ 'IPSecProposalFilterSet',
'TunnelFilterSet',
'TunnelTerminationFilterSet',
)
@@ -37,7 +42,7 @@ class TunnelFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
class Meta:
model = Tunnel
- fields = ['id', 'name', 'preshared_key', 'tunnel_id']
+ fields = ['id', 'name', 'tunnel_id']
def search(self, queryset, name, value):
if not value.strip():
@@ -97,35 +102,129 @@ class TunnelTerminationFilterSet(NetBoxModelFilterSet):
fields = ['id']
-class IPSecProfileFilterSet(NetBoxModelFilterSet):
- protocol = django_filters.MultipleChoiceFilter(
- choices=IPSecProtocolChoices
+class IKEProposalFilterSet(NetBoxModelFilterSet):
+ authentication_method = django_filters.MultipleChoiceFilter(
+ choices=AuthenticationMethodChoices
)
- ike_version = django_filters.MultipleChoiceFilter(
- choices=IKEVersionChoices
+ encryption_algorithm = django_filters.MultipleChoiceFilter(
+ choices=EncryptionAlgorithmChoices
)
- phase1_encryption = django_filters.MultipleChoiceFilter(
- choices=EncryptionChoices
+ authentication_algorithm = django_filters.MultipleChoiceFilter(
+ choices=AuthenticationAlgorithmChoices
)
- phase1_authentication = django_filters.MultipleChoiceFilter(
- choices=AuthenticationChoices
- )
- phase1_group = django_filters.MultipleChoiceFilter(
- choices=DHGroupChoices
- )
- phase2_encryption = django_filters.MultipleChoiceFilter(
- choices=EncryptionChoices
- )
- phase2_authentication = django_filters.MultipleChoiceFilter(
- choices=AuthenticationChoices
- )
- phase2_group = django_filters.MultipleChoiceFilter(
+ group = django_filters.MultipleChoiceFilter(
choices=DHGroupChoices
)
+ class Meta:
+ model = IKEProposal
+ fields = ['id', 'name', 'sa_lifetime']
+
+ def search(self, queryset, name, value):
+ if not value.strip():
+ return queryset
+ return queryset.filter(
+ Q(name__icontains=value) |
+ Q(description__icontains=value)
+ )
+
+
+class IKEPolicyFilterSet(NetBoxModelFilterSet):
+ version = django_filters.MultipleChoiceFilter(
+ choices=IKEVersionChoices
+ )
+ mode = django_filters.MultipleChoiceFilter(
+ choices=IKEModeChoices
+ )
+ proposal_id = MultiValueNumberFilter(
+ field_name='proposals__id'
+ )
+ proposals = ContentTypeFilter()
+
+ class Meta:
+ model = IKEPolicy
+ fields = ['id', 'name']
+
+ def search(self, queryset, name, value):
+ if not value.strip():
+ return queryset
+ return queryset.filter(
+ Q(name__icontains=value) |
+ Q(description__icontains=value)
+ )
+
+
+class IPSecProposalFilterSet(NetBoxModelFilterSet):
+ encryption_algorithm = django_filters.MultipleChoiceFilter(
+ choices=EncryptionAlgorithmChoices
+ )
+ authentication_algorithm = django_filters.MultipleChoiceFilter(
+ choices=AuthenticationAlgorithmChoices
+ )
+
+ class Meta:
+ model = IPSecProposal
+ fields = ['id', 'name', 'sa_lifetime_seconds', 'sa_lifetime_data']
+
+ def search(self, queryset, name, value):
+ if not value.strip():
+ return queryset
+ return queryset.filter(
+ Q(name__icontains=value) |
+ Q(description__icontains=value)
+ )
+
+
+class IPSecPolicyFilterSet(NetBoxModelFilterSet):
+ pfs_group = django_filters.MultipleChoiceFilter(
+ choices=DHGroupChoices
+ )
+ proposal_id = MultiValueNumberFilter(
+ field_name='proposals__id'
+ )
+ proposals = ContentTypeFilter()
+
+ class Meta:
+ model = IPSecPolicy
+ fields = ['id', 'name']
+
+ def search(self, queryset, name, value):
+ if not value.strip():
+ return queryset
+ return queryset.filter(
+ Q(name__icontains=value) |
+ Q(description__icontains=value)
+ )
+
+
+class IPSecProfileFilterSet(NetBoxModelFilterSet):
+ mode = django_filters.MultipleChoiceFilter(
+ choices=IPSecModeChoices
+ )
+ ike_policy_id = django_filters.ModelMultipleChoiceFilter(
+ queryset=IKEPolicy.objects.all(),
+ label=_('IKE policy (ID)'),
+ )
+ ike_policy = django_filters.ModelMultipleChoiceFilter(
+ field_name='ike_policy__name',
+ queryset=IKEPolicy.objects.all(),
+ to_field_name='name',
+ label=_('IKE policy (name)'),
+ )
+ ipsec_policy_id = django_filters.ModelMultipleChoiceFilter(
+ queryset=IPSecPolicy.objects.all(),
+ label=_('IPSec policy (ID)'),
+ )
+ ipsec_policy = django_filters.ModelMultipleChoiceFilter(
+ field_name='ipsec_policy__name',
+ queryset=IPSecPolicy.objects.all(),
+ to_field_name='name',
+ label=_('IPSec policy (name)'),
+ )
+
class Meta:
model = IPSecProfile
- fields = ['id', 'name', 'phase1_sa_lifetime', 'phase2_sa_lifetime', 'phase2_sa_lifetime_data']
+ fields = ['id', 'name']
def search(self, queryset, name, value):
if not value.strip():
diff --git a/netbox/vpn/forms/bulk_edit.py b/netbox/vpn/forms/bulk_edit.py
index 6969235f7..d645ca02b 100644
--- a/netbox/vpn/forms/bulk_edit.py
+++ b/netbox/vpn/forms/bulk_edit.py
@@ -9,7 +9,11 @@ from vpn.choices import *
from vpn.models import *
__all__ = (
+ 'IKEPolicyBulkEditForm',
+ 'IKEProposalBulkEditForm',
+ 'IPSecPolicyBulkEditForm',
'IPSecProfileBulkEditForm',
+ 'IPSecProposalBulkEditForm',
'TunnelBulkEditForm',
'TunnelTerminationBulkEditForm',
)
@@ -31,10 +35,6 @@ class TunnelBulkEditForm(NetBoxModelBulkEditForm):
label=_('IPSec profile'),
required=False
)
- preshared_key = forms.CharField(
- label=_('Pre-shared key'),
- required=False
- )
tenant = DynamicModelChoiceField(
label=_('Tenant'),
queryset=Tenant.objects.all(),
@@ -54,11 +54,11 @@ class TunnelBulkEditForm(NetBoxModelBulkEditForm):
model = Tunnel
fieldsets = (
(_('Tunnel'), ('status', 'encapsulation', 'tunnel_id', 'description')),
- (_('Security'), ('ipsec_profile', 'preshared_key')),
+ (_('Security'), ('ipsec_profile',)),
(_('Tenancy'), ('tenant',)),
)
nullable_fields = (
- 'ipsec_profile', 'preshared_key', 'tunnel_id', 'tenant', 'description', 'comments',
+ 'ipsec_profile', 'tunnel_id', 'tenant', 'description', 'comments',
)
@@ -75,61 +75,130 @@ class TunnelTerminationBulkEditForm(NetBoxModelBulkEditForm):
)
-class IPSecProfileBulkEditForm(NetBoxModelBulkEditForm):
- protocol = forms.ChoiceField(
- label=_('Protocol'),
- choices=add_blank_choice(IPSecProtocolChoices),
+class IKEProposalBulkEditForm(NetBoxModelBulkEditForm):
+ authentication_method = forms.ChoiceField(
+ label=_('Authentication method'),
+ choices=add_blank_choice(AuthenticationMethodChoices),
required=False
)
- ike_version = forms.ChoiceField(
- label=_('IKE version'),
+ encryption_algorithm = forms.ChoiceField(
+ label=_('Encryption algorithm'),
+ choices=add_blank_choice(EncryptionAlgorithmChoices),
+ required=False
+ )
+ authentication_algorithm = forms.ChoiceField(
+ label=_('Authentication algorithm'),
+ choices=add_blank_choice(AuthenticationAlgorithmChoices),
+ required=False
+ )
+ group = forms.ChoiceField(
+ label=_('Group'),
+ choices=add_blank_choice(DHGroupChoices),
+ required=False
+ )
+ sa_lifetime = forms.IntegerField(
+ required=False
+ )
+
+ model = IKEProposal
+ fieldsets = (
+ (None, ('name', 'description')),
+ (_('Parameters'), (
+ 'authentication_method', 'encryption_algorithm', 'authentication_algorithm', 'group', 'sa_lifetime',
+ )),
+ )
+ nullable_fields = (
+ 'description', 'sa_lifetime', 'comments',
+ )
+
+
+class IKEPolicyBulkEditForm(NetBoxModelBulkEditForm):
+ version = forms.ChoiceField(
+ label=_('Version'),
choices=add_blank_choice(IKEVersionChoices),
required=False
)
+ mode = forms.ChoiceField(
+ label=_('Mode'),
+ choices=add_blank_choice(IKEModeChoices),
+ required=False
+ )
+ preshared_key = forms.CharField(
+ label=_('Pre-shared key'),
+ required=False
+ )
+ certificate = forms.CharField(
+ label=_('Certificate'),
+ required=False
+ )
+
+ model = IKEPolicy
+ fieldsets = (
+ (None, ('name', 'description')),
+ (_('Parameters'), (
+ 'version', 'mode', 'preshared_key', 'certificate',
+ )),
+ )
+ nullable_fields = (
+ 'description', 'preshared_key', 'certificate', 'comments',
+ )
+
+
+class IPSecProposalBulkEditForm(NetBoxModelBulkEditForm):
+ encryption_algorithm = forms.ChoiceField(
+ label=_('Encryption algorithm'),
+ choices=add_blank_choice(EncryptionAlgorithmChoices),
+ required=False
+ )
+ authentication_algorithm = forms.ChoiceField(
+ label=_('Authentication algorithm'),
+ choices=add_blank_choice(AuthenticationAlgorithmChoices),
+ required=False
+ )
+ sa_lifetime_seconds = forms.IntegerField(
+ required=False
+ )
+ sa_lifetime_data = forms.IntegerField(
+ required=False
+ )
+
+ model = IPSecProposal
+ fieldsets = (
+ (None, ('name', 'description')),
+ (_('Parameters'), (
+ 'encryption_algorithm', 'authentication_algorithm', 'sa_lifetime_seconds', 'sa_lifetime_data',
+ )),
+ )
+ nullable_fields = (
+ 'description', 'sa_lifetime_seconds', 'sa_lifetime_data', 'comments',
+ )
+
+
+class IPSecPolicyBulkEditForm(NetBoxModelBulkEditForm):
+ pfs_group = forms.ChoiceField(
+ label=_('PFS group'),
+ choices=add_blank_choice(DHGroupChoices),
+ required=False
+ )
+
+ model = IPSecPolicy
+ fieldsets = (
+ (None, ('name', 'description')),
+ (_('Parameters'), (
+ 'pfs_group',
+ )),
+ )
+ nullable_fields = (
+ 'description', 'pfs_group', 'comments',
+ )
+
+
+class IPSecProfileBulkEditForm(NetBoxModelBulkEditForm):
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
- phase1_encryption = forms.ChoiceField(
- label=_('Encryption'),
- choices=add_blank_choice(EncryptionChoices),
- required=False
- )
- phase1_authentication = forms.ChoiceField(
- label=_('Authentication'),
- choices=add_blank_choice(AuthenticationChoices),
- required=False
- )
- phase1_group = forms.ChoiceField(
- label=_('Group'),
- choices=add_blank_choice(DHGroupChoices),
- required=False
- )
- phase1_sa_lifetime = forms.IntegerField(
- required=False
- )
- phase2_encryption = forms.ChoiceField(
- label=_('Encryption'),
- choices=add_blank_choice(EncryptionChoices),
- required=False
- )
- phase2_authentication = forms.ChoiceField(
- label=_('Authentication'),
- choices=add_blank_choice(AuthenticationChoices),
- required=False
- )
- phase2_group = forms.ChoiceField(
- label=_('Group'),
- choices=add_blank_choice(DHGroupChoices),
- required=False
- )
- phase2_sa_lifetime = forms.IntegerField(
- required=False
- )
- phase2_sa_lifetime_data = forms.IntegerField(
- required=False
- )
comments = CommentField()
model = IPSecProfile
@@ -137,14 +206,7 @@ class IPSecProfileBulkEditForm(NetBoxModelBulkEditForm):
(_('Profile'), (
'protocol', 'ike_version', 'description',
)),
- (_('Phase 1 Parameters'), (
- 'phase1_encryption', 'phase1_authentication', 'phase1_group', 'phase1_sa_lifetime',
- )),
- (_('Phase 2 Parameters'), (
- 'phase2_encryption', 'phase2_authentication', 'phase2_group', 'phase2_sa_lifetime',
- 'phase2_sa_lifetime_data',
- )),
)
nullable_fields = (
- 'description', 'phase1_sa_lifetime', 'phase2_sa_lifetime', 'phase2_sa_lifetime_data', 'comments',
+ 'description', 'comments',
)
diff --git a/netbox/vpn/forms/bulk_import.py b/netbox/vpn/forms/bulk_import.py
index db601b709..1b19af25f 100644
--- a/netbox/vpn/forms/bulk_import.py
+++ b/netbox/vpn/forms/bulk_import.py
@@ -10,7 +10,11 @@ from vpn.choices import *
from vpn.models import *
__all__ = (
+ 'IKEPolicyImportForm',
+ 'IKEProposalImportForm',
+ 'IPSecPolicyImportForm',
'IPSecProfileImportForm',
+ 'IPSecProposalImportForm',
'TunnelImportForm',
'TunnelTerminationImportForm',
)
@@ -43,8 +47,8 @@ class TunnelImportForm(NetBoxModelImportForm):
class Meta:
model = Tunnel
fields = (
- 'name', 'status', 'encapsulation', 'ipsec_profile', 'tenant', 'preshared_key', 'tunnel_id', 'description',
- 'comments', 'tags',
+ 'name', 'status', 'encapsulation', 'ipsec_profile', 'tenant', 'tunnel_id', 'description', 'comments',
+ 'tags',
)
@@ -108,46 +112,109 @@ class TunnelTerminationImportForm(NetBoxModelImportForm):
)
+class IKEProposalImportForm(NetBoxModelImportForm):
+ authentication_method = CSVChoiceField(
+ label=_('Authentication method'),
+ choices=AuthenticationMethodChoices
+ )
+ encryption_algorithm = CSVChoiceField(
+ label=_('Encryption algorithm'),
+ choices=EncryptionAlgorithmChoices
+ )
+ authentication_algorithmn = CSVChoiceField(
+ label=_('Authentication algorithm'),
+ choices=AuthenticationAlgorithmChoices
+ )
+ group = CSVChoiceField(
+ label=_('Group'),
+ choices=DHGroupChoices
+ )
+
+ class Meta:
+ model = IKEProposal
+ fields = (
+ 'name', 'description', 'authentication_method', 'encryption_algorithm', 'authentication_algorithmn',
+ 'group', 'sa_lifetime', 'tags',
+ )
+
+
+class IKEPolicyImportForm(NetBoxModelImportForm):
+ version = CSVChoiceField(
+ label=_('Version'),
+ choices=IKEVersionChoices
+ )
+ mode = CSVChoiceField(
+ label=_('Mode'),
+ choices=IKEModeChoices
+ )
+ # TODO: M2M field for proposals
+
+ class Meta:
+ model = IKEPolicy
+ fields = (
+ 'name', 'description', 'version', 'mode', 'proposals', 'preshared_key', 'certificate', 'tags',
+ )
+
+
+class IPSecProposalImportForm(NetBoxModelImportForm):
+ authentication_method = CSVChoiceField(
+ label=_('Authentication method'),
+ choices=AuthenticationMethodChoices
+ )
+ encryption_algorithm = CSVChoiceField(
+ label=_('Encryption algorithm'),
+ choices=EncryptionAlgorithmChoices
+ )
+ authentication_algorithmn = CSVChoiceField(
+ label=_('Authentication algorithm'),
+ choices=AuthenticationAlgorithmChoices
+ )
+ group = CSVChoiceField(
+ label=_('Group'),
+ choices=DHGroupChoices
+ )
+
+ class Meta:
+ model = IPSecProposal
+ fields = (
+ 'name', 'description', 'encryption_algorithm', 'authentication_algorithmn', 'sa_lifetime_seconds',
+ 'sa_lifetime_data', 'tags',
+ )
+
+
+class IPSecPolicyImportForm(NetBoxModelImportForm):
+ pfs_group = CSVChoiceField(
+ label=_('PFS group'),
+ choices=DHGroupChoices
+ )
+ # TODO: M2M field for proposals
+
+ class Meta:
+ model = IPSecPolicy
+ fields = (
+ 'name', 'description', 'proposals', 'pfs_group', 'tags',
+ )
+
+
class IPSecProfileImportForm(NetBoxModelImportForm):
- protocol = CSVChoiceField(
- label=_('Protocol'),
- choices=IPSecProtocolChoices,
+ mode = CSVChoiceField(
+ label=_('Mode'),
+ choices=IPSecModeChoices,
help_text=_('IPSec protocol')
)
- ike_version = CSVChoiceField(
- label=_('IKE version'),
- choices=IKEVersionChoices,
- help_text=_('IKE version')
+ ike_policy = CSVModelChoiceField(
+ label=_('IKE policy'),
+ queryset=IKEPolicy.objects.all(),
+ to_field_name='name'
)
- phase1_encryption = CSVChoiceField(
- label=_('Phase 1 Encryption'),
- choices=EncryptionChoices
- )
- phase1_authentication = CSVChoiceField(
- label=_('Phase 1 Authentication'),
- choices=AuthenticationChoices
- )
- phase1_group = CSVChoiceField(
- label=_('Phase 1 Group'),
- choices=DHGroupChoices
- )
- phase2_encryption = CSVChoiceField(
- label=_('Phase 2 Encryption'),
- choices=EncryptionChoices
- )
- phase2_authentication = CSVChoiceField(
- label=_('Phase 2 Authentication'),
- choices=AuthenticationChoices
- )
- phase2_group = CSVChoiceField(
- label=_('Phase 2 Group'),
- choices=DHGroupChoices
+ ipsec_policy = CSVModelChoiceField(
+ label=_('IPSec policy'),
+ queryset=IPSecPolicy.objects.all(),
+ to_field_name='name'
)
class Meta:
model = IPSecProfile
fields = (
- 'name', 'protocol', 'ike_version', 'phase1_encryption', 'phase1_authentication', 'phase1_group',
- 'phase1_sa_lifetime', 'phase2_encryption', 'phase2_authentication', 'phase2_group', 'phase2_sa_lifetime',
- 'phase2_sa_lifetime_data', 'description', 'comments', 'tags',
+ 'name', 'ike_policy', 'ipsec_policy', 'description', 'comments', 'tags',
)
diff --git a/netbox/vpn/forms/filtersets.py b/netbox/vpn/forms/filtersets.py
index 44ad79b7e..98a626857 100644
--- a/netbox/vpn/forms/filtersets.py
+++ b/netbox/vpn/forms/filtersets.py
@@ -8,7 +8,11 @@ from vpn.choices import *
from vpn.models import *
__all__ = (
+ 'IKEPolicyFilterForm',
+ 'IKEProposalFilterForm',
+ 'IPSecPolicyFilterForm',
'IPSecProfileFilterForm',
+ 'IPSecProposalFilterForm',
'TunnelFilterForm',
'TunnelTerminationFilterForm',
)
@@ -19,7 +23,7 @@ class TunnelFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
fieldsets = (
(None, ('q', 'filter_id', 'tag')),
(_('Tunnel'), ('status', 'encapsulation', 'tunnel_id')),
- (_('Security'), ('ipsec_profile_id', 'preshared_key')),
+ (_('Security'), ('ipsec_profile_id',)),
(_('Tenancy'), ('tenant_group_id', 'tenant_id')),
)
status = forms.MultipleChoiceField(
@@ -37,10 +41,6 @@ class TunnelFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
required=False,
label=_('IPSec profile')
)
- preshared_key = forms.CharField(
- required=False,
- label=_('Pre-shared key')
- )
tunnel_id = forms.IntegerField(
required=False,
label=_('Tunnel ID')
@@ -67,6 +67,97 @@ class TunnelTerminationFilterForm(NetBoxModelFilterSetForm):
tag = TagFilterField(model)
+class IKEProposalFilterForm(NetBoxModelFilterSetForm):
+ model = IKEProposal
+ fieldsets = (
+ (None, ('q', 'filter_id', 'tag')),
+ (_('Parameters'), ('authentication_method', 'encryption_algorithm', 'authentication_algorithm', 'group')),
+ )
+ authentication_method = forms.MultipleChoiceField(
+ label=_('Authentication method'),
+ choices=AuthenticationMethodChoices,
+ required=False
+ )
+ encryption_algorithm = forms.MultipleChoiceField(
+ label=_('Encryption algorithm'),
+ choices=EncryptionAlgorithmChoices,
+ required=False
+ )
+ authentication_algorithm = forms.MultipleChoiceField(
+ label=_('Authentication algorithm'),
+ choices=AuthenticationAlgorithmChoices,
+ required=False
+ )
+ group = forms.MultipleChoiceField(
+ label=_('Group'),
+ choices=DHGroupChoices,
+ required=False
+ )
+ tag = TagFilterField(model)
+
+
+class IKEPolicyFilterForm(NetBoxModelFilterSetForm):
+ model = IKEPolicy
+ fieldsets = (
+ (None, ('q', 'filter_id', 'tag')),
+ (_('Parameters'), ('version', 'mode', 'proposal_id')),
+ )
+ version = forms.MultipleChoiceField(
+ label=_('IKE version'),
+ choices=IKEVersionChoices,
+ required=False
+ )
+ mode = forms.MultipleChoiceField(
+ label=_('Mode'),
+ choices=IKEModeChoices,
+ required=False
+ )
+ proposal_id = DynamicModelMultipleChoiceField(
+ queryset=IKEProposal.objects.all(),
+ required=False,
+ label=_('Proposal')
+ )
+ tag = TagFilterField(model)
+
+
+class IPSecProposalFilterForm(NetBoxModelFilterSetForm):
+ model = IPSecProposal
+ fieldsets = (
+ (None, ('q', 'filter_id', 'tag')),
+ (_('Parameters'), ('encryption_algorithm', 'authentication_algorithm')),
+ )
+ encryption_algorithm = forms.MultipleChoiceField(
+ label=_('Encryption algorithm'),
+ choices=EncryptionAlgorithmChoices,
+ required=False
+ )
+ authentication_algorithm = forms.MultipleChoiceField(
+ label=_('Authentication algorithm'),
+ choices=AuthenticationAlgorithmChoices,
+ required=False
+ )
+ tag = TagFilterField(model)
+
+
+class IPSecPolicyFilterForm(NetBoxModelFilterSetForm):
+ model = IPSecPolicy
+ fieldsets = (
+ (None, ('q', 'filter_id', 'tag')),
+ (_('Parameters'), ('proposal', 'pfs_group')),
+ )
+ proposal_id = DynamicModelMultipleChoiceField(
+ queryset=IKEProposal.objects.all(),
+ required=False,
+ label=_('Proposal')
+ )
+ pfs_group = forms.MultipleChoiceField(
+ label=_('Mode'),
+ choices=DHGroupChoices,
+ required=False
+ )
+ tag = TagFilterField(model)
+
+
class IPSecProfileFilterForm(NetBoxModelFilterSetForm):
model = IPSecProfile
fieldsets = (
@@ -80,64 +171,19 @@ class IPSecProfileFilterForm(NetBoxModelFilterSetForm):
'phase2_sa_lifetime_data',
)),
)
- protocol = forms.MultipleChoiceField(
- label=_('Protocol'),
- choices=IPSecProtocolChoices,
+ mode = forms.MultipleChoiceField(
+ label=_('Mode'),
+ choices=IPSecModeChoices,
required=False
)
- ike_version = forms.MultipleChoiceField(
- label=_('IKE version'),
- choices=IKEVersionChoices,
- required=False
- )
- ipsec_profile_id = DynamicModelMultipleChoiceField(
- queryset=IPSecProfile.objects.all(),
+ ike_policy_id = DynamicModelMultipleChoiceField(
+ queryset=IKEPolicy.objects.all(),
required=False,
- label=_('IPSec profile')
+ label=_('IKE policy')
)
- phase1_encryption = forms.MultipleChoiceField(
- label=_('Encryption'),
- choices=EncryptionChoices,
- required=False
- )
- phase1_authentication = forms.MultipleChoiceField(
- label=_('Authentication'),
- choices=AuthenticationChoices,
- required=False
- )
- phase1_group = forms.MultipleChoiceField(
- label=_('Group'),
- choices=DHGroupChoices,
- required=False
- )
- phase1_sa_lifetime = forms.IntegerField(
+ ipsec_policy_id = DynamicModelMultipleChoiceField(
+ queryset=IPSecPolicy.objects.all(),
required=False,
- min_value=0,
- label=_('SA lifetime')
- )
- phase2_encryption = forms.MultipleChoiceField(
- label=_('Encryption'),
- choices=EncryptionChoices,
- required=False
- )
- phase2_authentication = forms.MultipleChoiceField(
- label=_('Authentication'),
- choices=AuthenticationChoices,
- required=False
- )
- phase2_group = forms.MultipleChoiceField(
- label=_('Group'),
- choices=DHGroupChoices,
- required=False
- )
- phase2_sa_lifetime = forms.IntegerField(
- required=False,
- min_value=0,
- label=_('SA lifetime')
- )
- phase2_sa_lifetime_data = forms.IntegerField(
- required=False,
- min_value=0,
- label=_('SA lifetime (data)')
+ label=_('IPSec policy')
)
tag = TagFilterField(model)
diff --git a/netbox/vpn/forms/model_forms.py b/netbox/vpn/forms/model_forms.py
index cc8cb4b1f..6f289d26e 100644
--- a/netbox/vpn/forms/model_forms.py
+++ b/netbox/vpn/forms/model_forms.py
@@ -5,14 +5,18 @@ from dcim.models import Device, Interface
from ipam.models import IPAddress
from netbox.forms import NetBoxModelForm
from tenancy.forms import TenancyForm
-from utilities.forms.fields import CommentField, DynamicModelChoiceField
+from utilities.forms.fields import CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField
from utilities.forms.widgets import HTMXSelect
from virtualization.models import VirtualMachine, VMInterface
from vpn.choices import *
from vpn.models import *
__all__ = (
+ 'IKEPolicyForm',
+ 'IKEProposalForm',
+ 'IPSecPolicyForm',
'IPSecProfileForm',
+ 'IPSecProposalForm',
'TunnelCreateForm',
'TunnelForm',
'TunnelTerminationForm',
@@ -30,15 +34,15 @@ class TunnelForm(TenancyForm, NetBoxModelForm):
fieldsets = (
(_('Tunnel'), ('name', 'status', 'encapsulation', 'description', 'tunnel_id', 'tags')),
- (_('Security'), ('ipsec_profile', 'preshared_key')),
+ (_('Security'), ('ipsec_profile',)),
(_('Tenancy'), ('tenant_group', 'tenant')),
)
class Meta:
model = Tunnel
fields = [
- 'name', 'status', 'encapsulation', 'description', 'tunnel_id', 'ipsec_profile', 'preshared_key',
- 'tenant_group', 'tenant', 'comments', 'tags',
+ 'name', 'status', 'encapsulation', 'description', 'tunnel_id', 'ipsec_profile', 'tenant_group', 'tenant',
+ 'comments', 'tags',
]
@@ -111,7 +115,7 @@ class TunnelCreateForm(TunnelForm):
fieldsets = (
(_('Tunnel'), ('name', 'status', 'encapsulation', 'description', 'tunnel_id', 'tags')),
- (_('Security'), ('ipsec_profile', 'preshared_key')),
+ (_('Security'), ('ipsec_profile',)),
(_('Tenancy'), ('tenant_group', 'tenant')),
(_('First Termination'), (
'termination1_role', 'termination1_type', 'termination1_parent', 'termination1_interface',
@@ -264,26 +268,87 @@ class TunnelTerminationCreateForm(NetBoxModelForm):
self.instance.interface = self.cleaned_data['interface']
+class IKEProposalForm(NetBoxModelForm):
+
+ fieldsets = (
+ (_('Proposal'), ('name', 'description', 'tags')),
+ (_('Parameters'), (
+ 'authentication_method', 'encryption_algorithm', 'authentication_algorithm', 'group', 'sa_lifetime',
+ )),
+ )
+
+ class Meta:
+ model = IKEProposal
+ fields = [
+ 'name', 'description', 'authentication_method', 'encryption_algorithm', 'authentication_algorithm', 'group',
+ 'sa_lifetime', 'tags',
+ ]
+
+
+class IKEPolicyForm(NetBoxModelForm):
+ proposals = DynamicModelMultipleChoiceField(
+ queryset=IKEProposal.objects.all()
+ )
+
+ fieldsets = (
+ (_('Policy'), ('name', 'description', 'tags')),
+ (_('Parameters'), ('version', 'mode', 'proposals')),
+ (_('Authentication'), ('preshared_key', 'certificate')),
+ )
+
+ class Meta:
+ model = IKEPolicy
+ fields = [
+ 'name', 'description', 'version', 'mode', 'proposals', 'preshared_key', 'certificate', 'tags',
+ ]
+
+
+class IPSecProposalForm(NetBoxModelForm):
+
+ fieldsets = (
+ (_('Proposal'), ('name', 'description', 'tags')),
+ (_('Parameters'), (
+ 'encryption_algorithm', 'authentication_algorithm', 'sa_lifetime_seconds', 'sa_lifetime_data',
+ )),
+ )
+
+ class Meta:
+ model = IPSecProposal
+ fields = [
+ 'name', 'description', 'encryption_algorithm', 'authentication_algorithm', 'sa_lifetime_seconds',
+ 'sa_lifetime_data', 'tags',
+ ]
+
+
+class IPSecPolicyForm(NetBoxModelForm):
+ proposals = DynamicModelMultipleChoiceField(
+ queryset=IPSecProposal.objects.all()
+ )
+
+ fieldsets = (
+ (_('Policy'), ('name', 'description', 'tags')),
+ (_('Parameters'), ('proposals', 'pfs_group')),
+ )
+
+ class Meta:
+ model = IPSecPolicy
+ fields = [
+ 'name', 'description', 'proposals', 'pfs_group', 'tags',
+ ]
+
+
class IPSecProfileForm(NetBoxModelForm):
comments = CommentField()
fieldsets = (
(_('Profile'), (
- 'name', 'protocol', 'ike_version', 'description', 'tags',
- )),
- (_('Phase 1 Parameters'), (
- 'phase1_encryption', 'phase1_authentication', 'phase1_group', 'phase1_sa_lifetime',
- )),
- (_('Phase 2 Parameters'), (
- 'phase2_encryption', 'phase2_authentication', 'phase2_group', 'phase2_sa_lifetime',
- 'phase2_sa_lifetime_data',
+ 'name', 'mode', 'description', 'tags',
)),
+ (_('Policies'), ('ipsec_policy', 'description', 'tags')),
)
class Meta:
model = IPSecProfile
fields = [
- 'name', 'protocol', 'ike_version', 'phase1_encryption', 'phase1_authentication', 'phase1_group',
- 'phase1_sa_lifetime', 'phase2_encryption', 'phase2_authentication', 'phase2_group', 'phase2_sa_lifetime',
- 'phase2_sa_lifetime_data', 'description', 'comments', 'tags',
+ 'name', 'description', 'mode', 'ipsec_policy', 'description', 'comments', 'tags',
]
diff --git a/netbox/vpn/migrations/0001_initial.py b/netbox/vpn/migrations/0001_initial.py
deleted file mode 100644
index e0753249c..000000000
--- a/netbox/vpn/migrations/0001_initial.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# Generated by Django 4.2.7 on 2023-11-15 19:50
-
-from django.db import migrations, models
-import django.db.models.deletion
-import taggit.managers
-import utilities.json
-
-
-class Migration(migrations.Migration):
-
- initial = True
-
- dependencies = [
- ('contenttypes', '0002_remove_content_type_name'),
- ('tenancy', '0011_contactassignment_tags'),
- ('ipam', '0067_ipaddress_index_host'),
- ('extras', '0099_cachedvalue_ordering'),
- ]
-
- operations = [
- migrations.CreateModel(
- name='IPSecProfile',
- fields=[
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
- ('created', models.DateTimeField(auto_now_add=True, null=True)),
- ('last_updated', models.DateTimeField(auto_now=True, null=True)),
- ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
- ('description', models.CharField(blank=True, max_length=200)),
- ('comments', models.TextField(blank=True)),
- ('name', models.CharField(max_length=100, unique=True)),
- ('protocol', models.CharField()),
- ('ike_version', models.PositiveSmallIntegerField(default=2)),
- ('phase1_encryption', models.CharField()),
- ('phase1_authentication', models.CharField()),
- ('phase1_group', models.PositiveSmallIntegerField()),
- ('phase1_sa_lifetime', models.PositiveIntegerField(blank=True, null=True)),
- ('phase2_encryption', models.CharField()),
- ('phase2_authentication', models.CharField()),
- ('phase2_group', models.PositiveSmallIntegerField()),
- ('phase2_sa_lifetime', models.PositiveIntegerField(blank=True, null=True)),
- ('phase2_sa_lifetime_data', models.PositiveIntegerField(blank=True, null=True)),
- ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
- ],
- options={
- 'verbose_name': 'tunnel',
- 'verbose_name_plural': 'tunnels',
- 'ordering': ('name',),
- },
- ),
- migrations.CreateModel(
- name='Tunnel',
- fields=[
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
- ('created', models.DateTimeField(auto_now_add=True, null=True)),
- ('last_updated', models.DateTimeField(auto_now=True, null=True)),
- ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
- ('description', models.CharField(blank=True, max_length=200)),
- ('comments', models.TextField(blank=True)),
- ('name', models.CharField(max_length=100, unique=True)),
- ('status', models.CharField(default='active', max_length=50)),
- ('encapsulation', models.CharField(max_length=50)),
- ('preshared_key', models.TextField(blank=True)),
- ('tunnel_id', models.PositiveBigIntegerField(blank=True, null=True)),
- ('ipsec_profile', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='tunnels', to='vpn.ipsecprofile')),
- ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
- ('tenant', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='tunnels', to='tenancy.tenant')),
- ],
- options={
- 'verbose_name': 'tunnel',
- 'verbose_name_plural': 'tunnels',
- 'ordering': ('name',),
- },
- ),
- migrations.CreateModel(
- name='TunnelTermination',
- fields=[
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
- ('created', models.DateTimeField(auto_now_add=True, null=True)),
- ('last_updated', models.DateTimeField(auto_now=True, null=True)),
- ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
- ('role', models.CharField(default='peer', max_length=50)),
- ('interface_id', models.PositiveBigIntegerField(blank=True, null=True)),
- ('interface_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype')),
- ('outside_ip', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='tunnel_termination', to='ipam.ipaddress')),
- ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
- ('tunnel', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='terminations', to='vpn.tunnel')),
- ],
- options={
- 'verbose_name': 'tunnel termination',
- 'verbose_name_plural': 'tunnel terminations',
- 'ordering': ('tunnel', 'role', 'pk'),
- },
- ),
- migrations.AddConstraint(
- model_name='tunneltermination',
- constraint=models.UniqueConstraint(fields=('interface_type', 'interface_id'), name='vpn_tunneltermination_interface', violation_error_message='An interface may be terminated to only one tunnel at a time.'),
- ),
- ]
diff --git a/netbox/vpn/models/crypto.py b/netbox/vpn/models/crypto.py
index 059d8f2f4..dacd40f81 100644
--- a/netbox/vpn/models/crypto.py
+++ b/netbox/vpn/models/crypto.py
@@ -2,88 +2,228 @@ from django.db import models
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
-from netbox.models import PrimaryModel
+from netbox.models import NetBoxModel, PrimaryModel
from vpn.choices import *
__all__ = (
+ 'IKEPolicy',
+ 'IKEProposal',
+ 'IPSecPolicy',
'IPSecProfile',
+ 'IPSecProposal',
)
+#
+# IKE
+#
+
+class IKEProposal(NetBoxModel):
+ name = models.CharField(
+ verbose_name=_('name'),
+ max_length=100,
+ unique=True
+ )
+ description = models.CharField(
+ verbose_name=_('description'),
+ max_length=200,
+ blank=True
+ )
+ authentication_method = models.CharField(
+ verbose_name=('authentication method'),
+ choices=AuthenticationMethodChoices
+ )
+ encryption_algorithm = models.CharField(
+ verbose_name=_('encryption algorithm'),
+ choices=EncryptionAlgorithmChoices
+ )
+ authentication_algorithm = models.CharField(
+ verbose_name=_('authentication algorithm'),
+ choices=AuthenticationAlgorithmChoices
+ )
+ group = models.PositiveSmallIntegerField(
+ verbose_name=_('group'),
+ choices=DHGroupChoices,
+ help_text=_('Diffie-Hellman group ID')
+ )
+ sa_lifetime = models.PositiveIntegerField(
+ verbose_name=_('SA lifetime'),
+ blank=True,
+ null=True,
+ help_text=_('Security association lifetime (in seconds)')
+ )
+
+ class Meta:
+ ordering = ('name',)
+ verbose_name = _('IKE proposal')
+ verbose_name_plural = _('IKE proposals')
+
+ def __str__(self):
+ return self.name
+
+ def get_absolute_url(self):
+ return reverse('vpn:ikeproposal', args=[self.pk])
+
+
+class IKEPolicy(NetBoxModel):
+ name = models.CharField(
+ verbose_name=_('name'),
+ max_length=100,
+ unique=True
+ )
+ description = models.CharField(
+ verbose_name=_('description'),
+ max_length=200,
+ blank=True
+ )
+ version = models.PositiveSmallIntegerField(
+ verbose_name=_('version'),
+ choices=IKEVersionChoices,
+ default=IKEVersionChoices.VERSION_2
+ )
+ mode = models.CharField(
+ verbose_name=_('mode'),
+ choices=IKEModeChoices
+ )
+ proposals = models.ManyToManyField(
+ to='vpn.IKEProposal',
+ related_name='ike_policies',
+ verbose_name=_('proposals')
+ )
+ preshared_key = models.TextField(
+ verbose_name=_('pre-shared key'),
+ blank=True
+ )
+ certificate = models.TextField(
+ verbose_name=_('certificate'),
+ blank=True
+ )
+
+ class Meta:
+ ordering = ('name',)
+ verbose_name = _('IKE policy')
+ verbose_name_plural = _('IKE policies')
+
+ def __str__(self):
+ return self.name
+
+ def get_absolute_url(self):
+ return reverse('vpn:ikeprofile', args=[self.pk])
+
+
+#
+# IPSec
+#
+
+class IPSecProposal(NetBoxModel):
+ name = models.CharField(
+ verbose_name=_('name'),
+ max_length=100,
+ unique=True
+ )
+ description = models.CharField(
+ verbose_name=_('description'),
+ max_length=200,
+ blank=True
+ )
+ encryption_algorithm = models.CharField(
+ verbose_name=_('encryption'),
+ choices=EncryptionAlgorithmChoices
+ )
+ authentication_algorithm = models.CharField(
+ verbose_name=_('authentication'),
+ choices=AuthenticationAlgorithmChoices
+ )
+ sa_lifetime_seconds = models.PositiveIntegerField(
+ verbose_name=_('SA lifetime (seconds)'),
+ blank=True,
+ null=True,
+ help_text=_('Security association lifetime (seconds)')
+ )
+ sa_lifetime_data = models.PositiveIntegerField(
+ verbose_name=_('SA lifetime (KB)'),
+ blank=True,
+ null=True,
+ help_text=_('Security association lifetime (in kilobytes)')
+ )
+
+ class Meta:
+ ordering = ('name',)
+ verbose_name = _('IPSec proposal')
+ verbose_name_plural = _('IPSec proposals')
+
+ def __str__(self):
+ return self.name
+
+ def get_absolute_url(self):
+ return reverse('vpn:ipsecproposal', args=[self.pk])
+
+
+class IPSecPolicy(NetBoxModel):
+ name = models.CharField(
+ verbose_name=_('name'),
+ max_length=100,
+ unique=True
+ )
+ description = models.CharField(
+ verbose_name=_('description'),
+ max_length=200,
+ blank=True
+ )
+ proposals = models.ManyToManyField(
+ to='vpn.IPSecProposal',
+ related_name='ipsec_policies',
+ verbose_name=_('proposals')
+ )
+ pfs_group = models.PositiveSmallIntegerField(
+ verbose_name=_('PFS group'),
+ choices=DHGroupChoices,
+ blank=True,
+ null=True,
+ help_text=_('Diffie-Hellman group for Perfect Forward Secrecy')
+ )
+
+ class Meta:
+ ordering = ('name',)
+ verbose_name = _('IPSec policy')
+ verbose_name_plural = _('IPSec policies')
+
+ def __str__(self):
+ return self.name
+
+ def get_absolute_url(self):
+ return reverse('vpn:ipsecpolicy', args=[self.pk])
+
+
class IPSecProfile(PrimaryModel):
name = models.CharField(
verbose_name=_('name'),
max_length=100,
unique=True
)
- protocol = models.CharField(
- verbose_name=_('protocol'),
- choices=IPSecProtocolChoices
+ mode = models.CharField(
+ verbose_name=_('mode'),
+ choices=IPSecModeChoices
)
- ike_version = models.PositiveSmallIntegerField(
- verbose_name=_('IKE version'),
- choices=IKEVersionChoices,
- default=IKEVersionChoices.VERSION_2
+ ike_policy = models.ForeignKey(
+ to='vpn.IKEPolicy',
+ on_delete=models.PROTECT,
+ related_name='ipsec_profiles'
)
-
- # Phase 1 parameters
- phase1_encryption = models.CharField(
- verbose_name=_('phase 1 encryption'),
- choices=EncryptionChoices
+ ipsec_policy = models.ForeignKey(
+ to='vpn.IPSecPolicy',
+ on_delete=models.PROTECT,
+ related_name='ipsec_profiles'
)
- phase1_authentication = models.CharField(
- verbose_name=_('phase 1 authentication'),
- choices=AuthenticationChoices
- )
- phase1_group = models.PositiveSmallIntegerField(
- verbose_name=_('phase 1 group'),
- choices=DHGroupChoices,
- help_text=_('Diffie-Hellman group')
- )
- phase1_sa_lifetime = models.PositiveIntegerField(
- verbose_name=_('phase 1 SA lifetime'),
- blank=True,
- null=True,
- help_text=_('Security association lifetime (in seconds)')
- )
-
- # Phase 2 parameters
- phase2_encryption = models.CharField(
- verbose_name=_('phase 2 encryption'),
- choices=EncryptionChoices
- )
- phase2_authentication = models.CharField(
- verbose_name=_('phase 2 authentication'),
- choices=AuthenticationChoices
- )
- phase2_group = models.PositiveSmallIntegerField(
- verbose_name=_('phase 2 group'),
- choices=DHGroupChoices,
- help_text=_('Diffie-Hellman group')
- )
- phase2_sa_lifetime = models.PositiveIntegerField(
- verbose_name=_('phase 2 SA lifetime (seconds)'),
- blank=True,
- null=True,
- help_text=_('Security association lifetime (seconds)')
- )
- phase2_sa_lifetime_data = models.PositiveIntegerField(
- verbose_name=_('phase 2 SA lifetime (KB)'),
- blank=True,
- null=True,
- help_text=_('Security association lifetime (in kilobytes)')
- )
- # TODO: Add PFS group?
clone_fields = (
- 'protocol', 'ike_version', 'phase1_encryption', 'phase1_authentication', 'phase1_group', 'phase1_sa_lifetime',
- 'phase2_encryption', 'phase2_authentication', 'phase2_group', 'phase2_sa_lifetime', 'phase2_sa_lifetime_data',
+ 'mode', 'ike_policy', 'ipsec_policy',
)
class Meta:
ordering = ('name',)
- verbose_name = _('tunnel')
- verbose_name_plural = _('tunnels')
+ verbose_name = _('IPSec profile')
+ verbose_name_plural = _('IPSec profiles')
def __str__(self):
return self.name
diff --git a/netbox/vpn/models/tunnels.py b/netbox/vpn/models/tunnels.py
index 4f3bd4110..4eba11ad6 100644
--- a/netbox/vpn/models/tunnels.py
+++ b/netbox/vpn/models/tunnels.py
@@ -45,10 +45,6 @@ class Tunnel(PrimaryModel):
blank=True,
null=True
)
- preshared_key = models.TextField(
- verbose_name=_('pre-shared key'),
- blank=True
- )
tunnel_id = models.PositiveBigIntegerField(
verbose_name=_('tunnel ID'),
blank=True,
diff --git a/netbox/vpn/tables.py b/netbox/vpn/tables.py
index 33eb6da85..3a358a972 100644
--- a/netbox/vpn/tables.py
+++ b/netbox/vpn/tables.py
@@ -1,5 +1,4 @@
import django_tables2 as tables
-from django.contrib.contenttypes.fields import GenericRelation
from django.utils.translation import gettext_lazy as _
from django_tables2.utils import Accessor
@@ -8,6 +7,10 @@ from netbox.tables import NetBoxTable, columns
from vpn.models import *
__all__ = (
+ 'IKEPolicyTable',
+ 'IKEProposalTable',
+ 'IPSecPolicyTable',
+ 'IPSecProposalTable',
'IPSecProfileTable',
'TunnelTable',
'TunnelTerminationTable',
@@ -42,8 +45,8 @@ class TunnelTable(TenancyColumnsMixin, NetBoxTable):
class Meta(NetBoxTable.Meta):
model = Tunnel
fields = (
- 'pk', 'id', 'name', 'status', 'encapsulation', 'ipsec_profile', 'tenant', 'tenant_group', 'preshared_key',
- 'tunnel_id', 'termination_count', 'description', 'comments', 'tags', 'created', 'last_updated',
+ 'pk', 'id', 'name', 'status', 'encapsulation', 'ipsec_profile', 'tenant', 'tenant_group', 'tunnel_id',
+ 'termination_count', 'description', 'comments', 'tags', 'created', 'last_updated',
)
default_columns = ('pk', 'name', 'status', 'encapsulation', 'tenant', 'terminations_count')
@@ -89,47 +92,164 @@ class TunnelTerminationTable(TenancyColumnsMixin, NetBoxTable):
default_columns = ('pk', 'tunnel', 'role', 'interface_parent', 'interface', 'ip_addresses', 'outside_ip')
-class IPSecProfileTable(TenancyColumnsMixin, NetBoxTable):
+class IKEProposalTable(NetBoxTable):
name = tables.Column(
verbose_name=_('Name'),
linkify=True
)
- protocol = columns.ChoiceFieldColumn(
- verbose_name=_('Protocol')
+ authentication_method = columns.ChoiceFieldColumn(
+ verbose_name=_('Authentication Method')
)
- ike_version = columns.ChoiceFieldColumn(
- verbose_name=_('IKE Version')
+ encryption_algorithm = columns.ChoiceFieldColumn(
+ verbose_name=_('Encryption Algorithm')
)
- phase1_encryption = columns.ChoiceFieldColumn(
- verbose_name=_('Phase 1 Encryption')
+ authentication_algorithm = columns.ChoiceFieldColumn(
+ verbose_name=_('Authentication Algorithm')
)
- phase1_authentication = columns.ChoiceFieldColumn(
- verbose_name=_('Phase 1 Authentication')
+ group = columns.ChoiceFieldColumn(
+ verbose_name=_('Group')
)
- phase1_group = columns.ChoiceFieldColumn(
- verbose_name=_('Phase 1 Group')
+ sa_lifetime = tables.Column(
+ verbose_name=_('SA Lifetime')
)
- phase2_encryption = columns.ChoiceFieldColumn(
- verbose_name=_('Phase 2 Encryption')
+ tags = columns.TagColumn(
+ url_name='vpn:ikeproposal_list'
)
- phase2_authentication = columns.ChoiceFieldColumn(
- verbose_name=_('Phase 2 Authentication')
+
+ class Meta(NetBoxTable.Meta):
+ model = IKEProposal
+ fields = (
+ 'pk', 'id', 'name', 'authentication_method', 'encryption_algorithm', 'authentication_algorithm',
+ 'group', 'sa_lifetime', 'description', 'tags', 'created', 'last_updated',
+ )
+ default_columns = (
+ 'pk', 'name', 'authentication_method', 'encryption_algorithm', 'authentication_algorithm', 'group',
+ 'sa_lifetime', 'description',
+ )
+
+
+class IKEPolicyTable(NetBoxTable):
+ name = tables.Column(
+ verbose_name=_('Name'),
+ linkify=True
)
- phase2_group = columns.ChoiceFieldColumn(
- verbose_name=_('Phase 2 Group')
+ version = columns.ChoiceFieldColumn(
+ verbose_name=_('Version')
+ )
+ mode = columns.ChoiceFieldColumn(
+ verbose_name=_('Mode')
+ )
+ proposals = tables.ManyToManyColumn(
+ linkify_item=True,
+ verbose_name=_('Proposals')
+ )
+ preshared_key = tables.Column(
+ verbose_name=_('Pre-shared Key')
+ )
+ certificate = tables.Column(
+ verbose_name=_('Certificate')
+ )
+ tags = columns.TagColumn(
+ url_name='vpn:ikepolicy_list'
+ )
+
+ class Meta(NetBoxTable.Meta):
+ model = IKEPolicy
+ fields = (
+ 'pk', 'id', 'name', 'version', 'mode', 'proposals', 'preshared_key', 'certificate', 'description', 'tags',
+ 'created', 'last_updated',
+ )
+ default_columns = (
+ 'pk', 'name', 'version', 'mode', 'proposals', 'description',
+ )
+
+
+class IPSecProposalTable(NetBoxTable):
+ name = tables.Column(
+ verbose_name=_('Name'),
+ linkify=True
+ )
+ encryption_algorithm = columns.ChoiceFieldColumn(
+ verbose_name=_('Encryption Algorithm')
+ )
+ authentication_algorithm = columns.ChoiceFieldColumn(
+ verbose_name=_('Authentication Algorithm')
+ )
+ sa_lifetime_seconds = tables.Column(
+ verbose_name=_('SA Lifetime (Seconds)')
+ )
+ sa_lifetime_data = tables.Column(
+ verbose_name=_('SA Lifetime (KB)')
+ )
+ tags = columns.TagColumn(
+ url_name='vpn:ipsecproposal_list'
+ )
+
+ class Meta(NetBoxTable.Meta):
+ model = IPSecProposal
+ fields = (
+ 'pk', 'id', 'name', 'encryption_algorithm', 'authentication_algorithm', 'sa_lifetime_seconds',
+ 'sa_lifetime_data', 'description', 'tags', 'created', 'last_updated',
+ )
+ default_columns = (
+ 'pk', 'name', 'encryption_algorithm', 'authentication_algorithm', 'sa_lifetime_seconds',
+ 'sa_lifetime_data', 'description',
+ )
+
+
+class IPSecPolicyTable(NetBoxTable):
+ name = tables.Column(
+ verbose_name=_('Name'),
+ linkify=True
+ )
+ proposals = tables.ManyToManyColumn(
+ linkify_item=True,
+ verbose_name=_('Proposals')
+ )
+ pfs_group = columns.ChoiceFieldColumn(
+ verbose_name=_('PFS Group')
+ )
+ tags = columns.TagColumn(
+ url_name='vpn:ipsecpolicy_list'
+ )
+
+ class Meta(NetBoxTable.Meta):
+ model = IPSecPolicy
+ fields = (
+ 'pk', 'id', 'name', 'proposals', 'pfs_group', 'tags', 'created', 'last_updated',
+ )
+ default_columns = (
+ 'pk', 'name', 'proposals', 'pfs_group', 'description',
+ )
+
+
+class IPSecProfileTable(NetBoxTable):
+ name = tables.Column(
+ verbose_name=_('Name'),
+ linkify=True
+ )
+ mode = columns.ChoiceFieldColumn(
+ verbose_name=_('Mode')
+ )
+ ike_policy = tables.Column(
+ linkify=True,
+ verbose_name=_('IKE Policy')
+ )
+ ipsec_policy = tables.Column(
+ linkify=True,
+ verbose_name=_('IPSec Policy')
)
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn(
- url_name='vpn:tunnel_list'
+ url_name='vpn:ipsecprofile_list'
)
class Meta(NetBoxTable.Meta):
model = IPSecProfile
fields = (
- 'pk', 'id', 'name', 'protocol', 'ike_version', 'phase1_encryption', 'phase1_authentication', 'phase1_group',
- 'phase1_sa_lifetime', 'phase2_encryption', 'phase2_authentication', 'phase2_group', 'phase2_sa_lifetime',
- 'phase2_sa_lifetime_data', 'description', 'comments', 'tags', 'created', 'last_updated',
+ 'pk', 'id', 'name', 'mode', 'ike_policy', 'ipsec_policy', 'description', 'comments', 'tags', 'created',
+ 'last_updated',
)
- default_columns = ('pk', 'name', 'protocol', 'ike_version', 'description')
+ default_columns = ('pk', 'name', 'mode', 'ike_policy', 'ipsec_policy', 'description')
diff --git a/netbox/vpn/urls.py b/netbox/vpn/urls.py
index bfb348a14..7fe548245 100644
--- a/netbox/vpn/urls.py
+++ b/netbox/vpn/urls.py
@@ -22,6 +22,38 @@ urlpatterns = [
path('tunnel-terminations/delete/', views.TunnelTerminationBulkDeleteView.as_view(), name='tunneltermination_bulk_delete'),
path('tunnel-terminations//', include(get_model_urls('vpn', 'tunneltermination'))),
+ # IKE proposals
+ path('ike-proposals/', views.IKEProposalListView.as_view(), name='ikeproposal_list'),
+ path('ike-proposals/add/', views.IKEProposalEditView.as_view(), name='ikeproposal_add'),
+ path('ike-proposals/import/', views.IKEProposalBulkImportView.as_view(), name='ikeproposal_import'),
+ path('ike-proposals/edit/', views.IKEProposalBulkEditView.as_view(), name='ikeproposal_bulk_edit'),
+ path('ike-proposals/delete/', views.IKEProposalBulkDeleteView.as_view(), name='ikeproposal_bulk_delete'),
+ path('ike-proposals//', include(get_model_urls('vpn', 'ikeproposal'))),
+
+ # IKE policies
+ path('ike-policys/', views.IKEPolicyListView.as_view(), name='ikepolicy_list'),
+ path('ike-policys/add/', views.IKEPolicyEditView.as_view(), name='ikepolicy_add'),
+ path('ike-policys/import/', views.IKEPolicyBulkImportView.as_view(), name='ikepolicy_import'),
+ path('ike-policys/edit/', views.IKEPolicyBulkEditView.as_view(), name='ikepolicy_bulk_edit'),
+ path('ike-policys/delete/', views.IKEPolicyBulkDeleteView.as_view(), name='ikepolicy_bulk_delete'),
+ path('ike-policys//', include(get_model_urls('vpn', 'ikepolicy'))),
+
+ # IPSec proposals
+ path('ipsec-proposals/', views.IPSecProposalListView.as_view(), name='ipsecproposal_list'),
+ path('ipsec-proposals/add/', views.IPSecProposalEditView.as_view(), name='ipsecproposal_add'),
+ path('ipsec-proposals/import/', views.IPSecProposalBulkImportView.as_view(), name='ipsecproposal_import'),
+ path('ipsec-proposals/edit/', views.IPSecProposalBulkEditView.as_view(), name='ipsecproposal_bulk_edit'),
+ path('ipsec-proposals/delete/', views.IPSecProposalBulkDeleteView.as_view(), name='ipsecproposal_bulk_delete'),
+ path('ipsec-proposals//', include(get_model_urls('vpn', 'ipsecproposal'))),
+
+ # IPSec policies
+ path('ipsec-policys/', views.IPSecPolicyListView.as_view(), name='ipsecpolicy_list'),
+ path('ipsec-policys/add/', views.IPSecPolicyEditView.as_view(), name='ipsecpolicy_add'),
+ path('ipsec-policys/import/', views.IPSecPolicyBulkImportView.as_view(), name='ipsecpolicy_import'),
+ path('ipsec-policys/edit/', views.IPSecPolicyBulkEditView.as_view(), name='ipsecpolicy_bulk_edit'),
+ path('ipsec-policys/delete/', views.IPSecPolicyBulkDeleteView.as_view(), name='ipsecpolicy_bulk_delete'),
+ path('ipsec-policys//', include(get_model_urls('vpn', 'ipsecpolicy'))),
+
# IPSec profiles
path('ipsec-profiles/', views.IPSecProfileListView.as_view(), name='ipsecprofile_list'),
path('ipsec-profiles/add/', views.IPSecProfileEditView.as_view(), name='ipsecprofile_add'),
diff --git a/netbox/vpn/views.py b/netbox/vpn/views.py
index aa63d00da..fe6acb46a 100644
--- a/netbox/vpn/views.py
+++ b/netbox/vpn/views.py
@@ -112,6 +112,186 @@ class TunnelTerminationBulkDeleteView(generic.BulkDeleteView):
table = tables.TunnelTerminationTable
+#
+# IKE proposals
+#
+
+class IKEProposalListView(generic.ObjectListView):
+ queryset = IKEProposal.objects.all()
+ filterset = filtersets.IKEProposalFilterSet
+ filterset_form = forms.IKEProposalFilterForm
+ table = tables.IKEProposalTable
+
+
+@register_model_view(IKEProposal)
+class IKEProposalView(generic.ObjectView):
+ queryset = IKEProposal.objects.all()
+
+
+@register_model_view(IKEProposal, 'edit')
+class IKEProposalEditView(generic.ObjectEditView):
+ queryset = IKEProposal.objects.all()
+ form = forms.IKEProposalForm
+
+
+@register_model_view(IKEProposal, 'delete')
+class IKEProposalDeleteView(generic.ObjectDeleteView):
+ queryset = IKEProposal.objects.all()
+
+
+class IKEProposalBulkImportView(generic.BulkImportView):
+ queryset = IKEProposal.objects.all()
+ model_form = forms.IKEProposalImportForm
+
+
+class IKEProposalBulkEditView(generic.BulkEditView):
+ queryset = IKEProposal.objects.all()
+ filterset = filtersets.IKEProposalFilterSet
+ table = tables.IKEProposalTable
+ form = forms.IKEProposalBulkEditForm
+
+
+class IKEProposalBulkDeleteView(generic.BulkDeleteView):
+ queryset = IKEProposal.objects.all()
+ filterset = filtersets.IKEProposalFilterSet
+ table = tables.IKEProposalTable
+
+
+#
+# IKE policies
+#
+
+class IKEPolicyListView(generic.ObjectListView):
+ queryset = IKEPolicy.objects.all()
+ filterset = filtersets.IKEPolicyFilterSet
+ filterset_form = forms.IKEPolicyFilterForm
+ table = tables.IKEPolicyTable
+
+
+@register_model_view(IKEPolicy)
+class IKEPolicyView(generic.ObjectView):
+ queryset = IKEPolicy.objects.all()
+
+
+@register_model_view(IKEPolicy, 'edit')
+class IKEPolicyEditView(generic.ObjectEditView):
+ queryset = IKEPolicy.objects.all()
+ form = forms.IKEPolicyForm
+
+
+@register_model_view(IKEPolicy, 'delete')
+class IKEPolicyDeleteView(generic.ObjectDeleteView):
+ queryset = IKEPolicy.objects.all()
+
+
+class IKEPolicyBulkImportView(generic.BulkImportView):
+ queryset = IKEPolicy.objects.all()
+ model_form = forms.IKEPolicyImportForm
+
+
+class IKEPolicyBulkEditView(generic.BulkEditView):
+ queryset = IKEPolicy.objects.all()
+ filterset = filtersets.IKEPolicyFilterSet
+ table = tables.IKEPolicyTable
+ form = forms.IKEPolicyBulkEditForm
+
+
+class IKEPolicyBulkDeleteView(generic.BulkDeleteView):
+ queryset = IKEPolicy.objects.all()
+ filterset = filtersets.IKEPolicyFilterSet
+ table = tables.IKEPolicyTable
+
+
+#
+# IPSec proposals
+#
+
+class IPSecProposalListView(generic.ObjectListView):
+ queryset = IPSecProposal.objects.all()
+ filterset = filtersets.IPSecProposalFilterSet
+ filterset_form = forms.IPSecProposalFilterForm
+ table = tables.IPSecProposalTable
+
+
+@register_model_view(IPSecProposal)
+class IPSecProposalView(generic.ObjectView):
+ queryset = IPSecProposal.objects.all()
+
+
+@register_model_view(IPSecProposal, 'edit')
+class IPSecProposalEditView(generic.ObjectEditView):
+ queryset = IPSecProposal.objects.all()
+ form = forms.IPSecProposalForm
+
+
+@register_model_view(IPSecProposal, 'delete')
+class IPSecProposalDeleteView(generic.ObjectDeleteView):
+ queryset = IPSecProposal.objects.all()
+
+
+class IPSecProposalBulkImportView(generic.BulkImportView):
+ queryset = IPSecProposal.objects.all()
+ model_form = forms.IPSecProposalImportForm
+
+
+class IPSecProposalBulkEditView(generic.BulkEditView):
+ queryset = IPSecProposal.objects.all()
+ filterset = filtersets.IPSecProposalFilterSet
+ table = tables.IPSecProposalTable
+ form = forms.IPSecProposalBulkEditForm
+
+
+class IPSecProposalBulkDeleteView(generic.BulkDeleteView):
+ queryset = IPSecProposal.objects.all()
+ filterset = filtersets.IPSecProposalFilterSet
+ table = tables.IPSecProposalTable
+
+
+#
+# IPSec policies
+#
+
+class IPSecPolicyListView(generic.ObjectListView):
+ queryset = IPSecPolicy.objects.all()
+ filterset = filtersets.IPSecPolicyFilterSet
+ filterset_form = forms.IPSecPolicyFilterForm
+ table = tables.IPSecPolicyTable
+
+
+@register_model_view(IPSecPolicy)
+class IPSecPolicyView(generic.ObjectView):
+ queryset = IPSecPolicy.objects.all()
+
+
+@register_model_view(IPSecPolicy, 'edit')
+class IPSecPolicyEditView(generic.ObjectEditView):
+ queryset = IPSecPolicy.objects.all()
+ form = forms.IPSecPolicyForm
+
+
+@register_model_view(IPSecPolicy, 'delete')
+class IPSecPolicyDeleteView(generic.ObjectDeleteView):
+ queryset = IPSecPolicy.objects.all()
+
+
+class IPSecPolicyBulkImportView(generic.BulkImportView):
+ queryset = IPSecPolicy.objects.all()
+ model_form = forms.IPSecPolicyImportForm
+
+
+class IPSecPolicyBulkEditView(generic.BulkEditView):
+ queryset = IPSecPolicy.objects.all()
+ filterset = filtersets.IPSecPolicyFilterSet
+ table = tables.IPSecPolicyTable
+ form = forms.IPSecPolicyBulkEditForm
+
+
+class IPSecPolicyBulkDeleteView(generic.BulkDeleteView):
+ queryset = IPSecPolicy.objects.all()
+ filterset = filtersets.IPSecPolicyFilterSet
+ table = tables.IPSecPolicyTable
+
+
#
# IPSec profiles
#