Manage AllowedIPs for client config file

This commit is contained in:
Eduardo Silva 2024-03-09 16:02:48 -03:00
parent 7561156235
commit 32931dfd16
11 changed files with 188 additions and 106 deletions

View File

@ -6,7 +6,7 @@ from django.utils import timezone
def get_peer_addresses(peers, include_networks): def get_peer_addresses(peers, include_networks):
addresses = [] addresses = []
for peer in peers.all(): for peer in peers.all():
peer_ips = peer.peerallowedip_set.all().order_by('priority') peer_ips = peer.peerallowedip_set.filter(config_file='server').order_by('priority')
if not include_networks: if not include_networks:
peer_ips = peer_ips.filter(priority=0) peer_ips = peer_ips.filter(priority=0)
@ -202,7 +202,7 @@ def generate_port_forward_firewall():
description = f" - {redirect_rule.description} " if redirect_rule.description else "" description = f" - {redirect_rule.description} " if redirect_rule.description else ""
rule_destination = redirect_rule.ip_address rule_destination = redirect_rule.ip_address
if redirect_rule.peer: if redirect_rule.peer:
peer_allowed_ip_address = PeerAllowedIP.objects.filter(peer=redirect_rule.peer, netmask=32, priority=0).first() peer_allowed_ip_address = PeerAllowedIP.objects.filter(peer=redirect_rule.peer, config_file='server', netmask=32, priority=0).first()
if peer_allowed_ip_address: if peer_allowed_ip_address:
rule_destination = peer_allowed_ip_address.allowed_ip rule_destination = peer_allowed_ip_address.allowed_ip
if rule_destination: if rule_destination:

View File

@ -9,7 +9,6 @@
<br> <br>
<h3>Upcoming Enhancements</h3> <h3>Upcoming Enhancements</h3>
<ul> <ul>
<li>Implementing AllowedIPs in the client configuration.</li>
<li>Improving "Pending changes" notification and separation (WireGuard from Firewall)</li> <li>Improving "Pending changes" notification and separation (WireGuard from Firewall)</li>
</ul> </ul>

View File

@ -47,30 +47,91 @@
</div> </div>
<div class="col-lg-6"> <div class="col-lg-6">
<label>IP Addresses</label> <div class="row">
{% for ip_address in peer_ip_list %} <div class="col-md-12">
<div class="d-flex justify-content-between align-items-center border-bottom mb-3"> <div class="d-flex justify-content-between align-items-center">
<p> <label>
<i class="fas fa-info-circle" title="AllowedIPs at Peer section of wg{{ current_peer.wireguard_instance.instance_id }}.conf"></i>
Peer IP Addresses and networks
</label>
<a class="btn btn-outline-primary btn-xs" href="/peer/manage_ip_address/?peer={{ current_peer.uuid }}&config=server" >Add IP Address</a>
</div>
{% if ip_address.missing_from_wireguard %} {% for ip_address in peer_ip_list %}
<a href='/peer/manage_ip_address/?ip={{ ip_address.uuid }}' class='bg-warning' title="This address does not appear in the wg show command output, likely indicating that another peer has an IP overlapping this network or that the configuration file is outdated."> <div class="d-flex justify-content-between align-items-center border-bottom mb-3">
<i class="fas fa-network-wired"></i> <p>
{{ ip_address}} <a href="/peer/manage_ip_address/?ip={{ ip_address.uuid }}">
</a> <i class="fas fa-network-wired"></i>
{% else %} {{ ip_address}}
<a href="/peer/manage_ip_address/?ip={{ ip_address.uuid }}"> </a>
<i class="fas fa-network-wired"></i>
{{ ip_address}}
</a>
{% endif %} </p>
<p class="d-flex flex-column text-right small">
{% if ip_address.priority == 0 %}
Main ip address
{% else %}
Priority: {{ ip_address.priority }}
{% endif %}
</p>
</div>
{% endfor %}
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="d-flex justify-content-between align-items-center">
<label>
<i class="fas fa-info-circle" title="AllowedIPs at client configuration file"></i>
Client Routing Configuration
</label>
<a class="btn btn-outline-primary btn-xs" href="/peer/manage_ip_address/?peer={{ current_peer.uuid }}&config=client" >Add Client route</a>
</div>
<div class="d-flex justify-content-between align-items-center border-bottom mb-3">
<p>
<a href="#"
{% if peer_client_ip_list %}
onclick="alert('The client is not configured to use the VPN as the default gateway.\n\nOnly the specific networks listed below are routed through the VPN.\n\nNote: These routes are not automatically pushed to the client. You will need to manually update the client configuration file to reflect these settings.');"
style="text-decoration: line-through;"
{% else %}
onclick="alert('The client is configured to use the VPN as the default gateway. \n\nThis setting routes all client internet traffic through the VPN, enhancing privacy and security across all connections.');"
{% endif %}
>
<i class="fas fa-network-wired"></i>
0.0.0.0/0, ::/0
</a>
</p>
<p class="d-flex flex-column text-right small">
default route
</p>
</div>
{% for ip_address in peer_client_ip_list %}
<div class="d-flex justify-content-between align-items-center border-bottom mb-3">
<p>
<a href="/peer/manage_ip_address/?ip={{ ip_address.uuid }}">
<i class="fas fa-network-wired"></i>
{{ ip_address}}
</a>
</p>
<p class="d-flex flex-column text-right small">
{% if ip_address.priority == 0 %}
Main ip address
{% else %}
Priority: {{ ip_address.priority }}
{% endif %}
</p>
</div>
{% endfor %}
</div>
</div>
</p>
<p class="d-flex flex-column text-right small">
Priority: {{ ip_address.priority }}
</p>
</div>
{% endfor %}
</div> </div>

