Zum Inhalt springen

Server Installation/OpenVPN: Unterschied zwischen den Versionen

Aus Opennet
Inhalt gelöscht Inhalt hinzugefügt
MathiasMahnke (Diskussion | Beiträge)
Leo (Diskussion | Beiträge)
→Zertifikatsanfrage: nsCertType ist deprecated und für mit OpenSSL zu Fehlermeldung
 
(29 dazwischenliegende Versionen von 3 Benutzern werden nicht angezeigt)
Zeile 5: Zeile 5:


=== Grundinstallation ===
=== Grundinstallation ===
{{hinweis|Der folgende Ablauf ist inzwischen in Form einer ansible-Konfiguration umgesetzt. Schau dir also für die Neu-Einrichtung eines OpenVPN-Servers für Openent die Details unter [[Server Installation/Ansible|ansible]] an.}}


* openvpn + openssl + python + ntp installieren
(Ggf. veraltet)
* ein bzw. zwei Instanzen aufbauen: <system> = opennet_ugw (Usergateway-VPN) | opennet_users (User-VPN)
* /etc/openvpn/<system>/openssl.cnf, ca.crt und connectcalc.py als Kopie besorgen, Leserechte setzen (''chmod go-rwx <system>'')
* /etc/openvpn/opennet_<system>.conf anpassen (Kopie besorgen), Key + Cert anpassen
* CSR/Key erstellen: ''openssl req -days 3650 -nodes -new -newkey rsa:2048 -keyout <hostname>.key -out <hostname>.csr -config openssl.cnf''
** Organizational Unit:
*** für User-VPN: Gateways
*** für UGW-VPN: user gateways
** Common Name: ?
* CSR absenden und unterschreiben lassen, Cert File und Certchain Cert File erzeugen
* Cert Ablage unter /etc/ssl, Symlinks setzen auf aktuelles File
* Key Ablage unter /etc/ssl/private, Leserechte setzen (''chgrp ssl-cert *.key && chmod g-rw *.key''), Symlink auf aktuelles File erzeugen
* Diffie Hellman PEM: ''openssl dhparam -out /etc/openvpn/dh2048.pem 2048''
* addgroup --system openvpn
* adduser --system --ingroup openvpn openvpn
* mkdir -p /var/log/openvpn
* chown -R openvpn. /var/log/openvpn
* echo "net.ipv4.ip_forward=1" >/etc/sysctl.d/opennet.conf
* olsrd.conf von erina oder subaru übernehmen und anpassen
* Firewall:
** chain INPUT proto udp dport (123 1600 1602) ACCEPT
** chain INPUT interface $IF_MESH proto udp dport 698 ACCEPT
** chain FORWARD interface $IF_ON_USERS outerface $IF_WAN ACCEPT
** table nat chain POSTROUTING outerface $IF_WAN saddr (192.168.0.0/16 10.0.0.0/8) MASQUERADE
* Alias-IP für das Mesh in /etc/network/interfaces eintragen:
auto lo:0
iface lo:0 inet static
address 192.168.0.246
netmask 255.255.255.255


TODO: DNS
* OpenVPN:
** openvpn + openssl installieren
** ein bzw. zwei Instanzen aufbauen: <system> = opennet_ugw (Usergateway-VPN) | opennet_users (User-VPN)
** /etc/openvpn/<system>/openssl.cnf als Kopie besorgen, Leserechte setzen (''chmod go-rwx <system>'')
** /etc/openvpn/opennet_<system>.conf anpassen (Kopie besorgen), key + cert anpassen
** Csr/Key erstellen: ''openssl req -days 3650 -nodes -new -keyout <hostname>.key -out <hostname>.csr -extensions server -config openssl.cnf''
*** opennet_users - Subject: C=DE, ST=Mecklenburg-Vorpommern, L=Rostock, O=Opennet, OU=Gateways, CN=<hostname>.on/emailAddress=admin@opennet-initiative.de
*** opennet_ugw - Subject: C=DE, ST=Mecklenburg-Vorpommern, L=Rostock, O=OpenNet, OU=user gateways, CN=<hostname>.on/emailAddress=admin@opennet-initiative.de
** Csr absenden und unterschreiben lassen, Crt einspielen, Leserechte setzen (''chmod go-rw *.key'')
** Diffie hellman PEM: ''openssl dhparam -out /etc/openvpn/dh2048.pem 2048''


