Hopefully make the VPN work with certificates, automatically pick ports, and have user privleges
diff --git a/xos/services/vpn/models.py b/xos/services/vpn/models.py
index 1c7af1b..6b7872c 100644
--- a/xos/services/vpn/models.py
+++ b/xos/services/vpn/models.py
@@ -1,5 +1,6 @@
from core.models import Service, TenantWithContainer
from django.db import transaction
+from xos.exceptions import XOSConfigurationError, XOSValidationError
VPN_KIND = "vpn"
@@ -14,6 +15,28 @@
app_label = "vpn"
verbose_name = "VPN Service"
+ default_attributes = {'exposed_ports': None}
+
+ @property
+ def exposed_ports(self):
+ return self.get_attribute("exposed_ports",
+ self.default_attributes["exposed_ports"])
+
+ @exposed_ports.setter
+ def exposed_ports(self, value):
+ self.set_attribute("exposed_ports", value)
+
+ def get_next_available_port(self, protocol):
+ if protocol != "udp" and protocol != "tcp":
+ raise XOSConfigurationError("Port protocol must be udp or tcp")
+ if not self.ports[protocol]:
+ raise XOSValidationError("No availble ports for protocol: " + protocol)
+ tenants = [tenant for tenant in VPNTenant.get_tenant_objects.all() if tenant.protocol == protocol]
+ port_numbers = self.exposed_ports[protocol]
+ for port_number in port_numbers:
+ if [tenant for tenant in tenants if tenant.port_number == port_number].count() == 0:
+ return port_number
+
class VPNTenant(TenantWithContainer):
"""Defines the Tenant for creating VPN servers."""
@@ -33,7 +56,8 @@
'ca_crt': None,
'port': None,
'script_text': None,
- 'failover_servers': []}
+ 'failover_servers': [],
+ 'protocol': None}
def __init__(self, *args, **kwargs):
vpn_services = VPNService.get_service_objects().all()
@@ -51,6 +75,14 @@
super(VPNTenant, self).delete(*args, **kwargs)
@property
+ def protocol(self):
+ return self.get_attribute("protocol", self.default_attributes["protocol"])
+
+ @protocol.setter
+ def protocol(self, value):
+ self.set_attribute("protocol", value)
+
+ @property
def addresses(self):
"""Mapping[str, str]: The ip, mac address, and subnet of the NAT network of this Tenant."""
if (not self.id) or (not self.instance):
@@ -155,50 +187,50 @@
def script_text(self, value):
self.set_attribute("script_text", value)
- def create_client_script(self, client_certificate):
+ def create_client_script(self, client_name):
script = ""
# write the configuration portion
script += ("printf \"%b\" \"")
- script += self.generate_client_conf(client_certificate)
+ script += self.generate_client_conf(client_name)
script += ("\" > client.conf\n")
script += ("printf \"%b\" \"")
for line in self.ca_crt:
script += (line.rstrip() + r"\n")
script += ("\" > ca.crt\n")
script += ("printf \"%b\" \"")
- for line in self.generate_client_cert(client_certificate):
+ for line in self.generate_client_cert(client_name):
script += (line.rstrip() + r"\n")
- script += ("\" > " + client_certificate + ".crt\n")
- for line in self.generate_client_key(client_certificate):
+ script += ("\" > " + client_name + ".crt\n")
+ for line in self.generate_client_key(client_name):
script += (line.rstrip() + r"\n")
- script += ("\" > " + client_certificate + ".key\n")
+ script += ("\" > " + client_name + ".key\n")
# make sure openvpn is installed
script += ("apt-get update\n")
script += ("apt-get install openvpn\n")
script += ("openvpn client.conf &\n")
# close the script
- return script;
+ return script
- def generate_client_cert(self, client_certificate):
- return open("/opt/openvpn/easyrsa3/pki/issued/" + client_certificate + ".crt").readlines()
+ def generate_client_cert(self, client_name):
+ return open("/opt/openvpn/easyrsa3/pki/issued/" + client_name + ".crt").readlines()
- def generate_client_key(self, client_certificate):
- return open("/opt/openvpn/easyrsa3/pki/private/" + client_certificate + ".key").readlines()
+ def generate_client_key(self, client_name):
+ return open("/opt/openvpn/easyrsa3/pki/private/" + client_name + ".key").readlines()
- def generate_client_conf(self, client_certificate):
+ def generate_client_conf(self, client_name):
"""str: Generates the client configuration to use to connect to this VPN server.
"""
conf = ("client\n" +
- "dev tun\n" +
- "proto udp\n" +
- "remote " + str(self.nat_ip) + " " + str(self.port_number) + "\n" +
- "resolv-retry infinite\n" +
- "nobind\n" +
- "ca ca.crt\n" +
- "cert " + client_certificate + ".crt\n" +
- "key " + client_certificate + ".key\n" +
- "comp-lzo\n" +
- "verb 3\n")
+ "dev tun\n" +
+ "proto " + self.protocol + "\n" +
+ "remote " + str(self.nat_ip) + " " + str(self.port_number) + "\n" +
+ "resolv-retry infinite\n" +
+ "nobind\n" +
+ "ca ca.crt\n" +
+ "cert " + client_name + ".crt\n" +
+ "key " + client_name + ".key\n" +
+ "comp-lzo\n" +
+ "verb 3\n")
if self.is_persistent:
conf += "persist-tun\n"
@@ -207,7 +239,6 @@
return conf
-
def model_policy_vpn_tenant(pk):
"""Manages the contain for the VPN Tenant."""
# This section of code is atomic to prevent race conditions