View File

@ -39,43 +39,14 @@
<b>Latest Handshake:</b> <span id="peer-latest-handshake-{{ peer.public_key }}"></span> <span style="display: none;" id="peer-stored-latest-handshake-{{ peer.public_key }}">{% if peer.peerstatus.last_handshake %}{{ peer.peerstatus.last_handshake|date:"U" }}{% else %}0{% endif %}</span><br> <b>Latest Handshake:</b> <span id="peer-latest-handshake-{{ peer.public_key }}"></span> <span style="display: none;" id="peer-stored-latest-handshake-{{ peer.public_key }}">{% if peer.peerstatus.last_handshake %}{{ peer.peerstatus.last_handshake|date:"U" }}{% else %}0{% endif %}</span><br>
<b>Endpoints:</b> <span id="peer-endpoints-{{ peer.public_key }}"></span><br> <b>Endpoints:</b> <span id="peer-endpoints-{{ peer.public_key }}"></span><br>
<b>Allowed IPs: </b><span id="peer-allowed-ips-{{ peer.public_key }}"> <b>Allowed IPs: </b><span id="peer-allowed-ips-{{ peer.public_key }}">
{% for address in peer.peerallowedip_set.all %}{% if address.priority == 0 %} {% for address in peer.peerallowedip_set.all %}
{% if address.missing_from_wireguard %} {% if address.priority == 0 and address.config_file == 'server' %}{{ address }}{% endif %}
<a href='#' class='bg-warning' title="This address does not appear in the wg show command output, likely indicating that another peer has an IP overlapping this network or that the configuration file is outdated.">{{ address }}</a> {% endfor %}
{% else %} {% for address in peer.peerallowedip_set.all %}
{{ address }} {% if address.priority >= 1 and address.config_file == 'server' %}{{ address }}{% endif %}
{% endif %} {% endfor %}
{% endif %}{% endfor %}
{% for address in peer.peerallowedip_set.all %}{% if address.priority >= 1 %}
{% if address.missing_from_wireguard %}
<a href='#' class='bg-warning' title="This address does not appear in the wg show command output, likely indicating that another peer has an IP overlapping this network or that the configuration file is outdated.">{{ address }}</a>
{% else %}
{{ address }}
{% endif %}
{% endif %}{% endfor %}
</span> </span>
</p> </p>
{% comment %}
<p>{% for address in peer.peerallowedip_set.all %}{% if address.priority == 0 %}
{% if address.missing_from_wireguard %}
<a href='#' class='bg-warning' title="This address does not appear in the wg show command output, likely indicating that another peer has an IP overlapping this network or that the configuration file is outdated.">{{ address }}</a>
{% else %}
{{ address }}
{% endif %}
{% endif %}{% endfor %}
{% for address in peer.peerallowedip_set.all %}{% if address.priority >= 1 %}
{% if address.missing_from_wireguard %}
<a href='#' class='bg-warning' title="This address does not appear in the wg show command output, likely indicating that another peer has an IP overlapping this network or that the configuration file is outdated.">{{ address }}</a>
{% else %}
{{ address }}
{% endif %}
{% endif %}{% endfor %}
</p>
{% endcomment %}
</div> </div>