=== Zertifikatsanfrage ===
* automatische ACL Aktualisierung:
** Nutzer openvpn-acl anlegen + absichern
** SSH Schlüsselpaar erzeugen: ''su openvpn-acl; cd .ssh/; ssh-keygen -t rsa'' (Sicherstellen, das $home und .ssh vorhanden sind!)
** SSH Public Key (id_rsa.pub) in opennetca@ratte:.ssh/authorized_keys hinzufügen
** cronttab für openvpn-acl mit "*/10 * * * * rsync -rt --delete --safe-links opennetca@139.30.3.52:'opennet_users opennet_users_disabled' /etc/openvpn/acl"


XCA/OpenSSL Vorlage (CN u. SubjectAltName entspr. Hostnamen ersetzen):
=== Portforwarding ===
oid_section = xca_oids
[ xca_oids ]
dom = 1.3.6.1.4.1.311.20.2
MsCaV = 1.3.6.1.4.1.311.21.1
msEFSFR = 1.3.6.1.4.1.311.10.3.4.1
iKEIntermediate = 1.3.6.1.5.5.8.2.2
nameDistinguisher = 0.2.262.1.10.7.20
id-kp-eapOverPPP = 1.3.6.1.5.5.7.3.13
id-kp-eapOverLAN = 1.3.6.1.5.5.7.3.14
[ req ]
default_bits = 1024
default_keyfile = privkey.pem
distinguished_name = xca_dn
x509_extensions = xca_extensions
req_extensions = xca_extensions
string_mask = MASK:0x2002
utf8 = yes
prompt = no
[ xca_dn ]
0.C=DE
1.ST=Mecklenburg-Vorpommern
2.O=Opennet Initiative e.V.
3.OU=Opennet Server
4.CN=aqua.opennet-initiative.de
5.emailAddress=admin@opennet-initiative.de
[ xca_extensions ]
subjectAltName=DNS:aqua.opennet-initiative.de, DNS:aqua.on-i.de, DNS:aqua.on
keyUsage=digitalSignature, keyEncipherment
extendedKeyUsage=serverAuth
basicConstraints=critical,CA:FALSE

=== Konfiguration ===

