update to work on different computer
Signed-off-by: Nico Schottelius <nico@nico-notebook.schottelius.org>
This commit is contained in:
		
					parent
					
						
							
								913e992a48
							
						
					
				
			
			
				commit
				
					
						938f0a3390
					
				
			
		
					 7 changed files with 139 additions and 88 deletions
				
			
		| 
						 | 
				
			
			@ -9,3 +9,17 @@
 | 
			
		|||
** Route a /40 network to its IPv6 address
 | 
			
		||||
** Install wireguard on it
 | 
			
		||||
** TODO Enable wireguard on boot
 | 
			
		||||
** TODO Create a new VPNPool on uncloud with
 | 
			
		||||
*** the network address (selecting from our existing pool)
 | 
			
		||||
*** the network size (/...)
 | 
			
		||||
*** the vpn host that provides the network (selecting the created VM)
 | 
			
		||||
*** the wireguard private key of the vpn host (using wg genkey)
 | 
			
		||||
*** http command
 | 
			
		||||
```
 | 
			
		||||
http -a nicoschottelius:$(pass
 | 
			
		||||
  ungleich.ch/nico.schottelius@ungleich.ch)
 | 
			
		||||
  http://localhost:8000/admin/vpnpool/ network=2a0a:e5c1:200:: \
 | 
			
		||||
  network_size=40 subnetwork_size=48
 | 
			
		||||
  vpn_hostname=vpn-2a0ae5c1200.ungleich.ch
 | 
			
		||||
  wireguard_private_key=...
 | 
			
		||||
```
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
import sys
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
from django.core.management.base import BaseCommand
 | 
			
		||||
 | 
			
		||||
from django.contrib.auth import get_user_model
 | 
			
		||||
 | 
			
		||||
from opennebula.models import VM as VMModel
 | 
			
		||||
