Konfiguracja kilku serwerów OpenVPN (TCP/UDP) z jedną podsiecią - Michał Sternadel Konfiguracja kilku serwerów OpenVPN (TCP/UDP) z jedną podsiecią

Światło: Zapal | Zgaś

Konfiguracja kilku serwerów OpenVPN (TCP/UDP) z jedną podsiecią

Dodano: 14.02.2022, 20:03:38

Pomimo istnienia dość sympatycznego i w miarę już przyjętego przez świat Wireguarda, OpenVPN wciąż jest dość szeroko używany zarówno w rozwiązaniach klasy biznesowej, jak i domowych bo dobry i tani, zwłaszcza po zaimplementowaniu algorytmu ChaCha20-Poly1305 stał się wydajnym bohaterem bez peleryny, który bezpiecznie i prędko przenosi ogrom danych. Założenia nie zawsze pozwalają na utworzenie mostka z konkretnym fizycznym interfejsem, a konfiguracja na bazie TUN taka, aby klient uzyskiwał konkretny adres z jednej podsieci, ale mógł sie łączyć zarówno przez protokół TCP jak i UDP jest skomplikowana. Nie każdy chce opierać VPN o TAP, mostkować, konfigurować mnóstwo dodatkowych usług, jak chociażby serwer DHCP. Trzymając się rozwiązań opartych na dwóch interfejsach TUN z tą samą podsiecią łatwo zauważyć, że będzie się to niejako "gryzło". OpenVPN nie posiada komplementarnego rozwiązania, pozwalającego zagregować jedną konfigurację na oba protokoły jednocześnie. Nikt nie zabrania nam jednak skonfigurować sobie kilku VPNów na różnych portach i protokołach i odpowiednio zmieniać trasy przy zestawieniu nowego połączenia od klienta w zależności od użytej konfiguracji. Założenia konfiguracji przedstawiam poniżej:

  • Jedna podsieć dla klientów: 192.168.168.0/24
  • Dostęp do serwera VPN na porcie 1194/TCP
  • Dostęp do serwera VPN na porcie 1194/UDP
  • Dostęp do serwera VPN na porcie 443/TCP
  • Konfiguracja oparta tym razem o certyfikaty
  • Możliwość połączeń pomiędzy klientami (również gdy jeden zestawi VPN innym kanałem od drugiego)

Co będzie nam potrzebne? Serwer z zewnętrznym adresem IP oraz zainstalowanym systemem operacyjnym Linux (już skonfigurowanym). Konfigurację przedstawię na bazie Debiana 11 i OpenVPN w wersji 2.5.1, ale nic oczywiście nie stoi na przeszkodzie, aby użyć innego Linuksa oraz starszej wersji OpenVPN (po drobnym dopasowaniu konfiguracji).

Rozpocznijmy od instalacji pakietów, które będziemy potrzebowali, a więc openvpn oraz easy-rsa:

apt update && apt install openvpn easy-rsa -y

Następnie przygotujmy wszelkie katalogi, certyfikaty oraz klucze:

mkdir -p /etc/openvpn/easyrsa && cd /etc/openvpn/easyrsa/
cp -R /usr/share/easy-rsa/* ./
mv vars.example vars
wget https://raw.githubusercontent.com/TinCanTech/easy-tls/master/easytls -O ./easytls && chmod +x easytls

Zmieńmy konfigurację w pliku vars według upodobań, zalecam zmienić okres ważności certyfikatu CA oraz certyfikatów serwera/klientów (EASYRSA_CA_EXPIRE oraz EASYRSA_CERT_EXPIRE), jeżeli VPN ma służyć do użytku wewnętrznego.

./easyrsa init-pki
./easyrsa build-ca # Podajmy hasło na przykład "cement15" i zapamiętajmy
./easyrsa gen-dh # Tutaj możemy zaparzyć kawę
./easyrsa gen-crl # Zapamiętane hasło potrzebne
./easytls init-tls
./easytls build-tls-crypt
./easyrsa build-server-full openvpnserver nopass # Jeszcze pamietać hasło należy
./easyrsa build-client-full klient1 # Hasło już prawie się zapomniało
./easyrsa build-client-full klient2 nopass
mkdir /etc/openvpn/ccd
touch /etc/openvpn/ipp.txt

Powyższe komendy wygenerują po kolei: certyfikat główny -- autoryzujący pozostałe certyfikaty, klucz Diffie-Hellmana, listę nieważnych certyfikatów, zainicjują klucze szyfrujące TLS, wygenerują i podpiszą certyfikat serwera bez hasła do klucza oraz dwa certyfikaty i klucze dla klientów z hasłem do kluczy.

Po wygenerowaniu stosownych plików możemy przygotować nasze pliki konfiguracyjne.

Server na porcie 1194/TCP:

cat << EOF > /etc/openvpn/server1194tcp.conf
local 0.0.0.0
lport 1194
proto tcp4
dev tun-ovpntcp1194
ca /etc/openvpn/easyrsa/pki/ca.crt
cert /etc/openvpn/easyrsa/pki/issued/openvpnserver.crt
key /etc/openvpn/easyrsa/pki/private/openvpnserver.key
dh /etc/openvpn/easyrsa/pki/dh.pem
topology subnet
server 192.168.168.0 255.255.255.0
client-config-dir /etc/openvpn/ccd
keepalive 15 120
remote-cert-tls client
tls-version-min 1.2
tls-crypt /etc/openvpn/easyrsa/pki/easytls/tls-crypt.key 0
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256
tls-groups prime256v1
cipher AES-256-CBC
auth SHA256
persist-key
persist-tun
crl-verify /etc/openvpn/easyrsa/pki/crl.pem
status /etc/openvpn/status.log 20
status-version 3
management 127.0.0.1 11194
verb 0
push "explicit-exit-notify 1"
ifconfig-pool-persist /etc/openvpn/ipp.txt
route-metric 5
log-append /var/log/openvpn/openvpnserver.log
script-security 2
learn-address /etc/openvpn/learn-address.sh
push "redirect-gateway def1"
EOF

Server na porcie 443/TCP:

cat << EOF > /etc/openvpn/server443tcp.conf
local 0.0.0.0
lport 443
proto tcp4
dev tun-ovpntcp443
ca /etc/openvpn/easyrsa/pki/ca.crt
cert /etc/openvpn/easyrsa/pki/issued/openvpnserver.crt
key /etc/openvpn/easyrsa/pki/private/openvpnserver.key
dh /etc/openvpn/easyrsa/pki/dh.pem
topology subnet
server 192.168.168.0 255.255.255.0
client-config-dir /etc/openvpn/ccd
keepalive 15 120
remote-cert-tls client
tls-version-min 1.2
tls-crypt /etc/openvpn/easyrsa/pki/easytls/tls-crypt.key 0
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256
tls-groups prime256v1
cipher AES-256-CBC
auth SHA256
persist-key
persist-tun
crl-verify /etc/openvpn/easyrsa/pki/crl.pem
status /etc/openvpn/status.log 20
status-version 3
management 127.0.0.1 10443
verb 0
push "explicit-exit-notify 1"
ifconfig-pool-persist /etc/openvpn/ipp.txt
route-metric 5
log-append /var/log/openvpn/openvpnserver.log
script-security 2
learn-address /etc/openvpn/learn-address.sh
push "redirect-gateway def1"
EOF

Server na porcie 1194/UDP:

cat << EOF > /etc/openvpn/server1194udp.conf
local 0.0.0.0
lport 1194
proto udp4
dev tun-ovpnudp1194
ca /etc/openvpn/easyrsa/pki/ca.crt
cert /etc/openvpn/easyrsa/pki/issued/openvpnserver.crt
key /etc/openvpn/easyrsa/pki/private/openvpnserver.key
dh /etc/openvpn/easyrsa/pki/dh.pem
topology subnet
server 192.168.168.0 255.255.255.0
client-config-dir /etc/openvpn/ccd
keepalive 15 120
remote-cert-tls client
tls-version-min 1.2
tls-crypt /etc/openvpn/easyrsa/pki/easytls/tls-crypt.key 0
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256
tls-groups prime256v1
cipher AES-256-CBC
auth SHA256
persist-key
persist-tun
crl-verify /etc/openvpn/easyrsa/pki/crl.pem
status /etc/openvpn/status.log 20
status-version 3
management 127.0.0.1 21194
verb 0
push "explicit-exit-notify 1"
ifconfig-pool-persist /etc/openvpn/ipp.txt
route-metric 5
log-append /var/log/openvpn/openvpnserver.log
script-security 2
learn-address /etc/openvpn/learn-address.sh
push "redirect-gateway def1"
EOF

Teraz cala magia, bo jak każdy mało znudzony czytelnik zauważył, że przedstawione listingi posiadają linię server 192.168.168.0 255.255.255.0, a więc zostaną utworzone trzy różne interfejsy z taką samą adresacją. Musimy nauczyć nasz serwer jak trasować pakiety pomiędzy nimi, w zależności od tego, który klient połączy się do VPN z użyciem którego interfejsu. Za to odpowiedzialne są linie: script-security 2 (możliwość uruchamiana skryptów przez demona openvpn - ostrożnie) oraz learn-address /etc/openvpn/learn-address.sh.

Stwórzmy plik learn-address.sh oraz ustawmy mu atrybut +x:

cat << EOF > /etc/openvpn/learn-address.sh 
#!/bin/bash
if [ \$# -lt 2 ]; then
  exit 0;
fi
action=\$1;
addr=\$2;
commonname=\$3
case \${action} in
  add|update)
    /usr/bin/sudo /sbin/ip route del \${addr}/32 > /dev/null 2>&1
    /usr/bin/sudo /sbin/ip route add \${addr}/32 dev \${dev} > /dev/null 2>&1
  ;;
  delete)
    /usr/bin/sudo /sbin/ip route del \${addr}/32 > /dev/null 2>&1
  ;;
  *)
    exit 1
  ;;
esac
exit 0
EOF
chmod +x /etc/openvpn/learn-address.sh

Pozostaje nam uruchomić trzy demony OpenVPN:

systemctl enable [email protected]
systemctl enable [email protected]
systemctl enable [email protected]
systemctl start [email protected]
systemctl start [email protected]
systemctl start [email protected]

Upewniając się wcześniej, że konfiguracja firewalla jest odpowiednia (więc przekazywanie pakietów i NAT/Maskarada):

echo "1" > /proc/sys/net/ipv4/ip_forward
iptables -A INPUT -i ens3 -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -i ens3 -p tcp --dport 1194 -j ACCEPT
iptables -A INPUT -i ens3 -p udp --dport 1194 -j ACCEPT
iptables -A FORWARD -i ens3 -o tun-ovpntcp1194 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i ens3 -o tun-ovpntcp443 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i ens3 -o tun-ovpnudp1194 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -s 192.168.168.0/24 -o ens3 -j ACCEPT
iptables -t nat -A POSTROUTING -s 192.168.168.0/24 ! -d 192.168.168.0/24 -o ens3 -j MASQUERADE

Jeżeli nigdzie nie popełniliśmy błędu, powinno wszystko wystartować i nasłuchiwać na skonfigurowanych portach, a my możemy przygotować konfiguracje dla klientów. Aby zautomatyzować sobie to trochę, posłużmy się poniższymi komendami:

mkdir -p /etc/openvpn/configs/
cat << EOF > /etc/openvpn/user-skeleton.conf
tls-client
pull
dev tun0
resolv-retry infinite
nobind
remote-cert-tls server
tls-version-min 1.2
key-method 2
verify-x509-name openvpnserver name
cipher AES-256-CBC
auth SHA256
auth-nocache
verb 0
redirect-gateway def1
key-direction 1
EOF

cat < /etc/openvpn/makeuserconfig.sh
#!/bin/bash
if [ -z \${1} ]; then
echo "No podajże nazwę klienta chociaż. Na ten przykład: \${0} klient1 port protokół"
echo "\${0} klient1 1194 tcp"
exit 1
fi
REMOTE=ABC.DEF.GHI.JKL # TUTAJ WKLEJAMY ZEWNĘTRZNE IP SERWERA
klient=\${1}
port=\${2}
proto=\${3}
outdir="/etc/openvpn/configs/"
template="/etc/openvpn/user-skeleton.conf"

echo "remote \${REMOTE} \${port}" >  \${outdir}\${klient}-\${port}-\${proto}.conf
if [ "\${proto}" == "udp" ] || [ "\${proto}" == "UDP" ] ; then
echo "proto udp4" >>  \${outdir}\${klient}-\${port}-\${proto}.conf
else
echo "proto tcp4-client" >>  \${outdir}\${klient}-\${port}-\${proto}.conf
fi
cat \${template} >>  \${outdir}\${klient}-\${port}-\${proto}.conf
echo "" >>  \${outdir}\${klient}-\${port}-\${proto}.conf
cat /etc/openvpn/easyrsa/pki/ca.crt  >>  \${outdir}\${klient}-\${port}-\${proto}.conf
echo "" >>  \${outdir}\${klient}-\${port}-\${proto}.conf
echo ""  >>  \${outdir}\${klient}-\${port}-\${proto}.conf
cat /etc/openvpn/easyrsa/pki/issued/\${klient}.crt >>  \${outdir}\${klient}-\${port}-\${proto}.conf
echo "" >>  \${outdir}\${klient}-\${port}-\${proto}.conf
echo "" >>  \${outdir}\${klient}-\${port}-\${proto}.conf
cat /etc/openvpn/easyrsa/pki/private/\${klient}.key >>  \${outdir}\${klient}-\${port}-\${proto}.conf
echo "" >>  \${outdir}\${klient}-\${port}-\${proto}.conf
echo "" >>  \${outdir}\${klient}-\${port}-\${proto}.conf
cat /etc/openvpn/easyrsa/pki/easytls/tls-crypt.key >>  \${outdir}\${klient}-\${port}-\${proto}.conf
echo "" >>  \${outdir}\${klient}-\${port}-\${proto}.conf
EOF
chmod +x /etc/openvpn/makeuserconfig.sh

Oraz wygenerujmy konfiguracje dla dwóch klientów (klient1 oraz klient2):

/etc/openvpn/makeuserconfig.sh klient1 1194 TCP
/etc/openvpn/makeuserconfig.sh klient1 1194 UDP
/etc/openvpn/makeuserconfig.sh klient1 443 TCP
/etc/openvpn/makeuserconfig.sh klient2 1194 TCP
/etc/openvpn/makeuserconfig.sh klient2 1194 UDP
/etc/openvpn/makeuserconfig.sh klient2 443 TCP

Należy mieć na uwadze, że tutaj openvpn musi być uruchomiony z użytkownika, który posiada uprawnienia do zmiany tablicy routingu, co siłą rzeczy niesie ze sobą pewne ryzyko, dotyczące bezpieczeństwa takiego rozwiązania. Rozważyć należy zatem czy warto jest podejmować to ryzyko. W obecnym przykładzie demony OpenVPN startują jako użytkownik root, ale w celu podniesienia bezpieczeństwa zachęcam do stworzenia odrębnego użytkownika systemowego, na którego prawach będzie działał OpenVPN, a któremy to z kolei przyznamy prawa do edycji tablicy routingu, czy to za pomocą sudo czy też opowiednich capabilities. Poniżej przykład użycia rozwiązania opartego na użytkowniku "vpnmajster" z odpowiednim wpisem w sudoers.d/vpnmajster.

Utwórzmy użytkownika vpnmajster:

adduser --system --disabled-login --disabled-password --no-create-home vpnmajster

Następnie stwórzmy plik /etc/sudoers.d/vpnmajster z odpowiednimi uprawnieniami:

cat < /etc/sudoers.d/vpnmajster
vpnmajster ALL = NOPASSWD:/sbin/ip route add 192.168.168.[1-2][0-9][0-9]/32 dev tun-ovpntcp1194
vpnmajster ALL = NOPASSWD:/sbin/ip route add 192.168.168.[1-2][0-9][0-9]/32 dev tun-ovpnudp1194
vpnmajster ALL = NOPASSWD:/sbin/ip route add 192.168.168.[1-2][0-9][0-9]/32 dev tun-ovpntcp443
vpnmajster ALL = NOPASSWD:/sbin/ip route del 192.168.168.[1-2][0-9][0-9]/32
vpnmajster ALL = NOPASSWD:/sbin/ip route add 192.168.168.[1-9][0-9]/32 dev tun-ovpntcp1194
vpnmajster ALL = NOPASSWD:/sbin/ip route add 192.168.168.[1-9][0-9]/32 dev tun-ovpnudp1194
vpnmajster ALL = NOPASSWD:/sbin/ip route add 192.168.168.[1-9][0-9]/32 dev tun-ovpntcp443
vpnmajster ALL = NOPASSWD:/sbin/ip route del 192.168.168.[1-9][0-9]/32
vpnmajster ALL = NOPASSWD:/sbin/ip route add 192.168.168.[1-9]/32 dev tun-ovpntcp1194
vpnmajster ALL = NOPASSWD:/sbin/ip route add 192.168.168.[1-9]/32 dev tun-ovpnudp1194
vpnmajster ALL = NOPASSWD:/sbin/ip route add 192.168.168.[1-9]/32 dev tun-ovpntcp443
vpnmajster ALL = NOPASSWD:/sbin/ip route del 192.168.168.[1-9]/32
EOF
chmod 0440 /etc/sudoers.d/vpnmajster

Dodajmy stosowną linijkę do plików konfiguracyjnych serwera oraz zrestartujmy usługę openvpn:

echo "user vpnmajster" >> /etc/openvpn/server1194tcp.conf
echo "user vpnmajster" >> /etc/openvpn/server1194udp.conf
echo "user vpnmajster" >> /etc/openvpn/server443tcp.conf
systemctl restart [email protected]
systemctl restart [email protected]
systemctl restart [email protected]

Gotowe. Czyż życie nie staje się proste po przeczytaniu zagmatwanego opisu?


Dodaj komentarz

Szybki kontakt:

Pozostaw zółtą karteczkę-wlepkę pod adresem:
Kraków, ul. Pawia 3 z id: #776AFFDA# oraz wiadomością. Jak nie zginie -- odczytam.

Ostatnie fotografie


Paproć
Paproć

Grzyb
Grzyb

  Więcej...