View File

@ -0,0 +1,18 @@
# Generated by Django 5.0.2 on 2024-03-08 18:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wireguard', '0019_alter_wireguardinstance_legacy_firewall'),
]
operations = [
migrations.AddField(
model_name='peerallowedip',
name='config_file',
field=models.CharField(choices=[('server', 'Server Config'), ('client', 'Client config')], default='server', max_length=6),
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 5.0.2 on 2024-03-08 18:49
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('wireguard', '0020_peerallowedip_config_file'),
]
operations = [
migrations.RemoveField(
model_name='peerallowedip',
name='missing_from_wireguard',
),
]

View File

@ -111,7 +111,7 @@ class PeerAllowedIP(models.Model):
priority = models.PositiveBigIntegerField(default=1) priority = models.PositiveBigIntegerField(default=1)
allowed_ip = models.GenericIPAddressField(protocol='IPv4') allowed_ip = models.GenericIPAddressField(protocol='IPv4')
netmask = models.IntegerField(default=32, choices=NETMASK_CHOICES) netmask = models.IntegerField(default=32, choices=NETMASK_CHOICES)
missing_from_wireguard = models.BooleanField(default=False) config_file = models.CharField(max_length=6, choices=(('server', 'Server Config'), ('client', 'Client config')), default='server')
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True) updated = models.DateTimeField(auto_now=True)

View File