from uncloud_vm.models import VMHost, VMProduct, VMNetworkCard, VMDiskImageProduct, VMDiskProduct, VMCluster
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
log = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
wireguard_template="""
 | 
			
		||||
 | 
			
		||||
[Interface]
 | 
			
		||||
ListenPort = 51820
 | 
			
		||||
PrivateKey = {privatekey}
 | 
			
		||||
 | 
			
		||||
# Nico, 2019-01-23, Switzerland
 | 
			
		||||
#[Peer]
 | 
			
		||||
#PublicKey = kL1S/Ipq6NkFf1MAsNRou4b9VoUsnnb4ZxgiBrH0zA8=
 | 
			
		||||
#AllowedIPs = 2a0a:e5c1:101::/48
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
class Command(BaseCommand):
 | 
			
		||||
    help = 'General uncloud commands'
 | 
			
		||||
 | 
			
		||||
    def add_arguments(self, parser):
 | 
			
		||||
        parser.add_argument('--hostname', action='store_true', help='Name of this VPN Host',
 | 
			
		||||
                            required=True)
 | 
			
		||||
 | 
			
		||||
    def handle(self, *args, **options):
 | 
			
		||||
#        for net
 | 
			
		||||
        if options['bootstrap']:
 | 
			
		||||
            self.bootstrap()
 | 
			
		||||
 | 
			
		||||
        self.create_vpn_config(options['hostname'])
 | 
			
		||||
 | 
			
		||||
    def create_vpn_config(self, hostname):
 | 
			
		||||
        for pool in VPNPool.objects.filter(vpn_hostname
 | 
			
		||||
        default_cluster = VPNNetwork.objects.get_or_create(name="default")
 | 
			
		||||
#        local_host =
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
# Generated by Django 3.0.5 on 2020-04-03 17:27
 | 
			
		||||
# Generated by Django 3.0.5 on 2020-04-06 21:38
 | 
			
		||||
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
import django.contrib.postgres.fields.jsonb
 | 
			
		||||
| 
						 | 
				
			
			@ -28,22 +28,23 @@ class Migration(migrations.Migration):
 | 
			
		|||
            name='VPNPool',
 | 
			
		||||
            fields=[
 | 
			
		||||
                ('extra_data', django.contrib.postgres.fields.jsonb.JSONField(blank=True, editable=False, null=True)),
 | 
			
		||||
                ('network', models.GenericIPAddressField(editable=False, primary_key=True, serialize=False)),
 | 
			
		||||
                ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
 | 
			
		||||
                ('network', models.GenericIPAddressField(unique=True)),
 | 
			
		||||
                ('network_size', models.IntegerField(validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(128)])),
 | 
			
		||||
                ('subnetwork_size', models.IntegerField(validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(128)])),
 | 
			
		||||
                ('vpn_hostname', models.CharField(max_length=256)),
 | 
			
		||||
                ('wireguard_private_key', models.CharField(max_length=48)),
 | 
			
		||||
            ],
 | 
			
		||||
            options={
 | 
			
		||||
                'abstract': False,
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.CreateModel(
 | 
			
		||||
            name='VPNProduct',
 | 
			
		||||
            name='VPNNetworkReservation',
 | 
			
		||||
            fields=[
 | 
			
		||||
                ('extra_data', django.contrib.postgres.fields.jsonb.JSONField(blank=True, editable=False, null=True)),
 | 
			
		||||
                ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
 | 
			
		||||
                ('status', models.CharField(choices=[('PENDING', 'Pending'), ('AWAITING_PAYMENT', 'Awaiting payment'), ('BEING_CREATED', 'Being created'), ('SCHEDULED', 'Scheduled'), ('ACTIVE', 'Active'), ('MODIFYING', 'Modifying'), ('DELETED', 'Deleted'), ('DISABLED', 'Disabled'), ('UNUSABLE', 'Unusable')], default='PENDING', max_length=32)),
 | 
			
		||||
                ('network', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='uncloud_net.VPNPool')),
 | 
			
		||||
                ('order', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='uncloud_pay.Order')),
 | 
			
		||||
                ('owner', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
 | 
			
		||||
                ('address', models.GenericIPAddressField(primary_key=True, serialize=False)),
 | 
			
		||||
                ('vpnpool', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='uncloud_net.VPNPool')),
 | 
			
		||||
            ],
 | 
			
		||||
            options={
 | 
			
		||||
                'abstract': False,
 | 
			
		||||
| 
						 | 
				
			
			@ -53,8 +54,12 @@ class Migration(migrations.Migration):
 | 
			
		|||
            name='VPNNetwork',
 | 
			
		||||
            fields=[
 | 
			
		||||
                ('extra_data', django.contrib.postgres.fields.jsonb.JSONField(blank=True, editable=False, null=True)),
 | 
			
		||||
                ('network', models.GenericIPAddressField(editable=False, primary_key=True, serialize=False)),
 | 
			
		||||
                ('vpnpool', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='uncloud_net.VPNPool')),
 | 
			
		||||
                ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
 | 
			
		||||
                ('status', models.CharField(choices=[('PENDING', 'Pending'), ('AWAITING_PAYMENT', 'Awaiting payment'), ('BEING_CREATED', 'Being created'), ('SCHEDULED', 'Scheduled'), ('ACTIVE', 'Active'), ('MODIFYING', 'Modifying'), ('DELETED', 'Deleted'), ('DISABLED', 'Disabled'), ('UNUSABLE', 'Unusable')], default='PENDING', max_length=32)),
 | 
			
		||||
                ('wireguard_public_key', models.CharField(max_length=48)),
 | 
			
		||||
                ('network', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='uncloud_net.VPNNetworkReservation')),
 | 
			
		||||
                ('order', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='uncloud_pay.Order')),
 | 
			
		||||
                ('owner', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
 | 
			
		||||
            ],
 | 
			
		||||
            options={
 | 
			
		||||
                'abstract': False,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,70 +0,0 @@
 | 
			
		|||
# Generated by Django 3.0.5 on 2020-04-06 20:21
 | 
			
		||||
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
import django.db.models.deletion
 | 
			
		||||
import uuid
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('uncloud_pay', '0001_initial'),
 | 
			
		||||
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
 | 
			
		||||
        ('uncloud_net', '0001_initial'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='vpnnetwork',
 | 
			
		||||
            name='order',
 | 
			
		||||
            field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='uncloud_pay.Order'),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='vpnnetwork',
 | 
			
		||||
            name='owner',
 | 
			
		||||
            field=models.ForeignKey(default=0, editable=False, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
 | 
			
		||||
            preserve_default=False,
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='vpnnetwork',
 | 
			
		||||
            name='status',
 | 
			
		||||
            field=models.CharField(choices=[('PENDING', 'Pending'), ('AWAITING_PAYMENT', 'Awaiting payment'), ('BEING_CREATED', 'Being created'), ('SCHEDULED', 'Scheduled'), ('ACTIVE', 'Active'), ('MODIFYING', 'Modifying'), ('DELETED', 'Deleted'), ('DISABLED', 'Disabled'), ('UNUSABLE', 'Unusable')], default='PENDING', max_length=32),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='vpnnetwork',
 | 
			
		||||
            name='network',
 | 
			
		||||
            field=models.GenericIPAddressField(editable=False, unique=True),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='vpnnetwork',
 | 
			
		||||
            name='uuid',
 | 
			
		||||
            field=models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='vpnnetwork',
 | 
			
		||||
            name='wireguard_public_key',
 | 
			
		||||
            field=models.CharField(default='', max_length=48),
 | 
			
		||||
            preserve_default=False,
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='vpnpool',
 | 
			
		||||
            name='vpn_hostname',
 | 
			
		||||
            field=models.CharField(default='', max_length=256),
 | 
			
		||||
            preserve_default=False,
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='vpnpool',
 | 
			
		||||
            name='wireguard_private_key',
 | 
			
		||||
            field=models.CharField(default='', max_length=48),
 | 
			
		||||
            preserve_default=False,
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='vpnpool',
 | 
			
		||||
            name='network',
 | 
			
		||||
            field=models.GenericIPAddressField(primary_key=True, serialize=False),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.DeleteModel(
 | 
			
		||||
            name='VPNProduct',
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +1,5 @@
 | 
			
		|||
import uuid
 | 
			
		||||
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.contrib.auth import get_user_model
 | 
			
		||||
from django.core.validators import MinValueValidator, MaxValueValidator
 | 
			
		||||
| 
						 | 
				
			
			@ -15,24 +17,36 @@ class VPNPool(UncloudModel):
 | 
			
		|||
    Network address pools from which VPNs can be created
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    network = models.GenericIPAddressField(primary_key=True)
 | 
			
		||||
    uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
 | 
			
		||||
 | 
			
		||||
    network = models.GenericIPAddressField(unique=True)
 | 
			
		||||
    network_size = models.IntegerField(validators=[MinValueValidator(0),
 | 
			
		||||
                                                   MaxValueValidator(128)])
 | 
			
		||||
 | 
			
		||||
    subnetwork_size = models.IntegerField(validators=[MinValueValidator(0),
 | 
			
		||||
                                                   MaxValueValidator(128)])
 | 
			
		||||
 | 
			
		||||
    vpn_hostname = models.CharField(max_length=256)
 | 
			
		||||
 | 
			
		||||
    wireguard_private_key = models.CharField(max_length=48)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VPNNetwork(Product):
 | 
			
		||||
class VPNNetworkReservation(UncloudModel):
 | 
			
		||||
    """
 | 
			
		||||
    A selected network. Used for tracking reservations / used networks
 | 
			
		||||
    This class tracks the used VPN networks. It will be deleted, when the product is cancelled.
 | 
			
		||||
    """
 | 
			
		||||
    vpnpool = models.ForeignKey(VPNPool,
 | 
			
		||||
                                  on_delete=models.CASCADE)
 | 
			
		||||
 | 
			
		||||
    network = models.GenericIPAddressField(editable=False,
 | 
			
		||||
                                           unique=True)
 | 
			
		||||
    address = models.GenericIPAddressField(primary_key=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VPNNetwork(Product):
 | 
			
		||||
    """
 | 
			
		||||
    A selected network. Used for tracking reservations / used networks
 | 
			
		||||
    """
 | 
			
		||||
    network = models.ForeignKey(VPNNetworkReservation,
 | 
			
		||||
                                on_delete=models.CASCADE,
 | 
			
		||||
                                editable=False)
 | 
			
		||||
 | 
			
		||||
    wireguard_public_key = models.CharField(max_length=48)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,7 @@
 | 
			
		|||
import base64
 | 
			
		||||
 | 
			
		||||
from django.contrib.auth import get_user_model
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from rest_framework import serializers
 | 
			
		||||
 | 
			
		||||
from .models import *
 | 
			
		||||
| 
						 | 
				
			
			@ -10,9 +13,48 @@ class VPNPoolSerializer(serializers.ModelSerializer):
 | 
			
		|||
 | 
			
		||||
class VPNNetworkSerializer(serializers.ModelSerializer):
 | 
			
		||||
 | 
			
		||||
    network_size = serializers.IntegerField(min_value=0,
 | 
			
		||||
                                            max_value=128)
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = VPNNetwork
 | 
			
		||||
        fields = '__all__'
 | 
			
		||||
 | 
			
		||||
    # This is required for finding the VPN pool, but does not
 | 
			
		||||
    # exist in the model
 | 
			
		||||
    network_size = serializers.IntegerField(min_value=0,
 | 
			
		||||
                                            max_value=128)
 | 
			
		||||
 | 
			
		||||
    def validate_wireguard_public_key(self, value):
 | 
			
		||||
        msg = _("Supplied key is not a valid wireguard public key")
 | 
			
		||||
 | 
			
		||||
        """ FIXME: verify that this does not create broken wireguard config files,
 | 
			
		||||
        i.e. contains \n or similar!
 | 
			
		||||
        We might even need to be more strict to not break wireguard...
 | 
			
		||||
        """
 | 
			
		||||
        print(value)
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            base64.standard_b64decode(value)
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            raise serializers.ValidationError(msg)
 | 
			
		||||
 | 
			
		||||
        if '\n' in value:
 | 
			
		||||
            raise serializers.ValidationError(msg)
 | 
			
		||||
 | 
			
		||||
        return value
 | 
			
		||||
 | 
			
		||||
    def validate(self, data):
 | 
			
		||||
 | 
			
		||||
        # FIXME: filter for status = active or similar
 | 
			
		||||
        all_pools = VPNPool.objects.all()
 | 
			
		||||
        sizes = [ p.subnetwork_size for p in all_pools ]
 | 
			
		||||
 | 
			
		||||
        pools = VPNPool.objects.filter(subnetwork_size=data['network_size'])
 | 
			
		||||
 | 
			
		||||
        if len(pools) == 0:
 | 
			
		||||
            msg = _("No pool available for networks with size = {}. Available are: {}".format(data['network_size'], sizes))
 | 
			
		||||
            raise serializers.ValidationError(msg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        return data
 | 
			
		||||
 | 
			
		||||
    def create(self, validated_data):
 | 
			
		||||
        from_pool =
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
 | 
			
		||||
from django.shortcuts import render
 | 
			
		||||
 | 
			
		||||
from rest_framework import viewsets, permissions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue