Server Installation/OpenVPN: Unterschied zwischen den Versionen
→Opennet CA CRL Aktualisierung: üeberarbeitet |
Leo (Diskussion | Beiträge) →Zertifikatsanfrage: nsCertType ist deprecated und für mit OpenSSL zu Fehlermeldung |
||
| (21 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 installieren |
* openvpn + openssl + python + ntp installieren |
||
* ein bzw. zwei Instanzen aufbauen: <system> = opennet_ugw (Usergateway-VPN) | opennet_users (User-VPN) |
* 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/<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 |
* /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 |
* CSR/Key erstellen: ''openssl req -days 3650 -nodes -new -newkey rsa:2048 -keyout <hostname>.key -out <hostname>.csr -config openssl.cnf'' |
||
** Organizational Unit: |
|||
* CSR absenden und unterschreiben lassen, Cert einspielen, Leserechte setzen (''chgrp ssl-cert *.key && chmod g-rw *.key'') |
|||
*** für User-VPN: Gateways |
|||
* Cert Ablage unter /etc/ssl und Key Ablage unter /etc/ssl/private |
|||
*** 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'' |
* 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): |
XCA/OpenSSL Vorlage (CN u. SubjectAltName entspr. Hostnamen ersetzen): |
||
| Zeile 42: | Zeile 68: | ||
5.emailAddress=admin@opennet-initiative.de |
5.emailAddress=admin@opennet-initiative.de |
||
[ xca_extensions ] |
[ xca_extensions ] |
||
nsCertType=server |
|||
subjectAltName=DNS:aqua.opennet-initiative.de, DNS:aqua.on-i.de, DNS:aqua.on |
subjectAltName=DNS:aqua.opennet-initiative.de, DNS:aqua.on-i.de, DNS:aqua.on |
||
keyUsage=digitalSignature |
keyUsage=digitalSignature, keyEncipherment |
||
extendedKeyUsage=serverAuth |
|||
basicConstraints=critical,CA:FALSE |
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 |
||
* |
* X = 14 |
||
* |
* 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 |
||
==== |
==== 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. |
|||
==== |
==== 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 |
|||
} |
|||
# /config |
|||
def iplongtostring(longip): |
|||
return socket.inet_ntop(socket.AF_INET,struct.pack('>L',longip)) |
|||
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); |
|||
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> |
|||
==== Python Script connect_script.py ==== |
|||
<pre> |
|||
#!/usr/bin/python |
|||
from connectcalc import * |
|||
target_filename = sys.argv[1] |
|||
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 -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 === |
=== DHCP Options: DNS + Domain === |
||
| Zeile 200: | Zeile 134: | ||
In der OpenVPN User Instanz ('''opennet_users.conf''') sich selbst und einen alternativen DNS als DHCP Push Option aufnehmen: |
In der OpenVPN User Instanz ('''opennet_users.conf''') sich selbst und einen alternativen DNS als DHCP Push Option aufnehmen: |
||
# dns push for mobile clients |
# dns push for mobile clients |
||
... siehe oben ... |
|||
push "dhcp-option DOMAIN opennet-initiative.de" |
|||
push "dhcp-option DNS 10.1.0.1" |
push "dhcp-option DNS 10.1.0.1" |
||
push "dhcp-option DNS 192.168.0. |
push "dhcp-option DNS 192.168.0.<gw-ip>" |
||
=== Opennet CA CRL Überprüfung === |
|||
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 |
|||
=== Opennet CA CRL Aktualisierung === |
=== Opennet CA CRL Aktualisierung === |
||
| Zeile 224: | Zeile 142: | ||
Um die CRL Dateien der [[Opennet CA]] abzuholen ist ein Cronjob notwendig. Technisches zur CA siehe auch [[Server Installation/Opennet CA]]. |
Um die CRL Dateien der [[Opennet CA]] abzuholen ist ein Cronjob notwendig. Technisches zur CA siehe auch [[Server Installation/Opennet CA]]. |
||
CRL Download Script: |
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!): |
Verzeichnis vorbereiten und Script ablegen (ggf. analog für ugw!): |
||
| Zeile 235: | Zeile 153: | ||
tar xfzv ca-bundle.tar.gz |
tar xfzv ca-bundle.tar.gz |
||
rm ca-bundle.tar.gz |
rm ca-bundle.tar.gz |
||
dpkg-reconfigure ca-certificates # ask -> checkmark new certs! |
|||
cd /tmp |
cd /tmp |
||
git clone https://dev.opennet-initiative.de/git/on_opennetca |
|||
cp on_opennetca/opennetca_crldownload.sh /usr/local/sbin/ |
cp on_opennetca/opennetca_crldownload.sh /usr/local/sbin/ |
||
rm -rf on_opennetca |
rm -rf on_opennetca |
||
| Zeile 245: | Zeile 163: | ||
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-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 |
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 |
|||
[[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
|| }} }}
{{
#switch: | left =| #default = }}
{{#if:
| {{{image}}}
| [[Image:{{#switch:notice
| danger = Ambox warning pn.svg
| warning = Ambox warning pn.svg
| caution = Ambox important.svg
| approval = Thumb_up_icon.svg
| proposal = Ambox warning purple.svg
| detail = Ambox style.png
| protection = Ambox protection.png
| notice
| #default = Information icon4.svg
}} | {{#switch:
| left = 20x20px
| #default = 40x40px
}} ]]
}}{{#switch:
| left =
| #default = | 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 ansible an. | {{#switch:
| left = {{{imageright}}}
| #default = {{{imageright}}}
}} |
- 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: ?
- Organizational Unit:
- 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
- opennet_users.conf: Konfiguration des OpenVPN-Servers für Nutzer-Tunnel
- opennet_ugw.conf: Konfiguration des OpenVPN-Servers für Mesh-Verbindungen
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