@ -18,8 +18,10 @@ class PeerForm(forms.ModelForm):
class PeerAllowedIPForm(forms.ModelForm): class PeerAllowedIPForm(forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
current_peer = kwargs.pop('current_peer', None) current_peer = kwargs.pop('current_peer', None)
config_file = kwargs.pop('config_file', None)
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.current_peer = current_peer self.current_peer = current_peer
self.config_file = config_file
allowed_ip = forms.GenericIPAddressField(label='Allowed IP or Network', required=True) allowed_ip = forms.GenericIPAddressField(label='Allowed IP or Network', required=True)
netmask = forms.ChoiceField(choices=NETMASK_CHOICES, label='Netmask', initial=24, required=True) netmask = forms.ChoiceField(choices=NETMASK_CHOICES, label='Netmask', initial=24, required=True)
@ -33,29 +35,34 @@ class PeerAllowedIPForm(forms.ModelForm):
if allowed_ip is None: if allowed_ip is None:
raise forms.ValidationError("Please provide a valid IP address.") raise forms.ValidationError("Please provide a valid IP address.")
wireguard_network = ipaddress.ip_network(f"{self.current_peer.wireguard_instance.address}/{self.current_peer.wireguard_instance.netmask}", strict=False) if self.config_file == 'server':
wireguard_network = ipaddress.ip_network(f"{self.current_peer.wireguard_instance.address}/{self.current_peer.wireguard_instance.netmask}", strict=False)
if priority == 0:
zero_priority_ips_query = PeerAllowedIP.objects.filter(peer=self.current_peer, config_file='server', priority=0)
if self.instance:
zero_priority_ips_query = zero_priority_ips_query.exclude(uuid=self.instance.uuid)
if zero_priority_ips_query.exists():
raise forms.ValidationError("A peer can have only one IP with priority zero.")
if priority == 0: duplicated_ip = PeerAllowedIP.objects.filter(config_file='server', allowed_ip=allowed_ip)
zero_priority_ips_query = PeerAllowedIP.objects.filter(peer=self.current_peer, priority=0) if self.instance:
if self.instance: duplicated_ip = duplicated_ip.exclude(uuid=self.instance.uuid)
zero_priority_ips_query = zero_priority_ips_query.exclude(uuid=self.instance.uuid) if duplicated_ip.exists():
if zero_priority_ips_query.exists(): raise forms.ValidationError("This IP is already in use by another peer.")
raise forms.ValidationError("A peer can have only one IP with priority zero.") if ipaddress.ip_address(allowed_ip) not in wireguard_network:
raise forms.ValidationError("The IP address does not belong to the Peer's WireGuard instance network range. Please check the IP address or change the priority.")
duplicated_ip = PeerAllowedIP.objects.filter(allowed_ip=allowed_ip) if str(netmask) != str(32):
if self.instance: raise forms.ValidationError("The netmask for priority 0 IP must be 32.")
duplicated_ip = duplicated_ip.exclude(uuid=self.instance.uuid) if self.current_peer.wireguard_instance.address == allowed_ip:
if duplicated_ip.exists(): raise forms.ValidationError("The IP address is the same as the Peer's WireGuard instance address.")
raise forms.ValidationError("This IP is already in use by another peer.") else:
if ipaddress.ip_address(allowed_ip) not in wireguard_network: if ipaddress.ip_address(allowed_ip) in wireguard_network:
raise forms.ValidationError("The IP address does not belong to the Peer's WireGuard instance network range. Please check the IP address or change the priority.") raise forms.ValidationError("The IP address belongs to the Peer's WireGuard instance network range. Please check the IP address or change use priority 0 instead.")
if str(netmask) != str(32): elif self.config_file == 'client':
raise forms.ValidationError("The netmask for priority 0 IP must be 32.") if priority < 1:
if self.current_peer.wireguard_instance.address == allowed_ip: raise forms.ValidationError("Priority must be greater than or equal to 1")
raise forms.ValidationError("The IP address is the same as the Peer's WireGuard instance address.")
else: else:
if ipaddress.ip_address(allowed_ip) in wireguard_network: raise forms.ValidationError('Invalid config file')
raise forms.ValidationError("The IP address belongs to the Peer's WireGuard instance network range. Please check the IP address or change use priority 0 instead.")
class Meta: class Meta:
model = PeerAllowedIP model = PeerAllowedIP

View File

@ -22,7 +22,7 @@ def generate_peer_default(wireguard_instance):
# the code below can be an issue for larger networks, for now it's fine, but it should be optimized in the future # the code below can be an issue for larger networks, for now it's fine, but it should be optimized in the future
used_ips = set(WireGuardInstance.objects.all().values_list('address', flat=True)) | \ used_ips = set(WireGuardInstance.objects.all().values_list('address', flat=True)) | \
set(PeerAllowedIP.objects.filter(priority=0).values_list('allowed_ip', flat=True)) set(PeerAllowedIP.objects.filter(config_file='server', priority=0).values_list('allowed_ip', flat=True))
free_ip_address = None free_ip_address = None
for ip in network.hosts(): for ip in network.hosts():
@ -88,6 +88,7 @@ def view_wireguard_peer_manage(request):
wireguard_instance=current_instance, wireguard_instance=current_instance,
) )
PeerAllowedIP.objects.create( PeerAllowedIP.objects.create(
config_file='server',
peer=new_peer, peer=new_peer,
allowed_ip=new_peer_data['allowed_ip'], allowed_ip=new_peer_data['allowed_ip'],
priority=0, priority=0,
@ -115,7 +116,8 @@ def view_wireguard_peer_manage(request):
messages.warning(request, 'Error deleting peer|Invalid confirmation message. Type "delete" to confirm.') messages.warning(request, 'Error deleting peer|Invalid confirmation message. Type "delete" to confirm.')
return redirect('/peer/manage/?peer=' + str(current_peer.uuid)) return redirect('/peer/manage/?peer=' + str(current_peer.uuid))
page_title = 'Update Peer ' page_title = 'Update Peer '
peer_ip_list = current_peer.peerallowedip_set.all().order_by('priority') peer_ip_list = current_peer.peerallowedip_set.filter(config_file='server').order_by('priority')
peer_client_ip_list = current_peer.peerallowedip_set.filter(config_file='client').order_by('priority')
if current_peer.name: if current_peer.name:
page_title += current_peer.name page_title += current_peer.name
else: else:
@ -133,31 +135,28 @@ def view_wireguard_peer_manage(request):
else: else:
return redirect('/peer/list/') return redirect('/peer/list/')
context = { context = {
'page_title': page_title, 'current_instance': current_instance, 'current_peer': current_peer, 'form': form, 'peer_ip_list': peer_ip_list 'page_title': page_title, 'current_instance': current_instance, 'current_peer': current_peer, 'form': form,
'peer_ip_list': peer_ip_list, 'peer_client_ip_list': peer_client_ip_list
} }
return render(request, 'wireguard/wireguard_manage_peer.html', context) return render(request, 'wireguard/wireguard_manage_peer.html', context)
def view_manage_ip_address(request): def view_manage_ip_address(request):
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists(): if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists():
return render(request, 'access_denied.html', {'page_title': 'Access Denied'}) return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
config_file = request.GET.get('config', 'server')
if request.GET.get('peer'): if request.GET.get('peer'):
current_peer = get_object_or_404(Peer, uuid=request.GET.get('peer')) current_peer = get_object_or_404(Peer, uuid=request.GET.get('peer'))
page_title = 'Add new IP address for Peer ' #page_title = 'Add new IP address for Peer ' + str(current_peer)
current_ip = None current_ip = None
if current_peer.name:
page_title += current_peer.name
else:
page_title += current_peer.public_key
elif request.GET.get('ip'): elif request.GET.get('ip'):
current_ip = get_object_or_404(PeerAllowedIP, uuid=request.GET.get('ip')) current_ip = get_object_or_404(PeerAllowedIP, uuid=request.GET.get('ip'))
current_peer = current_ip.peer current_peer = current_ip.peer
page_title = 'Update IP address for Peer ' config_file = current_ip.config_file
if current_peer.name: #page_title = 'Update IP address for Peer ' + str(current_peer)
page_title += current_peer.name
else:
page_title += current_peer.public_key[:10] + ("..." if len(current_peer.public_key) > 16 else "")
if request.GET.get('action') == 'delete': if request.GET.get('action') == 'delete':
if request.GET.get('confirmation') == 'delete': if request.GET.get('confirmation') == 'delete':
current_ip.delete() current_ip.delete()
@ -168,13 +167,20 @@ def view_manage_ip_address(request):
else: else:
messages.warning(request, 'Error deleting IP address|Invalid confirmation message. Type "delete" to confirm.') messages.warning(request, 'Error deleting IP address|Invalid confirmation message. Type "delete" to confirm.')
return redirect('/peer/ip/?ip=' + str(current_ip.uuid)) return redirect('/peer/ip/?ip=' + str(current_ip.uuid))
if config_file not in ['client', 'server']:
config_file = 'server'
if config_file == 'client':
page_title = 'Manage client route'
else:
page_title = 'Manage IP address or Network'
if request.method == 'POST': if request.method == 'POST':
form = PeerAllowedIPForm(request.POST or None, instance=current_ip, current_peer=current_peer) form = PeerAllowedIPForm(request.POST or None, instance=current_ip, current_peer=current_peer, config_file=config_file)
if form.is_valid(): if form.is_valid():
this_form = form.save(commit=False) this_form = form.save(commit=False)
if not current_ip: if not current_ip:
this_form.peer = current_peer this_form.peer = current_peer
this_form.config_file = config_file
this_form.save() this_form.save()
current_peer.wireguard_instance.pending_changes = True current_peer.wireguard_instance.pending_changes = True
current_peer.wireguard_instance.save() current_peer.wireguard_instance.save()

View File

@ -23,15 +23,18 @@ def generate_peer_config(peer_uuid):
peer = get_object_or_404(Peer, uuid=peer_uuid) peer = get_object_or_404(Peer, uuid=peer_uuid)
wg_instance = peer.wireguard_instance wg_instance = peer.wireguard_instance
priority_zero_ip = PeerAllowedIP.objects.filter(peer=peer, priority=0).first() priority_zero_ip = PeerAllowedIP.objects.filter(config_file='server', peer=peer, priority=0).first()
if not priority_zero_ip: if not priority_zero_ip:
return "No IP with priority zero found for this peer." return "No IP with priority zero found for this peer."
client_address = f"{priority_zero_ip.allowed_ip}/{priority_zero_ip.netmask}" client_address = f"{priority_zero_ip.allowed_ip}/{priority_zero_ip.netmask}"
#allowed_ips = PeerAllowedIP.objects.filter(peer=peer).exclude(uuid=priority_zero_ip.uuid).order_by('priority') allowed_ips = PeerAllowedIP.objects.filter(peer=peer, config_file='client').order_by('priority')
#allowed_ips_line = ", ".join([f"{ip.allowed_ip}/{ip.netmask}" for ip in allowed_ips]) if allowed_ips:
allowed_ips_line = ", ".join([f"{ip.allowed_ip}/{ip.netmask}" for ip in allowed_ips])
else:
allowed_ips_line = "0.0.0.0/0, ::/0"
config_lines = [ config_lines = [
"[Interface]", "[Interface]",
@ -41,7 +44,7 @@ def generate_peer_config(peer_uuid):
"\n[Peer]", "\n[Peer]",
f"PublicKey = {wg_instance.public_key}", f"PublicKey = {wg_instance.public_key}",
f"Endpoint = {wg_instance.hostname}:{wg_instance.listen_port}", f"Endpoint = {wg_instance.hostname}:{wg_instance.listen_port}",
f"AllowedIPs = 0.0.0.0/0, ::/0", f"AllowedIPs = {allowed_ips_line}",
f"PresharedKey = {peer.pre_shared_key}" if peer.pre_shared_key else "", f"PresharedKey = {peer.pre_shared_key}" if peer.pre_shared_key else "",
f"PersistentKeepalive = {peer.persistent_keepalive}", f"PersistentKeepalive = {peer.persistent_keepalive}",
] ]
@ -85,7 +88,7 @@ def export_wireguard_configs(request):
rule_text_down = "" rule_text_down = ""
rule_destination = redirect_rule.ip_address rule_destination = redirect_rule.ip_address
if redirect_rule.peer: if redirect_rule.peer:
peer_allowed_ip_address = PeerAllowedIP.objects.filter(peer=redirect_rule.peer, netmask=32, priority=0).first() peer_allowed_ip_address = PeerAllowedIP.objects.filter(config_file='server', peer=redirect_rule.peer, netmask=32, priority=0).first()
if peer_allowed_ip_address: if peer_allowed_ip_address:
rule_destination = peer_allowed_ip_address.allowed_ip rule_destination = peer_allowed_ip_address.allowed_ip
if rule_destination: if rule_destination:
@ -128,7 +131,7 @@ def export_wireguard_configs(request):
f"PresharedKey = {peer.pre_shared_key}" if peer.pre_shared_key else "", f"PresharedKey = {peer.pre_shared_key}" if peer.pre_shared_key else "",
f"PersistentKeepalive = {peer.persistent_keepalive}", f"PersistentKeepalive = {peer.persistent_keepalive}",
] ]
allowed_ips = PeerAllowedIP.objects.filter(peer=peer).order_by('priority') allowed_ips = PeerAllowedIP.objects.filter(config_file='server', peer=peer).order_by('priority')
allowed_ips_line = "AllowedIPs = " + ", ".join([f"{ip.allowed_ip}/{ip.netmask}" for ip in allowed_ips]) allowed_ips_line = "AllowedIPs = " + ", ".join([f"{ip.allowed_ip}/{ip.netmask}" for ip in allowed_ips])
peer_lines.append(allowed_ips_line) peer_lines.append(allowed_ips_line)
config_lines.extend(peer_lines) config_lines.extend(peer_lines)

View File

@ -129,6 +129,6 @@ STATICFILES_DIRS = [
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
WIREGUARD_WEBADMIN_VERSION = 9507 WIREGUARD_WEBADMIN_VERSION = 9601
from wireguard_webadmin.production_settings import * from wireguard_webadmin.production_settings import *