* [https://dev.opennet-initiative.de/browser/on_ansible/roles/ugw-server/templates/opennet_users.conf opennet_users.conf]: Konfiguration des OpenVPN-Servers für Nutzer-Tunnel
* [https://dev.opennet-initiative.de/browser/on_ansible/roles/ugw-server/templates/opennet_ugw.conf opennet_ugw.conf]: Konfiguration des OpenVPN-Servers für Mesh-Verbindungen

=== Portforwarding / Client-IP-Vergabe ===


==== Algorithmus ====
==== Algorithmus ====


* die Basis-Zahl ''n'' hängt vom Common Name des Nutzer-Zertifikats ab:
* Setze n gleich 10000.
** 1.X.aps.on: 10000
* Falls der Common Name des client-Certificates weder der Form "*.aps.on" noch der Form "*.mobile.on" entspricht gibt es keine zu diesem System geforwardeten ports. Andernfalls:
** 2.X.aps.on: 15100
* Falls der CN der Form "*.mobile.on" entspricht, setze n gleich n+2550
** 3.X.aps.on: 20200
* Setze n gleich n+(10*([Systemnummer ("*" in oberen Beispielen)] -1))
** X.mobile.on: 12550
* Die Portrange ist n bis n+9
* der erste Port ist ''n + 10 * X''
* der letzte Port ist ''n + 10 * X + 9''


''Beispiel:''
''Beispiel:''
* CN des Zertifikats ist 14.mobile.on
* CN des Zertifikats ist 14.mobile.on
* 10000
* X = 14
* 10000 + 255*10 = 12550
* n = 12550
* 12550 + (10*(14-1)) = 12680
* 12550 + (10*(14-1)) = 12680
* Portbereich wäre dann von 12680 bis 12689
* Portbereich wäre dann von 12680 bis 12689


==== Sudo Rechte Connect Script ====
==== Python-Skripte ====
Beim Aufbau und bei der Trennung einer OpenVPN-Verbindung wird ein Python-Skript ausgeführt, um die Vergabe der Client-IPs, sowie die Ermittlung der Portweiterleitungen umzusetzen.


Die folgenden Skript-Dateien liegen im Verzeichnis ''/etc/openvpn/openner_users/'':
Damit das vom OpenVPN Daemon aufgerufene Connect-Script die DNAT Einträge erzeugen kann per ''visudo'' aufnehmen:
* [https://dev.opennet-initiative.de/browser/on_ansible/roles/ugw-server/files/openvpn/opennet_users/connect_script.py connection_script.py]: dieses Skript wird vm OpenVPN-Prozess (Nutzer-Tunnel) beim Verbindungsaufbau aufgerufen
openvpn ALL=(root) NOPASSWD:/sbin/iptables
* [https://dev.opennet-initiative.de/browser/on_ansible/roles/python-module/files/opennet/addresses.py addresses.py]: diese Modul enthält Funktionen zur IP- und Port-Ermittlung, die von dem obigen Nutzertunnel-Skript benötigt werden
* [https://dev.opennet-initiative.de/browser/on_ansible/roles/ugw-server/files/openvpn/opennet_ugw/connect_script.py connect_script.py]: dieses Skript wird vm OpenVPN-Prozess (Mesh-Verbindung) bei Verbindungsänderungen aufgerufen


Die Skripte, die in OpenVPN als "connect"-Hooks konfiguriert sind, müssen sehr schnell ausgeführt werden, da der OpenVPN-Prozess während der Ausführungszeit blockiert ist und Verkehrspakete verwirft. Daher ist in dem obigen ''connect''-Skript für die Nutzertunnel inzwischen nicht mehr die Erstellung der Portweiterleitung enthalten (dies braucht ca. 30ms). Stattdessen wird im 3-Minuten-Takt das Skript [https://dev.opennet-initiative.de/browser/on_ansible/roles/ugw-server/files/openvpn/opennet_ugw/files/scripts/rebuild_user_port_forwards.py rebuild_user_portforwards.py] als Cron-Job ausgeführt. Portweiterleitungen erscheinen somit leicht verzögert - dafür reduziert sich jedoch die Häufigkeit von Paketverlusten durch die kürzere Ausführungszeit des ''connect''-Skripts.
Hinweis: Der Aufruf muss dann auch mit voller Pfadangabe in den Scripten erfolgen.


==== Python Script connectcalc.py ====
==== Firewall-Regeln prüfen ====


Mittels der obigen Skripte werden DNAT-Einträge erzeugt. Diese können auf jedem UGW-Server geprüft werden:
<pre>
iptables -L -v -n -t nat
#!/usr/bin/python


In der Chain "user_dnat" sollen dann die Portweiterleitungen der mit OpenVPN verbundenen APs zu finden sein.
import sys
import os
import socket
import struct
import re


Die Nutzer-Portweiterleitungen werden regelmäßig via Cron-Job an den aktuellen Stand der OpenVPN-Client-Liste angepasst. Siehe oben ''Python-Skripte''.
#config


=== Bash Script tls-verify.sh ===
def extract_numstring_aps(cn):
retval = int(cn[:-7])
if not (1 <= retval <= 255):
raise ValueError('Invalid cn %r.' % cn)
return retval
def extract_numstring_aps_long(cn):
retval = int(cn[2:-7])
if not (1 <= retval <= 255):
raise ValueError('Invalid cn %r.' % cn)
return retval


Mit einem gepatchten OpenVPN können Client Zertifikate exportiert werden. Hierzu hatten wir in Vergangenheit folgendes Script im Einsatz:
def extract_numstring_wifidog_long(cn):
#!/bin/bash
retval = int(cn[2:-11])
filename=$(echo $2 | awk 'BEGIN{RS="[/\\;.?$]";FS="="} {printf $2"_"} END{print".crt"}')
if not (1 <= retval <= 255):
cp $peer_cert /etc/openvpn/opennet_users/certs/${untrusted_ip}$filename
raise ValueError('Invalid cn %r.' % cn)
return retval


Eingebunden über diese Einträge im Config-File:
def extract_numstring_mobile(cn):
# added to export certs, only works with patched openvpn
retval = int(cn[:-10])
tls-export-cert /tmp
if not (1 <= retval <= 255):
tls-verify /etc/openvpn/opennet_users/tls_verify.sh
raise ValueError('Invalid cn %r.' % cn)
return retval


Diese Konfiguration kann nicht gleichzeitig mit dem CRL capath Check betrieben werden und ist daher hier nur geschichtlich dokumentiert.
client_ranges = {
'[0-9][0-9]?[0-9]?\.aps\.on': (167838718, 4, 10000, extract_numstring_aps), #10.1.4.0
'1[\._-][0-9][0-9]?[0-9]?\.aps\.on': (167838718, 4, 10000, extract_numstring_aps_long), #10.1.4.0
'[0-9][0-9]?[0-9]?\.mobile\.on': (167839742, 4, 12550, extract_numstring_mobile), #10.1.8.0
'2[\._-][0-9][0-9]?[0-9]?\.aps\.on': (167841790, 4, 15100, extract_numstring_aps_long), #10.1.16.0
}


=== DHCP Options: DNS + Domain ===
# /config


In der OpenVPN User Instanz ('''opennet_users.conf''') sich selbst und einen alternativen DNS als DHCP Push Option aufnehmen:
def iplongtostring(longip):
# dns push for mobile clients
return socket.inet_ntop(socket.AF_INET,struct.pack('>L',longip))
... siehe oben ...
push "dhcp-option DNS 10.1.0.1"
push "dhcp-option DNS 192.168.0.<gw-ip>"


=== Opennet CA CRL Aktualisierung ===
def get_targetvalues(client_cn):
ipbase = 0;
for cn_schema in client_ranges:
if (re.match(cn_schema, client_cn)):
(ipbase, step, portbase, ns_extractor) = client_ranges[cn_schema]
cn_address = ns_extractor(client_cn);
break
if not ipbase:
raise ValueError('Invalid CN %r.' % client_cn)
return (ipbase, step, portbase, cn_address);


Um die CRL Dateien der [[Opennet CA]] abzuholen ist ein Cronjob notwendig. Technisches zur CA siehe auch [[Server Installation/Opennet CA]].
def calc_targetip(ipbase, cn_address, step):
targetip_long = ipbase + cn_address*step;
targetip = iplongtostring(targetip_long);
ifconfig_arg_1 = iplongtostring(targetip_long-1);
return (targetip, ifconfig_arg_1);
def calc_targetports(cn_address, portbase):
targetport_begin = portbase + (cn_address-1)*10;
targetport_end = targetport_begin+9;
return (targetport_begin, targetport_end);
</pre>


CRL Download Script: https://dev.opennet-initiative.de/browser/on_opennetca/opennetca_crldownload.sh?format=txt
==== Python Script connect_script.py ====


Verzeichnis vorbereiten und Script ablegen (ggf. analog für ugw!):
<pre>
apt-get install subversion
#!/usr/bin/python
mkdir /etc/ssl/crl/
from connectcalc import *
cd /usr/share/ca-certificates/
mkdir opennet-initiative.de
cd opennet-initiative.de
wget http://ca.opennet-initiative.de/ca-bundle.tar.gz
tar xfzv ca-bundle.tar.gz
rm ca-bundle.tar.gz
dpkg-reconfigure ca-certificates # ask -> checkmark new certs!
cd /tmp
git clone https://dev.opennet-initiative.de/git/on_opennetca
cp on_opennetca/opennetca_crldownload.sh /usr/local/sbin/
rm -rf on_opennetca


Crontab unter ''/etc/crontab'' erweitern (ggf. analog für ugw!):
target_filename = sys.argv[1]
# Opennet CA CRL Download, used by crl verify in openvpn process
client_cn = os.getenv('common_name')
45 1,13 * * * root opennetca_crldownload.sh opennet-root.crl /etc/ssl/crl /etc/ssl/certs/opennet-root.pem >/dev/null
if not client_cn:
45 1,13 * * * root opennetca_crldownload.sh opennet-vpn-user.crl /etc/ssl/crl /etc/ssl/certs/opennet-vpn-user.pem >/dev/null
raise ValueError("Missing env-variable 'common_name'")


=== Opennet CA CRL Überprüfung ===
ipbase, step, portbase, cn_address = get_targetvalues(client_cn);
targetip, ifconfig_arg_1 = calc_targetip(ipbase, cn_address, step);
targetport_begin, targetport_end = calc_targetports(cn_address, portbase);


'''Hinweis: '''Derzeit nicht in Verwendung - statt dessen via ''crl-verify''
os.system('sudo /sbin/iptables -t nat -A user_dnat -p tcp --dport %s:%s -j DNAT --to-destination %s' % \
(targetport_begin, targetport_end, targetip))
os.system('sudo /sbin/iptables -t nat -A user_dnat -p udp --dport %s:%s -j DNAT --to-destination %s' % \
(targetport_begin, targetport_end, targetip))


target_file = file(target_filename, 'w')
target_file.write('ifconfig-push %s %s\n' % (targetip, ifconfig_arg_1))
target_file.close()
</pre>

==== Python Script disconnect_script.py ====

<pre>
#!/usr/bin/python
from connectcalc import *

client_cn = os.getenv('common_name')
if not client_cn:
raise ValueError("Missing env-variable 'common_name'")

ipbase, step, portbase, cn_address = get_targetvalues(client_cn);
targetip, ifconfig_arg_1 = calc_targetip(ipbase, cn_address, step);
targetport_begin, targetport_end = calc_targetports(cn_address, portbase);

os.system('sudo /sbin/iptables -t nat -D user_dnat -p tcp --dport %s:%s -j DNAT --to-destination %s' % \
(targetport_begin, targetport_end, targetip))
os.system('sudo /sbin/iptables -t nat -D user_dnat -p udp --dport %s:%s -j DNAT --to-destination %s' % \
(targetport_begin, targetport_end, targetip))
</pre>

==== Kontrolle ====

Es werden DNAT Einträge erzeugt, Kontrolle auf jedem GW Server mit:
iptables -L -v -n -t nat

In der Chain "user_dnat" sollen dann die Portweiterleitungen der mit OpenVPN verbundenen APs zu finden sein.

=== DHCP Options: DNS + Domain ===

In der OpenVPN User Instanz ('''opennet_users.conf''') sich selbst und einen alternativen DNS als DHCP Push Option aufnehmen:
# dns push for mobile clients
push "dhcp-option DOMAIN opennet-initiative.de"
push "dhcp-option DNS 10.1.0.1"
push "dhcp-option DNS 192.168.0.254"

=== Opennet CA CRL Überprüfung ===


In jeder OpenVPN Instanz (''opennet_*.conf'') die Certificate Revocation List (CRL) Überprüfung einschalten (analog für UGW Instanz):
In jeder OpenVPN Instanz (''opennet_*.conf'') die Certificate Revocation List (CRL) Überprüfung einschalten (analog für UGW Instanz):
Zeile 193: Zeile 177:
chown openvpn:openvpn ca
chown openvpn:openvpn ca
cd ca
cd ca
ln -s ../root.crt ca/`openssl x509 -hash -noout -in ../root.crt`.0
ln -s /etc/ssl/certs/opennet-root.pem `openssl x509 -hash -noout -in /etc/ssl/certs/opennet-root.pem`.0
ln -s ../../crl/root.crl ca/`openssl x509 -hash -noout -in ../root.crt`.r0
ln -s /etc/ssl/crl/opennet-root.crl `openssl x509 -hash -noout -in /etc/ssl/certs/opennet-root.pem`.r0
ln -s ../vpnuser.crt ca/`openssl x509 -hash -noout -in ../vpnuser.crt`.0
ln -s /etc/ssl/certs/opennet-vpn-user.pem `openssl x509 -hash -noout -in /etc/ssl/certs/opennet-vpn-user.pem`.0
ln -s ../../crl/vpnuser.crl ca/`openssl x509 -hash -noout -in ../vpnuser.crt`.r0
ln -s /etc/ssl/crl/opennet-vpn-user.crl `openssl x509 -hash -noout -in /etc/ssl/certs/opennet-vpn-user.pem`.r0

=== Opennet CA CRL Aktualisierung ===

Um die CRL Dateien der [[Opennet CA]] abzuholen ist ein Cronjob notwendig. Technisches zur CA siehe auch [[Server Installation/Opennet CA]].

CRL Download Script: http://svn.opennet-initiative.de/filedetails.php?repname=on_opennetca&path=%2Fopennetca_crldownload.sh)

Verzeichnis vorbereiten und Script ablegen (ggf. analog für ugw!):
apt-get install subversion
mkdir /etc/openvpn/crl/
chown openvpn /etc/openvpn/crl/
cd /etc/openvpn/opennet_users/
wget http://ca.opennet-initiative.de/root.crt
wget http://ca.opennet-initiative.de/vpnuser.crt
chown openvpn root.crt
chown openvpn vpnuser.crt
cd /tmp
svn checkout svn://svn.opennet-initiative.de/on_opennetca
cp on_opennetca/opennetca_crldownload.sh /etc/openvpn/opennetca_crldownload.sh
rm -rf on_opennetca

Script testen (ggf. analog für ugw!):
su openvpn
bash
cd /etc/openvpn/
./opennetca_crldownload.sh root.crl crl opennet_users/root.crt
./opennetca_crldownload.sh vpnuser.crl crl opennet_users/vpnuser.crt
ls -la crl/
rm crl/root.crl*
rm crl/vpnuser.crl*

Crontab unter ''/etc/crontab'' erweitern (ggf. analog für ugw!):
# Opennet CA CRL Download, used by crl-verify in openvpn process
45 1,13 * * * openvpn /etc/openvpn/opennetca_crldownload.sh root.crl /etc/openvpn/crl /etc/openvpn/opennet_users/root.crt >/dev/null
45 1,13 * * * openvpn /etc/openvpn/opennetca_crldownload.sh vpnuser.crl /etc/openvpn/crl /etc/openvpn/opennet_users/vpnuser.crt >/dev/null


[[Kategorie:Server]]
[[Kategorie:Server]]

Aktuelle Version vom 7. Oktober 2023, 14:47 Uhr

Nutzerndokumentation

Grundinstallation

| warning = #b22222 solid;background-color: #ffdddd;"> | caution = #f28500 solid;background-color: #ffffaa;"> | approval = #00ff00 solid;background-color: #deffde;"> | proposal = #9932cc solid;background-color: #e4d8ff;"> | detail = #f4c430 solid;background-color: #fbfbfb;"> | protection = #bba solid;background-color: #fbfbfb;"> | notice | #default = #1e90ff solid;background-color: #fbfbfb;"> }} {{#switch: | blank | none =

| #default =

}}

{{#if: | {{#ifeq:|none

 | 
| }} }}


  • openvpn + openssl + python + ntp installieren
  • ein bzw. zwei Instanzen aufbauen: <system> = opennet_ugw (Usergateway-VPN) | opennet_users (User-VPN)
  • /etc/openvpn/<system>/openssl.cnf, ca.crt und connectcalc.py als Kopie besorgen, Leserechte setzen (chmod go-rwx <system>)
  • /etc/openvpn/opennet_<system>.conf anpassen (Kopie besorgen), Key + Cert anpassen
  • CSR/Key erstellen: openssl req -days 3650 -nodes -new -newkey rsa:2048 -keyout <hostname>.key -out <hostname>.csr -config openssl.cnf
    • Organizational Unit:
      • für User-VPN: Gateways
      • für UGW-VPN: user gateways
    • Common Name: ?
  • CSR absenden und unterschreiben lassen, Cert File und Certchain Cert File erzeugen
  • Cert Ablage unter /etc/ssl, Symlinks setzen auf aktuelles File
  • Key Ablage unter /etc/ssl/private, Leserechte setzen (chgrp ssl-cert *.key && chmod g-rw *.key), Symlink auf aktuelles File erzeugen
  • Diffie Hellman PEM: openssl dhparam -out /etc/openvpn/dh2048.pem 2048
  • addgroup --system openvpn
  • adduser --system --ingroup openvpn openvpn
  • mkdir -p /var/log/openvpn
  • chown -R openvpn. /var/log/openvpn
  • echo "net.ipv4.ip_forward=1" >/etc/sysctl.d/opennet.conf
  • olsrd.conf von erina oder subaru übernehmen und anpassen
  • Firewall:
    • chain INPUT proto udp dport (123 1600 1602) ACCEPT
    • chain INPUT interface $IF_MESH proto udp dport 698 ACCEPT
    • chain FORWARD interface $IF_ON_USERS outerface $IF_WAN ACCEPT
    • table nat chain POSTROUTING outerface $IF_WAN saddr (192.168.0.0/16 10.0.0.0/8) MASQUERADE
  • Alias-IP für das Mesh in /etc/network/interfaces eintragen:
 auto lo:0
 iface lo:0 inet static
       address 192.168.0.246
       netmask 255.255.255.255

TODO: DNS

Zertifikatsanfrage

XCA/OpenSSL Vorlage (CN u. SubjectAltName entspr. Hostnamen ersetzen):

oid_section = xca_oids
[ xca_oids ]
dom = 1.3.6.1.4.1.311.20.2
MsCaV = 1.3.6.1.4.1.311.21.1
msEFSFR = 1.3.6.1.4.1.311.10.3.4.1
iKEIntermediate = 1.3.6.1.5.5.8.2.2
nameDistinguisher = 0.2.262.1.10.7.20
id-kp-eapOverPPP = 1.3.6.1.5.5.7.3.13
id-kp-eapOverLAN = 1.3.6.1.5.5.7.3.14
[ req ]
default_bits = 1024
default_keyfile = privkey.pem
distinguished_name = xca_dn
x509_extensions = xca_extensions
req_extensions = xca_extensions
string_mask = MASK:0x2002
utf8 = yes
prompt = no
[ xca_dn ]
0.C=DE
1.ST=Mecklenburg-Vorpommern
2.O=Opennet Initiative e.V.
3.OU=Opennet Server
4.CN=aqua.opennet-initiative.de
5.emailAddress=admin@opennet-initiative.de
[ xca_extensions ]
subjectAltName=DNS:aqua.opennet-initiative.de, DNS:aqua.on-i.de, DNS:aqua.on
keyUsage=digitalSignature, keyEncipherment
extendedKeyUsage=serverAuth
basicConstraints=critical,CA:FALSE

Konfiguration

Portforwarding / Client-IP-Vergabe

Algorithmus

  • die Basis-Zahl n hängt vom Common Name des Nutzer-Zertifikats ab:
    • 1.X.aps.on: 10000
    • 2.X.aps.on: 15100
    • 3.X.aps.on: 20200
    • X.mobile.on: 12550
  • der erste Port ist n + 10 * X
  • der letzte Port ist n + 10 * X + 9

Beispiel:

  • CN des Zertifikats ist 14.mobile.on
  • X = 14
  • n = 12550
  • 12550 + (10*(14-1)) = 12680
  • Portbereich wäre dann von 12680 bis 12689

Python-Skripte

Beim Aufbau und bei der Trennung einer OpenVPN-Verbindung wird ein Python-Skript ausgeführt, um die Vergabe der Client-IPs, sowie die Ermittlung der Portweiterleitungen umzusetzen.

Die folgenden Skript-Dateien liegen im Verzeichnis /etc/openvpn/openner_users/:

  • connection_script.py: dieses Skript wird vm OpenVPN-Prozess (Nutzer-Tunnel) beim Verbindungsaufbau aufgerufen
  • addresses.py: diese Modul enthält Funktionen zur IP- und Port-Ermittlung, die von dem obigen Nutzertunnel-Skript benötigt werden
  • connect_script.py: dieses Skript wird vm OpenVPN-Prozess (Mesh-Verbindung) bei Verbindungsänderungen aufgerufen

Die Skripte, die in OpenVPN als "connect"-Hooks konfiguriert sind, müssen sehr schnell ausgeführt werden, da der OpenVPN-Prozess während der Ausführungszeit blockiert ist und Verkehrspakete verwirft. Daher ist in dem obigen connect-Skript für die Nutzertunnel inzwischen nicht mehr die Erstellung der Portweiterleitung enthalten (dies braucht ca. 30ms). Stattdessen wird im 3-Minuten-Takt das Skript rebuild_user_portforwards.py als Cron-Job ausgeführt. Portweiterleitungen erscheinen somit leicht verzögert - dafür reduziert sich jedoch die Häufigkeit von Paketverlusten durch die kürzere Ausführungszeit des connect-Skripts.

Firewall-Regeln prüfen

Mittels der obigen Skripte werden DNAT-Einträge erzeugt. Diese können auf jedem UGW-Server geprüft werden:

iptables -L -v -n -t nat

In der Chain "user_dnat" sollen dann die Portweiterleitungen der mit OpenVPN verbundenen APs zu finden sein.

Die Nutzer-Portweiterleitungen werden regelmäßig via Cron-Job an den aktuellen Stand der OpenVPN-Client-Liste angepasst. Siehe oben Python-Skripte.

Bash Script tls-verify.sh

Mit einem gepatchten OpenVPN können Client Zertifikate exportiert werden. Hierzu hatten wir in Vergangenheit folgendes Script im Einsatz:

#!/bin/bash
filename=$(echo $2 | awk 'BEGIN{RS="[/\\;.?$]";FS="="} {printf $2"_"} END{print".crt"}')
cp $peer_cert /etc/openvpn/opennet_users/certs/${untrusted_ip}$filename

Eingebunden über diese Einträge im Config-File:

# added to export certs, only works with patched openvpn
tls-export-cert /tmp
tls-verify /etc/openvpn/opennet_users/tls_verify.sh

Diese Konfiguration kann nicht gleichzeitig mit dem CRL capath Check betrieben werden und ist daher hier nur geschichtlich dokumentiert.

DHCP Options: DNS + Domain

In der OpenVPN User Instanz (opennet_users.conf) sich selbst und einen alternativen DNS als DHCP Push Option aufnehmen:

# dns push for mobile clients 
... siehe oben ...
push "dhcp-option DNS 10.1.0.1"
push "dhcp-option DNS 192.168.0.<gw-ip>"

Opennet CA CRL Aktualisierung

Um die CRL Dateien der Opennet CA abzuholen ist ein Cronjob notwendig. Technisches zur CA siehe auch Server Installation/Opennet CA.

CRL Download Script: https://dev.opennet-initiative.de/browser/on_opennetca/opennetca_crldownload.sh?format=txt

Verzeichnis vorbereiten und Script ablegen (ggf. analog für ugw!):

apt-get install subversion
mkdir /etc/ssl/crl/
cd /usr/share/ca-certificates/
mkdir opennet-initiative.de
cd opennet-initiative.de
wget http://ca.opennet-initiative.de/ca-bundle.tar.gz
tar xfzv ca-bundle.tar.gz
rm ca-bundle.tar.gz
dpkg-reconfigure ca-certificates   # ask -> checkmark new certs!
cd /tmp
git clone https://dev.opennet-initiative.de/git/on_opennetca
cp on_opennetca/opennetca_crldownload.sh /usr/local/sbin/
rm -rf on_opennetca

Crontab unter /etc/crontab erweitern (ggf. analog für ugw!):

# Opennet CA CRL Download, used by crl verify in openvpn process
45 1,13	* * *	root	opennetca_crldownload.sh opennet-root.crl /etc/ssl/crl /etc/ssl/certs/opennet-root.pem >/dev/null
45 1,13 * * *   root	opennetca_crldownload.sh opennet-vpn-user.crl /etc/ssl/crl /etc/ssl/certs/opennet-vpn-user.pem >/dev/null

Opennet CA CRL Überprüfung

Hinweis: Derzeit nicht in Verwendung - statt dessen via crl-verify

In jeder OpenVPN Instanz (opennet_*.conf) die Certificate Revocation List (CRL) Überprüfung einschalten (analog für UGW Instanz):

# check cert against opennet ca revocation list
capath /etc/openvpn/opennet_users/ca/

Hierzu das CA Verzeichnis wie folgt erstellen (analog für UGW Instanz):

cd /etc/openvpn/opennet_users
mkdir ca
chown openvpn:openvpn ca
cd ca
ln -s /etc/ssl/certs/opennet-root.pem `openssl x509 -hash -noout -in /etc/ssl/certs/opennet-root.pem`.0
ln -s /etc/ssl/crl/opennet-root.crl `openssl x509 -hash -noout -in /etc/ssl/certs/opennet-root.pem`.r0
ln -s /etc/ssl/certs/opennet-vpn-user.pem `openssl x509 -hash -noout -in /etc/ssl/certs/opennet-vpn-user.pem`.0
ln -s /etc/ssl/crl/opennet-vpn-user.crl `openssl x509 -hash -noout -in /etc/ssl/certs/opennet-vpn-user.pem`.r0